Skip to content

gavkat/mission-control

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mission Control

A multi-tenant B2B platform for space organisations to plan missions and intelligently assign crew based on skills, availability, and workload.

Core value: Define a mission's skill requirements and get intelligent, constraint-aware crew suggestions in seconds — replacing hours of manual cross-referencing.

Tech Stack

Layer Technology
Framework React Router 7 (framework mode, SSR)
Language TypeScript 5.9
Database Prisma Postgres (managed)
ORM Prisma 7 with tenant-scoped client extensions
Auth BetterAuth with organization plugin
UI shadcn/ui + Tailwind CSS 4 + Radix UI
Forms Conform + Zod validation
Deployment Vercel
Testing Vitest + Playwright

Features

Multi-Tenant Authentication & RBAC

Every organisation is a fully isolated tenant. Data never leaks across organisations.

Three roles with server-enforced permissions:

  • Directors — manage org settings, approve/reject missions, full visibility
  • Mission Leads — plan missions, run the matcher, submit for approval (cannot approve own missions)
  • Crew Members — manage own profile, set availability, respond to assignments

Crew Management

  • Structured skill profiles with 1–5 proficiency levels (Novice → Expert)
  • Organisation-scoped skill catalog managed by Directors
  • Calendar-based availability with date ranges
  • Assignment history showing past and current missions

Mission Lifecycle

Missions follow a state machine with role-gated transitions:

stateDiagram-v2
    [*] --> Draft
    Draft --> Submitted : Mission Lead submits
    Submitted --> Approved : Director approves
    Submitted --> Rejected : Director rejects
    Rejected --> Draft : Mission Lead revises
    Approved --> Active : Director activates
    Active --> Complete : Director completes
    Complete --> [*]
Loading

Each mission defines skill requirements (skill + minimum proficiency + crew count needed) used by the matching engine.

Auto-Matching Engine

The matching engine scores and ranks crew against mission requirements using three weighted factors:

flowchart LR
    M[Mission Requirements] --> E[Matching Engine]
    C[Crew Pool] --> E
    E --> R[Ranked Results]

    subgraph Scoring
        S[Skill Match] --- |proficiency vs requirement| Score
        A[Availability] --- |date overlap with mission| Score
        W[Workload Balance] --- |current assignment load| Score
    end

    E --> Scoring
    Scoring --> R
Loading
  • Transparent scoring — each result shows a per-factor breakdown so users understand the ranking
  • Strategy pattern — the algorithm sits behind a MatchingStrategy interface, allowing new algorithms (ML, constraint-based) to be plugged in without changing consumers

Dashboard

Org-level operational metrics at a glance: active missions, pending approvals, crew utilization, and upcoming assignments. Views are role-scoped — Directors see the full picture, Leads see their missions, Crew see their schedule.

Architecture

flowchart TB
    Browser["Browser (React 19)"]

    subgraph RR7["React Router 7"]
        MW["Middleware\n(auth + tenant context)"]
        Loaders["Route Loaders\n(server-side data)"]
        Actions["Route Actions\n(server-side mutations)"]
    end

    subgraph Services["Server Services"]
        Auth["BetterAuth\n(sessions, org membership)"]
        MissionSvc["Mission Service\n(lifecycle, CRUD)"]
        CrewSvc["Crew Service\n(profiles, skills)"]
        Engine["Matching Engine\n(strategy pattern)"]
    end

    subgraph Data["Data Layer"]
        Prisma["Prisma Client\n($extends per-request)"]
        DB[(Prisma Postgres)]
    end

    Browser <--> RR7
    MW --> Loaders
    MW --> Actions
    Loaders --> Services
    Actions --> Services
    Services --> Prisma
    Prisma --> DB
Loading

Key Architectural Decisions

Decision Rationale
Per-request tenant-scoped Prisma client $extends injects orgId into every query automatically — developers can't accidentally leak data across tenants
React Router middleware for auth Single enforcement point for session validation, org resolution, and RBAC. No loader handles its own auth.
Strategy pattern for matching The weighted scorer is the v1 algorithm. The interface supports swapping in ML or constraint-based algorithms without touching callers.
Server-side RBAC enforcement Client-side checks are UX sugar. All permissions enforced in loaders/actions.
Loader revalidation After any mutation, RR7 automatically re-runs active loaders — no manual cache invalidation needed

Data Model

erDiagram
    Organization ||--o{ Member : has
    User ||--o{ Member : "belongs to"
    Organization ||--o{ Skill : defines
    Organization ||--o{ Mission : owns
    Organization ||--o{ CrewProfile : has

    CrewProfile ||--o{ CrewSkill : has
    CrewProfile ||--o{ Availability : schedules
    CrewProfile ||--o{ MissionAssignment : assigned

    Skill ||--o{ CrewSkill : "proficiency in"
    Skill ||--o{ MissionSkillRequirement : "required by"

    Mission ||--o{ MissionSkillRequirement : requires
    Mission ||--o{ MissionAssignment : staffed

    CrewProfile {
        string id PK
        string orgId FK
        string memberId
        string bio
    }
    CrewSkill {
        string id PK
        string skillId FK
        int proficiency "1-5"
    }
    Mission {
        string id PK
        string orgId FK
        string name
        date startDate
        date endDate
        enum status "DRAFT|SUBMITTED|APPROVED|..."
    }
    MissionSkillRequirement {
        string skillId FK
        int minProficiency "1-5"
        int crewCount
    }
Loading

All domain tables include orgId — the tenant-scoped Prisma client filters on this automatically.

Getting Started

Prerequisites

  • Node.js 20+
  • A Prisma Postgres database (or any PostgreSQL instance)

Installation

npm install

Environment

Create a .env file:

DATABASE_URL="your-prisma-postgres-connection-string"
BETTER_AUTH_SECRET="your-random-secret"

Development

npx prisma migrate dev    # Apply database migrations
npm run dev               # Start dev server at http://localhost:5173

Testing

npm test                  # Unit tests (Vitest)
npm run test:e2e          # E2E tests (Playwright)

Production Build

npm run build             # Runs migrations, generates Prisma client, typechecks, builds
npm start                 # Serve production build

Project Structure

app/
├── routes/                 # React Router file-based routes
│   ├── _auth.*.tsx         # Unauthenticated shell (login)
│   ├── _app.*.tsx          # Authenticated shell (sidebar, tenant context)
│   └── api.auth.$.ts       # BetterAuth API handler
├── services/               # Server-only domain logic (.server.ts)
│   ├── auth.server.ts      # BetterAuth configuration
│   ├── db.server.ts        # Prisma client + tenant scoping
│   └── permissions.ts      # RBAC role definitions
├── components/
│   ├── ui/                 # shadcn/ui primitives
│   ├── auth/               # Sign-in, org creation forms
│   ├── crew/               # Crew cards, skills, availability
│   ├── missions/           # Mission forms, Kanban board, cards
│   └── layout/             # Sidebar, navigation
└── lib/                    # Shared utilities
prisma/
└── schema.prisma           # Database schema (18 models)

Demo Accounts

Test accounts are documented in .scratch/test-accounts.md.

Organisation User Role Email Password
Test Org Homer Simpson Director homer@test.com 12345678
Test Org Marge Simpson Mission Lead marge@test.com xwwSdwaKkroYeRoW
Test Org Bart Simpson Mission Lead bart@test.com #k8Tchqv%2C9jLmQ
Test Org Maggie Simpson Mission Lead maggie@test.com SDBQ@TN#nt@r3ge6

Current Status

Phase 1 (Foundation) is complete — authentication, RBAC, tenant isolation, and the app shell are working.

Phase Status Description
1. Foundation Complete Multi-tenant auth, RBAC, tenant-isolated data access
2. Crew & Missions Not started Crew profiles, skill management, mission lifecycle
3. Matching Engine Not started Weighted crew-to-mission scoring with transparency
4. Dashboard & Deploy Not started Metrics, seed data, UX polish, Vercel deployment

What's Not Yet Implemented

  • Crew skill profiles & availability calendar — schema exists, UI and service layer pending (Phase 2)
  • Mission CRUD & lifecycle state machine — schema and enum exist, workflow logic pending (Phase 2)
  • Auto-matching engine — architecture designed (strategy pattern), implementation pending (Phase 3)
  • Operational dashboard & metrics — pending all domain data (Phase 4)
  • Seed data — will populate realistic demo scenario once all models are in place (Phase 4)
  • Vercel deployment — final phase after polish

Deliberately Out of Scope

  • Email/push notifications — focus on core workflows
  • Real-time collaboration / WebSockets — RR7 loader revalidation is sufficient
  • OAuth / social login — email/password via BetterAuth is sufficient for v1
  • Custom role creation — three fixed roles demonstrate the pattern without the complexity
  • Billing / subscriptions — not relevant to the domain
  • Mobile native app — responsive web design covers mobile use cases

Roadmap

See .planning/ROADMAP.md for the full phased roadmap with success criteria per phase.

Next up: Phase 2 — Crew profiles with structured skills, calendar-based availability, mission CRUD with skill requirements, and the approval lifecycle (Draft → Submitted → Approved → Active → Complete).

Releases

No releases published

Packages

 
 
 

Contributors