Files
boat/DEVELOPMENT.md
Maxime Van Hees 4d024a39f4 first MVP
2025-11-14 21:07:10 +01:00

116 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Boat — Local Development Runbook
This runbook explains how to run the Boat MVP locally, seed demo data, and troubleshoot common issues.
Project layout highlights
- [app.page()](src/app/page.tsx:1) — Graph landing page that fetches /api/graph and renders the Cytoscape graph
- [components/Graph.tsx](src/components/Graph.tsx:1) — Cytoscape wrapper with zoom/pan, fit, and selection details
- [components/PersonForm.tsx](src/components/PersonForm.tsx:1) — Create person form
- [components/PeopleSelect.tsx](src/components/PeopleSelect.tsx:1) — Typeahead selector against /api/people
- [components/ConnectionForm.tsx](src/components/ConnectionForm.tsx:1) — Create connection form with ordered introducer chain
- [app.people.new.page()](src/app/people/new/page.tsx:1) — Page for adding a person
- [app.connections.new.page()](src/app/connections/new/page.tsx:1) — Page for adding a connection
- [api.people.route()](src/app/api/people/route.ts:1), [api.people.id.route()](src/app/api/people/[id]/route.ts:1) — People API
- [api.connections.route()](src/app/api/connections/route.ts:1), [api.connections.id.route()](src/app/api/connections/[id]/route.ts:1) — Connections API
- [api.graph.route()](src/app/api/graph/route.ts:1) — Graph snapshot API
- [lib.db()](src/lib/db.ts:1) — Prisma client singleton
- [lib.validators()](src/lib/validators.ts:1) — Zod schemas
- [prisma.schema()](prisma/schema.prisma:1) — Data model
- [prisma.migration.sql](prisma/migrations/20251114191515_connection_pair_constraints/migration.sql:1) — Undirected uniqueness + self-edge constraints
- [prisma.seed()](prisma/seed.ts:1) — Seed script for 20 demo people and ~30 connections
Prerequisites
- Docker (to run local Postgres quickly)
- Node 20+ and npm
1) Start Postgres (Docker)
If you havent yet started the Docker Postgres container, run:
- docker volume create boat-pgdata
- docker run -d --name boat-postgres -p 5432:5432 -e POSTGRES_DB=boat -e POSTGRES_USER=boat -e POSTGRES_PASSWORD=boat -v boat-pgdata:/var/lib/postgresql/data postgres:16
Verify its running:
- docker ps | grep boat-postgres
2) Environment variables
This repo already includes [.env](.env:1) pointing to the Docker Postgres:
DATABASE_URL="postgresql://boat:boat@localhost:5432/boat?schema=public"
3) Install deps and generate Prisma Client
From the app directory:
- npm install
- npx prisma generate
4) Migrate the database
- npx prisma migrate dev --name init
- npx prisma migrate dev (if new migrations were added)
Note: Constraints for undirected uniqueness and self-edges are included in [prisma.migration.sql](prisma/migrations/20251114191515_connection_pair_constraints/migration.sql:1).
5) Seed demo data (20 people)
- npm run db:seed
This executes [prisma.seed()](prisma/seed.ts:1) and inserts people and connections.
6) Run the Next.js dev server
Important: run from the app directory, not workspace root.
- npm run dev
Access:
- http://localhost:3000 (or the alternate port if 3000 is busy)
7) Using the app
- Landing page shows the global graph
- Toolbar buttons:
- Add Person → [app.people.new.page()](src/app/people/new/page.tsx:1)
- Add Connection → [app.connections.new.page()](src/app/connections/new/page.tsx:1)
- Reload — refetches data for the graph
- Click nodes or edges to show details in the side panel
8) API quick tests
- List people:
- curl "http://localhost:3000/api/people?limit=10"
- Create person:
- curl -X POST "http://localhost:3000/api/people" -H "Content-Type: application/json" -d '{"name":"Jane Demo","sectors":["agriculture"]}'
- Create/update connection (undirected):
- curl -X POST "http://localhost:3000/api/connections" -H "Content-Type: application/json" -d '{"personAId":"<idA>","personBId":"<idB>","introducedByChain":[],"eventLabels":["event:demo"]}'
Troubleshooting
A) “npm enoent Could not read package.json at /home/maxime/boat/package.json”
- You ran npm in the workspace root. Use the app directory:
- cd boat-web
- npm run dev
B) “Unable to acquire lock … .next/dev/lock”
- Another Next dev instance is running or a stale lock exists.
- Kill dev: pkill -f "next dev" (Unix)
- Remove lock: rm -f .next/dev/lock
- Then: npm run dev
C) “Failed to load external module @prisma/client … cannot find module '.prisma/client/default'”
- Prisma client must be generated after schema changes or misconfigured generator.
- Ensure generator in [prisma.schema()](prisma/schema.prisma:7) is:
generator client { provider = "prisma-client-js" }
- Regenerate: npx prisma generate
- If still failing, remove stale output and regenerate:
- rm -rf node_modules/.prisma
- npx prisma generate
D) Port 3000 already in use
- Run on a different port:
- npm run dev -- -p 3001
Tech notes
- The undirected edge uniqueness is enforced via functional unique index on LEAST/GREATEST and a no-self-edge CHECK in [prisma.migration.sql](prisma/migrations/20251114191515_connection_pair_constraints/migration.sql:1).
- Deleting a person cascades to connections (MVP behavior).
- Sectors, interests, and eventLabels are free-text arrays (TEXT[]).
- Introduced-by chain is an ordered list of person IDs (existing people only).
- UI intentionally minimal and open as per MVP brief.
Acceptance checklist mapping
- Create person: [api.people.route()](src/app/api/people/route.ts:1) + [PersonForm.tsx](src/components/PersonForm.tsx:1) ✔
- Create connection: [api.connections.route()](src/app/api/connections/route.ts:1) + [ConnectionForm.tsx](src/components/ConnectionForm.tsx:1) ✔
- Global graph view: [api.graph.route()](src/app/api/graph/route.ts:1) + [Graph.tsx](src/components/Graph.tsx:1) ✔
- Persistence: Postgres via Prisma ✔