- Monorepo: Turborepo + pnpm workspaces with 7 apps/packages - Backend: NestJS scaffold with 9 modules (auth, tenant, curriculum, simulation, portfolio, ai-coach, analytics, classroom, gamification) - Frontend: React 18 + Vite + TailwindCSS + shadcn/ui with 10 pages, 14 UI primitives, 3 Zustand stores - Database: Prisma schema with 19 models, 13 enums, seed script, multi-tenant ready - Docker: Dev, production, and Portainer Compose files with Traefik reverse proxy - Configuration: .env.example (47 vars), Zod validation, frontend-safe env exposure - i18n: English + Greek locale files (10 files), ICU MessageFormat, react-i18next - Shared packages: @investplay/types, @investplay/ui, @investplay/i18n, @investplay/utils - CI/CD: GitHub Actions (lint, typecheck, test, build, deploy, PR checks) - Documentation: CONTEXT.md, ARCHITECTURE.md (10 Mermaid diagrams), API.md, LOCALIZATION.md, DEVELOPMENT-ROADMAP.md - Infrastructure: Dockerfiles (dev + prod), nginx configs, backup/healthcheck scripts - Security: JWT auth guards, role-based access, rate limiting, Helmet, CORS, PII sanitization
14 KiB
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
- Project documentation and roadmap
- Monorepo structure (Turborepo + pnpm workspaces)
- Docker Compose for local dev (PostgreSQL, Redis, MinIO, Payload CMS)
- Docker Compose for Contabo/Portainer production deployment
- Environment variable system (.env per service, validation via Zod)
- NestJS backend scaffold with core modules (75 files, 9 modules)
- Prisma schema — 19 models, 13 enums, users, tenants, roles, classrooms
- Auth module (JWT + SSO ready)
- Tenant module (multi-tenancy, feature flags)
- React + Vite frontend scaffold (55+ files, 10 pages, 14 UI primitives)
- TailwindCSS + shadcn/ui design system
- i18n infrastructure (EN + EL, 10 locale files, ICU MessageFormat)
- Shared packages:
@investplay/types,@investplay/ui,@investplay/i18n,@investplay/utils - Payload CMS scaffold with Docker support
- ESLint + Prettier + Husky pre-commit hooks
- CI pipeline (lint, typecheck, test, build) + deploy + PR checks
- 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-i18nextwith 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.DateTimeFormatwith 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 |
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.