arcanesync-server/AGENTS.md

88 lines
3.1 KiB
Markdown

# Agents
## Project Overview
`arcanesync` — cloud sync backend for the arcanegram telegram client fork. Authenticates every request via Telegram Mini App `initData` (HMAC-SHA256) and persists per-user sync state in postgres.
## Stack
- **Runtime**: Node 24+, tsx (no build step)
- **Package manager**: pnpm
- **HTTP**: Hono on `@hono/node-server`
- **DB**: PostgreSQL via `pg` + drizzle-orm; migrations via drizzle-kit
- **Linting**: @antfu/eslint-config v8 (eslint.config.mjs)
- **Env**: env-var + native `loadEnvFile`
- **Container**: Docker, node:24-alpine; docker-compose for postgres
## Structure
```
src/
├── index.ts # entrypoint — wires hono app, starts server
├── db/
│ ├── db.ts # pg pool + drizzle instance
│ ├── schema.ts # drizzle schema
│ ├── migrate.ts # migration runner (pnpm db:migrate)
│ └── migrations/ # generated sql
├── lib/
│ ├── initdata.ts # telegram initData hmac validator
│ └── initdata.test.ts
├── middleware/
│ └── auth.ts # `Authorization: tma <initData>` guard
├── routes/
│ ├── health.ts # GET /health
│ ├── miniapp.ts # GET /miniapp (botfather stub)
│ └── sync.ts # GET/PUT /sync
└── shared/
└── config.ts # env config
```
## Endpoints
- `GET /health` — liveness
- `GET /miniapp` — mini app stub registered with botfather
- `GET /sync` — auth required. returns `{version, data}`
- `PUT /sync` — auth required. body `{baseVersion, patch}`. 200 on accept, 409 on version conflict (returns current `{version, data}`)
Auth header: `Authorization: tma <initData>`. Validation enforces hmac correctness and `auth_date` freshness.
## Conventions
- ESM only (`"type": "module"`)
- Path alias `@/*``src/*` — imports must end with `.js` (nodenext resolution)
- No build step — tsx runs TS directly in dev and prod
- `cross-env` for cross-platform env vars in npm scripts
- No useless comments
- Split code into multiple files rather than monoliths
- Lowercase strings (errors, keys, log messages) where reasonable
## Commands
- `pnpm dev` — watch mode
- `pnpm start` — production run
- `pnpm lint` / `pnpm lint:fix`
- `pnpm test` — node:test runner via tsx
- `pnpm db:generate` — drizzle-kit generate
- `pnpm db:migrate` — apply migrations
- `pnpm db:studio` — drizzle studio
## Env
| var | default | meaning |
|---|---|---|
| `PORT` | `3000` | http port |
| `DATABASE_URL` | required | postgres dsn |
| `BOT_TOKEN` | required | telegram bot token (mini-app-enabled) |
| `AUTH_DATE_MAX_AGE_SECONDS` | `86400` | initData freshness window |
| `MAX_PAYLOAD_BYTES` | `65536` | per-PUT payload cap |
## Lint Rules
- `no-console: off`
- `antfu/no-top-level-await: off`
- Stylistic: 2-space indent, single quotes
- JSON key ordering enforced (auto-fixed)
## Docker
Single-stage `node:24-alpine`, no build. Copies source, installs prod deps, runs `pnpm db:migrate` then `pnpm start`. `docker-compose.yml` provides postgres for local dev.