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 test
src/
βββ 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_URL
environment 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 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 check
This 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.ts
factory with dependency injection - Example:
POST /api/users
with 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=true
to 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: true
for 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/database
npm run build
npm start
- Create service class with constructor injection:
constructor(private repository: Repository<Entity>)
- Add service creation method to
Composer
class 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
Composer
and 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.ts
entities array - Update fixtures if needed
- Follow service and route patterns above
- Modify
src/config/database.ts
for configuration - Extend
src/database/initialization.ts
for 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
/health
endpoint for connection status - Look for database files in
./data/
directory - Use
DATABASE_TYPE=postgres
to 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
/health
endpoint 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