Responsive web application for booking open workspaces, closed offices, and meeting rooms. Built with Clean Architecture, React + TypeScript + Material UI, .NET 8, PostgreSQL 16, and Microsoft Entra ID.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PRESENTATION LAYER β
β βββββββββββββββββββββββ βββββββββββββββββββββββββββββββ β
β β React Frontend β β .NET 8 Web API β β
β β (Material UI) β β (API Endpoints) β β
β βββββββββββββββββββββββ βββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β APPLICATION LAYER β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Use Cases / Application Services / DTOs / Validators β β
β β (WorkplaceBooking.Application) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DOMAIN LAYER β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Entities / Value Objects / Domain Events / Interfaces β β
β β (WorkplaceBooking.Domain) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INFRASTRUCTURE LAYER β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββ βββββββββββββ β
β β EF Core β β Identity β β Email β β Backgroundβ β
β β Repositories β β (Entra ID) β β Service β β Workers β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββ βββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATA LAYER β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PostgreSQL 16 (booking schema) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Layer | Technology | Version |
|---|---|---|
| Frontend | React + TypeScript + Material UI | React 18, TS 5, MUI 5 |
| Backend | .NET 8 Web API | .NET 8.0 LTS |
| Database | PostgreSQL | 16 |
| Auth | Microsoft Entra ID | OIDC/OAuth 2.0 |
| Infrastructure | Ubuntu + Docker Compose + Nginx | 24.04 LTS |
| CI/CD | GitHub Actions | Latest |
workplace-booking-platform/
βββ docs/
β βββ architecture/ # Architecture documentation
β βββ adr/ # Architecture Decision Records
βββ backend/ # .NET 8 backend (Clean Architecture)
β βββ src/
β β βββ WorkplaceBooking.Domain/ # Domain layer (pure C#)
β β βββ WorkplaceBooking.Application/ # Application layer (CQRS/MediatR)
β β βββ WorkplaceBooking.Infrastructure/ # EF Core, repositories, services
β β βββ WorkplaceBooking.SharedKernel/ # Primitives, results, exceptions
β β βββ WorkplaceBooking.API/ # API layer (controllers)
β βββ tests/ # xUnit test projects
β βββ WorkplaceBooking.sln
βββ frontend/ # React + TypeScript + MUI (scaffold)
β βββ src/
β βββ Dockerfile
βββ database/
β βββ scripts/ # SQL bootstrap (001 schema -> 009 seed)
βββ infrastructure/
β βββ docker/ # Docker Compose (base + dev override)
β βββ nginx/ # Nginx configs (dev + production TLS)
β βββ database/ # Seed helpers
βββ .github/workflows/ # CI/CD (GitHub Actions)
βββ render.yaml # Render Blueprint (deploy para pruebas)
- Docker Desktop 4.0+
- .NET 8 SDK (for local backend development)
- Node.js 20 LTS (for local frontend development)
- Git
# Clone and navigate
cd workplace-booking-platform
# Start all services (PostgreSQL, API, Frontend, Nginx, SMTP dev)
docker-compose -f infrastructure/docker/docker-compose.yml \
-f infrastructure/docker/docker-compose.override.yml up -d
# Access applications
# Frontend: http://localhost (Nginx reverse proxy)
# API: http://localhost:8080
# Swagger: http://localhost:8080/swagger
# Scalar: http://localhost:8080/scalar
# pgAdmin: http://localhost:5050 (admin@booking.local / admin) [dev override]
# SMTP UI: http://localhost:2500 [dev override]Backend:
cd backend
dotnet restore WorkplaceBooking.sln
# Database: create schema + extensions, then apply scripts in order
# psql ... -f database/scripts/001_extensions_schema.sql (extensions + schema)
# psql ... -f database/scripts/003_users_roles_profiles.sql
# ... up to 008_seed_data.sql
dotnet run --project src/WorkplaceBooking.ApiFrontend:
cd frontend
npm install
npm run dev- Provider: Microsoft Entra ID (Azure AD)
- Flow: Authorization Code + PKCE (SPA)
- Tokens: JWT Access Tokens + Refresh Tokens (HttpOnly cookies)
- Claims: email, name, jobTitle, department, groups β roles
The database uses schema booking with key tables:
resources- 91 bookable spaces (60 open, 24 closed, 7 meeting rooms)reservations- Time-based bookings with exclusion constraintscheckins- QR-based check-ins for officesnotification_outbox- Transactional outbox for emailsaudit_logs- Immutable audit trailapp_users,business_profiles,application_roles- RBAC/ABAC
See FRD Document for complete schema.
- Primary:
#FFD800(Yellow) - Primary Dark:
#0E0E0E(Near Black) - Backgrounds:
#FFFFFF,#F5F5F5,#F6F0CB - Text:
#0E0E0E,#2A2A2A - Breakpoints: xs(0), sm(600), md(900), lg(1200), xl(1536)
- Accessibility: WCAG AA minimum
# Backend tests
cd backend
dotnet test WorkplaceBooking.sln --configuration Release --collect:"XPlat Code Coverage"
# Frontend (scaffold; add tests as pages are implemented)
cd frontend
npm run lint # ESLint
npm run build # TypeScript check + Vite buildGitHub Actions workflow includes:
- Build & Test - Backend + Frontend
- Security - CodeQL (SAST), Dependabot (SCA), OWASP ZAP (DAST)
- Docker Build - Multi-stage, multi-arch images
- Deploy - Staging (auto), Production (manual approval)
| Document | Description |
|---|---|
| Architecture | Complete system architecture |
| Diagrams | Mermaid diagrams (C4, sequences, ER) |
| Technical Decisions | 25 key decisions with rationale |
| Dependencies | Full dependency catalog |
| ADRs | 18 Architecture Decision Records |
- OWASP Top 10 mitigated
- HTTPS everywhere (Nginx TLS termination)
- JWT validation with JWKS
- Rate limiting (Nginx + ASP.NET Core)
- CSP, HSTS, security headers
- No secrets in repo (Docker secrets / Key Vault)
- Audit logging on all mutations
- Logging: Serilog β Console/Seq (structured JSON)
- Metrics: Prometheus
/metricsendpoint - Tracing: OpenTelemetry β Tempo/Jaeger
- Health:
/health,/health/live,/health/ready
El repo incluye render.yaml (Blueprint) que crea PostgreSQL + API:
- Sube el repo a GitHub y en Render: New β Blueprint β selecciona el repo.
- Llena los secretos marcados
sync: false(AzureAd / Email) en el dashboard. - Bootstrap de la BD (una sola vez): ejecuta
database/bootstrap_full.sql(script combinado que crea extensiones, esquemabooking, tablas, seed de 91 recursos y el usuario de desarrollo). Alternativa manual: ejecutardatabase/scripts/001_...a008_seed_data.sqlen orden. - Verifica:
GET https://<api>.onrender.com/health/liveβHealthy. - CI/CD: agrega los secrets
RENDER_DEPLOY_HOOK_URLyRENDER_APP_URLen GitHub para auto-desplegar en cada push amain.
Nota: en pruebas la API corre con
ASPNETCORE_ENVIRONMENT=Development(auth local, sin Entra ID). Para producciΓ³n cambia aProductiony configura Entra ID real.
Internal use only - Confidential.
Built with Clean Architecture principles for maintainability, testability, and scalability.