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=3000- GET /api/users- List all users
- GET /api/users/:id- Get user by ID
- POST /api/users- Create new user
- PUT /api/users/:id- Update user
- DELETE /api/users/:id- Delete user
- GET /- API information
- GET /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