workshop/packages/spike/CLAUDE.md
Corey Johnson 04aa7c1c91 Add typed event logging system and restructure server
Implement a centralized logging system with typed events (webhook, PR, comment, review, Discord relay, errors, etc.) that feeds a pub/sub pattern. Events are logged to console (with ANSI colors: green=normal, yellow=skipped, red=errors, cyan=PR#) and persisted to JSONL files organized by git commit SHA.

Restructure server code into src/server/ directory with separate route handlers. Add a new /logs endpoint with an HTML viewer that displays events in a searchable table with type/repo filtering and browser timezone conversion. Remove the old /errors endpoint.

Improvements:
- All webhook handlers, Discord events, and errors now use log() instead of console.* calls
- Error objects are properly serialized to JSONL (message + stack extracted)
- Path traversal vulnerability fixed in readLogFile()
- Failed API calls and caught errors are now always logged
- Graceful error handling with fallbacks where appropriate (e.g., missing Discord users)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-10 08:58:47 -07:00

2.3 KiB

Spike

Discord-Gitea bridge bot. Syncs PRs, comments, and code reviews between a Gitea server (git.nose.space) and Discord.

Architecture

src/
├── server/        — HTTP server, routes, and web pages (logs viewer, auth)
├── config.ts      — Dev/prod environment config (DB paths, channel IDs, username mappings)
├── log.ts         — Typed event logging (pub/sub, console + JSONL file listeners)
├── discord/       — Discord bot client, event listeners, slash commands
├── gitea/         — Gitea API calls, types, username conversion
└── bridge/        — Wiring between Gitea and Discord (webhook handler, DB, Discord helpers)

Dependencies flow one way: bridge/ → gitea/, bridge/ → discord/. Neither gitea/ nor discord/ imports from the other.

Libs

Each directory with an index.ts barrel is a standalone lib. Read the lib's README for its public API — you don't need to read internals to use it.

  • server/ — HTTP server, webhook route, log viewer page, auth page.
  • gitea/ — Pure Gitea API client and types. No side effects, no Discord, no DB.
  • discord/ — Discord bot client, events, slash commands. Hands off to bridge for Gitea integration.
  • bridge/ — The glue. Webhook handler, Discord helpers, SQLite DB for ID mappings.

Import rules:

  • External code imports from the barrel only: import { handleGiteaWebhook } from "./bridge"
  • Never reach into internal files: import { handleGiteaWebhook } from "./bridge/webhook-handler"
  • Internal files within a lib can import from each other freely

This keeps AI context small. When working on code that uses a lib, only read the lib's README — not every internal file.

Running

  • bun run subdomain:dev — Start with hot reload
  • bun run subdomain:start — Start for production
  • bun test — Run integration tests (requires Tailscale funnel + test env vars)

Environment Variables

  • DISCORD_TOKEN — Discord bot token
  • DISCORD_CLIENT_ID — Discord application client ID
  • GITEA_API_TOKEN — Gitea API token
  • DATA_DIR — Data directory (prod only)
  • NODE_ENVproduction or omit for dev
  • PORT — Server port (default 3000)