A TypeScript architecture playground for experimenting with AI-assisted development patterns. Features flexible database setup (PGlite/PostgreSQL), pure dependency injection, comprehensive testing strategies, and patterns optimized for Claude Code collaboration.
- AI-Assisted Development: Patterns and documentation optimized for Claude Code collaboration
- Pure Dependency Injection: Clean architecture with the Composer pattern (no DI framework)
- Flexible Database Configuration: Seamlessly switch between PGlite and PostgreSQL
- Lightning-Fast Unit Tests: Test business logic with fake repositories (~300ms for full suite)
- Architecture Experiments: Playground for testing different TypeScript patterns
- Environment-Optimized:
- Development: File-based PGlite with persistent state
- Testing: In-memory PGlite for fast, isolated tests
- Production: Full PostgreSQL
- Modern Stack: TypeScript, Express, TypeORM with constructor injection
- Zero Setup: Works out of the box without PostgreSQL installation
- Type-Safe: Full TypeScript coverage with proper entity definitions
# Install dependencies
npm install
# Run all validation checks (recommended first step)
npm run ci
# Start development server (uses file-based PGlite)
npm run dev
# Start with fresh database and fixtures
npm run dev:fresh
# Use full PostgreSQL in development
npm run dev:postgres
# Run tests (uses in-memory PGlite)
npm testsrc/
βββ config/ # Database configuration
βββ database/ # TypeORM setup and fixtures
βββ di/ # Dependency injection (Composer pattern)
βββ entities/ # Database entities
βββ routes/ # API route factory functions
βββ services/ # Business logic with dependency injection
βββ test/
β βββ unit/ # Unit tests (fast, with fake repositories)
β βββ integration/ # Integration tests (full stack with real databases)
β βββ database/ # Entity integration tests
β βββ routes/ # HTTP route integration tests
βββ server.ts # Express server entry point
- Uses file-based PGlite (
./data/dev.db) - Persists data between restarts
- Automatically loads fixtures on first run
- Fast startup, no external dependencies
- Uses in-memory PGlite
- Fresh database for each test
- Isolated and fast
- Fixtures loaded automatically
- Uses full PostgreSQL
- Configure via
DATABASE_URLenvironment variable - Migrations and proper schema management
# Database configuration
NODE_ENV=development|test|production
DATABASE_TYPE=postgres # Force PostgreSQL in any environment
DATABASE_URL=postgresql://... # PostgreSQL connection string
FORCE_FIXTURES=true # Load fixtures even with existing data
# Server configuration
PORT=3000GET /api/users- List all usersGET /api/users/:id- Get user by IDPOST /api/users- Create new userPUT /api/users/:id- Update userDELETE /api/users/:id- Delete user
GET /- API informationGET /health- Health check with database status
The project uses a clear separation between unit and integration tests:
# Run complete validation suite (TypeScript, linting, formatting, tests)
npm run ci
# Unit tests (fast, pure business logic)
npm run test:unit # Run unit tests once
npm run test:watch:unit # Unit tests in watch mode
# Integration tests (slower, full stack with database)
npm run test:integration # Run integration tests once
npm run test:watch:integration # Integration tests in watch mode
# All tests
npm test # Run all tests (unit + integration)
npm run test:watch # All tests in watch mode
npm run test:coverage # All tests with coverage
# Individual validation steps
npm run typecheck # TypeScript compilation check
npm run lint # Code quality check
npm run format:check # Code formatting checkThis project uses a comprehensive three-layer testing strategy with dependency injection for optimal speed and reliability:
β‘ Unit Tests (src/test/unit/)
- Lightning fast: ~300ms for entire suite, no database overhead
- Test business logic with fake repositories:
{ findOne: async () => mockUser } as any - Services receive injected dependencies for easy mocking
- Focus on: error handling, business rules, edge cases, validation
- Example:
UserService.createUser()with success/failure/validation scenarios
π Entity Integration Tests (src/test/integration/)
- Test database layer with TypeORM entities and real PGlite databases
- Each test gets isolated in-memory database via
src/test/integration/setup.ts - Test data persistence, constraints, relationships, TypeORM behavior
- Example: User entity CRUD operations, constraint violations
π Route Integration Tests (src/test/integration/)
- Test complete HTTP β Routes β Services β Database flow with real Composer
- Use supertest for real HTTP requests through Express app
- Created via
src/test/integration/test-app.tsfactory with dependency injection - Example:
POST /api/userswith validation, persistence, error handling, status codes
ποΈ Architecture Benefits:
- Dependency Injection: Services constructor-inject repositories, routes inject services
- Pure DI Pattern: Composer class handles wiring (no framework complexity)
- Testing Speed: Unit tests for logic (~2ms each), integration for confidence (~10s suite)
- Clear Separation: Unit (business logic) β Integration (data/HTTP) β Full Stack (E2E)
# Remove existing database and start clean
npm run dev:fresh# Use real PostgreSQL (must be running locally)
npm run dev:postgres
# Use PostgreSQL with fresh fixtures
npm run dev:postgres:fresh# Regular development (preserves your data)
npm run dev- File doesn't exist: Creates database with fixtures
- File exists: Uses existing data, runs any pending migrations
- Explicit fixtures: Use
FORCE_FIXTURES=trueto reload
Development fixtures include sample users:
- John Doe ([email protected])
- Jane Smith ([email protected])
- Bob Johnson ([email protected])
Fixtures are loaded automatically in:
- New development databases
- All test environments
- When
FORCE_FIXTURES=true
- Uses TypeORM's
synchronize: truefor rapid iteration - Schema changes are applied automatically
- Disable synchronization
- Use proper migration files
- Run migrations with
npm run migration:run
NODE_ENV=production
DATABASE_URL=postgresql://user:password@host:port/databasenpm run build
npm start- Create service class with constructor injection:
constructor(private repository: Repository<Entity>) - Add service creation method to
Composerclass insrc/di/composer.ts - Write fast unit tests with fake repositories in
src/test/unit/ - Update route factory to receive the service as parameter
- Create route factory function in
src/routes/that takes service dependencies - Update
Composerand server setup to wire the route with dependencies - Add integration tests in
src/test/integration/using the real composer - Test all HTTP methods, status codes, error cases, and edge cases
- Create entity in
src/entities/ - Add to
dataSource.tsentities array - Update fixtures if needed
- Follow service and route patterns above
- Modify
src/config/database.tsfor configuration - Extend
src/database/initialization.tsfor setup logic - Add migrations in
src/migrations/for production
# Development
npm run dev # Standard development
npm run dev:fresh # Reset database
npm run dev:postgres # Use real PostgreSQL
# Validation & Testing
npm run ci # Run all checks (recommended)
npm test # Run all tests (unit + integration)
npm run test:unit # Run unit tests only (fast)
npm run test:integration # Run integration tests only
npm run test:watch # All tests in watch mode
npm run test:watch:unit # Unit tests in watch mode
npm run test:watch:integration # Integration tests in watch mode
# Production
npm run build # Build for production
npm start # Start production server
# Database Management
npm run db:reset # Reset database completely
npm run db:seed # Load fixtures into existing DB
# Utilities
npm run clean # Remove build artifacts
npm run reset # Clean reinstall- Check
/healthendpoint for connection status - Look for database files in
./data/directory - Use
DATABASE_TYPE=postgresto test with real PostgreSQL
- PGlite: Slower than native PostgreSQL but zero setup
- File-based: Faster startup than PostgreSQL for development
- In-memory: Fastest for testing, no persistence
MIT License - feel free to use this as a playground for your TypeScript and AI development experiments!
- Check the
/healthendpoint for system status - Review the console output for initialization details
- Ensure all dependencies are installed with
npm install - For PostgreSQL mode, verify your database is running and accessible