Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
- name: Typecheck
run: pnpm typecheck

# No-op until the frontend has a test script.
# Database tests start Postgres with Testcontainers, so they need Docker.
- name: Test
run: pnpm run --if-present test

Expand Down
17 changes: 17 additions & 0 deletions web/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,20 @@ This version has breaking changes — APIs, conventions, and file structure may
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->

## Data access

Domain modules in `src/lib/<domain>/` (starting with `reviews`) are the only way the app reads, validates, and writes that domain's data.

- Import a domain only through its entry points: `@/lib/<domain>` on the server, or `@/lib/<domain>/shared` from client components. Files behind them are internal.
- Name functions by what they do: `load*` reads the database, `fetch*` makes network calls, and `assert*` throws (or redirects) when an invariant doesn't hold.
- Let callers decide what to see through filters, such as `labelled: "include" | "exclude" | "only"`, rather than returning flags for callers to filter on.
- Report expected failures as typed reasons (`{ ok: false, reason }`) and map them to messages in the app, next to the UI that shows them.
- Database functions take an optional `signal: AbortSignal` and pass it to Kysely with `abortable(signal)`. Lookups that should be cheap default it to `AbortSignal.timeout(CHEAP_QUERY_TIMEOUT_MS)`.
- Validate input with Zod schemas exported from the domain's `shared` entry point.

## Tests

- Write a few focused tests that check behaviour people rely on, such as "only an account's newest review counts", not implementation details like the exact SQL or which helper was called.
- Test through a module's entry points, so tests survive refactors behind them.
- Prefer real dependencies over mocks: database tests run against Postgres with the real migrations (`setUpTestDatabase`, needs Docker). Fake only what's outside the system, such as a user's PDS.
6 changes: 5 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@atproto/api": "0.29.1",
"@atproto/lex": "0.3.14",
"@atproto/oauth-client-node": "0.5.11",
"@atproto/syntax": "0.7.7",
"@observablehq/plot": "0.6.17",
"@opentelemetry/api": "1.10.0",
"@opentelemetry/instrumentation-pg": "0.77.0",
Expand All @@ -41,10 +42,13 @@
"react-dom": "19.3.0",
"server-only": "0.0.1",
"xast-util-to-xml": "4.0.0",
"xastscript": "4.0.0"
"xastscript": "4.0.0",
"zod": "4.6.6"
},
"devDependencies": {
"@atproto/common-web": "0.5.15",
"@tailwindcss/turbopack": "4.3.3",
"@testcontainers/postgresql": "12.2.1",
"@types/d3-geo": "3.1.1",
"@types/geojson": "7946.0.16",
"@types/negotiator": "0.6.5",
Expand Down
Loading
Loading