A parking management system built with Clean Architecture principles using PHP 8.3, PostgreSQL (relational data), MongoDB (flexible data), and Docker.
- Architecture
- Prerequisites
- Installation
- Running the Project
- Database
- API Endpoints
- Testing
- Project Structure
This project follows Clean Architecture principles with clear separation of concerns:
- Domain Layer: Business entities and repository interfaces (no dependencies)
- Application Layer: Use cases and DTOs (depends only on Domain)
- Infrastructure Layer: Database implementations, external services (depends on Domain)
- Presentation Layer: HTTP controllers, routing (depends on Application)
This project uses a hybrid database approach:
PostgreSQL (Relational Data):
- Users, parkings, reservations, payments
- Parking sessions (stationnements)
- Subscriptions (abonnements)
- Structured data with relationships
MongoDB (Flexible Data):
- Pricing grids (custom rates per parking)
- Subscription time slots (flexible schedules)
- Invoices (variable structure)
- Parking events logs
- System logs
- Docker Desktop (or Docker Engine + Docker Compose)
- Git
- PHP 8.3 or higher
- PostgreSQL 14 or higher
- MongoDB 7 or higher
- Composer
- Apache or Nginx (optional, can use PHP built-in server)
git clone <repository-url>
cd clean_architecturecp .env.exemple .envEdit .env with your database credentials:
# PostgreSQL Database Configuration
POSTGRES_USER=parking_user
POSTGRES_PASSWORD=your_secure_password
POSTGRES_DB=parking_db
# Application Database Connection
DB_HOST=db # Use 'localhost' if running without Docker
DB_NAME=parking_db
DB_USER=parking_user
DB_PASSWORD=your_secure_password
DB_PORT=5432
# MongoDB Configuration
MONGO_USER=parking_mongo
MONGO_PASSWORD=your_mongo_password
MONGO_DB=parking_db# Build and start containers
docker compose up -d --build
# View logs
docker compose logs -fThe application will be available at:
- API: http://localhost
- PostgreSQL: localhost:5432
- MongoDB: localhost:27017
# Start containers
docker compose up -d
# Stop containers
docker compose down
# Stop and remove volumes (fresh database)
docker compose down -v# View logs
docker compose logs -f web
docker compose logs -f db
# Access web container shell
docker exec -it parking_app_web bash
# Access PostgreSQL shell
docker exec -it parking_app_db psql -U parking_user -d parking_db
# Access MongoDB shell
docker exec -it parking_app_mongodb mongosh -u parking_mongo -p your_mongo_password parking_db
# Restart containers
docker compose restart
# Rebuild after code changes
docker compose up -d --buildcomposer installCreate a PostgreSQL database and user:
CREATE DATABASE parking_db;
CREATE USER parking_user WITH PASSWORD 'your_secure_password';
GRANT ALL PRIVILEGES ON DATABASE parking_db TO parking_user;psql -U parking_user -d parking_db -f src/docker/postgres/init.sqlUpdate .env file:
DB_HOST=localhost
DB_NAME=parking_db
DB_USER=parking_user
DB_PASSWORD=your_secure_passwordphp -S localhost:8000 -t publicThe application will be available at: http://localhost:8000
The PostgreSQL database includes the following tables:
- users: User accounts (owners, customers, admins) with company info
- parkings: Parking spots/locations with GPS and opening hours
- reservations: Booking records with payment status
- payments: Payment transactions
- stationnements: Actual parking sessions (entry/exit tracking)
- abonnements: Subscriptions with custom time slots
The MongoDB database includes the following collections:
- pricing_grids: Custom pricing rates per parking (15min, 30min, 1h, 2h, day, night, special rates)
- subscription_time_slots: Flexible time schedules for subscriptions
- invoices: Detailed invoice metadata (items, taxes, totals)
- parking_events: Entry/exit logs and events
- system_logs: Application logs and errors
The database is automatically seeded with test data on first initialization:
| Role | Description | |
|---|---|---|
[email protected] |
Admin | System administrator |
[email protected] |
Owner | Parking spot owner |
[email protected] |
Customer | Regular customer |
- Central Parking Spot: Paris city center (€5.50/hour)
- Airport Parking: Near CDG Airport (€3.00/hour)
# Stop containers and remove volumes
docker compose down -v
# Restart (will recreate database with seed data)
docker compose up -d# Drop and recreate database
psql -U postgres -c "DROP DATABASE parking_db;"
psql -U postgres -c "CREATE DATABASE parking_db;"
psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE parking_db TO parking_user;"
# Re-run initialization script
psql -U parking_user -d parking_db -f src/docker/postgres/init.sqlWith Docker:
# PostgreSQL
docker exec -it parking_app_db psql -U parking_user -d parking_db
# MongoDB
docker exec -it parking_app_mongodb mongosh -u parking_mongo -p your_mongo_password parking_dbWithout Docker:
# PostgreSQL
psql -U parking_user -d parking_db
# MongoDB
mongosh -u parking_mongo -p your_mongo_password parking_dbcurl http://localhost/healthResponse:
{
"status": "ok",
"message": "Clean Architecture Parking API is running",
"timestamp": "2025-11-25T10:00:00+00:00",
"environment": {
"php_version": "8.3.x",
"db_host": "db"
}
}curl http://localhost/db-testResponse:
{
"status": "success",
"message": "Database connection successful",
"database": {
"version": "PostgreSQL 14.x...",
"host": "db",
"name": "parking_db",
"tables_count": "6"
}
}curl http://localhost/mongo-testResponse:
{
"status": "success",
"message": "MongoDB connection successful",
"database": {
"host": "mongodb",
"name": "parking_db",
"collections_count": "5"
}
}# With Docker
docker exec -it parking_app_web ./vendor/bin/phpunit
# Without Docker
./vendor/bin/phpunit# With Docker
docker exec -it parking_app_web ./vendor/bin/phpunit --coverage-html coverage
# Without Docker
./vendor/bin/phpunit --coverage-html coverage/
├── bin/ # Executable scripts
├── config/ # Configuration files
│ ├── database.php # PostgreSQL PDO configuration
│ └── mongodb.php # MongoDB client configuration
├── public/ # Web root (Front Controller)
│ └── index.php # Application entry point
├── src/ # Application source code
│ ├── Application/ # Use Cases and DTOs
│ │ ├── dtos/
│ │ ├── services/
│ │ └── usecases/
│ ├── Domain/ # Business entities and rules
│ │ ├── Entities/
│ │ └── Repositories/ # Repository interfaces
│ ├── Infrastructure/ # Technical implementations
│ │ ├── persistences/ # Database repositories
│ │ │ ├── PostgreSQL/ # SQL repositories
│ │ │ └── MongoDB/ # NoSQL repositories
│ │ └── services/ # External services
│ ├── Presentation/ # HTTP layer
│ │ └── router.php
│ └── docker/ # Docker configuration
│ ├── php/
│ │ └── Dockerfile
│ ├── postgres/
│ │ └── init.sql # PostgreSQL schema
│ └── mongodb/
│ └── init-mongo.js # MongoDB collections
├── tests/ # Test files
├── .env # Environment variables (not in git)
├── .env.exemple # Environment template
├── composer.json # PHP dependencies
└── docker-compose.yml # Docker services configuration
The project uses PSR-4 autoloading with the following namespaces:
App\Domain\→src/Domain/App\Application\→src/Application/App\Infrastructure\→src/Infrastructure/App\Presentation\→src/Presentation/
- PHP 8.3+ with strict types
- Clean Architecture principles
- Hybrid database architecture (PostgreSQL + MongoDB)
- Repository pattern for data access
- Dependency injection
- SOLID principles
MIT
HETIC Student Project
Port already in use:
# Change ports in docker-compose.yml
ports:
- "8080:80" # Instead of "80:80"Database connection fails:
# Check if database is ready
docker compose logs db
# Restart database
docker compose restart dbPermission issues:
# Fix permissions
sudo chown -R $USER:$USER .Composer not found:
# Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composerPostgreSQL connection refused:
# Check if PostgreSQL is running
sudo systemctl status postgresql
# Start PostgreSQL
sudo systemctl start postgresqlPHP extensions missing:
# Install required extensions
sudo apt-get install php8.3-pgsql php8.3-zip php8.3-gd php8.3-mongodbMongoDB connection issues:
# Check MongoDB logs
docker compose logs mongodb
# Restart MongoDB
docker compose restart mongodb- Implement your first use case in
src/Application/usecases/ - Create repository implementations in
src/Infrastructure/persistences/ - Add controllers in
src/Presentation/ - Write tests in
tests/ - Expand the API with more endpoints
Happy coding! 🎉