341 lines
13 KiB
Markdown
341 lines
13 KiB
Markdown
|
|
# MOPC Platform - Claude Code Context
|
||
|
|
|
||
|
|
## Project Overview
|
||
|
|
|
||
|
|
**MOPC (Monaco Ocean Protection Challenge)** is a secure jury online voting platform for managing project selection rounds. The platform enables jury members to evaluate submitted ocean conservation projects, with Phase 1 supporting two selection rounds:
|
||
|
|
|
||
|
|
- **Round 1**: ~130 projects → ~60 semi-finalists
|
||
|
|
- **Round 2**: ~60 projects → 6 finalists
|
||
|
|
|
||
|
|
**Domain**: `monaco-opc.com`
|
||
|
|
|
||
|
|
The platform is designed for future expansion into a comprehensive program management system including learning hub, communication workflows, and partner modules.
|
||
|
|
|
||
|
|
## Key Decisions
|
||
|
|
|
||
|
|
| Decision | Choice |
|
||
|
|
|----------|--------|
|
||
|
|
| Evaluation Criteria | Fully configurable per round (admin defines) |
|
||
|
|
| CSV Import | Flexible column mapping (admin maps columns) |
|
||
|
|
| Max File Size | 500MB (for videos) |
|
||
|
|
| Observer Role | Included in Phase 1 |
|
||
|
|
| First Admin | Database seed script |
|
||
|
|
| Past Evaluations | Visible read-only after submit |
|
||
|
|
| Grace Period | Admin-configurable per juror/project |
|
||
|
|
| Smart Assignment | AI-powered (GPT) + Smart Algorithm fallback |
|
||
|
|
| AI Data Privacy | All data anonymized before sending to GPT |
|
||
|
|
|
||
|
|
## Brand Identity
|
||
|
|
|
||
|
|
| Name | Hex | Usage |
|
||
|
|
|------|-----|-------|
|
||
|
|
| Primary Red | `#de0f1e` | CTAs, alerts |
|
||
|
|
| Dark Blue | `#053d57` | Headers, sidebar |
|
||
|
|
| White | `#fefefe` | Backgrounds |
|
||
|
|
| Teal | `#557f8c` | Links, secondary |
|
||
|
|
|
||
|
|
**Typography**: Montserrat (600/700 for headings, 300/400 for body)
|
||
|
|
|
||
|
|
## Tech Stack
|
||
|
|
|
||
|
|
| Layer | Technology | Version |
|
||
|
|
|-------|-----------|---------|
|
||
|
|
| **Framework** | Next.js (App Router) | 15.x |
|
||
|
|
| **Language** | TypeScript | 5.x |
|
||
|
|
| **UI Components** | shadcn/ui | latest |
|
||
|
|
| **Styling** | Tailwind CSS | 3.x |
|
||
|
|
| **API Layer** | tRPC | 11.x |
|
||
|
|
| **Database** | PostgreSQL | 16.x |
|
||
|
|
| **ORM** | Prisma | 6.x |
|
||
|
|
| **Authentication** | NextAuth.js (Auth.js) | 5.x |
|
||
|
|
| **AI** | OpenAI GPT | 4.x SDK |
|
||
|
|
| **Animation** | Motion (Framer Motion) | 11.x |
|
||
|
|
| **Notifications** | Sonner | 1.x |
|
||
|
|
| **Command Palette** | cmdk | 1.x |
|
||
|
|
| **File Storage** | MinIO (S3-compatible) | External |
|
||
|
|
| **Email** | Nodemailer + Poste.io | External |
|
||
|
|
| **Containerization** | Docker Compose | 2.x |
|
||
|
|
| **Reverse Proxy** | Nginx | External |
|
||
|
|
|
||
|
|
## Architecture Principles
|
||
|
|
|
||
|
|
1. **Type Safety First**: End-to-end TypeScript from database to UI via Prisma → tRPC → React
|
||
|
|
2. **Mobile-First Responsive**: All components designed for mobile, enhanced for desktop
|
||
|
|
3. **Full Control**: No black-box services; every component is understood and maintainable
|
||
|
|
4. **Extensible Data Model**: JSON fields for future attributes without schema migrations
|
||
|
|
5. **Security by Default**: RBAC, audit logging, secure file access with pre-signed URLs
|
||
|
|
|
||
|
|
## File Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
mopc-platform/
|
||
|
|
├── CLAUDE.md # This file - project context
|
||
|
|
├── docs/
|
||
|
|
│ └── architecture/ # Architecture documentation
|
||
|
|
│ ├── README.md # System overview
|
||
|
|
│ ├── database.md # Database design
|
||
|
|
│ ├── api.md # API design
|
||
|
|
│ ├── infrastructure.md # Deployment docs
|
||
|
|
│ └── ui.md # UI/UX patterns
|
||
|
|
├── src/
|
||
|
|
│ ├── app/ # Next.js App Router pages
|
||
|
|
│ │ ├── (auth)/ # Public auth routes (login, verify)
|
||
|
|
│ │ ├── (admin)/ # Admin dashboard (protected)
|
||
|
|
│ │ ├── (jury)/ # Jury interface (protected)
|
||
|
|
│ │ ├── api/ # API routes
|
||
|
|
│ │ │ └── trpc/ # tRPC endpoint
|
||
|
|
│ │ ├── layout.tsx # Root layout
|
||
|
|
│ │ └── page.tsx # Home/landing
|
||
|
|
│ ├── components/
|
||
|
|
│ │ ├── ui/ # shadcn/ui components
|
||
|
|
│ │ ├── forms/ # Form components (evaluation, etc.)
|
||
|
|
│ │ ├── layouts/ # Layout components (sidebar, nav)
|
||
|
|
│ │ └── shared/ # Shared components
|
||
|
|
│ ├── lib/
|
||
|
|
│ │ ├── auth.ts # NextAuth configuration
|
||
|
|
│ │ ├── prisma.ts # Prisma client singleton
|
||
|
|
│ │ ├── trpc/ # tRPC client & server setup
|
||
|
|
│ │ ├── minio.ts # MinIO client
|
||
|
|
│ │ └── email.ts # Email utilities
|
||
|
|
│ ├── server/
|
||
|
|
│ │ ├── routers/ # tRPC routers by domain
|
||
|
|
│ │ │ ├── program.ts
|
||
|
|
│ │ │ ├── round.ts
|
||
|
|
│ │ │ ├── project.ts
|
||
|
|
│ │ │ ├── user.ts
|
||
|
|
│ │ │ ├── assignment.ts
|
||
|
|
│ │ │ ├── evaluation.ts
|
||
|
|
│ │ │ ├── audit.ts
|
||
|
|
│ │ │ ├── settings.ts
|
||
|
|
│ │ │ └── gracePeriod.ts
|
||
|
|
│ │ ├── services/ # Business logic services
|
||
|
|
│ │ └── middleware/ # RBAC & auth middleware
|
||
|
|
│ ├── hooks/ # React hooks
|
||
|
|
│ ├── types/ # Shared TypeScript types
|
||
|
|
│ └── utils/ # Utility functions
|
||
|
|
├── prisma/
|
||
|
|
│ ├── schema.prisma # Database schema
|
||
|
|
│ ├── migrations/ # Migration files
|
||
|
|
│ └── seed.ts # Seed data
|
||
|
|
├── public/ # Static assets
|
||
|
|
├── docker/
|
||
|
|
│ ├── Dockerfile # Production build
|
||
|
|
│ ├── docker-compose.yml # Production stack
|
||
|
|
│ └── docker-compose.dev.yml # Development stack
|
||
|
|
├── tests/
|
||
|
|
│ ├── unit/ # Unit tests
|
||
|
|
│ └── e2e/ # End-to-end tests
|
||
|
|
└── config files... # package.json, tsconfig, etc.
|
||
|
|
```
|
||
|
|
|
||
|
|
## Coding Standards
|
||
|
|
|
||
|
|
### TypeScript
|
||
|
|
- Strict mode enabled
|
||
|
|
- Explicit return types for functions
|
||
|
|
- Use `type` over `interface` for consistency (unless extending)
|
||
|
|
- Prefer `unknown` over `any`
|
||
|
|
|
||
|
|
### React/Next.js
|
||
|
|
- Use Server Components by default
|
||
|
|
- `'use client'` only when needed (interactivity, hooks)
|
||
|
|
- Collocate components with their routes when specific to that route
|
||
|
|
- Use React Query (via tRPC) for server state
|
||
|
|
|
||
|
|
### Naming Conventions
|
||
|
|
- **Files**: kebab-case (`user-profile.tsx`)
|
||
|
|
- **Components**: PascalCase (`UserProfile`)
|
||
|
|
- **Functions/Variables**: camelCase (`getUserById`)
|
||
|
|
- **Constants**: SCREAMING_SNAKE_CASE (`MAX_FILE_SIZE`)
|
||
|
|
- **Database Tables**: PascalCase in Prisma (`User`, `Project`)
|
||
|
|
- **Database Columns**: camelCase in Prisma (`createdAt`)
|
||
|
|
|
||
|
|
### Styling
|
||
|
|
- Tailwind CSS utility classes
|
||
|
|
- Mobile-first: base styles for mobile, `md:` for tablet, `lg:` for desktop
|
||
|
|
- Use shadcn/ui components as base, customize via CSS variables
|
||
|
|
- No inline styles; no separate CSS files unless absolutely necessary
|
||
|
|
|
||
|
|
### API Design (tRPC)
|
||
|
|
- Group by domain: `trpc.program.create()`, `trpc.round.list()`
|
||
|
|
- Use Zod for input validation
|
||
|
|
- Return consistent response shapes
|
||
|
|
- Throw `TRPCError` with appropriate codes
|
||
|
|
|
||
|
|
## Common Commands
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Development
|
||
|
|
npm run dev # Start Next.js dev server
|
||
|
|
npm run db:studio # Open Prisma Studio
|
||
|
|
npm run db:push # Push schema changes (dev only)
|
||
|
|
npm run db:migrate # Run migrations
|
||
|
|
npm run db:seed # Seed database
|
||
|
|
|
||
|
|
# Testing
|
||
|
|
npm run test # Run unit tests
|
||
|
|
npm run test:e2e # Run E2E tests
|
||
|
|
npm run test:coverage # Test with coverage
|
||
|
|
|
||
|
|
# Build & Deploy
|
||
|
|
npm run build # Production build
|
||
|
|
npm run start # Start production server
|
||
|
|
docker compose up -d # Start Docker stack
|
||
|
|
docker compose logs -f app # View app logs
|
||
|
|
|
||
|
|
# Code Quality
|
||
|
|
npm run lint # ESLint
|
||
|
|
npm run format # Prettier
|
||
|
|
npm run typecheck # TypeScript check
|
||
|
|
```
|
||
|
|
|
||
|
|
## Windows Development Notes
|
||
|
|
|
||
|
|
**IMPORTANT**: On Windows, all Docker commands must be run using PowerShell (`powershell -Command "..."`), not bash/cmd. This is required for proper Docker Desktop integration.
|
||
|
|
|
||
|
|
**IMPORTANT**: When invoking PowerShell from bash, always use `-ExecutionPolicy Bypass` to skip the user profile script which is blocked by execution policy:
|
||
|
|
```bash
|
||
|
|
powershell -ExecutionPolicy Bypass -Command "..."
|
||
|
|
```
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
# Docker commands on Windows (use PowerShell)
|
||
|
|
docker compose -f docker/docker-compose.dev.yml up -d
|
||
|
|
docker compose -f docker/docker-compose.dev.yml build --no-cache app
|
||
|
|
docker compose -f docker/docker-compose.dev.yml logs -f app
|
||
|
|
docker compose -f docker/docker-compose.dev.yml down
|
||
|
|
```
|
||
|
|
|
||
|
|
## Environment Variables
|
||
|
|
|
||
|
|
```env
|
||
|
|
# Database
|
||
|
|
DATABASE_URL="postgresql://user:pass@localhost:5432/mopc"
|
||
|
|
|
||
|
|
# NextAuth
|
||
|
|
NEXTAUTH_URL="https://monaco-opc.com"
|
||
|
|
NEXTAUTH_SECRET="your-secret-key"
|
||
|
|
|
||
|
|
# MinIO (existing separate stack)
|
||
|
|
MINIO_ENDPOINT="http://localhost:9000"
|
||
|
|
MINIO_ACCESS_KEY="your-access-key"
|
||
|
|
MINIO_SECRET_KEY="your-secret-key"
|
||
|
|
MINIO_BUCKET="mopc-files"
|
||
|
|
|
||
|
|
# Email (Poste.io - existing)
|
||
|
|
SMTP_HOST="localhost"
|
||
|
|
SMTP_PORT="587"
|
||
|
|
SMTP_USER="noreply@monaco-opc.com"
|
||
|
|
SMTP_PASS="your-smtp-password"
|
||
|
|
EMAIL_FROM="MOPC Platform <noreply@monaco-opc.com>"
|
||
|
|
|
||
|
|
# OpenAI (for smart assignment)
|
||
|
|
OPENAI_API_KEY="your-openai-api-key"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Key Architectural Decisions
|
||
|
|
|
||
|
|
### 1. Next.js App Router over Pages Router
|
||
|
|
**Rationale**: Server Components reduce client bundle, better data fetching patterns, layouts system
|
||
|
|
|
||
|
|
### 2. tRPC over REST
|
||
|
|
**Rationale**: End-to-end type safety without code generation, excellent DX with autocomplete
|
||
|
|
|
||
|
|
### 3. Prisma over raw SQL
|
||
|
|
**Rationale**: Type-safe queries, migration system, works seamlessly with TypeScript
|
||
|
|
|
||
|
|
### 4. NextAuth.js over custom auth
|
||
|
|
**Rationale**: Battle-tested, supports magic links, session management built-in
|
||
|
|
|
||
|
|
### 5. MinIO (external) over local file storage
|
||
|
|
**Rationale**: S3-compatible, pre-signed URLs for security, scalable, already deployed
|
||
|
|
|
||
|
|
### 6. JSON fields for extensibility
|
||
|
|
**Rationale**: `metadata_json`, `settings_json` allow adding attributes without migrations
|
||
|
|
|
||
|
|
### 7. Soft deletes with status fields
|
||
|
|
**Rationale**: Audit trail preservation, recovery capability, referential integrity
|
||
|
|
|
||
|
|
## User Roles (RBAC)
|
||
|
|
|
||
|
|
| Role | Permissions |
|
||
|
|
|------|------------|
|
||
|
|
| **SUPER_ADMIN** | Full system access, all programs, user management |
|
||
|
|
| **PROGRAM_ADMIN** | Manage specific programs, rounds, projects, jury |
|
||
|
|
| **JURY_MEMBER** | View assigned projects only, submit evaluations |
|
||
|
|
| **OBSERVER** | Read-only access to dashboards (optional) |
|
||
|
|
|
||
|
|
## Important Constraints
|
||
|
|
|
||
|
|
1. **Jury can only see assigned projects** - enforced at query level
|
||
|
|
2. **Voting windows are strict** - submissions blocked outside active window
|
||
|
|
3. **Evaluations are versioned** - edits create new versions
|
||
|
|
4. **All admin actions are audited** - immutable audit log
|
||
|
|
5. **Files accessed via pre-signed URLs** - no public bucket access
|
||
|
|
6. **Mobile responsiveness is mandatory** - every view must work on phones
|
||
|
|
7. **File downloads require project authorization** - jury/mentor must be assigned to the project
|
||
|
|
8. **Mentor endpoints require MENTOR role** - uses `mentorProcedure` middleware
|
||
|
|
|
||
|
|
## Security Notes
|
||
|
|
|
||
|
|
### CSRF Protection
|
||
|
|
tRPC mutations are protected against CSRF attacks because:
|
||
|
|
- tRPC uses `application/json` content type, which triggers CORS preflight on cross-origin requests
|
||
|
|
- Browsers block cross-origin JSON POSTs by default (Same-Origin Policy)
|
||
|
|
- NextAuth's own routes (`/api/auth/*`) have built-in CSRF token protection
|
||
|
|
- No custom CORS headers are configured to allow external origins
|
||
|
|
|
||
|
|
**Do NOT add permissive CORS headers** (e.g., `Access-Control-Allow-Origin: *`) without also implementing explicit CSRF token validation on all mutation endpoints.
|
||
|
|
|
||
|
|
### Rate Limiting
|
||
|
|
- tRPC API: 100 requests/minute per IP
|
||
|
|
- Auth endpoints: 10 POST requests/minute per IP
|
||
|
|
- Account lockout: 5 failed password attempts triggers 15-minute lockout
|
||
|
|
|
||
|
|
## External Services (Pre-existing)
|
||
|
|
|
||
|
|
These services are already running on the VPS in separate Docker Compose stacks:
|
||
|
|
|
||
|
|
- **MinIO**: `http://localhost:9000` - S3-compatible storage
|
||
|
|
- **Poste.io**: `localhost:587` - SMTP server for emails
|
||
|
|
- **Nginx**: Host-level reverse proxy with SSL (certbot)
|
||
|
|
|
||
|
|
The MOPC platform connects to these via environment variables.
|
||
|
|
|
||
|
|
## Phase 1 Scope
|
||
|
|
|
||
|
|
### In Scope
|
||
|
|
- Round management (create, configure, activate/close)
|
||
|
|
- Project import (CSV) and file uploads
|
||
|
|
- Jury invitation (magic link)
|
||
|
|
- Manual project assignment (single + bulk)
|
||
|
|
- Evaluation form (configurable criteria)
|
||
|
|
- Autosave + final submit
|
||
|
|
- Voting window enforcement
|
||
|
|
- Progress dashboards
|
||
|
|
- CSV export
|
||
|
|
- Audit logging
|
||
|
|
|
||
|
|
### Out of Scope (Phase 2+)
|
||
|
|
- Auto-assignment algorithm
|
||
|
|
- Typeform/Notion integrations
|
||
|
|
- WhatsApp notifications
|
||
|
|
- Learning hub
|
||
|
|
- Partner modules
|
||
|
|
- Public website
|
||
|
|
|
||
|
|
## Testing Strategy
|
||
|
|
|
||
|
|
- **Unit Tests**: Business logic, utilities, validators
|
||
|
|
- **Integration Tests**: tRPC routers with test database
|
||
|
|
- **E2E Tests**: Critical user flows (Playwright)
|
||
|
|
- **Manual Testing**: Responsive design on real devices
|
||
|
|
|
||
|
|
## Documentation Links
|
||
|
|
|
||
|
|
- [Architecture Overview](./docs/architecture/README.md)
|
||
|
|
- [Database Design](./docs/architecture/database.md)
|
||
|
|
- [API Design](./docs/architecture/api.md)
|
||
|
|
- [Infrastructure](./docs/architecture/infrastructure.md)
|
||
|
|
- [UI/UX Patterns](./docs/architecture/ui.md)
|