first MVP

This commit is contained in:
Maxime Van Hees
2025-11-14 21:07:10 +01:00
parent 31327c9969
commit 4d024a39f4
26 changed files with 2729 additions and 64 deletions

115
DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,115 @@
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 ✔