An auditable, AI-assisted program digital-thread platform for complex hardware-and-software delivery programs. It connects requirements, schedules, costs, risks, testing, logistics, suppliers, and field feedback, and uses AI to identify cross-program impacts and propose evidence-backed mitigation options — while keeping human approval, traceability, and source attribution mandatory at every step.
All program, supplier, and personnel data in this repository is fictional, synthetic, and unclassified. Nothing here references a real employer, program, customer, classified system, or export-controlled detail.
Phase 3 of 8 (Core workflow UI) — complete. Workspaces, database
schema, deterministic seed data, authentication, the full deterministic
program-analysis service layer (packages/core/src/analysis), and a real
database-driven dashboard, program overview, event-entry form, and
read-only audit shell all exist and are verified working. A Program
Manager can record a supplier-delay or general-update event today, which
is written transactionally with a matching audit entry — but nothing
analyzes it yet: there is still no AI layer, no mitigation options, and no
approval/apply workflow; see Phase roadmap and
Limitations below.
Development follows a phase-gated process defined in
PROJECT_GUIDE.md and docs/SPEC.md:
one phase is authorized and built at a time, each with its own quality gate.
docs/TASKS.md tracks detailed, resumable status, and
docs/DECISIONS.md records why non-obvious choices were
made.
The MVP is built around one protected end-to-end path, in this order of
priority (see docs/SPEC.md §18 for the full cut list if scope needs to
shrink):
event → deterministic analysis → bounded AI interpretation →
three mitigation options → approval → apply preview → audit
Every normal calculation (schedule exposure, budget exposure, risk scoring, readiness) is deterministic code, never an LLM guess. The AI layer only explains evidence and proposes options — it can never mutate program data, approve anything, or apply a change.
npm workspaces monorepo:
apps/web Next.js App Router UI, route handlers, server actions
(dashboard, program overview, event entry, audit — Phase 3, done)
packages/core Zod schemas, deterministic services (Phase 2, done),
event-entry contract + recordProgramEvent (Phase 3, done),
Prisma schema/client, AI evidence builder, mock
fixtures (Phase 4)
packages/mcp-server Read-only MCP server (placeholder — built in Phase 7)
docs/ Spec, plans, tasks, decisions, architecture, threat model
evals/ AI pipeline evaluations (Phase 6)
Prisma's schema is centralized in packages/core/prisma — both apps/web
and the future packages/mcp-server read the database only through
packages/core, so there is a single source of truth for the data model.
Full request/data flow and the Prisma domain model are documented in
docs/ARCHITECTURE.md.
- Next.js (App Router) + React + TypeScript (strict mode)
- PostgreSQL + Prisma ORM (driver adapter:
@prisma/adapter-pg) - Auth.js v5 (Credentials provider, JWT sessions)
- Zod for all external input/output validation
- Tailwind CSS
- Vitest (unit tests); Playwright (Phase 5+)
- Docker Compose (local Postgres); GitHub Actions (CI)
- Structured JSON logging (Phase 4+)
- nvm (or another way to get exactly Node 24.x)
- Docker Desktop (or another Docker Compose–compatible runtime)
- npm (ships with Node)
This project pins Node 24.x (Active LTS). The exact patch is recorded in
.nvmrc.
Node 25 is an odd-numbered major that never received LTS and is now EOL; this project targets Node 24 (Active LTS). Don't develop or build against Node 25 even if it happens to be your system default.
nvm install
nvm usegit clone <this-repo>
cd Mission-Thread-AI
nvm use
npm installEnvironment files live at the repo root, not per-package.
cp .env.example .env
cp .env.test.example .env.testGenerate a real AUTH_SECRET for .env locally (the example file ships
with a placeholder):
npx auth secretapps/web (Next.js) only reads .env/.env.local from its own directory,
so link the root file into place once:
ln -s ../../.env apps/web/.envThe Postgres container is mapped to host port 55432, not 5432 — this
avoids colliding with a Postgres you might already have running locally
(see docs/DECISIONS.md). One container hosts two logical databases:
missionthread_dev and missionthread_test.
Safe, non-destructive setup and validation:
npm run db:up # start Postgres (docker compose up -d postgres)
npm run db:generate # generate the Prisma client
npm run db:validate # validate the Prisma schema
npm run db:migrate # apply migrations to missionthread_devSeeding is destructive — it clears every row in the target database
before recreating the deterministic fixtures, so it requires a
deliberately named, target-specific command rather than a plain db:seed:
npm run db:seed:dev:destructive # clears and reseeds missionthread_dev — nothing elseThis works via a shared guard (packages/core/src/db-safety.ts) that only
authorizes an exact, approved (host, port, database) target — never a
name that merely looks right — for an explicitly declared scope (dev
here), and only for the one child process this command spawns; see
.env.example for why the authorization flag itself is never checked into
any example file. The scope is never inferred from DATABASE_URL: a
dev-scoped run can't touch the test database even if DATABASE_URL
were ever misconfigured to point at it, and vice versa.
Integration tests must never run against the dev database. The reset
script only authorizes an exact approved local test target
(localhost:55432/missionthread_test or 127.0.0.1:55432/missionthread_test)
— not merely a database name containing "test":
npm run db:reset:test # drops, re-migrates, and reseeds missionthread_test onlyCI uses a third, separate command (db:seed:github-actions:internal) that
only authorizes the GitHub Actions service database and only runs inside
an actual GitHub Actions job — it's not a normal local-development command
and shouldn't be run by hand.
npm run devVisit http://localhost:3000 — you'll be redirected to /login.
Seeded by npm run db:seed:dev:destructive, one per role. The password below is a fixed,
publicly documented local-development-only credential, not a real
secret — it authenticates against your own local database only.
| Role | |
|---|---|
pm@missionthread.example |
Program Manager |
lead@missionthread.example |
Engineering Lead |
exec@missionthread.example |
Executive Viewer |
Password for all three: MissionThread-Demo-2026!
Build the application image:
docker build -t missionthread-ai .prisma generate runs during the build with a non-secret, unreachable
placeholder DATABASE_URL (it never opens a connection at build time —
see the Dockerfile's comment); the real database configuration is supplied
entirely at container runtime, via docker run's -e flags or your
deployment platform's environment configuration, never baked into the
image.
A container cannot reach the host's Docker Compose Postgres through its
own localhost — that would resolve inside the container, not on your
machine. Use Docker Desktop's host.docker.internal address instead:
docker run --rm -p 3000:3000 \
-e DATABASE_URL="postgresql://missionthread:missionthread_local_dev_password@host.docker.internal:55432/missionthread_dev" \
-e AUTH_SECRET="<generate one with: npx auth secret>" \
-e AUTH_TRUST_HOST=true \
-e AI_MODE=mock \
missionthread-aiRequired runtime variables: DATABASE_URL, AUTH_SECRET, AI_MODE=mock,
and AUTH_TRUST_HOST=true (or an explicit AUTH_URL) — Auth.js v5 rejects
requests with an untrusted Host header by default, which a container
behind a mapped port will otherwise trigger. Visit http://localhost:3000/login
once the container is up.
docker-compose.yml currently defines only the Postgres service, not an
application container — the command above talks to that same Compose
Postgres instance from outside Docker's internal network.
npm run lint # ESLint across all workspaces
npm run format:check # Prettier check
npm run format # Prettier write
npm run typecheck # tsc --noEmit across all workspaces
npm run test # Vitest unit tests (packages/core)
npm run build # production build of apps/web
npm run smoke:test # build + automated end-to-end smoke testsmoke:test builds the production app, then runs
apps/web/scripts/smoke-test.mjs against it, always pointed at the
dedicated test database (loaded from .env.test, never the dev database —
see the script's own comment for why). It exercises the full auth flow:
unauthenticated redirects to /login (verifying both the redirect status
and the actual destination), invalid credentials failing safely, valid
seeded credentials authenticating, session contents (user ID and role),
the authenticated dashboard rendering real seeded data, protected nav
routes, and sign-out actually invalidating the session — run against the
dedicated test database, never the dev database. The exact number of
checks isn't documented here since it isn't maintained from one
authoritative source; read apps/web/scripts/smoke-test.mjs for the
current, complete list.
All of the above are run in CI (.github/workflows/ci.yml) with
AI_MODE=mock, so the pipeline never needs a live model API key.
/login— Credentials sign-in (Zod-validated, scrypt +timingSafeEqualpassword verification, JWT session)./— Executive dashboard: readiness score with factor breakdown, requirement/verification-gap/milestone/risk/defect counts, budget planned/actual/variance, latest supplier-delay schedule exposure, and recent events — all from the Phase 2 deterministic services and real Postgres data. A failed calculation shows an explicit "unavailable" state, never an invented0./programs/edgelink-x— full program overview: components, requirements with component traceability and verification-gap status, milestones, dependency relationships, risk register, test outcomes, open defects, budget items and variance, suppliers, and recent events (submitted supplier notes are clearly labeled as untrusted content and rendered as plain text, never HTML)./programs/edgelink-x/events/new— Program Manager only. Records aSUPPLIER_DELAYorGENERAL_UPDATEevent. Server-side validated, authorized, and written transactionally with a matchingEVENT_RECORDEDaudit entry — see "Security and authorization" below. A non-manager is redirected away before the form renders, and the underlying mutation independently rejects a non-manager role regardless./audit— read-only, filterable audit history (action, actor type, target type, trace ID — each validated against a fixed allowlist), newest first, capped at 50 rows.
Nothing beyond event intake and its audit trail is wired up yet — there is no AI analysis, no mitigation options, and no approval/apply workflow in this phase.
- Passwords are hashed with Node's
crypto.scrypt(OWASP-recommended parameters) and verified withcrypto.timingSafeEqual; seepackages/core/src/auth/password.ts. - Sessions use Auth.js v5 with the JWT strategy explicitly (no database session/Account/VerificationToken models — unnecessary for a Credentials-only setup).
- All input to the Credentials provider is validated with Zod before it touches the database.
- Authorization is enforced server-side on the one mutation that exists so
far (
recordProgramEvent(), event entry): it re-fetches the actor's current role from the database on every call, never trusting a session/JWT claim that could be stale. UI role-gating (hiding the "Record event" link, redirecting a non-manager away from the event-entry page) is a convenience only, never treated as sufficient on its own — seedocs/DECISIONS.md, "Mutation authorization." No Next.js middleware/proxy is used for auth in this phase —auth()is called directly in server layouts and pages, which keeps Prisma andnode:cryptoout of the Edge runtime entirely.
Not built yet (Phase 4). The eventual design: an LLMProvider interface
with a deterministic mock mode (no API key, used in CI and demos) and
an optional live mode (one provider adapter, server-only secret,
validated output with exactly one retry on failure). See docs/SPEC.md §9–10.
- Phase 1–3 build. The deterministic program-logic services
(traceability, dependency chains, verification gaps, related defects,
schedule/budget exposure, risk scoring, readiness scoring, bounded
evidence assembly) exist in
packages/core/src/analysis, and a real dashboard, program overview, event-entry form, and audit shell now call them against live Postgres data. Event intake is the only mutation that exists — there is still no AI pipeline, no mitigation options, and no approval/apply workflow (Phase 4+). next-authis on the v5 beta channel (5.0.0-beta.31) — it's the version Auth.js's own docs currently recommend for the App Router, but it is pre-1.0 and could introduce breaking changes on upgrade.- In-memory rate limiting (Phase 6+) will be single-process only — not suitable for a horizontally scaled deployment, and will be documented as such when built.
- Audit append-only-ness (Phase 5+) is enforced at the application layer only — no update/delete route will exist, but this is not cryptographic immutability.
- Three known moderate npm audit advisories exist in transitive
dev-tooling dependencies (an optional nested
@prisma/dev→ old@hono/node-server, and Next's internally bundledpostcsscopy). Both suggested "fixes" would downgrade Prisma or Next to old/breaking versions, which is a worse trade than the advisories themselves; tracked for revisiting as upstream releases land. - No production cloud infrastructure, Kubernetes, queues, or public signup
— intentionally out of scope for this MVP (
docs/SPEC.md§3).
| Phase | Scope |
|---|---|
| 0 | Plan (architecture, risks, planning docs) — done |
| 1 | Foundation (workspaces, schema, seed, auth, shell) — done |
| 2 | Deterministic program logic (traceability/schedule/budget/risk/readiness/evidence) — done |
| 3 | Core workflow UI (dashboard, event entry, audit shell on real data) — done |
| 4 | AI impact analysis (LLMProvider, mock/live, structured output, retry) |
| 5 | Approval and audit (state machine, apply preview, append-only audit) |
| 6 | Security and evals (threat model, prompt-injection defenses, evals) |
| 7 | Graph and MCP (React Flow thread view, read-only MCP server) |
| 8 | Delivery (full CI, Docker, browser tests, live eval, polish) |
Full detail: docs/IMPLEMENTATION_PLAN.md.
Read PROJECT_GUIDE.md and
docs/SPEC.md before making changes — they define the
phase-gate process, hard security/testing rules, and fixed architecture
this project follows. Check docs/DECISIONS.md before
re-deciding something that's already been settled.
If your local editor or development tooling keeps its own config/state
directory in the repo root, exclude it locally via .git/info/exclude
rather than adding a tool-specific entry to the tracked .gitignore.
No license has been chosen yet. All rights reserved by the author unless and until a license file is added.
