Skip to main content

Technical context

Short context of the stack and why I chose it. Scope: Stage 1.


Stack at a glance

  • Runtime: Node.js 20+ (upgraded for package compatibility).
  • Frontend: Next.js 15 with React 18, TypeScript, Tailwind CSS v3.
  • Backend: Next.js API Routes, Prisma ORM.
  • DB: PostgreSQL (local, then k8s).
  • Maps: OpenStreetMap (no API keys required) for thumbnail backgrounds.
  • Image Processing: Sharp.js for thumbnail generation.
  • Workers: TypeScript execution with tsx (4 concurrent processes).
  • Styling: Tailwind CSS v3 (downgraded from v4 for CI compatibility).
  • AI: ChatGPT 5 (explore), Claude 4 Sonnet in Cursor (execute; locked).
  • Auth: Strava OAuth + refresh service.
  • Infra: k3s/kind + FluxCD (GitOps) + NAS storage.
  • Debug: Chrome DevTools (cache disabled), structured logs.

Why this stack

  • I want control (self-hosted), portability, and low cost.
  • Node + Prisma + Postgres is quick to iterate and easy to reason about.
  • Next.js API routes cover both web and API in one place for now.
  • GitOps with Flux keeps me honest: everything declarative, easy rollbacks.

Coding style & rules of engagement

  • Prompts follow Assumptions → Request → Safeguards.
  • Small, testable steps. One change → one run.
  • No “Auto” model switching in Cursor. Keep Claude 4 Sonnet locked.
  • Admin “test scripts” are ephemeral; real features get proper routes.
  • AU 24‑hour formatting in UI; SI units; no fabricated splits.

Quality bars (stage 1)

  • API p95 < 50ms on core routes
  • Zero duplicates on re-sync.
  • Thumbnails always present or have a fallback.
  • Best efforts and rankings reproducible and explainable.
  • Backups exist and we've actually tested a restore.

Performance architecture

  • Background Workers: 4 concurrent processes (WEB, THUMB, STRAVA, ACTIVITY).
  • Lazy Loading: Intersection Observer API for efficient image loading.
  • Smart Caching: HTTP caching with stale-while-revalidate headers.
  • Database Optimization: Field selection and proper indexing.
  • Request Reduction: 95% fewer HTTP requests on page load.
  • Response Times: Sub-50ms API responses with intelligent field exclusion.

Code quality & development tooling

Code formatting and linting

  • Prettier - Enforces consistent code formatting across all files.
  • ESLint - Static code analysis with TypeScript and Next.js rules.
  • Husky - Git hooks for automated quality checks.
  • lint-staged - Runs tools only on staged files for performance.

Git hooks

Automated quality gates.

  • Pre-commit: TypeScript type checking + Prettier formatting + ESLint fixes.
  • Commit message: Enforces conventional commit format (type(scope?): description).

Configuration files

  • .prettierrc - Code formatting rules (semicolons, quotes, line width, etc.).
  • .prettierignore - Files excluded from formatting (node_modules, build outputs).
  • eslint.config.js - Modern ESLint v9 flat configuration.
  • .husky/pre-commit - Pre-commit quality checks.
  • .husky/commit-msg - Commit message validation.

Testing and quality assurance

Testing framework

  • Jest - JavaScript testing framework with coverage reporting.
  • React Testing Library - React component testing utilities.
  • @testing-library/jest-dom - Custom Jest matchers for DOM testing.
  • @testing-library/user-event - User interaction simulation.

Test configuration

  • jest.config.mjs - Jest configuration with Next.js integration.
  • jest.setup.js - Global test setup and mocks.
  • Coverage thresholds: Temporarily disabled for Foundation phase (focused on components and lib directories only).

GitLab CI/CD pipeline

Automated quality checks

  • Type checking - TypeScript compilation validation.
  • Code formatting - Prettier format verification.
  • Linting - ESLint rule enforcement.
  • Testing - Jest unit and integration tests with coverage.
  • Documentation sync - Ensures docs match codebase.
  • Dependencies - Audit for security vulnerabilities.
  • Bundle analysis - Size and performance monitoring.
  • React hooks - Hooks rules validation.

Pipeline stages

  1. .pre - Dependency installation with native module build tools.
  2. validate - Type checking, formatting, linting, documentation sync.
  3. test - Jest unit tests with PostgreSQL test database and coverage.
  4. quality - Export checks, dependency audit, React hooks validation, bundle analysis, comprehensive validation.
  5. security - npm security audit for vulnerabilities.

Smart execution

  • Skips on documentation-only changes (docs: commits).
  • Caches node_modules for faster builds.
  • Runs tests with coverage reporting.
  • Artifacts: coverage reports, test results, bundle analysis.

Coverage and reporting

  • JUnit XML reports for test results.
  • Cobertura XML for coverage data.
  • Coverage threshold enforcement.
  • Bundle size tracking.

Scripts

# Development
npm run dev # Start all workers (web + thumbnail + strava + activity)
npm run build # Build for production
npm run start # Start production server

# Workers
npm run thumb:worker # Run thumbnail worker only
npm run strava:worker # Run strava sync worker only
npm run activity:worker # Run activity fetch worker only

# Code Quality
npm run format # Format all files with Prettier
npm run format:check # Check formatting without changes
npm run lint # Run ESLint
npm run lint:fix # Fix ESLint issues automatically
npm run typecheck # Run TypeScript compiler checks

# Testing
npm test # Run all tests
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage report

# Quality Validation
npm run validate # Run all validation checks (type, lint, format, test)
npm run check-exports # Check for unused exports
npm run check-deps # Check dependencies
npm run check-size # Analyze bundle size
npm run check-hooks # Check React hooks

# Webhooks & Database
npm run webhook:setup # Setup webhook subscriptions (interactive)
npm run webhook:create # Create Strava webhook subscription
npm run webhook:list # List webhook subscriptions
npm run webhook:clean # Delete all webhook subscriptions
npm run prisma:studio # Open database admin UI

# Documentation
npm run docs:check # Validate documentation matches codebase

Security (stage 1)

  • Secrets encrypted at rest; mounted as volumes in k8s.
  • Minimal RBAC for admin endpoints.
  • Data minimisation and retention (don’t keep what I don’t need).

Technology decisions and trade-offs

TailwindCSS version decision

v3 vs v4.

Current Choice: TailwindCSS v3.4.16

Context:

  • Initially implemented TailwindCSS v4 for latest features and performance.
  • Encountered CI compatibility issues with lightningcss native binaries.
  • Error: Cannot find module '../lightningcss.linux-x64-gnu.node'.

Root cause analysis:

  • TailwindCSS v4 uses Lightning CSS for performance improvements.
  • Lightning CSS requires platform-specific native binaries.
  • GitLab CI Kubernetes environment had binary resolution issues.
  • Not a stability issue - v4 is production-ready, but a deployment complexity issue.

Decision rationale:

  • Foundation Priority: Stability and CI reliability over cutting-edge performance.
  • Risk Management: v3 has proven CI compatibility across all environments.
  • Development Velocity: Focus on features rather than tooling troubleshooting.
  • Browser Support: v3 provides broader compatibility without additional configuration.

Future migration path:

  • Document v4 migration strategy for post-Foundation implementation.
  • Investigate proper GitLab CI environment configuration for native binaries.
  • Consider migration in Phase 2 when development bandwidth allows.
  • Potential solutions: platform-specific package installation, multi-stage Docker builds.

GitLab CI Environment Considerations

Base image choice: node:20 (debian-based)

  • Switched from Alpine Linux for better native module compatibility.
  • Provides glibc instead of musl for broader package support.
  • Includes Python and build tools for native compilation.
  • Better compatibility with modern JavaScript packages using native binaries.

Project structure

.
├── src/ # Source code directory
│ ├── app/ # Next.js App Router structure
│ │ ├── api/ # API routes
│ │ │ ├── admin/ # Admin endpoints
│ │ │ │ ├── activity-jobs/ # Activity job management
│ │ │ │ ├── calculate-best-efforts/ # Best efforts calculation
│ │ │ │ ├── clear-best-efforts/ # Clear best efforts data
│ │ │ │ ├── fix-fastest-pace/ # Pace correction utilities
│ │ │ │ ├── resync/ # Data resynchronisation
│ │ │ │ ├── sync-streams/ # GPS stream synchronisation
│ │ │ │ ├── thumbnails/ # Thumbnail management
│ │ │ │ └── webhooks/ # Webhook administration
│ │ │ ├── strava/ # Strava API integration
│ │ │ │ ├── activities/ # Activity data endpoints
│ │ │ │ ├── auth/ # OAuth authentication
│ │ │ │ ├── auth-check/ # Authentication validation
│ │ │ │ ├── callback/ # OAuth callback handler
│ │ │ │ ├── disconnect/ # Account disconnection
│ │ │ │ ├── export/ # Data export functionality
│ │ │ │ ├── logout/ # Session termination
│ │ │ │ ├── splits/[id]/ # Activity splits data
│ │ │ │ ├── status/ # Connection status
│ │ │ │ ├── sync/ # Manual synchronisation
│ │ │ │ ├── webhook/ # Webhook processing
│ │ │ │ ├── webhook-debug/ # Webhook debugging
│ │ │ │ └── webhook-simple/ # Simplified webhook handler
│ │ │ ├── activities/ # Activity management
│ │ │ │ ├── [id]/ # Individual activity endpoints
│ │ │ │ │ ├── map/ # Activity map data
│ │ │ │ │ ├── splits/ # Activity splits
│ │ │ │ │ ├── streams/ # GPS stream data
│ │ │ │ │ ├── thumbnail/ # Route thumbnail generation
│ │ │ │ │ └── route.ts # Activity details
│ │ │ │ └── route.ts # Activities list
│ │ │ ├── analytics/ # Analytics and metrics
│ │ │ │ ├── best-efforts/ # Best effort calculations
│ │ │ │ ├── best-efforts-cached/ # Cached best efforts
│ │ │ │ ├── filters/ # Data filtering
│ │ │ │ ├── gps-best-efforts/ # GPS-based calculations
│ │ │ │ └── peak/ # Peak performance metrics
│ │ │ ├── runs/ # Run-specific endpoints
│ │ │ └── debug/ # Debug utilities
│ │ │ └── athlete/ # Athlete debugging tools
│ │ ├── activities/ # Activity pages
│ │ │ └── [id]/ # Individual activity views
│ │ │ ├── page.tsx # Activity detail page
│ │ │ └── splits/ # Activity splits view
│ │ │ └── page.tsx # Splits detail page
│ │ ├── analytics/ # Analytics dashboard
│ │ │ └── page.tsx # Analytics page
│ │ ├── layout.tsx # Root layout
│ │ ├── page.tsx # Home page
│ │ └── globals.css # Global styles (TailwindCSS v3)
│ ├── components/ # React components
│ │ ├── MapOverlay.tsx # Route map overlay component
│ │ └── __tests__/ # Component tests
│ │ └── MapOverlay.test.tsx # MapOverlay component tests
│ ├── lib/ # Utility libraries
│ │ ├── activity-jobs.ts # Activity job management
│ │ ├── db.ts # Database connection and utilities
│ │ ├── rate-limiter.ts # API rate limiting
│ │ ├── strava.ts # Strava API utilities
│ │ ├── strava-tokens.ts # Strava token management
│ │ ├── thumb.ts # Thumbnail generation
│ │ ├── webhook-cache.ts # Webhook caching utilities
│ │ └── __tests__/ # Library tests
│ │ ├── db.test.ts # Database utility tests
│ │ └── strava.test.ts # Strava utility tests
│ ├── server/ # Background workers
│ │ ├── activity-fetch-worker.ts # Activity data fetching
│ │ ├── strava-worker.ts # Strava synchronisation worker
│ │ └── thumb-worker.ts # Thumbnail generation worker
│ └── types/ # TypeScript type definitions
│ └── jest.d.ts # Jest custom matcher types
├── prisma/ # Database configuration
│ ├── migrations/ # Database migrations (14 migrations)
│ │ ├── 20250915093539_init/
│ │ ├── 20250915135244_add_activity_and_split/
│ │ ├── 20250915151523_add_activity_thumb/
│ │ ├── 20250916012607_add_thumbnail_job/
│ │ ├── 20250916014429_add_thumbnail_relation/
│ │ ├── 20250916040013_add_cascade_delete_thumbnail_jobs/
│ │ ├── 20250916123907_add_extended_activity_fields/
│ │ ├── 20250916140642_add_best_efforts/
│ │ ├── 20250917131615_add_strava_tokens/
│ │ ├── 20250917150843_extend_split_model/
│ │ ├── 20250918121220_add_activity_fetch_jobs/
│ │ ├── 20250918133103_add_webhook_subscription_cache/
│ │ ├── 20250918135202_add_strava_token_audit_trail/
│ │ ├── 20250918140837_remove_unique_athleteid_constraint/
│ │ └── migration_lock.toml
│ └── schema.prisma # Database schema definition
├── memory_bank/ # Project documentation
│ ├── activeContext.md # Current development context
│ ├── Concise_Lean_Canvas_Fitness_App.md # Business model
│ ├── dataModels.md # Database schema documentation
│ ├── debugDiary.md # Development debugging log
│ ├── decisionLog.md # Architecture and technology decisions
│ ├── deploymentGuide.md # Deployment and configuration guide
│ ├── git.md # Git workflow and CI/CD documentation
│ ├── kubernetesDeployment.md # Kubernetes deployment guide
│ ├── productContext.md # Product requirements and context
│ ├── progress.md # Development progress tracking
│ ├── projectbrief.md # Project overview and goals
│ ├── systemServices.md # System architecture and services
│ ├── techContext.md # Technical stack and decisions
│ └── WEBHOOKS.md # Webhook implementation details
├── scripts/ # Project automation scripts
│ ├── doc-sync-check.ts # Documentation synchronisation validation
│ └── setup-webhooks.ts # Webhook setup automation
├── Examples/ # Example configurations and references
├── .vscode/ # VS Code configuration
│ ├── settings.json # Editor settings for TailwindCSS
│ ├── extensions.json # Recommended extensions
│ └── css_custom_data.json # CSS custom data for TailwindCSS
├── .husky/ # Git hooks
│ ├── pre-commit # Pre-commit quality checks
│ ├── commit-msg # Commit message validation
│ ├── pre-push # Pre-push formatting validation
│ └── _/ # Husky internal files
├── coverage/ # Test coverage reports (generated)
│ ├── junit.xml # JUnit test results
│ ├── cobertura-coverage.xml # Cobertura coverage report
│ ├── lcov.info # LCOV coverage data
│ └── lcov-report/ # HTML coverage report
├── .env.example # Environment variables template
├── .env # Environment variables (not in Git)
├── .gitignore # Git ignore patterns
├── .prettierrc # Prettier configuration
├── .prettierignore # Prettier ignore patterns
├── eslint.config.mjs # ESLint configuration (v9 flat config)
├── jest.config.mjs # Jest testing configuration
├── jest.setup.js # Jest global setup and mocks
├── .gitlab-ci.yml # GitLab CI/CD pipeline configuration
├── backup.sh # Project backup script
├── nas-backup.sh # NAS backup script
├── fr.sh # Additional utility script
├── next.config.ts # Next.js configuration
├── next-env.d.ts # Next.js TypeScript definitions
├── postcss.config.js # PostCSS configuration
├── tailwind.config.js # TailwindCSS configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.test.json # TypeScript test configuration
├── package.json # Project dependencies and scripts
├── package-lock.json # Dependency lock file
├── policy.yml # Security/policy configuration
├── README.md # Project documentation
└── README-old.md # Previous README version

This structure reflects a comprehensive fitness tracking application with:

  • Real-time Strava integration via webhooks and OAuth.
  • Background workers for data processing and thumbnail generation.
  • Comprehensive testing framework with Jest and React Testing Library.
  • Enterprise-grade CI/CD with GitLab pipeline automation.
  • Complete documentation in the memory bank.
  • Quality tooling with automated formatting, linting, and Git hooks.
  • Backup and recovery scripts for data protection.

Roadmap tie‑in

  • Stage 1 lays the ground for Stage 2 (iOS + HealthKit).
  • Analytics and data shape now will make later features simpler.
  • Comprehensive testing framework enables confident feature development.
  • GitLab CI/CD pipeline ensures quality at scale.