Backend system for barber shop booking, focused on layered architecture, explicit domain modeling, and database-enforced integrity.
The project prioritizes clear business rules, domain isolation, and SQL-first design for Node.js applications.
Reservation system connecting users and barbers, with schedule conflicts prevented at the database level via constraints.
No redundant application-level pre-validation for concurrency is performed; conflicts are treated as integrity violations and propagated to the domain/application layer.
Core principles:
- Invariants enforced in both domain and database layers
- Unidirectional dependencies between layers
- Documented architectural decisions
- Node.js + TypeScript
- NestJS (application composition and boundary)
- PostgreSQL
- Drizzle ORM (infrastructure layer only)
- pnpm
- Jest (fully configured for integration and unit testing)
Migrations: SQL-first, manually written for explicit control over schema and constraints.
Layered architecture with unidirectional dependencies:
src/
├── domain # Entities, value objects, errors, and contracts
├── application # Use cases and orchestration
└── infrastructure # Database adapters, ORM, and external integrations
Dependency rules:
domainis fully isolated, no external dependenciesapplicationdepends only ondomaininfrastructureimplements contracts defined indomainorapplication- ESLint enforces architecture rules
Full architectural decisions are documented in docs/adr.
-
User Identity root. Email and password hash are validated via Value Objects.
-
Barber Specialization of
Usersharing the same identifier. Stores role-specific data inbarberstable. -
Client Any
Userwho creates a reservation. Not an explicit entity in the domain.
Detailed source of truth: docs/use-cases.md
Implemented and in-progress use cases:
- Create user
- Create barber
- Create reservation
- Cancel reservation
- List barber schedule
- List client reservations
-
PostgreSQL as source of truth
-
Constraints enforce:
- Relational integrity
- Prevention of overlapping reservations
-
Reservation conflicts are detected at the database level and translated to domain errors
-
This approach minimizes race conditions and simplifies application logic
- Unit tests validate domain logic and value objects
- Integration tests enforce invariants under real concurrent conditions
- Transactional repositories and concurrency barrier utilities simulate race conditions
- PostgreSQL
EXCLUDE USING gistconstraints enforce real concurrency protection - Testing workflow and conventions documented in
docs/testing.md
The core system exposes an interactive API documentation using Swagger. When the application is running, the documentation is available at /docs. This allows for exploration of all available endpoints, request schemas, and response types.
To ensure stability and protect the system against abuse, the API implements request rate limiting. Using NestJS Throttler, limits are enforced at the HTTP layer, mitigating brute-force attempts and denial-of-service scenarios.
- ADRs (architectural decisions):
docs/adr - Detailed use cases:
docs/use-cases.md - Testing conventions and concurrency model:
docs/testing.md