diff --git a/CLAUDE.md b/CLAUDE.md
index 6ab9fdd5..6bccb770 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -10,15 +10,19 @@ Changemaker Lite is a self-hosted political campaign platform built with Docker
**Status Summary:**
- ✅ Phases 1-14 Complete (Foundation through Monitoring + DevOps)
-- ✅ Security Audit Complete (13 findings addressed, Feb 2026)
-- ✅ NAR 2025 Server Import (Canadian electoral data)
-- ✅ Media Manager Integration (dual API architecture)
-- ✅ Email Templates System
-- ✅ Data Quality Dashboard
-- ✅ Observability Dashboard
-- ✅ **Drizzle to Prisma Migration Complete** (Media API consolidated to single-ORM, Feb 2026)
-- ✅ **Automated Pangolin Setup** (One-command tunnel deployment, Feb 2026)
-- ✅ **Migration Drift Fixed** (Baseline catch-up migration, 14 migrations cover full schema, Feb 2026)
+- ✅ Drizzle to Prisma Migration Complete (single-ORM, Feb 2026)
+- ✅ Automated Pangolin Setup (one-command tunnel deployment)
+- ✅ 3 Security Audits Complete (Feb 2025 + Mar 22/27/30 2026)
+- ✅ Social Connections + Calendar (friendship, shared views, availability finder)
+- ✅ Payments + Ticketed Events (Stripe integration, check-in scanner)
+- ✅ Meeting Planner + Straw Polls (scheduling, voting)
+- ✅ SMS Campaign Connector (Termux Android bridge)
+- ✅ Docs CMS (blog authoring, access policies, collaboration, version history)
+- ✅ User Provisioning Framework (Gitea, Vaultwarden, Listmonk)
+- ✅ Granular Admin Roles (9 admin roles + module-specific RBAC)
+- ✅ Collaborative Docs Editing (Y.js CRDT + Hocuspocus)
+- ✅ Engagement Scoring + EventBus + Gitea SSO
+- ✅ MCP Server (Claude Code integration, 27 core + 40 on-demand tools)
- 🚧 Phase 15 (Testing + Polish) - Next
---
@@ -59,10 +63,9 @@ Changemaker Lite is a self-hosted political campaign platform built with Docker
changemaker.lite/
├── api/ # Dual API servers (Express + Fastify)
│ ├── prisma/
-│ │ ├── schema.prisma # 30+ models: User, Campaign, Location, Shift, etc.
-│ │ ├── migrations/ # Prisma migration history
+│ │ ├── schema.prisma # 186 models: User, Campaign, Location, Shift, Payment, Social, etc.
+│ │ ├── migrations/ # 44 Prisma migrations (full schema history)
│ │ └── seed.ts # Admin user, settings, page blocks
-│ ├── drizzle/ # Media tables (Drizzle ORM)
│ ├── Dockerfile.media # Fastify media server container
│ └── src/
│ ├── server.ts # Express API entry point (port 4000)
@@ -70,10 +73,10 @@ changemaker.lite/
│ ├── config/
│ │ └── env.ts # Zod-validated environment config (100+ vars)
│ ├── middleware/ # auth, rbac, rate-limit, validate, error-handler
-│ ├── modules/
+│ ├── modules/ # 40 modules total
│ │ ├── auth/ # JWT login, register, refresh, logout
│ │ ├── users/ # User CRUD + pagination + search
-│ │ ├── settings/ # Site settings singleton
+│ │ ├── settings/ # Site settings singleton (20+ feature flags)
│ │ ├── services/ # Service health checks
│ │ ├── influence/
│ │ │ ├── campaigns/ # Campaign CRUD + public routes
@@ -90,16 +93,39 @@ changemaker.lite/
│ │ │ ├── canvass/ # Canvassing sessions + visits + routes
│ │ │ ├── tracking/ # GPS tracking sessions (volunteer + admin routes)
│ │ │ └── settings/ # Map settings singleton
-│ │ ├── pages/
-│ │ │ ├── pages-admin.routes.ts # Landing page CRUD
-│ │ │ ├── pages-public.routes.ts # Public page renderer
-│ │ │ └── blocks.routes.ts # Block library API
+│ │ ├── pages/ # Landing page CRUD + block library + public renderer
│ │ ├── email-templates/ # Email template CRUD + rendering
-│ │ ├── media/ # Fastify media API (videos, reactions, jobs)
+│ │ ├── media/ # Fastify media API (videos, reactions, jobs, analytics)
+│ │ ├── social/ # Friendships, challenges, spotlights, referrals
+│ │ ├── calendar/ # Calendar layers, items, shared views, availability
+│ │ ├── payments/ # Stripe products, donations, subscriptions
+│ │ ├── ticketed-events/ # Event ticketing, tiers, check-in
+│ │ ├── sms/ # SMS campaigns via Termux Android bridge
+│ │ ├── meeting-planner/ # Meeting scheduling with polls
+│ │ ├── meetings/ # Meeting agendas, minutes, action items
+│ │ ├── polls/ # Straw polls with comments + voting
+│ │ ├── docs/ # MkDocs health checks + export routes
+│ │ ├── docs-analytics/ # Docs page view tracking
+│ │ ├── docs-comments/ # Gitea-backed comments on docs
+│ │ ├── people/ # CRM people module
+│ │ ├── events/ # Gancio event integration
+│ │ ├── newsletter/ # Newsletter management
│ │ ├── listmonk/ # Newsletter sync admin routes
│ │ ├── pangolin/ # Tunnel management (Newt integration)
-│ │ ├── docs/ # MkDocs + Code Server health checks
+│ │ ├── rocketchat/ # Rocket.Chat integration
+│ │ ├── jitsi/ # Jitsi video conferencing auth
+│ │ ├── registry/ # Docker image registry management
+│ │ ├── upgrade/ # Auto-upgrade checks + deployment
+│ │ ├── gitea-setup/ # Gitea SSO + API token management
+│ │ ├── volunteer-invite/ # Invite codes + setup workflows
+│ │ ├── gallery-ads/ # Media gallery ads
+│ │ ├── homepage/ # Homepage stats + dashboard
+│ │ ├── search/ # Cross-module search
+│ │ ├── reports/ # Analytics + reporting
+│ │ ├── og/ # Open Graph metadata
│ │ ├── qr/ # QR code PNG generation (public)
+│ │ ├── dashboard/ # Admin dashboard data
+│ │ ├── activity/ # Activity feed
│ │ └── observability/ # Prometheus/Grafana/Alertmanager integration
│ ├── services/ # email, email-queue, geocode-queue, listmonk, pangolin, docker
│ ├── types/ # express.d.ts (Request augmentation)
@@ -119,23 +145,25 @@ changemaker.lite/
│ │ ├── media/ # VideoCard, BulkActions, gallery components
│ │ ├── email-templates/ # Email template components
│ │ └── observability/ # Monitoring components
-│ ├── pages/
-│ │ ├── auth/ # LoginPage
-│ │ ├── influence/ # CampaignsPage, ResponsesPage, RepresentativesPage, EmailQueuePage
-│ │ ├── map/ # LocationsPage, CutsPage, ShiftsPage, MapSettingsPage, DataQualityDashboardPage
-│ │ ├── volunteer/ # VolunteerMapPage, VolunteerShiftsPage, MyActivityPage, MyRoutesPage
-│ │ ├── public/ # CampaignsListPage, CampaignPage, ResponseWallPage, MapPage, ShiftsPage, LandingPage, MediaGalleryPage, MediaViewerPage
-│ │ ├── media/ # LibraryPage, SharedMediaPage, MediaJobsPage, AnalyticsDashboardPage
-│ │ ├── services/ # MiniQRPage, MailHogPage, CodeEditorPage, N8nPage, GiteaPage, NocoDBPage
-│ │ └── (root) # DashboardPage, UsersPage, SettingsPage, CanvassDashboardPage, WalkSheetPage, CutExportPage, LandingPagesPage, PageEditorPage, EmailTemplatesPage, ListmonkPage, PangolinPage, ObservabilityPage
-│ ├── stores/ # auth.store.ts, canvass.store.ts (Zustand)
-│ ├── lib/ # api.ts, media-api.ts, media-public-api.ts (axios)
+│ ├── pages/ # 52 root pages + 8 subdirectories
+│ │ ├── influence/ # Campaign moderation, effectiveness, impact stories, straw polls
+│ │ ├── map/ # LocationsPage, CutsPage, ShiftsPage, MapSettingsPage, DataQualityDashboard
+│ │ ├── media/ # Library, Playlists, Analytics, Gallery Ads, Comment Moderation
+│ │ ├── payments/ # Dashboard, Products, Plans, Donations, Subscribers, Settings
+│ │ ├── social/ # Dashboard, Graph, Moderation, Referrals, Spotlights, Challenges
+│ │ ├── sms/ # Dashboard, Contacts, Campaigns, Conversations, Templates, Setup
+│ │ ├── events/ # Ticketed Events, Event Detail, Check-in Scanner
+│ │ ├── volunteer/ # Map, Shifts, Routes, Calendar, Friends, Profile, Groups, Achievements
+│ │ ├── public/ # Homepage, Campaigns, Map, Events, Media Gallery, Pricing, Donations, Meet
+│ │ └── (root) # Dashboard, Users, Settings, Docs*, MeetingPlanner, Observability, etc.
+│ ├── stores/ # 9 Zustand stores (auth, canvass, chat-widget, command-palette, favorites, settings, social, tour, tracking)
+│ ├── lib/ # api.ts, media-api.ts, media-public-api.ts, nav-defaults.ts, service-url.ts, y-textarea.ts
│ ├── hooks/ # useDebounce, useLocalStorage
│ └── types/ # api.ts, canvass.ts, media.ts (TypeScript interfaces)
│
-├── media-manager/ # Legacy media manager (reference)
+├── mcp-server/ # Claude Code MCP server (27 core + 40 on-demand tools)
├── nginx/ # Reverse proxy config (subdomain routing + CSP)
-├── configs/ # Prometheus, Grafana, Alertmanager configs
+├── configs/ # Prometheus, Grafana, Alertmanager, Pangolin configs
├── scripts/ # Deployment, backup, upgrade, registry scripts
│ ├── install.sh # Curl-friendly installer (downloads tarball + runs config.sh)
│ ├── build-and-push.sh # Build production images → push to Gitea registry
@@ -144,9 +172,10 @@ changemaker.lite/
│ ├── upgrade.sh # 6-phase upgrade (git or release-tarball mode)
│ ├── upgrade-check.sh # Check for updates (git or Gitea API)
│ ├── upgrade-watcher.sh # Systemd bridge for admin GUI upgrades
-│ └── backup.sh # PostgreSQL + Listmonk + uploads backup
-├── docker-compose.yml # V2 orchestration (20+ services)
-├── docker-compose.v1.yml # V1 backup (reference)
+│ ├── backup.sh / restore.sh # PostgreSQL + Listmonk + uploads backup/restore
+│ └── validate-env.sh # Required env variable validation
+├── docker-compose.yml # V2 orchestration (40+ services)
+├── docker-compose.prod.yml # Production (image-only, no source mounts)
├── .env.example # All required environment variables
└── V2_PLAN.md # Full 14-phase roadmap
```
@@ -238,27 +267,34 @@ cd api && npm run dev:media
|---------|-----|---------------------|
| Admin GUI | http://localhost:3000 | See INITIAL_ADMIN_EMAIL/INITIAL_ADMIN_PASSWORD in .env |
| API | http://localhost:4000 | - |
+| Media API | http://localhost:4100 | - |
| NocoDB | http://localhost:8091 | See `NC_ADMIN_EMAIL`/`NC_ADMIN_PASSWORD` in .env |
+| Gitea | http://localhost:3030 | See `GITEA_ADMIN_USER`/`GITEA_ADMIN_PASSWORD` in .env |
| MailHog | http://localhost:8025 | - |
| Grafana | http://localhost:3001 | admin / admin |
| Prometheus | http://localhost:9090 | - |
| Listmonk | http://localhost:9001 | See `LISTMONK_WEB_ADMIN_USER`/`PASSWORD` in .env |
+| Rocket.Chat | http://localhost:3100 | See RC env vars in .env |
+| Excalidraw | http://localhost:8090 | - |
+| Vaultwarden | http://localhost:8093 | See `VAULTWARDEN_ADMIN_TOKEN` in .env |
### Feature Flags
-Enable optional features in `.env`:
+Most features are toggled via **SiteSettings** in the database (admin Settings page). Some also have `.env` overrides:
```bash
-# Media Manager
-ENABLE_MEDIA_FEATURES=true
-
-# Listmonk Newsletter Sync
-LISTMONK_SYNC_ENABLED=true
-
-# Email Test Mode (sends to MailHog instead of SMTP)
-EMAIL_TEST_MODE=true
+# .env feature flags (env-level)
+ENABLE_MEDIA_FEATURES=true # Media manager
+ENABLE_PAYMENTS=true # Stripe integration
+ENABLE_SMS=true # SMS campaigns
+ENABLE_CHAT=true # Rocket.Chat
+ENABLE_MEET=true # Jitsi meetings
+LISTMONK_SYNC_ENABLED=true # Newsletter sync
+EMAIL_TEST_MODE=true # MailHog vs SMTP
```
+**Database feature flags (SiteSettings):** `enableInfluence`, `enableMap`, `enableNewsletter`, `enableLandingPages`, `enableMediaFeatures`, `enablePayments`, `enableGalleryAds`, `enableChat`, `enableEvents`, `enableDocsComments`, `enableSms`, `enablePeople`, `enableSocial`, `enableMeet`, `enableMeetingPlanner`, `enableTicketedEvents`, `enableSocialCalendar`, `enablePolls`, `enableDocsCollaboration`, `enableUserProvisioning`
+
---
## Development Commands
@@ -272,7 +308,6 @@ cd api && npm run dev:media # Fastify media dev server (port 4100)
cd api && npx tsc --noEmit # Type-check
cd api && npx prisma migrate dev # Run/create Prisma migrations
cd api && npx prisma studio # Browse database
-cd api && npx drizzle-kit push # Push Drizzle schema changes (media)
```
### Admin Development
@@ -295,7 +330,6 @@ docker compose logs -f media-api
# Database operations
docker compose exec api npx prisma migrate dev
-docker compose exec api npx drizzle-kit push
# Stop services
docker compose down
@@ -513,20 +547,25 @@ cd api && npx tsc --noEmit && cd ../admin && npx tsc --noEmit
| **Core Services** | | |
| 3000 | Admin GUI | Vite dev / React production |
| 4000 | Express API | Main V2 API (Prisma) |
-| 4100 | Fastify Media API | Video library (Drizzle) |
+| 4100 | Fastify Media API | Video library (Prisma) |
| 5433 | V2 PostgreSQL | Localhost (container: 5432) |
| 6379 | Redis | Cache, rate limit, BullMQ |
| **Supporting Services** | | |
| 3001 | Grafana | Metrics visualization |
| 3010 | Homepage | Service dashboard |
-| 3030 | Gitea | Git hosting |
+| 3030 | Gitea | Git hosting + SSO |
+| 3100 | Rocket.Chat | Team chat (embed proxy) |
| 4001 | MkDocs Site | Served docs |
| 4003 | MkDocs Dev | Live preview |
| 5432 | Listmonk PostgreSQL | Listmonk DB |
| 5678 | n8n | Workflow automation |
| 8025 | MailHog | Email capture (dev) |
| 8089 | Mini QR | QR generator |
+| 8090 | Excalidraw | Collaborative whiteboard |
| 8091 | NocoDB | Data browser |
+| 8092 | Gancio | Event management |
+| 8093 | Vaultwarden | Password manager |
+| 8443 | Jitsi Web | Video conferencing |
| 8885 | Mini QR Proxy | Iframe-friendly |
| 8888 | Code Server | Web IDE |
| 9001 | Listmonk | Newsletter platform |
@@ -551,11 +590,17 @@ cd api && npx tsc --noEmit && cd ../admin && npx tsc --noEmit
| `docs.cmlite.org` | MkDocs (4003) | Docs site |
| `code.cmlite.org` | Code Server (8888) | Web IDE |
| `n8n.cmlite.org` | n8n (5678) | Workflow automation |
-| `git.cmlite.org` | Gitea (3030) | Git hosting |
+| `git.cmlite.org` | Gitea (3030) | Git hosting + SSO |
| `home.cmlite.org` | Homepage (3010) | Dashboard |
| `grafana.cmlite.org` | Grafana (3001) | Metrics viz |
| `listmonk.cmlite.org` | Listmonk (9001) | Newsletters |
| `qr.cmlite.org` | Mini QR (8089) | QR generator |
+| `chat.cmlite.org` | Rocket.Chat (3100) | Team chat |
+| `meet.cmlite.org` | Jitsi (8443) | Video conferencing |
+| `events.cmlite.org` | Gancio (8092) | Event management |
+| `draw.cmlite.org` | Excalidraw (8090) | Collaborative whiteboard |
+| `vault.cmlite.org` | Vaultwarden (8093) | Password manager |
+| `mail.cmlite.org` | MailHog (8025) | Email capture (dev) |
| `cmlite.org` | MkDocs Static (4004) | **Documentation/marketing site only** |
**Clean separation:** Root domain (`${DOMAIN}`) serves MkDocs documentation site. All application functionality (admin GUI, public campaigns, map, shifts, media gallery) is accessible via `app.${DOMAIN}` subdomain. This provides clear separation between public documentation and the application.
@@ -564,7 +609,7 @@ cd api && npx tsc --noEmit && cd ../admin && npx tsc --noEmit
## Common Patterns
-**Note:** See `MEMORY.md` for comprehensive development patterns, gotchas, and lessons learned. Below are V2-specific patterns only.
+**Note:** Below are the key development patterns for this project.
### API Router Structure
- Service layer (`*.service.ts`) — business logic, database queries
@@ -579,47 +624,57 @@ cd api && npx tsc --noEmit && cd ../admin && npx tsc --noEmit
- Login redirects: ADMIN_ROLES → `/app`, USER/TEMP → `/volunteer`
### Frontend Architecture
-- Admin pages: `admin/src/pages/` (AppLayout)
+- Admin pages: `admin/src/pages/` + subdirs (AppLayout)
- Public pages: `admin/src/pages/public/` (PublicLayout, dark theme)
- Volunteer pages: `admin/src/pages/volunteer/` (VolunteerLayout)
-- Zustand stores: `auth.store.ts`, `canvass.store.ts`
+- Zustand stores (9): auth, canvass, chat-widget, command-palette, favorites, settings, social, tour, tracking
- API clients: `{ api }` from `lib/api.ts`, `mediaApi` from `lib/media-api.ts`
-### Database ORMs
-- **Prisma** (main API): Use `UncheckedCreateInput`/`UncheckedUpdateInput` for foreign keys, `Prisma.InputJsonValue` for JSON arrays
-- **Drizzle** (media API): Separate schema file, push with `npx drizzle-kit push`, no migrations generated
+### Database ORM
+- **Prisma** (both APIs): 186 models in single `schema.prisma`. Use `UncheckedCreateInput`/`UncheckedUpdateInput` for foreign keys, `Prisma.InputJsonValue` for JSON arrays
### Prisma Migration Workflow
- **Always use `prisma migrate dev`** for schema changes (not `prisma db push`) — `db push` applies changes directly but doesn't create migration files, causing drift
-- **Migration history:** 14 migrations in `api/prisma/migrations/` fully cover the schema (baseline catch-up applied Feb 2026)
-- **Fixing drift:** Use `prisma migrate diff --from-migrations ... --to-schema-datamodel ... --script` with a shadow DB to generate catch-up SQL, then `prisma migrate resolve --applied`. See MEMORY.md for detailed steps
+- **Migration history:** 44 migrations in `api/prisma/migrations/` fully cover the schema
- **Production deploys:** Use `prisma migrate deploy` (not `migrate dev`)
-### V2-Specific Gotchas
+### Key Gotchas
- **Prisma migrations:** Never use `db push` — always `migrate dev` to keep history in sync
- Nginx media API block must come BEFORE general API block
- `IMAGE_TAG=local` (default) never pulls from registry; set to SHA or `latest` for pre-built images
- **Release vs source installs:** Detected by `VERSION` file + absence of `.git/`; release uses `docker-compose.prod.yml`, source uses `docker-compose.yml`
- **`api/dist/` is gitignored** — never commit; if root-owned from container builds, fix with `chown`
-- See MEMORY.md "Common Gotchas" for additional gotchas (ports, volumes, media upload, registry, etc.)
+- **`!` in passwords** triggers bash history expansion — use Write tool to write JSON to file, then `curl -d @file`
+- **Port mappings:** API container 4000 → host 4002, Admin container 3000 → host 3002
+- **BullMQ** needs its own Redis connections (pass URL string, not shared ioredis instance)
+- **Public pages** use `axios` directly (no auth interceptor), admin pages use `{ api }` from lib
+- **Prisma JSON fields:** typed arrays need `as unknown as Prisma.InputJsonValue` cast
+- **nginx conf.d files** have `.template` counterparts used by envsubst at startup
---
## Security & Configuration
-### Security Audit
-Comprehensive security audit completed 2025-02-11, addressing 13 findings. See `SECURITY_AUDIT_2025-02-11.md` for full report.
+### Security Audits
+Four security audits completed. See audit reports for full details:
+- **Feb 2025:** 13 findings (password policy, rate limits, token rotation, XSS prevention). `SECURITY_AUDIT_2025-02-11.md`
+- **Mar 22 2026:** JWT algorithm lockdown, invite secret separation, webhook hardening, CSV injection, QR DoS
+- **Mar 27 2026:** 33 findings (30 fixed) — IDOR, XSS, path traversal, MongoDB auth, SSTI, open redirect
+- **Mar 30 2026:** 19 findings — IDOR action items/ticketed events, nginx rate limit, JWT secret reuse
-**Key improvements:**
+**Key security features:**
- Password policy: 12+ chars, uppercase, lowercase, digit (schema-enforced)
-- Rate limits on auth endpoints (10/min per IP)
-- Refresh token rotation (atomic transaction)
+- Rate limits on auth endpoints (10/min per IP) + nginx rate limiting
+- Refresh token rotation (atomic Prisma transaction)
+- JWT algorithm locked to HS256, separate invite secret
- User enumeration prevention (401 not 404)
- Redis authentication required
-- XSS/injection prevention (HTML escaping)
-- Path traversal protection
+- XSS/injection prevention (HTML escaping, DOMPurify, SSTI protection)
+- Path traversal protection (resolve + startsWith checks)
- Encryption key for DB secrets (`ENCRYPTION_KEY` required in all environments)
-- Nginx security headers (HSTS, Permissions-Policy, CSP)
+- Nginx security headers (HSTS, Permissions-Policy, CSP, X-Forwarded-For)
+- MongoDB keyfile authentication
+- httpOnly cookies for refresh tokens
### Required Environment Variables
See `.env.example` for all 100+ variables. Critical ones:
@@ -642,8 +697,8 @@ See `.env.example` for all 100+ variables. Critical ones:
When deploying to a production domain via Pangolin tunnel, you MUST update the `.env` file to include the production domain in `CORS_ORIGINS`:
```bash
-# Example for betteredmonton.org
-CORS_ORIGINS=http://app.betteredmonton.org,https://app.betteredmonton.org,http://localhost:3000,http://localhost
+# Example for cmlite.org
+CORS_ORIGINS=http://app.cmlite.org,https://app.cmlite.org,http://localhost:3000,http://localhost
# Also set production mode
NODE_ENV=production
@@ -672,18 +727,16 @@ docker compose restart api
4. Save changes
**Critical resources to fix first:**
-- `api.betteredmonton.org` - Main API (all endpoints fail without this)
-- `app.betteredmonton.org` - Admin GUI + public pages
-- `media.betteredmonton.org` - Media API
+- `api.${DOMAIN}` - Main API (all endpoints fail without this)
+- `app.${DOMAIN}` - Admin GUI + public pages
+- `media.${DOMAIN}` - Media API
**Verification:**
```bash
# Should return JSON, NOT a 302 redirect
-curl https://api.betteredmonton.org/api/health
+curl https://api.cmlite.org/api/health
```
-**See Also:** `PRODUCTION_403_FIX.md` for detailed step-by-step instructions.
-
### CORS Errors in Production
**Symptom:** Browser console shows CORS errors when accessing production domain.
@@ -706,25 +759,21 @@ Check container status (`docker compose ps`), verify credentials in `.env`, chec
## V1 Reference (Legacy)
-V1 code archived in `influence/`, `map/`, and `docker-compose.v1.yml`. Two independent Express apps using NocoDB REST API. See individual README files for V1 documentation:
-- `influence/README.MD` — Features, config, campaign management
-- `map/README.md` — Features, config, setup instructions
-- Both use session-based auth, bcryptjs passwords, Bull job queues
+V1 code has been removed from the repo. History preserved as `v1-archive` git tag. `docker-compose.v1.yml` remains as reference only.
---
## Key Configuration Files
### Infrastructure
-- `docker-compose.yml` — Development orchestration (build blocks + source mounts, 20+ services)
+- `docker-compose.yml` — Development orchestration (build blocks + source mounts, 40+ services)
- `docker-compose.prod.yml` — Production orchestration (image-only, no source mounts, `IMAGE_TAG:-latest`)
- `.env` / `.env.example` — Environment variables (100+ vars)
- `config.sh` — Interactive setup wizard (14 steps, release-mode aware)
### Database
-- `api/prisma/schema.prisma` — Main schema (30+ Prisma models)
-- `api/prisma/migrations/` — 14 migration files (fully cover schema as of Feb 2026)
-- `api/drizzle.config.ts` — Drizzle config for media tables
+- `api/prisma/schema.prisma` — Main schema (186 Prisma models)
+- `api/prisma/migrations/` — 44 migration files (full schema history)
- `api/prisma/seed.ts` — Database seeding
### Nginx
@@ -742,5 +791,5 @@ V1 code archived in `influence/`, `map/`, and `docker-compose.v1.yml`. Two indep
### Documentation
- `CLAUDE.md` — Project-wide instructions (this file)
- `V2_PLAN.md` — Full 14-phase roadmap
-- `SECURITY_AUDIT_2025-02-11.md` — Security audit report
-- `MEMORY.md` — Development patterns and gotchas
+- `SECURITY_AUDIT_2025-02-11.md` — Initial security audit report
+- `.mcp.json` — MCP server configuration for Claude Code
diff --git a/admin/src/components/AppLayout.tsx b/admin/src/components/AppLayout.tsx
index 47ce2ca5..f63c3dfe 100644
--- a/admin/src/components/AppLayout.tsx
+++ b/admin/src/components/AppLayout.tsx
@@ -647,11 +647,14 @@ export default function AppLayout() {
const getIcon = (iconName: string) => ADMIN_ICON_OVERRIDES[iconName] ?? ICON_MAP[iconName] ??