Documentation for AI agents and developers working with the SubControl codebase
SubControl is a full-stack subscription tracking application built as a demonstration of modern web development best practices. The project showcases a production-ready monorepo architecture with comprehensive testing, CI/CD, and infrastructure as code.
Live Demo: https://subcontrol.online/
API Documentation: https://backend-u7jt.onrender.com/api/
This is an npm workspaces monorepo with the following structure:
SubControl/
├── apps/
│ ├── backend/ # NestJS API server
│ ├── frontend/ # React SPA application
│ └── landing/ # Next.js landing page
├── packages/
│ └── shared-dtos/ # Shared TypeScript DTOs between frontend/backend
└── e2e/ # Playwright end-to-end tests
Backend (apps/backend/):
- NestJS with TypeScript (strict mode)
- PostgreSQL with Prisma ORM
- JWT authentication with Passport
- Winston logging
- BugSnag error tracking
- Swagger/OpenAPI documentation
- Jest for testing (90% coverage requirement)
Frontend (apps/frontend/):
- React 19 with TypeScript
- Ant Design UI components
- TanStack React Query for data fetching
- Zustand for state management
- Styled Components with design tokens
- React Testing Library
Landing Page (apps/landing/):
- Next.js with App Router
- Mantine UI components
- Hybrid rendering (SSG + CSR)
- Shared theme state with main app
E2E (e2e/):
- Playwright for end-to-end testing
id: Auto-increment integeremail: Unique identifierpassword: Bcrypt hashedisDemo: Boolean flag for demo accounts- Relations: Has many subscriptions
id: Auto-increment integername: Subscription nameuserId: Foreign key to Userperiod: Enum (YEARLY, MONTHLY, WEEKLY)centsPerPeriod: Integer (money stored as cents for precision)currency: Enum (USD, EUR, GBP, JPY, AUD, CAD, RUB, TRY, OTHER)startedAt: DatecancelledAt: Optional datedeletedAt: Soft delete timestamp
Location: /apps/backend/prisma/schema.prisma
- Node.js version specified in
.nvmrc - Docker (for local PostgreSQL)
- npm >= 8.0.0
# Install dependencies
npm install
# Start local database
docker-compose up -d
# Run migrations
cd apps/backend
npx prisma migrate dev
# Start backend (development)
cd apps/backend
npm run start:dev
# Start frontend (development)
cd apps/frontend
npm start
# Start landing page (development)
cd apps/landing
npm run dev
# Run E2E tests
cd e2e
npm test# Build shared DTOs (required before building apps)
npm run build:dtos
# Build backend
cd apps/backend
npm run build
# Build frontend
cd apps/frontend
npm run build
# Build landing
cd apps/landing
npm run buildThe backend follows NestJS module architecture with no circular dependencies:
- auth/: JWT authentication, login/register endpoints
- users/: User management
- subscriptions/: CRUD operations for subscriptions
- health/: Health check endpoints
- transformers/: Response filtering service to prevent sensitive data exposure
- prisma/: Database service module
Key Files:
/apps/backend/src/main.ts- Application bootstrap, CORS, validation pipes, global filters/apps/backend/src/app.module.ts- Root module/apps/backend/src/utils/swagger.ts- Swagger configuration with demo user support/apps/backend/src/config/winston-logger.config.ts- Logging configuration
- components/: Reusable UI components
- pages/: Route-level components
- queries/: React Query hooks for API calls
- hooks/: Custom React hooks (e.g.,
useDemo.ts) - store/: Zustand stores (e.g., theme switcher)
- router/: React Router configuration
- utils/: Utility functions
The packages/shared-dtos/ package contains TypeScript interfaces and validation DTOs that are shared between frontend and backend, ensuring type safety across the stack.
Structure:
auth/: Login/register DTOssubscriptions/: Subscription request/response DTOs
-
Integration Tests (
apps/backend/tests/integration/)- Test controllers with real database (test DB)
- Can run in parallel
- Example:
subscriptions.controller.spec.ts
-
Unit Tests (
apps/backend/tests/unit/)- Test individual services and utilities
- Example:
prisma.service.spec.ts
-
E2E Tests (
apps/backend/tests/e2e/)- Test full API workflows
- Configuration:
jest-e2e.json
Coverage Requirement: 90% (configured in jest.config.js)
- React Testing Library for component integration tests
- Example:
apps/frontend/src/pages/Login.test.tsx
- Playwright tests for critical user flows
- Example:
e2e/tests/main-flow-smoke.spec.ts
- Request Validation: ValidationPipe with
whitelist: trueremoves extra fields - Response Filtering: Transformer service filters responses per DTOs
- Password Security: Bcrypt hashing
- JWT Authentication: Secure token-based auth
- CORS: Configured for specific origins only
- No Sensitive Logs: Only log IDs, never passwords or tokens
- Production:
https://backend-u7jt.onrender.com/api/v1 - Local:
http://localhost:3001/api/v1
Auth:
POST /auth/register- Register new userPOST /auth/login- Login and get JWT token
Subscriptions:
GET /subscriptions- List user's subscriptionsPOST /subscriptions- Create subscriptionGET /subscriptions/:id- Get single subscriptionPATCH /subscriptions/:id- Update subscriptionDELETE /subscriptions/:id- Soft delete subscription
Health:
GET /health- Health check
All protected endpoints require JWT token in Authorization header:
Authorization: Bearer <token>
- Uses Prisma ORM
- Connection string in
DATABASE_URLenvironment variable - Local dev uses Docker PostgreSQL (docker-compose.yml)
- Location:
/apps/backend/prisma/migrations/ - Command:
npx prisma migrate dev - All migrations are version controlled
- Seed files in
/apps/backend/tests/seeds/ - Used for testing
DATABASE_URL=postgresql://user:password@localhost:5432/main_database
JWT_SECRET=your-secret-key
BUGSNAG_API_KEY=your-bugsnag-key
NODE_ENV=development|production
REACT_APP_API_URL=http://localhost:3001/api/v1
- Location:
.github/workflows/ - Runs on: Push to main, pull requests
- Checks:
- Linting (ESLint)
- Code formatting (Prettier)
- Tests (Jest, Playwright)
- Build validation
- Infrastructure as code:
render.yaml - Backend hosted on Render
- Frontend hosted on Render
- Landing page hosted on Render
# Lint all code
npm run lint
# Fix linting issues
npm run lint:fix
# Check formatting
npm run format:check
# Format code
npm run format- Strict mode enabled in all
tsconfig.jsonfiles - No implicit any
- Strict null checks
-
Naming:
- Files: kebab-case (e.g.,
subscriptions.controller.ts) - Classes: PascalCase (e.g.,
SubscriptionsController) - Variables/functions: camelCase (e.g.,
getUserSubscriptions) - Constants: UPPER_SNAKE_CASE (e.g.,
MAX_RETRIES)
- Files: kebab-case (e.g.,
-
Module Organization:
- Each feature in its own module
- Services contain business logic
- Controllers handle HTTP
- DTOs define interfaces
-
Testing:
- Test files next to source:
*.spec.ts - Descriptive test names
- Arrange-Act-Assert pattern
- Test files next to source:
- Create/update DTO in
packages/shared-dtos/ - Add controller method in
apps/backend/src/modules/[module]/[module].controller.ts - Add service method in
apps/backend/src/modules/[module]/[module].service.ts - Add Swagger decorators to controller
- Write integration test in
apps/backend/tests/integration/ - Ensure 90% coverage maintained
- Create component in
apps/frontend/src/pages/ - Create styled components in
.styled.tsfile - Add React Query hooks in
apps/frontend/src/queries/ - Update router in
apps/frontend/src/router/ - Write tests with React Testing Library
- Ensure responsive design (mobile, tablet, desktop)
- Update
apps/backend/prisma/schema.prisma - Run
npx prisma migrate dev --name descriptive-migration-name - Update related DTOs in
packages/shared-dtos/ - Update services using the changed models
- Update tests
- Rebuild shared DTOs:
npm run build:dtos
# Root level (for tooling)
npm install -D <package>
# Specific app
npm install --workspace=apps/backend <package>
npm install --workspace=apps/frontend <package>
# Shared package
npm install --workspace=packages/shared-dtos <package>- Money as Cents: All monetary values stored as integers (cents) for precision
- Database Indexing: Email is unique indexed, foreign keys indexed
- Soft Deletes: Subscriptions use
deletedAtinstead of hard deletes - React Memoization: Complex calculations memoized
- Code Splitting: React lazy loading for routes
- Image Optimization: Next.js Image component for landing page
- Winston logger configured per environment
- Logs location:
apps/backend/logs/ - No sensitive data in logs (IDs only)
- React DevTools
- TanStack Query DevTools (enabled in development)
- Zustand DevTools
# Open Prisma Studio
cd apps/backend
npx prisma studio- Demo User Support: Swagger docs can run requests as demo user
- Theme Persistence: Theme state shared between landing and app via cookies
- Responsive Forms: Form elements auto-adjust size on mobile
- Loading States: Skeletons used instead of spinners
- Error Boundary: BugSnag integration for error tracking
- Always rebuild shared DTOs after changes:
npm run build:dtos - Database migrations are required for schema changes
- 90% test coverage is enforced on backend
- No circular dependencies in NestJS modules
- Money must be in cents (integer), never floats
- Dates are stored as Date type in database (no time component for subscription dates)
- Soft deletes for subscriptions (set
deletedAt, don't actually delete) - Validation pipe filters requests - extra fields are removed
- Transformer service filters responses - sensitive fields removed
- Use enums from Prisma schema, don't create duplicate string unions
- README.md: User-facing documentation
- Swagger Docs: https://backend-u7jt.onrender.com/api/
- Prisma Schema:
/apps/backend/prisma/schema.prisma - Test Examples: See
apps/backend/tests/integration/for patterns
This project emphasizes:
- Type Safety: TypeScript strict mode everywhere
- Testing: Integration tests over unit tests (Testing Trophy)
- Security: Input validation, output filtering, secure authentication
- Performance: Optimized rendering, efficient queries, proper indexing
- Maintainability: Clear structure, no circular dependencies, comprehensive docs
- Developer Experience: Good tooling, clear conventions, automated checks
- Production Ready: CI/CD, monitoring, logging, error tracking
Last Updated: December 2025 Repository: https://github.com/loburets/SubControl