Mirror of https://github.com/roostorg/coop
github.com/roostorg/coop
1# AGENTS.md
2
3Instructions for AI coding agents working on Coop. `README.md` is for humans; this file is for machines. The nearest `AGENTS.md` to the edited file wins; explicit user prompts override everything.
4
5This file inherits from the ROOST community policy — read it once:
6- [ROOST community `AGENTS.md`](https://github.com/roostorg/community/blob/main/software-development-practices/agents.md) — pan-org agent rules (dependency approval, CI/CD approval, small diffs, PR standards).
7- [ROOST `CONTRIBUTING.md`](https://github.com/roostorg/.github/blob/main/CONTRIBUTING.md) — contribution standards (explainable, reviewable, digestible).
8
9## Architecture
10
11Four independent packages, **not an npm workspace** — each has its own `package.json` and lockfile:
12
13- `/` — root scripts, graphql-codegen, docker compose orchestration
14- `/server` — Express + Apollo GraphQL API (ESM, `"type": "module"`)
15- `/client` — React + Vite + Apollo Client frontend (Ant Design, TailwindCSS)
16- `/db` — migration runner for Postgres, ClickHouse, Scylla
17- `/migrator` — package and CLI tool for database migrations
18
19Node **24** (`.nvmrc`). Running on Node 20 produces `EBADENGINE` warnings and can fail native builds.
20
21Reference files: `README.md` (getting started), `server/bin/README.md` (utility scripts), `docs/` (architecture, ADRs).
22
23## Design
24
25- **API:** REST + GraphQL (Apollo Server); client uses Apollo Client with InMemoryCache; server resolvers live in `server/graphql/resolvers/`.
26- **GraphQL authoring:** Inline in resolver files with `/* GraphQL */` comment markers — codegen discovers queries this way. Searching for `gql` or `graphql` alone misses most of it.
27- **GraphQL codegen:** `npm run generate` (from root) regenerates `client/src/graphql/generated.ts` and `server/graphql/generated.ts`. **Never hand-edit** either `generated.ts`. **Never hand-merge** either `generated.ts` during a rebase/merge — pick one side with `git checkout --ours|--theirs <file>`, then run `npm run generate`. Hand-merging produces output that parses but drifts from the schema.
28- **Data model:** Use Knex query builder for Postgres; ClickHouse via raw SQL in `server/clickhouse/`; Scylla via Cassandra driver.
29- **Dependency injection:** Server uses BottleJS DI (wired in `server/iocContainer/`). Register services in `iocContainer`, don't export singletons from service files. Consumers receive dependencies via DI rather than importing directly. Bypassing `iocContainer` will work at runtime but breaks test mocking patterns.
30
31## Build and run
32
33Prerequisites: Node 24 (`.nvmrc`), Docker + Docker Compose v2, 8 GiB RAM recommended (running an instance requires 4 GiB, the rest will be used by development tools).
34
35```bash
36# Start backing services (Postgres, ClickHouse, Scylla, Redis)
37npm run up
38
39# Install dependencies in all packages
40npm install
41(cd client && npm install)
42(cd server && npm install)
43(cd db && npm install)
44
45# Populate .env files for /server and /db, then run migrations
46npm run db:update -- --env staging --db api-server-pg
47npm run db:update -- --env staging --db scylla
48npm run db:update -- --env staging --db clickhouse
49
50# Create organization and admin user
51npm run create-org
52
53# Start dev servers (separate terminals recommended)
54npm run client:start # React dev server
55npm run server:start # Express + GraphQL API
56npm run generate:watch # (optional) watch GraphQL changes
57```
58
59Client: http://localhost:3001 · Server: http://localhost:3000
60
61## Testing
62
63Integration tests spin up services via docker compose. Unit tests run in-process.
64
65```bash
66# Run all tests (via docker compose)
67docker compose run --rm test
68
69# Server unit tests (no Docker)
70(cd server && npm test)
71
72# Client unit tests (no Docker)
73(cd client && npm test)
74```
75
76Lint / format / type-check (no Docker needed):
77
78```bash
79npm run lint # lint all packages
80npm run format # format all packages
81(cd server && npm run lint)
82(cd client && npm run lint)
83```
84
85If tests fail with database errors, check migration logs via `docker compose logs migrations`.
86
87## CI
88
89CI runs entirely via GitHub Actions (`.github/workflows/apply_pr_checks.yaml`). All PR checks are defined as `docker compose` services so you can reproduce any CI job locally. Run them in your shell (paste-as-is — each command's exit code matches the corresponding CI step's exit code):
90
91```bash
92docker compose run --rm codegen-check
93docker compose run --rm backend npm run lint
94docker compose run --rm backend npm run build
95docker compose run --rm client npm run lint
96docker compose run --rm client npm run build
97docker compose run --rm test
98```
99
100Individual checks:
101
102| CI job | Local command |
103| --- | --- |
104| `check_generated_graphql` | `docker compose run --rm codegen-check` |
105| `check_api_server` (lint) | `docker compose run --rm backend npm run lint` |
106| `check_api_server` (build) | `docker compose run --rm backend npm run build` |
107| `run_frontend_checks_if_changed` (lint) | `docker compose run --rm client npm run lint` |
108| `run_frontend_checks_if_changed` (build) | `docker compose run --rm client npm run build` |
109| `check_api_server` (test) | `docker compose run --rm test` |
110
111Tear down:
112
113```bash
114docker compose down # stop containers, keep DB volumes
115docker compose down -v # also drop DB volumes (fresh DBs next run)
116```
117
118Note: `check_migration_order` runs only in GitHub Actions — it's GitHub-specific and not needed locally. When adding a migration, use `date -u +"%Y.%m.%dT%H.%M.%S"` for the filename prefix.
119
120## Security
121
122- No secrets in code or committed files. Use environment variables via `.env` (gitignored).
123- Do not disable lint or type rules to silence errors. Fix the underlying issue, or use a narrowly-scoped `// eslint-disable-next-line <rule>` / `// @ts-expect-error` with a comment explaining why.
124- Before adding a new dependency, check it for known CVEs and confirm the license is compatible with `LICENSE` (Apache 2.0).
125- Default Docker bindings are `127.0.0.1`; do not change bind addresses without explicit instruction.
126
127## Code review
128
129- Keep diffs small and focused; split unrelated changes into separate PRs.
130- PR titles are descriptive and imperative ("Add X", "Fix Y").
131- New behavior requires a test. Bug fixes require a regression test.
132- All CI checks (above) must pass before requesting review.
133
134## Code style
135
136- **TypeScript:** ESLint + Prettier (configs in `.eslintrc.cjs` and `.prettierrc` per package). Run `npm run lint` and `npm run format` from root.
137- **Naming:** Use camelCase for variables/functions; PascalCase for components/classes; SCREAMING_SNAKE_CASE for constants.
138- **GraphQL:** Type-safe resolvers and queries via codegen; never hand-edit `generated.ts`.
139- **Imports:** Absolute imports configured via `tsconfig.json` paths; prefer `@/` prefix over relative paths where configured.
140
141## Dependencies
142
143- Dependencies are declared in each package's `package.json` and locked in `package-lock.json`. Add with `npm install --save <pkg>` and commit the updated lockfile.
144- Every new or upgraded package including transitive dependencies requires human approval. Confirm the license is compatible with `LICENSE` (Apache 2.0) and that there are no known CVEs.
145- Same conflict-resolution rule applies to any `package-lock.json`: take one side with `git checkout --ours|--theirs <file>`, then run `npm install` in that package to reconcile.
146
147**Install gotchas:**
148
149CI runs `npm ci` from root. If `npm ci` hits `ERESOLVE` in any package, the lockfile has drifted from `package.json` — regenerate it against a known-good base:
150
151```bash
152git checkout main -- <pkg>/package-lock.json
153(cd <pkg> && npm install)
154```
155
156**Do not reach for `--legacy-peer-deps`** as a fix — it papers over real peer violations and CI's `npm ci` will fail on the next agent's machine.
157
158## Codespaces
159
160Two things differ from a local dev setup:
161
1621. **Use the production client build**, not the vite dev server: `(cd client && npm run build)`, then `npm run server:start` serves the built assets. Vite's HMR websocket does not reliably traverse the Codespace port proxy.
1632. **Apollo's GraphQL URI must be relative** (`/api/v1/graphql`). Hard-coded `http://localhost:3000/...` breaks because the Codespace proxies to a different host. Source of truth is the `HttpLink` in `client/src/index.tsx`.
164
165## ROOST guiding principles
166
167- **Commands over prose.** Prefer `docker compose run --rm test` over descriptive paragraphs.
168- **Same review bar.** PRs authored with agent assistance are held to the same standards as any other PR.
169- **Boundaries with alternatives.** When stating a restriction, provide the alternative path (e.g. don't edit `generated.ts` — regenerate via `npm run generate`).
170- **Iterate over time.** Start minimal. When you give an agent the same instruction twice, add it to this file.
171- **Contributors update `AGENTS.md`.** When you find a gap, update this file as part of your PR.
172
173## Human-approval-required actions
174
175Stop and get explicit human approval before:
176
177- Changing license headers, copyright notices, or any legal text (including `LICENSE`).
178- Modifying release, signing, or deploy workflows: `.github/workflows/publish-*.yaml`, production Dockerfiles (`Dockerfile`, `client/Dockerfile`), `docker-compose.yaml`, or `package.json` `"scripts"` that affect deployment.
179- Database migrations — anything added under `db/src/scripts/<service>/` runs against real data. Confirm schema design and rollback story with a maintainer ensure to use CURRENT_USER to support any user on postgres.
180- Deleting or renaming an existing GraphQL type or field — this breaks cached Apollo client state and any downstream consumer. Additive changes are usually safe; removals need a migration plan.
181- Rewiring `server/iocContainer` in a way that changes service lifecycles or startup order — cascading effects on tests and boot.
182- Auth, session, or request middleware (under `server/api.ts`) — security-sensitive; prefer a small, reviewable PR with explicit callouts.
183- Adding, removing, or upgrading any library or package (including transitive dependencies in `package-lock.json`) — confirm licenses are compatible with Apache 2.0 and that there are no known CVEs.
184- Multi-thousand-line diffs — ROOST policy is that reviewers can digest the change. Split into reviewable PRs; regenerated codegen and lockfile bumps are the only exceptions.
185
186## Commit attribution
187
188Agent-authored commits should include a `Co-Authored-By` trailer naming the agent, e.g.:
189```
190Co-Authored-By: <agent-name>
191```
192Coop is open source and contributions flow upstream; attribution matters for maintainer trust.
193
194## Don't
195
196- Hand-merge `generated.ts` or lockfiles.
197- Install with `--legacy-peer-deps` as a workaround.
198- Commit `.env`, credentials, or API keys.
199- Bypass `iocContainer` by importing server singletons directly.
200- Silently modify a migration file that has already been applied to a shared environment — add a new forward migration instead.