Local tooling for the Project Manager / Admin Agent tool: a Dockerized Postgres database owned by Prisma, plus a local web admin (Fastify API + React) for CRUD over the data.
Quick start for the web admin:
docker compose up -d postgres→pnpm install→pnpm dev, then open http://localhost:5173. Full details in Web admin (Phase 2a).
| Component | Runs in | Role |
|---|---|---|
| PostgreSQL | Docker | Holds the application data. Schema is owned by Prisma. |
| Prisma | Host (pnpm) | Single owner of the schema and migrations. |
| Fastify API | Host (pnpm) | REST CRUD over all models via the Prisma client. Port 3001. |
| React + Vite | Host (pnpm) | Web admin UI. Port 5173, proxies /api to the API. |
host machine docker
┌────────────────────────┐ ┌───────────────────────────────┐
│ Prisma CLI / API / Vite │ ──────▶ │ postgres:16 (vol: postgres_data) │
│ (pnpm) │ :5432 │ │
└────────────────────────┘ └───────────────────────────────┘
Prisma, the Fastify API, and the Vite dev server all run on the host and
connect to Postgres via the published port 127.0.0.1:5432.
- Docker Desktop (Compose v2+)
- Node.js (tested with v24)
- pnpm (tested with v11)
# 1. Configure environment
copy .env.example .env # then edit POSTGRES_PASSWORD / DATABASE_URL
# (keep DATABASE_URL in sync with POSTGRES_*)
# 2. Install dependencies
pnpm install
# 3. Start Postgres, then create the database schema
docker compose up -d postgres
pnpm exec prisma migrate dev # applies migrations + generates the client
# 4. Start the web admin (API + Vite)
pnpm dev # then open http://localhost:5173| Task | Command |
|---|---|
| Start Postgres | docker compose up -d |
| Stop the stack (keep data) | docker compose down |
| Stop and wipe all data/volumes | docker compose down -v |
| Tail logs | docker compose logs -f |
| Service status / health | docker compose ps |
Prisma 7 reads its connection string from prisma.config.ts (which loads .env
via dotenv). The prisma-client generator emits the client to generated/prisma
(git-ignored).
| Task | Command |
|---|---|
| Create + apply a new migration (dev) | pnpm exec prisma migrate dev --name <change> |
| Apply existing migrations (CI / prod-style) | pnpm exec prisma migrate deploy |
| Check migration / drift status | pnpm exec prisma migrate status |
| Regenerate the client | pnpm exec prisma generate |
| Browse data in a local GUI | pnpm exec prisma studio |
Schema ownership: make all schema changes in
prisma/schema.prismaand migrate. Do not alter table structure from the admin UI (or any tool outside Prisma) — Prisma must stay the source of truth.
Seven models with createdAt / updatedAt on each:
- Capability — name, agent (
helpdesk|admin), description, status (live|beta|roadmap) - Customer — name, tier, pilotStage, owner, contractStatus, notes
- Meeting — → Customer, occurredAt, transcriptPath, attendees, summary
- Item — → Meeting (nullable), → Customer, type (
feedback|custom_req|interest|misc), rawText, interpretedText, → Capability (nullable), classification (standard|config|custom|roadmap|out_of_scope), status, priority, jiraKey, meta (JSON) - Todo — → Customer (nullable), → Item (nullable), description, status, due, owner
- Bottleneck — → Customer (nullable), description, severity, status, meta (JSON)
- Artifact — → Customer, type (
prd|spec|mmd), path, version
Relationships: a Customer has many Meetings, Items, Todos, Bottlenecks, Artifacts;
a Meeting has many Items; a Capability has many Items (via linkedCapability);
an Item has many Todos.
A local web admin for CRUD and navigation over the database. No auth, no LLM
features, no schema changes — it consumes the existing generated Prisma 7 client
(generated/prisma) via the @prisma/adapter-pg driver adapter, reading the same
DATABASE_URL from .env.
- Backend — Fastify (ESM + TypeScript, run with
tsx) athttp://127.0.0.1:3001. REST CRUD for all seven models under/api/<resource>(capabilities,customers,meetings,items,todos,bottlenecks,artifacts), plus/api/health. Customer-scoped lists accept?customerId=; items also accept?type=&classification=. - Frontend — React + Vite + TypeScript at
http://localhost:5173. Vite proxies/apito the backend, so there's no CORS and a single origin in the browser.
docker compose up -d postgres # database must be running
pnpm install # first time only
pnpm dev # starts BOTH the API (3001) and Vite (5173)Then open http://localhost:5173. (Run the API or web alone with pnpm dev:api
/ pnpm dev:web.)
Uses
127.0.0.1(notlocalhost) for the API host and the Vite proxy target, becauselocalhostresolves to IPv6 here and the services bind IPv4.
- Capabilities — global catalog, full CRUD.
- Customers — list; click a customer to open its detail view with tabs:
- Overview — customer fields (editable) + counts of related records.
- Meetings, Requirements (Items, filterable by type & classification, showing the linked Capability and Jira key), To-dos, Bottlenecks, Artifacts — full CRUD, each scoped to the selected customer.
server/ db.ts (Prisma + pg adapter) crud.ts (generic CRUD factory)
resources.ts (per-model config) index.ts (Fastify app)
web/ index.html src/ (main.tsx, api.ts, enums.ts, components/, pages/, pages/tabs/)
vite.config.ts tsconfig.json
postgres_data— application data (PostgreSQL).
This is a Docker-managed named volume. docker compose down -v removes it
(destroys all data).