diff --git a/AGENTS.md b/AGENTS.md index 63aa65a..3d578e9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,59 +2,87 @@ ## Project Overview -TypeScript ESM boilerplate. Runtime-only via `tsx`, no build step. +`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 +- **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 +- **Container**: Docker, node:24-alpine; docker-compose for postgres ## Structure ``` src/ -├── index.ts # entrypoint +├── 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 ` guard +├── routes/ +│ ├── health.ts # GET /health +│ ├── miniapp.ts # GET /miniapp (botfather stub) +│ └── sync.ts # GET/PUT /sync └── shared/ - └── config.ts # env config + └── config.ts # env config ``` -## Preferred Folder Structure +## Endpoints -``` -src/ -├── index.ts # entrypoint -├── shared/ # cross-cutting concerns (config, types, utilities) -└── lib/ # third-party wrappers, adapters -``` +- `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}`) -Expand based on project type as needed. Keep `src/index.ts` as the single entrypoint. +Auth header: `Authorization: tma `. Validation enforces hmac correctness and `auth_date` freshness. ## Conventions - ESM only (`"type": "module"`) -- Path alias `@/*` maps to `src/*` — imports must end with `.js` extension (nodenext resolution) +- 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` — check -- `pnpm lint:fix` — auto-fix +- `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` — console.log is allowed +- `no-console: off` - `antfu/no-top-level-await: off` - Stylistic: 2-space indent, single quotes - JSON key ordering enforced (auto-fixed) ## Docker -Single-stage, no build. Copies source, installs prod deps, runs via `pnpm start`. +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. diff --git a/eslint.config.mjs b/eslint.config.mjs index 05fa42e..290e93d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -6,9 +6,13 @@ export default antfu({ quotes: 'single', }, typescript: true, + // project uses node --test, not vitest + vitest: false, ignores: ['.omc', 'src/db/migrations'], rules: { 'no-console': 'off', 'antfu/no-top-level-await': 'off', + // project uses node --test, not vitest + 'test/no-import-node-test': 'off', }, }) diff --git a/package.json b/package.json index 9cdac06..7b1c15c 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "name": "boilerplate", + "name": "arcanesync-backend", "type": "module", "version": "0.1.0", "packageManager": "pnpm@10.13.1", - "description": "typescript esm boilerplate", + "description": "cloud sync backend for the arcanegram telegram client fork", "engines": { "node": ">=24.0.0" },