5.0 KiB
Development Guide
Prerequisites
- Node.js >= 24
- pnpm >= 9
- Docker
First-time Setup
pnpm setup
This creates server/.env from the example, installs all dependencies, starts PostgreSQL, runs migrations, and seeds baseline data.
If you prefer to do it manually:
pnpm run db:up # start PostgreSQL
cp server/.env.example server/.env # first time only
pnpm install
pnpm run db:migrate
pnpm run db:seed
Running the App
pnpm dev
Starts the server and client concurrently with hot reload.
| Service | URL |
|---|---|
| API | http://localhost:3000/api |
| Client | http://localhost:5173 |
If PostgreSQL stopped (e.g. after a machine restart):
pnpm run db:up # then pnpm dev
Database Workflows
Apply pending migrations
After pulling changes that include new migrations:
pnpm run db:migrate
Add a schema change
- Edit the relevant file in
server/src/db/schema/ - Generate a migration:
This creates a new SQL file in
cd server && pnpm db:generate add-book-tagsserver/src/db/migrations/. Review it before applying. - Apply it:
pnpm run db:migrate
Pre-launch rule: Before the app ships, maintain a single baseline migration (
0000_*.sql) rather than stacking incremental ones. When adding a schema change pre-launch:rm -rf server/src/db/migrations docker compose -f docker-compose.dev.yml down -v pnpm run db:up cd server && pnpm db:generate baseline pnpm run db:migrateAfter go-live, never wipe migrations. Every change gets its own incremental migration.
Full database reset
Wipes all data, re-runs migrations, re-seeds, and clears generated files (covers, author images):
pnpm run db:reset
Use this when:
- Migrations are in a broken or inconsistent state
- A migration requires starting from scratch (e.g. column type change with no clean upgrade path)
- You want a known-clean local state
Inspect the database
cd server && pnpm db:studio
Opens Drizzle Studio in your browser for browsing and editing tables directly.
Testing
pnpm run test # all tests (server + client)
pnpm run test:server # server unit tests only
pnpm run test:client # client unit tests only
pnpm run test:e2e:smoke # e2e smoke suite (requires running DB)
pnpm run test:e2e:scanner # scanner e2e suite (uses dedicated projectx_e2e DB)
pnpm run test:e2e:scanner:file-ops # scanner file operation e2e suite
Watch mode while working on a specific area:
cd server && pnpm test:watch
Scanner e2e details
pnpm run test:e2e:scannerprepares and migrates a dedicated e2e database (projectx_e2e) on each run.- Local runs auto-start PostgreSQL with
docker-compose.dev.ymlif needed. - Results are written to
test-results/server/:scanner-e2e-junit.xmlscanner-e2e-scenarios.json
Scanner file operation e2e details
pnpm run test:e2e:scanner:file-opsprepares and migrates the same dedicated e2e database (projectx_e2e) before running.- Local runs auto-start PostgreSQL with
docker-compose.dev.ymlif needed. - Results are written to
test-results/server/:scanner-file-ops-e2e-junit.xmlscanner-file-ops-e2e-scenarios.json
Scanner e2e in CI (manual)
- Open GitHub Actions and run the Scanner E2E workflow manually (
workflow_dispatch). - The workflow runs the full scanner scenario matrix against a service-container Postgres instance.
- It uploads
test-results/server/as an artifact and publishes JUnit annotations.
Scanner file operation e2e in CI
- Open GitHub Actions and run the Scanner File Ops E2E workflow manually (
workflow_dispatch) or wait for the nightly run. - The workflow runs the full file operation matrix against a service-container Postgres instance.
- It uploads
test-results/server/as an artifact and publishes JUnit annotations.
Code Quality
Run before pushing:
pnpm run verify:fast # lint + typecheck + tests (same as pre-push hook)
pnpm run verify # above + e2e smoke (run before opening a PR)
Individual checks:
pnpm run lint:check # check for lint errors
pnpm run lint:fix # auto-fix lint errors
pnpm run typecheck # server + client baseline typecheck
pnpm run typecheck:full # server + full client typecheck (slower)
Format:
cd server && npx prettier --write .
cd client && npx prettier --write .
Common Scenarios
Pulled changes that include a new migration
pnpm run db:migrate
Pulled changes that changed the DB schema significantly and your local state is stale
pnpm run db:reset
Something is wrong and you want a completely clean slate
pnpm run db:reset
If that is not enough (e.g. Docker volume is corrupted):
docker compose -f docker-compose.dev.yml down -v
pnpm run db:up
pnpm run db:migrate
pnpm run db:seed