Skip to content

Conversation

@george-taschina
Copy link

@george-taschina george-taschina commented Jan 30, 2026

Technical Challenge - Changes Documentation

Original State (origin/main)

The original codebase was a minimal starter with:

API (packages/api):

  • Single 35-line index.ts file with inline Express setup
  • Hardcoded room data from seed file
  • No error handling, logging, or architecture
  • Express v4

Client (packages/client):

  • Basic React app with CSS files per component
  • Components in flat src/components/ and src/pages/ folders
  • Hardcoded progress (always 10%)
  • No answer submission functionality

Infrastructure:

  • Basic docker-compose with just MongoDB
  • No CI/CD

Changes Made (14 commits)

1. Express v4 → v5 Migration + Docker Environment

Commit: 886bea9, 8bbd298

  • Upgraded Express to v5
  • Added Dockerfile.dev for API and client
  • Added services to docker-compose.yml with hot reload
  • Exposed MongoDB port for local development
  • Added CLAUDE.md with project documentation

Full Docker dev environment:

docker-compose up      # Start all services (API, client, MongoDB)
docker-compose down    # Stop all services

No Node.js installation required - hot reload via volume mounts.

2. Backend & Frontend Architecture Refactor

Commit: b198e1b

Transformed single-file API into layered architecture:

packages/api/src/
├── app.ts                 # Express app factory
├── routes.ts              # Route aggregation
├── config/
│   ├── database.ts        # MongoDB singleton
│   └── env.ts             # Zod-validated env vars
├── common/
│   ├── middleware/        # requestId, requestLogger, errorHandler, notFound
│   └── utils/             # ApiError, ApiResponse, logger (Winston)
└── modules/
    ├── health/            # /health endpoint
    └── room/              # handlers, service, repository, validators
  • All responses wrapped in {success, data} or {success, error}
  • Routes prefixed with /api/v1
  • Jest + mongodb-memory-server for testing

3. Shared Types Package

Commit: 6c4a534

Created packages/shared with TypeScript types:

  • Room, Task, Question, QuestionProgress
  • ApiSuccessResponse, ApiErrorResponse
  • Used by both frontend and backend

4. Answer Submission Feature

Commit: a267558

Backend:

  • POST /rooms/:roomCode/questions/:questionOrder endpoint
  • Case-insensitive answer comparison
  • Returns hint on wrong answer
  • findQuestion() and updateQuestionProgress() repository methods
  • Answer field excluded from GET response (security)

Frontend:

  • useSubmitAnswer mutation hook
  • Submit button with loading/error states
  • Visual feedback on correct/incorrect

5. Auto-Complete "No Answer Needed" Questions

Commit: 1213970

  • Added requiresAnswer field to Question type
  • Backend sets based on answer === null
  • Frontend shows disabled input with "No answer needed" placeholder
  • "Continue" button auto-marks as correct

6. Progress Calculation Fix

Commit: bc06e0d

  • Progress now calculated from actual correct answers
  • correctQuestions / totalQuestions * 100

7. XSS Protection

Commit: ba2efb9

  • Created SafeHTML component with DOMPurify
  • Used for question HTML rendering

8. Security Hardening

Commit: cf9b5f7

Security Measure Implementation
CORS Whitelist via ALLOWED_ORIGINS env var
Rate Limiting 100 req/15min on answer submission
Security Headers Helmet middleware
Input Validation roomCode regex /^[a-z0-9-]+$/, answer max 500 chars
Body Size JSON limit 10kb
XSS Room title/describe wrapped in SafeHTML

9. Test Coverage Improvement

Commit: 9f0a02d

Coverage: 14% → 83%

New test files:

  • tests/unit/common/utils/ApiError.test.ts
  • tests/unit/common/utils/ApiResponse.test.ts
  • tests/unit/common/middleware/errorHandler.test.ts
  • tests/unit/modules/room/room.handlers.test.ts
  • tests/unit/modules/room/room.validators.test.ts

Fixed integration test (missing requiresAnswer field)

10. Test Output Cleanup

Commit: e4dcab9

  • Logger silenced during tests (silent: true when NODE_ENV=test)

11. CI/CD Pipeline

Commit: 743d8ab

.github/workflows/ci.yml:

  • Runs on push/PR to main
  • MongoDB service container
  • Steps: install → check (lint+format) → build → test

New packages: packages/shared

New directories:

  • packages/api/src/config/
  • packages/api/src/common/
  • packages/api/src/modules/
  • packages/api/tests/
  • packages/client/src/features/
  • packages/client/src/shared/
  • .github/workflows/

Verification Commands

pnpm install          # Install dependencies
pnpm check            # Lint + format check
pnpm build            # TypeScript compilation
pnpm test             # 59 tests (49 API + 10 client)

# Development (Option 1: Local)
docker-compose up -d mongo
pnpm dev              # API :3001, Client :3000

# Development (Option 2: Full Docker)
docker-compose up     # All services with hot reload
docker-compose down   # Stop all services

🤖 Generated with Claude Code

George Taschina and others added 17 commits January 29, 2026 13:49
…ocker-compose for development environments.

Added CLAUDE.md file.
Updated API's index.ts for migration
- Add Dockerfile.dev for API and client packages
- Update docker-compose.yml with api/client services
- Enable vite host binding for container access

Co-Authored-By: Claude <noreply@anthropic.com>
- Add config layer with Zod env validation + MongoDB singleton
- Add common utils: ApiError, ApiResponse, Winston logger
- Add middleware: requestId, requestLogger, errorHandler, notFound
- Create modules/room with routes/handlers/service/repository pattern
- Add /health endpoint for monitoring
- Wrap all responses in {success, data} or {success, error} envelope
- Move routes to /api/v1 prefix
- Add Jest + mongodb-memory-server tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When pnpm installs winston, it puts the actual files in /workspace/node_modules/.pnpm/... and creates a symlink at /workspace/packages/api/node_modules/winston.

When you mount your host folder:

The real files in .pnpm/ are replaced by your host's (empty) .pnpm/ folder.

The symlink now points to a file that doesn't exist.

Node.js throws the Cannot find package 'winston' error because the link is "dead."
- Fix integration test to insert into separate collections (rooms, tasks, questions)
- Add --forceExit to Jest for proper test exit
- Change vitest to run mode instead of watch
- Exclude dist folders from biome check

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- POST /rooms/:roomCode/questions/:questionOrder endpoint
- Case-insensitive answer comparison, hint on wrong answer
- Repository: findQuestion, updateQuestionProgress methods
- Exclude answer field from room GET response
- Frontend: useSubmitAnswer hook, loading/error states
- Seed data updated with answers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add requiresAnswer field to Question type. Backend sets based on null
answer and auto-marks correct. Frontend shows disabled input with
"No answer needed" placeholder and "Continue" button.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add helmet for security headers
- Configure CORS origin whitelist via ALLOWED_ORIGINS env
- Add rate limiting (100 req/15min) on answer submission
- Add roomCode regex validation, answer max length
- Sanitize room title/describe with SafeHTML

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix integration test missing requiresAnswer field
- Add tests for submitAnswer in RoomService
- Add tests for ApiError, ApiResponse, errorHandler
- Add tests for room handlers and validators
- Exclude coverage folder from biome

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…sion hook

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant