# InvestPlay — Development Roadmap > **Status:** Phase 1 — Foundation > **Last Updated:** 2026-06-12 > **Target:** Production-grade, multi-tenant, multi-platform financial literacy platform --- ## Architecture Decisions | Decision | Choice | Rationale | |----------|--------|-----------| | Monorepo Tool | **Turborepo** | Better DX than Nx for this scale; native ESM support | | Package Manager | **pnpm** | Disk-efficient, strict dependency resolution | | Backend Framework | **NestJS** | Modular, DI, GraphQL native, WebSocket integrated | | Frontend Framework | **React + Vite** | Fast HMR, modern tooling, Capacitor/Tauri compatible | | CMS | **Payload CMS** (self-hosted) | Code-first, TypeScript-native, block-based content, i18n built-in | | Database ORM | **Prisma** | Type-safe, migration-first, multi-schema for tenant isolation | | Cache | **Redis** | BullMQ queues + session store + rate limiting | | Auth | **Clerk** (initial) → **Auth0** (B2B SSO) | Fast B2C start, SAML SSO for institutions | | i18n Framework | **next-intl / react-i18next** | ICU message format, locale-aware routing | | CSS Framework | **TailwindCSS** + **shadcn/ui** | Design tokens, accessible components | | Containerization | **Docker Compose** (dev) + **Portainer** (prod) | Consistent local/remote, easy management | | CI/CD | **GitHub Actions** | Free for public repos, Docker layer caching | --- ## Development Phases ### PHASE 1 — Foundation ✅ COMPLETED (2026-06-12) **Goal:** Running monorepo, Docker dev environment, auth, basic API, empty UI shell - [x] Project documentation and roadmap - [x] Monorepo structure (Turborepo + pnpm workspaces) - [x] Docker Compose for local dev (PostgreSQL, Redis, MinIO, Payload CMS) - [x] Docker Compose for Contabo/Portainer production deployment - [x] Environment variable system (.env per service, validation via Zod) - [x] NestJS backend scaffold with core modules (75 files, 9 modules) - [x] Prisma schema — 19 models, 13 enums, users, tenants, roles, classrooms - [x] Auth module (JWT + SSO ready) - [x] Tenant module (multi-tenancy, feature flags) - [x] React + Vite frontend scaffold (55+ files, 10 pages, 14 UI primitives) - [x] TailwindCSS + shadcn/ui design system - [x] i18n infrastructure (EN + EL, 10 locale files, ICU MessageFormat) - [x] Shared packages: `@investplay/types`, `@investplay/ui`, `@investplay/i18n`, `@investplay/utils` - [x] Payload CMS scaffold with Docker support - [x] ESLint + Prettier + Husky pre-commit hooks - [x] CI pipeline (lint, typecheck, test, build) + deploy + PR checks - [x] Comprehensive documentation (CONTEXT.md, ARCHITECTURE.md, API.md, LOCALIZATION.md) ### PHASE 2 — Core Learning (MVP B2C) **Goal:** Self-guided learner can complete lessons and earn XP - [ ] CMS block renderer in frontend (Hero, Text, Quiz, Calculator blocks) - [ ] Lesson progression engine (track → module → lesson → block) - [ ] XP and leveling system - [ ] Badges and achievements - [ ] Quiz/assessment engine - [ ] User dashboard with progress visualization - [ ] Streak tracking - [ ] B2C auth flow (email + social) ### PHASE 3 — Simulations & Gamification **Goal:** Interactive simulations and mini-games work end-to-end - [ ] Blind Scenario engine (historical CSV → WebSocket tick stream) - [ ] Synthetic market generator - [ ] Portfolio management (virtual trades, ROI calculation) - [ ] Budget Game (50/30/20 drag-and-drop) - [ ] Debt Snowball mini-game - [ ] Hype Trap narrative challenge - [ ] Anti-cheat mechanisms - [ ] Simulation leaderboards ### PHASE 4 — AI Coach **Goal:** Context-aware educational AI with cost controls - [ ] AI proxy service (NestJS → OpenAI/Gemini) - [ ] Context injection pipeline - [ ] Token bucket rate limiting (per user, per tenant) - [ ] BYOK (Bring Your Own Key) mode - [ ] Socratic prompt engineering - [ ] Audit logging - [ ] PII sanitization before LLM calls - [ ] Graceful fallback when quota exhausted ### PHASE 5 — Classroom & Institutions (B2B MVP) **Goal:** Teachers can manage classrooms and institutions can deploy - [ ] Teacher dashboard - [ ] Classroom creation with invite codes - [ ] Assignment system - [ ] Live "Time Machine" classroom simulation - [ ] Cohort analytics and heatmaps - [ ] Intervention alerts - [ ] PDF/CSV report generation - [ ] Institution admin panel - [ ] White-label configuration - [ ] Stripe Connect B2B billing - [ ] SSO integration (SAML/OIDC) ### PHASE 6 — Mobile & Desktop **Goal:** Native app wrappers for iOS, Android, Windows, macOS, Linux - [ ] Capacitor wrapper (iOS + Android) - [ ] Push notifications (FCM) - [ ] Offline lesson caching - [ ] Tauri v2 wrapper (Windows, macOS, Linux) - [ ] Desktop-specific features (offline mode, system tray) ### PHASE 7 — Analytics & Reporting **Goal:** Data-driven insights for institutions and platform operators - [ ] Behavioral telemetry pipeline - [ ] Aggregated materialized views (nightly rollups) - [ ] Teacher analytics dashboard - [ ] PDF/CSV automated report generation - [ ] GDPR anonymization pipeline - [ ] Opt-out mechanism for research aggregation - [ ] "Gen Z Financial Behavior Index" report templates ### PHASE 8 — Localization Expansion **Goal:** Full EU language support - [ ] Add DE, FR, ES, IT, PT, NL locales - [ ] CMS content localization workflow - [ ] Locale-specific financial examples (taxes, regulations) - [ ] RTL support readiness - [ ] Locale-aware currency and number formatting ### PHASE 9 — Production Hardening **Goal:** Enterprise-grade security, performance, and reliability - [ ] Load testing (k6 / Artillery) - [ ] Penetration testing - [ ] Database backup/restore automation - [ ] Disaster recovery plan - [ ] Multi-region deployment (EU data residency) - [ ] SOC 2 / ISO 27001 readiness - [ ] SLA monitoring and alerting --- ## i18n Strategy ### Implementation - **UI Strings:** `react-i18next` with ICU MessageFormat in JSON files per locale - **Educational Content:** Payload CMS localized collections (each lesson has locale variants) - **Currency/Number Formatting:** `Intl.NumberFormat` (browser-native, no extra library) - **Date Formatting:** `Intl.DateTimeFormat` with locale-aware relative time ### Locale File Structure ``` packages/i18n/src/locales/ en/ common.json # Buttons, nav, errors finance.json # Financial terms, instrument names gamification.json # XP, badges, achievement names classroom.json # Teacher dashboard, assignments ai-coach.json # AI chat UI strings gr/ common.json finance.json ... ``` ### Initial Languages (Phase 1) - English (en) — Primary development language - Greek (el) — Market entry requirement ### Expansion Languages (Phase 8) - German (de), French (fr), Spanish (es), Italian (it), Portuguese (pt), Dutch (nl) - All EU official languages eventually --- ## Deployment Architecture ### Local Development (Windows) ``` docker compose -f docker-compose.dev.yml up ``` Services: - `api` — NestJS backend (hot-reload via tsx watch) - `web` — Vite React frontend (HMR on port 5173) - `cms` — Payload CMS (port 3000) - `postgres` — PostgreSQL 16 (port 5432) - `redis` — Redis 7 (port 6379) - `minio` — S3-compatible storage (ports 9000/9001) ### Contabo Production (via Portainer) ``` docker compose -f docker-compose.prod.yml up -d ``` Portainer stack deployment with: - Traefik reverse proxy (auto-SSL via Let's Encrypt) - Multi-stage Docker builds (CI → GHCR → Portainer pull) - Health checks on all containers - Log rotation via Docker logging drivers - Database backup sidecar container --- ## Environment Variables All configuration through environment variables. No hardcoded secrets. ### Required ENV Files ``` .env.example # Template for all vars (committed) .env # Local overrides (gitignored) .env.production.example # Production template (committed) ``` ### Key Variable Categories | Category | Variables | |----------|-----------| | Database | `DATABASE_URL`, `DATABASE_POOL_MIN`, `DATABASE_POOL_MAX` | | Redis | `REDIS_URL`, `REDIS_PASSWORD` | | Auth | `JWT_SECRET`, `JWT_EXPIRES_IN`, `CLERK_SECRET_KEY` | | AI | `OPENAI_API_KEY`, `GEMINI_API_KEY`, `AI_DEFAULT_DAILY_LIMIT` | | Storage | `S3_ENDPOINT`, `S3_ACCESS_KEY`, `S3_SECRET_KEY`, `S3_BUCKET` | | Email | `RESEND_API_KEY`, `EMAIL_FROM` | | Billing | `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET` | | Tenant | `TENANT_DEFAULT_AI_MODE`, `TENANT_MAX_TOKENS_MONTHLY` | | i18n | `DEFAULT_LOCALE`, `SUPPORTED_LOCALES` | --- ## Repository Structure ``` investplay/ ├── apps/ │ ├── api/ # NestJS backend │ │ ├── src/ │ │ │ ├── modules/ │ │ │ │ ├── auth/ │ │ │ │ ├── tenant/ │ │ │ │ ├── curriculum/ │ │ │ │ ├── simulation/ │ │ │ │ ├── portfolio/ │ │ │ │ ├── ai-coach/ │ │ │ │ ├── analytics/ │ │ │ │ ├── classroom/ │ │ │ │ └── gamification/ │ │ │ ├── common/ │ │ │ │ ├── guards/ │ │ │ │ ├── decorators/ │ │ │ │ ├── filters/ │ │ │ │ └── interceptors/ │ │ │ ├── config/ │ │ │ └── main.ts │ │ ├── prisma/ │ │ │ ├── schema.prisma │ │ │ └── migrations/ │ │ ├── test/ │ │ ├── Dockerfile │ │ └── package.json │ ├── web/ # React + Vite frontend │ │ ├── src/ │ │ │ ├── components/ │ │ │ ├── pages/ │ │ │ ├── hooks/ │ │ │ ├── stores/ │ │ │ ├── lib/ │ │ │ ├── styles/ │ │ │ └── i18n/ │ │ ├── public/ │ │ ├── index.html │ │ ├── vite.config.ts │ │ ├── Dockerfile │ │ └── package.json │ ├── cms/ # Payload CMS │ │ ├── src/ │ │ │ └── collections/ │ │ ├── package.json │ │ └── Dockerfile │ ├── mobile/ # Capacitor wrapper │ └── desktop/ # Tauri v2 wrapper ├── packages/ │ ├── types/ # @investplay/types │ │ ├── src/ │ │ │ ├── user.ts │ │ │ ├── tenant.ts │ │ │ ├── curriculum.ts │ │ │ ├── simulation.ts │ │ │ ├── portfolio.ts │ │ │ └── analytics.ts │ │ └── package.json │ ├── ui/ # @investplay/ui │ │ ├── src/ │ │ │ ├── components/ │ │ │ └── lib/ │ │ └── package.json │ ├── i18n/ # @investplay/i18n │ │ ├── src/ │ │ │ └── locales/ │ │ └── package.json │ └── utils/ # @investplay/utils │ ├── src/ │ └── package.json ├── docker/ │ ├── docker-compose.dev.yml │ ├── docker-compose.prod.yml │ ├── traefik/ │ │ ├── traefik.yml │ │ └── dynamic.yml │ └── nginx/ │ └── nginx.conf ├── scripts/ │ ├── setup.sh │ ├── seed.ts │ └── backup.sh ├── docs/ │ ├── DEVELOPMENT-ROADMAP.md │ ├── CONTEXT.md │ ├── API.md │ └── ARCHITECTURE.md ├── .github/ │ └── workflows/ │ ├── ci.yml │ └── deploy.yml ├── .env.example ├── .env.production.example ├── turbo.json ├── pnpm-workspace.yaml ├── package.json ├── tsconfig.base.json ├── .eslintrc.js ├── .prettierrc └── README.md ``` --- ## Database Schema (Core Entities) ``` User — id, email, role, locale, tenantId, xp, level Tenant — id, name, domain, branding, featureFlags, aiMode Classroom — id, name, tenantId, teacherId, inviteCode ClassroomStudent — id, classroomId, userId, joinedAt Module — id, cmsId, track, order, tenantId Lesson — id, cmsId, moduleId, order, estimatedMins UserProgress — id, userId, lessonId, status, score, completedAt QuizAttempt — id, userId, quizId, answers, score, timestamp Trade — id, userId, simulationId, asset, amount, timestamp Portfolio — id, userId, simulationId, cashBalance, holdings Badge — id, name, description, icon, criteria UserBadge — id, userId, badgeId, earnedAt AILog — id, tenantId, userId, tokensUsed, timestamp AnalyticsEvent — id, userId, eventType, metadata, timestamp ``` --- ## Key Technical Decisions ### Multi-Tenancy Strategy **Schema-level isolation** via PostgreSQL schemas (one per tenant) for maximum data isolation. Tenant-specific connection pooling via Prisma's multi-schema preview feature. ### API Design - **Primary:** GraphQL for all CRUD operations (type-safe, no over-fetching) - **Real-time:** WebSockets (Socket.io) for live simulations and leaderboards - **Webhooks:** REST endpoints for Stripe, Resend, third-party integrations ### AI Cost Control Backend-side hard enforcement (not reliant on OpenAI budget alerts): - Redis token bucket per user (daily) and per tenant (monthly) - Hard cutoff at quota exhaustion (no grace period) - Admin alert when approaching 80% of monthly quota ### Security - JWT with RS256 (asymmetric) for service-to-service auth - GraphQL query depth limiting (max depth 7) - Rate limiting on all public endpoints - CORS whitelist per tenant domain - Helmet.js for HTTP security headers - Input validation via Zod on every endpoint - Prompt injection defense in AI proxy --- ## Tracking Progress tracked via this file. Each completed task gets `[x]`. Git commits follow Conventional Commits format. CI badges added once pipelines are running.