# Parking Manager A manager-centric parking spot management application with fair assignment algorithm. ## Features - **Manager-centric model**: Managers own parking spots, not offices - **Fair assignment algorithm**: Users with lowest parking/presence ratio get priority - **Presence tracking**: Calendar-based presence marking (present/remote/absent) - **Closing days**: Support for specific dates and weekly recurring closures - **Guarantees & exclusions**: Per-user parking rules - **Authelia/LLDAP integration**: SSO authentication with group-based roles ## Architecture ``` ├── app/ │ ├── routes/ # API endpoints │ │ ├── auth.py # Authentication + holidays │ │ ├── users.py # User management │ │ ├── offices.py # Office CRUD │ │ ├── managers.py # Manager rules (closing days, guarantees) │ │ ├── presence.py # Presence marking │ │ └── parking.py # Parking assignments │ └── config.py # Application configuration ├── database/ │ ├── models.py # SQLAlchemy ORM models │ └── connection.py # Database setup ├── services/ │ ├── auth.py # JWT + password handling │ ├── parking.py # Fair assignment algorithm │ ├── holidays.py # Public holiday calculation │ └── notifications.py # Email notifications (TODO: scheduler) ├── frontend/ │ ├── pages/ # HTML pages │ ├── js/ # JavaScript modules │ └── css/ # Stylesheets └── main.py # FastAPI application entry ``` ## Quick Start (Development) ```bash # Create virtual environment python3 -m venv .venv source .venv/bin/activate # Install dependencies pip install -r requirements.txt # Run development server python main.py ``` Access at http://localhost:8000 ## Docker Deployment ```bash # Build image docker build -t parking-manager . # Run with environment variables docker run -d \ -p 8000:8000 \ -v ./data:/app/data \ -e SECRET_KEY=your-secret-key \ -e AUTHELIA_ENABLED=true \ parking-manager ``` Or use Docker Compose: ```bash docker compose up -d ``` ## Environment Variables | Variable | Description | Default | |----------|-------------|---------| | `SECRET_KEY` | JWT signing key | Random (dev only) | | `HOST` | Bind address | `0.0.0.0` | | `PORT` | Server port | `8000` | | `DATABASE_URL` | SQLite path | `sqlite:///data/parking.db` | | `AUTHELIA_ENABLED` | Enable Authelia SSO | `false` | | `ALLOWED_ORIGINS` | CORS origins | `*` | ### SMTP (Notifications - Optional) | Variable | Description | |----------|-------------| | `SMTP_HOST` | SMTP server hostname | | `SMTP_PORT` | SMTP port (default: 587) | | `SMTP_USER` | SMTP username | | `SMTP_PASSWORD` | SMTP password | | `SMTP_FROM` | From email address | ## Authentication ### Standalone Mode Built-in JWT authentication with bcrypt password hashing. Users register/login via `/login` and `/register`. ### Authelia Mode When `AUTHELIA_ENABLED=true`, the app trusts Authelia headers: - `Remote-User`: User email/username - `Remote-Name`: Display name - `Remote-Groups`: Comma-separated group list Group mapping: - `parking-admins` → admin role - `parking-managers` → manager role - Others → employee role ## User Roles | Role | Permissions | |------|-------------| | **admin** | Full access, manage users/offices | | **manager** | Manage assigned offices, set rules | | **employee** | Mark own presence, view calendar | ## API Endpoints ### Authentication - `POST /api/auth/login` - Login - `POST /api/auth/register` - Register (standalone mode) - `POST /api/auth/logout` - Logout - `GET /api/auth/me` - Current user info - `GET /api/auth/holidays/{year}` - Public holidays ### Users - `GET /api/users` - List users (admin) - `POST /api/users` - Create user (admin) - `PUT /api/users/{id}` - Update user (admin) - `DELETE /api/users/{id}` - Delete user (admin) - `GET /api/users/me/profile` - Own profile - `PUT /api/users/me/settings` - Own settings ### Offices - `GET /api/offices` - List offices - `POST /api/offices` - Create office (admin) - `PUT /api/offices/{id}` - Update office (admin) - `DELETE /api/offices/{id}` - Delete office (admin) ### Managers - `GET /api/managers` - List managers - `GET /api/managers/{id}` - Manager details - `PUT /api/managers/{id}/settings` - Update parking quota (admin) - `GET/POST/DELETE /api/managers/{id}/closing-days` - Specific closures - `GET/POST/DELETE /api/managers/{id}/weekly-closing-days` - Recurring closures - `GET/POST/DELETE /api/managers/{id}/guarantees` - Parking guarantees - `GET/POST/DELETE /api/managers/{id}/exclusions` - Parking exclusions ### Presence - `POST /api/presence/mark` - Mark presence - `POST /api/presence/mark-bulk` - Bulk mark - `GET /api/presence/my-presences` - Own presences - `GET /api/presence/team` - Team calendar (manager/admin) ### Parking - `GET /api/parking/assignments/{date}` - Day's assignments - `GET /api/parking/my-assignments` - Own assignments - `POST /api/parking/manual-assign` - Manual assignment - `POST /api/parking/reassign-spot` - Reassign spot ## Fairness Algorithm Parking spots are assigned based on a fairness ratio: ``` ratio = parking_days / office_days ``` Users with the lowest ratio get priority. Guaranteed users are always assigned first. ## License MIT