Skip to content

divyat2605/spec-driven-development

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

23 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

AgentClinic

A full-stack clinic management system for AI agents β€” built with spec-driven development.
Staff can manage agents, track ailments, book therapy, and monitor clinic activity from a unified dashboard.


Next.js TypeScript Prisma SQLite Tailwind CSS Vercel


πŸš€ Live Demo Β· πŸ“‹ Specs Β· πŸ› Report Bug Β· ✨ Request Feature


πŸ“½οΈ Demo Preview

(Preview GIF β€” run locally or visit the live demo to explore)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  πŸ₯ AgentClinic Dashboard                          [Staff View] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  πŸ‘Ύ Agents   β”‚  πŸ“Š Stats           πŸ—“ Upcoming Appointments      β”‚
β”‚  πŸ€’ Ailments β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β€’ Agent-7 β†’ CBT @ 14:00      β”‚
β”‚  πŸ’Š Therapy  β”‚  β”‚ 12 Active    β”‚   β€’ Agent-3 β†’ DBT @ 15:30      β”‚
β”‚  πŸ“… Appts    β”‚  β”‚ 3 Critical   β”‚   β€’ Agent-11 β†’ EMDR @ 16:00    β”‚
β”‚  πŸ“ˆ Dash     β”‚  β”‚ 5 Sessions   β”‚                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

✨ Features at a Glance

Feature Description
πŸ‘Ύ Agents Create and manage AI agents with status tracking (active, recovering, discharged)
πŸ€’ Ailments Log ailments with severity levels and timestamps
πŸ’Š Therapy Types Define therapy sessions with custom duration, type, and metadata
πŸ“… Appointments Book agents into therapy slots with date, time, and therapist assignment
πŸ“Š Dashboard Staff overview with real-time stats, filters, and upcoming appointment feed

πŸ—‚οΈ Project Structure

agenticclinic/
β”œβ”€β”€ app/                        # Next.js 15 App Router
β”‚   β”œβ”€β”€ api/                    # REST API endpoints (route handlers)
β”‚   β”‚   β”œβ”€β”€ agents/             # GET, POST /api/agents
β”‚   β”‚   β”œβ”€β”€ ailments/           # GET, POST /api/ailments
β”‚   β”‚   β”œβ”€β”€ therapy-types/      # GET, POST /api/therapy-types
β”‚   β”‚   └── appointments/       # GET, POST /api/appointments
β”‚   β”œβ”€β”€ agents/                 # Agent management UI
β”‚   β”‚   β”œβ”€β”€ page.tsx            # Agent list
β”‚   β”‚   └── [id]/page.tsx       # Agent detail
β”‚   β”œβ”€β”€ ailments/               # Ailment tracking UI
β”‚   β”œβ”€β”€ therapy-types/          # Therapy management UI
β”‚   β”œβ”€β”€ appointments/           # Appointment booking UI
β”‚   β”œβ”€β”€ dashboard/              # Staff dashboard
β”‚   β”œβ”€β”€ layout.tsx              # Root layout + nav
β”‚   └── globals.css             # Tailwind v4 base styles
β”‚
β”œβ”€β”€ lib/
β”‚   └── prisma.ts               # Prisma singleton (prevents hot-reload leaks)
β”‚
β”œβ”€β”€ prisma/
β”‚   β”œβ”€β”€ schema.prisma           # Database schema (models + relations)
β”‚   └── migrations/             # Auto-generated migration history
β”‚
└── specs/                      # Spec-driven development documents
    β”œβ”€β”€ phase-1-agents.md
    β”œβ”€β”€ phase-2-therapy.md
    β”œβ”€β”€ phase-3-dashboard.md
    └── phase-4-polish.md

πŸ—οΈ Architecture Overview

                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚         Browser (Client)      β”‚
                        β”‚   Next.js Client Components   β”‚
                        β”‚   (React, Tailwind v4, fetch) β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚ HTTP/HTTPS
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚      Next.js 15 App Router     β”‚
                        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                        β”‚  β”‚   Server Components      β”‚  β”‚
                        β”‚  β”‚   (SSR, streaming)       β”‚  β”‚
                        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                        β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                        β”‚  β”‚   Route Handlers (API)   β”‚  β”‚
                        β”‚  β”‚   /api/* endpoints       β”‚  β”‚
                        β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                        └────────────-β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚ Prisma Client
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚        Prisma ORM             β”‚
                        β”‚  Type-safe queries, migrationsβ”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚     SQLite (local / Vercel)   β”‚
                        β”‚  agents, ailments, therapy,   β”‚
                        β”‚  appointments tables          β”‚
                        └─────────────────────────────-β”€β”˜

Data Flow

User Action β†’ Client Component
    β†’ fetch('/api/resource', { method: 'POST', body })
        β†’ Route Handler (app/api/...)
            β†’ prisma.resource.create({ data: ... })
                β†’ SQLite write
                    β†’ 200 OK + JSON
                        β†’ Client re-render / revalidation

βš–οΈ Architecture Tradeoffs

Why Next.js App Router (not Pages Router)?

App Router βœ… Pages Router
Server Components βœ… Native ❌ None
Streaming & Suspense βœ… Built-in ⚠️ Manual
Nested Layouts βœ… Easy ⚠️ Workarounds
API co-location βœ… route.ts next to page ⚠️ /pages/api/
Bundle size βœ… Smaller (RSC) ⚠️ Full JS per page

Tradeoff accepted: App Router has a steeper learning curve and some ecosystem libraries lag on support. Worth it for the streaming dashboard and reduced client-side JavaScript.


Why SQLite (not PostgreSQL/MySQL)?

SQLite wins for this stage because:

  • Zero configuration β€” no server process, no connection pooling
  • Vercel-compatible via embedded file storage (for demo deploys)
  • Prisma handles schema + migrations identically β€” swap the DATABASE_URL and the code doesn't change

Tradeoffs accepted:

  • No concurrent writes at scale (single writer lock)
  • Not suitable for multi-region deployments
  • File-based β†’ doesn't work on stateless serverless with persistent storage needs

Scaling path: Switch datasource db in schema.prisma from sqlite to postgresql, update DATABASE_URL, run prisma migrate deploy. Application code changes: zero.


Why Prisma (not raw SQL / Drizzle / TypeORM)?

Concern Prisma
Type safety βœ… Auto-generated types from schema
Migration tracking βœ… First-class migrate dev / migrate deploy
Schema as source of truth βœ… Single schema.prisma file
Learning curve βœ… Gentle, great docs
Bundle size ⚠️ Heavier than Drizzle for edge deployments
Edge runtime support ⚠️ Requires Prisma Accelerate for true edge

Why not Drizzle? Drizzle is excellent and lighter β€” worth considering at scale. Prisma was chosen here for developer velocity and type-safety guarantees during spec-driven development where schema evolves rapidly.


Why Spec-Driven Development?

The entire project was spec-first: requirements β†’ validation criteria β†’ code. This means:

  • Every feature has a written contract before implementation
  • Refactoring never breaks undocumented behaviour (because behaviour is documented)
  • Onboarding new contributors is faster (read the spec, understand the intent)

See the /specs folder for all phase documents.


πŸ“ Database Schema

model Agent {
  id           Int           @id @default(autoincrement())
  name         String
  status       String        // "active" | "recovering" | "discharged"
  createdAt    DateTime      @default(now())
  ailments     Ailment[]
  appointments Appointment[]
}

model Ailment {
  id        Int      @id @default(autoincrement())
  agentId   Int
  agent     Agent    @relation(fields: [agentId], references: [id])
  name      String
  severity  String   // "mild" | "moderate" | "severe" | "critical"
  createdAt DateTime @default(now())
}

model TherapyType {
  id           Int           @id @default(autoincrement())
  name         String        // e.g. "CBT", "EMDR", "DBT"
  durationMins Int
  appointments Appointment[]
}

model Appointment {
  id            Int         @id @default(autoincrement())
  agentId       Int
  agent         Agent       @relation(fields: [agentId], references: [id])
  therapyTypeId Int
  therapyType   TherapyType @relation(fields: [therapyTypeId], references: [id])
  scheduledAt   DateTime
  createdAt     DateTime    @default(now())
}

Key design decisions:

  • Ailments are 1-to-many with Agent (an agent can have multiple ailments)
  • Appointments join Agent ↔ TherapyType (many-to-many resolved via Appointment)
  • Severity and status use string enums (vs DB-level enums) for portability across SQLite β†’ PostgreSQL

πŸš€ Scaling Roadmap

Phase 1 β†’ Now (Current State)

Single Vercel deployment
SQLite (file-based)
Monolithic Next.js app
No auth

Phase 2 β†’ Production-Ready

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Auth Layer (NextAuth.js / Clerk)                   β”‚
β”‚  Role-based: Staff vs Admin vs Read-only            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  PostgreSQL (Supabase / Railway / Neon)             β”‚
β”‚  Connection pooling via PgBouncer or Prisma Accelerate β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  API rate limiting (Upstash Redis)                  β”‚
β”‚  Input validation (Zod schemas on all route handlers)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Migration effort: 1–2 days. Prisma + Next.js abstractions mean the application layer barely changes.

Phase 3 β†’ Scale (Multi-Tenant / High Traffic)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Multi-tenant schema (tenantId on all models)                  β”‚
β”‚  Or: separate DB per clinic (schema-per-tenant pattern)        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Next.js deployed to Vercel Edge + Prisma Accelerate           β”‚
β”‚  Or: containerized (Docker) on Railway / Fly.io / ECS          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Background jobs (appointment reminders, report generation)    β”‚
β”‚  β†’ Trigger.dev or Inngest for durable workflows                β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Observability: Sentry (errors) + Axiom (logs) + Vercel Speed  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Phase 4 β†’ Enterprise

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Read replicas for dashboard queries (analytics-heavy)          β”‚
β”‚  CQRS: separate read models for reporting                       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Audit log table (all mutations tracked with actor + timestamp) β”‚
β”‚  HIPAA-style compliance layer (for real medical contexts)       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  REST β†’ tRPC or GraphQL for typed client-server contracts       β”‚
β”‚  (tRPC is the natural next step given the TypeScript-first codebase) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”‘ Key System Thinking

The "Replace the DB in One Day" Principle

The architecture deliberately keeps the persistence layer behind a Prisma abstraction. This means:

  • Switching from SQLite β†’ PostgreSQL: change DATABASE_URL, re-run migrations
  • Switching from Prisma β†’ Drizzle: swap lib/prisma.ts, update query syntax in API routes only
  • Switching from REST β†’ tRPC: add server/router.ts, generate types, update client fetches

The application's domain logic (agents, ailments, appointments) never directly touches the DB driver.

Why Co-located API Routes?

app/agents/page.tsx and app/api/agents/route.ts live near each other intentionally. When you're reading the agents feature, both the UI and the API contract are a single folder away. This reduces the "context switching cost" of full-stack development.

Spec-First = Safer Refactors

Because every feature started as a written spec (in /specs), refactors don't guess at intent. The spec defines the contract; the code fulfils it. Tests (when added) verify against the spec, not the implementation.


πŸš€ Getting Started

Prerequisites

  • Node.js 20+
  • npm

Install

git clone https://github.com/divyat2605/spec-driven-development.git
cd agenticclinic
npm install

Database

npx prisma migrate dev --name init
npx prisma generate

Run

npm run dev

Open http://localhost:3000


πŸ—ΊοΈ Development Roadmap

Phase 1  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  Agents & Ailments foundation       βœ… Done
Phase 2  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  Therapy types & Appointments        βœ… Done
Phase 3  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  Dashboard & staff workflows         βœ… Done
Phase 4  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  Polish, tests & deployment          βœ… Done
──────────────────────────────────────────────────────────────────
Phase 5  β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  Auth + role-based access            πŸ”œ Next
Phase 6  β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  PostgreSQL + connection pooling     πŸ”œ Planned
Phase 7  β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  tRPC + end-to-end type safety       πŸ’‘ Exploring
Phase 8  β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  Multi-tenant & audit logging        πŸ’‘ Exploring

🀝 Contributing

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Write a spec first in /specs β€” this project is spec-driven
  4. Implement against the spec
  5. Open a PR referencing the spec document

πŸ“„ License

MIT Β© divyat2605


Built with πŸ€– for πŸ€– β€” because even AI agents deserve good healthcare.

Made with Next.js Β· Prisma Β· SQLite Β· Tailwind CSS Β· Spec-Driven Development

About

A full-stack AI agent clinic built with spec-driven development. Next.js 15, TypeScript, Prisma, PostgreSQL, Tailwind CSS. Deployed on Vercel.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages