# Spike

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

## Architecture

```
src/
├── server.tsx     — HTTP server (webhook endpoint, health check, error log)
├── config.ts      — Dev/prod environment config (DB paths, channel IDs, username mappings)
├── 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.

- **[gitea/](src/gitea/README.md)** — Pure Gitea API client and types. No side effects, no Discord, no DB.
- **[discord/](src/discord/README.md)** — Discord bot client, events, slash commands. Hands off to bridge for Gitea integration.
- **[bridge/](src/bridge/README.md)** — 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_ENV` — `production` or omit for dev
- `PORT` — Server port (default 3000)
