Architecture Overview
This document provides a high-level overview of the Aaperture application architecture.
Project Structure
aaperture/
├── backend/ # NestJS backend API
├── frontend/ # React frontend application
├── infra/ # Infrastructure (Docker, Liquibase, Caddy)
├── openapi/ # OpenAPI specification
└── docs/ # Documentation
Technology Stack
Backend
- Framework: NestJS (Node.js 22)
- Language: TypeScript
- Database: PostgreSQL with Kysely (type-safe query builder)
- Migrations: Liquibase
- Authentication: JWT + Google OAuth
- File Storage: Cloudflare R2 (S3-compatible)
- WebSocket: Socket.IO
- Validation: Zod
- Cache: Redis (ioredis) for performance and rate limiting
- Rate Limiting: Custom guard with Redis backend
Frontend
- Framework: React 18
- Language: TypeScript
- Routing: TanStack Router
- State Management: Zustand
- Forms: TanStack Form
- API Client: TanStack Query
- Styling: Tailwind CSS
- UI Components: Custom components (shadcn/ui style)
- Internationalization: react-i18next
- WebSocket: Socket.IO Client
- PWA: Progressive Web App with Service Worker (vite-plugin-pwa)
- Push Notifications: Browser push notifications support
Architecture Principles
Clean Architecture & Domain Driven Design
- Domain Layer: Business logic and entities
- Application Layer: Use cases and services
- Infrastructure Layer: Database, external services, APIs
- Presentation Layer: Controllers, DTOs, validation
Key Patterns
- Repository Pattern: Data access abstraction
- Service Layer: Business logic encapsulation
- DTO Pattern: Data transfer objects for API boundaries
- Guard Pattern: Authentication and authorization
- Module Pattern: Feature-based organization
Module Organization
Backend Modules
Core Modules
- auth: Authentication, JWT, Google OAuth, user guards
- users: User management, profile, company information
- db: Database service with Kysely (with configurable timeouts)
- storage: File upload/download to Cloudflare R2
- websocket: Real-time communication
- cache: Redis cache service for performance
- rate-limiting: API rate limiting with Redis backend
- export: Data export service (CSV, Excel, JSON)
- common/timeout: Centralized timeout configuration and management (see TIMEOUT_MANAGEMENT.md)
Business Modules
- duplicates: Duplicate management and registration
- sessions: Session management (weddings, photo sessions)
- contacts: Contact management with location
- tags: Tagging system for sessions and contacts
- notifications: User notification system (in-app + push notifications)
- extraction: OCR and LLM-based data extraction
Frontend Modules
Core
- auth: Authentication context and hooks
- client: API client hooks (TanStack Query)
- components: Reusable UI components
- pages: Page components
- router: Routing configuration
- store: Zustand state management
- i18n: Internationalization
Data Flow
Authentication Flow
- User logs in via Google OAuth
- Backend validates and creates/updates user
- JWT token generated and returned
- Frontend stores token and user data
- Token included in all API requests
- Backend validates token and user status (ACTIVE)
API Request Flow
- Frontend: TanStack Query hook calls API client
- API Client: Adds JWT token to request
- Backend: JWT Guard validates token
- Backend: ActiveUserGuard checks user status
- Backend: Service executes business logic
- Backend: Returns response
- Frontend: TanStack Query updates cache
WebSocket Flow
- Frontend: Connects to WebSocket with JWT token
- Backend: Validates token and establishes connection
- Backend: Emits events to specific users or all users
- Frontend: Receives events and updates UI
Database Schema
Core Tables
- users: User accounts (email, display name, locale, currency, timezone)
- user_metadata: Extended user data (address, phone, company info)
- sessions: Sessions (weddings, photo sessions)
- contacts: Contacts with location data
- tags: Reusable tags
- duplicates: Duplicate registrations
- notifications: User notifications
Relationships
- Users have one user_metadata
- Sessions belong to users (owner_id)
- Contacts belong to users (owner_id)
- Sessions have many contacts (session_contacts)
- Sessions have many tags (session_tags)
- Contacts have many sessions (via session_contacts)
Security
Authentication
- JWT tokens with expiration
- Google OAuth integration
- Token refresh mechanism
Authorization
- User status checks (ACTIVE required for most operations)
- Resource ownership verification
- Permission-based access control (subscription plans with granular permissions)
Guards
AuthGuard('jwt'): Validates JWT tokenActiveUserGuard: Ensures user is ACTIVEverifyUserOwnership: Checks resource ownershipverifyUserCanModify: Combines ACTIVE + ownership checks
Type Safety
OpenAPI-Driven Types
- All API types generated from OpenAPI specification
- Shared types between frontend and backend
- Type-safe API client and server
Database Types
- Kysely provides type-safe database queries
- Database schema types in
database.types.ts - Auto-completion for table and column names
Testing
Backend
- Unit tests with Vitest
- In-memory implementations for repositories
- Test coverage for services and controllers
Frontend
- Unit tests with Vitest
- Component tests
- API client tests
Deployment
Development
- Docker Compose for local development
- Caddy for HTTPS reverse proxy
- Hot reload for both frontend and backend
Production
- Docker containers
- Nginx reverse proxy
- PostgreSQL database
- Cloudflare R2 for file storage
- Liquibase for database migrations
Documentation
See individual module README files for detailed documentation:
backend/src/auth/README.md- Authentication and guardsbackend/src/db/README.md- Database usagebackend/src/storage/README.md- File storagebackend/src/extraction/README.md- OCR and LLM extractionbackend/src/websocket/README.md- WebSocket implementationfrontend/src/client/websocket/README.md- WebSocket clientfrontend/src/store/README.md- State management