# CLAUDE.md - Project Intelligence ## Project Overview **Org-Parking** is a manager-centric parking spot management system for organizations. It features fair parking assignment based on presence/parking ratio, supporting both standalone JWT authentication and Authelia/LLDAP SSO integration. ### Technology Stack - **Backend:** FastAPI + SQLAlchemy + SQLite - **Frontend:** Vanilla JavaScript (no frameworks) - **Auth:** JWT tokens + Authelia SSO support - **Containerization:** Docker + Docker Compose ### Architecture ``` app/routes/ → API endpoints (auth, users, managers, presence, parking) services/ → Business logic (parking algorithm, auth, notifications) database/ → SQLAlchemy models and connection frontend/ → Static HTML pages + JS modules utils/ → Auth middleware ``` ## Build & Run Commands ```bash # Development python -m uvicorn main:app --reload --host 0.0.0.0 --port 8000 # Docker docker compose up -d # Dependencies pip install -r requirements.txt # Initialize test database python create_test_db.py ``` ## Code Style & Conventions ### Python - FastAPI async patterns with `Depends()` for dependency injection - Pydantic models for request/response validation - SQLAlchemy ORM (no raw SQL) - UUIDs as string primary keys: `str(uuid.uuid4())` - Dates stored as TEXT in "YYYY-MM-DD" format ### JavaScript - ES6 modules with centralized API client (`/js/api.js`) - Token stored in localStorage, auto-included in requests - Utility functions in `/js/utils.js` - Role-based navigation in `/js/nav.js` ### Authentication - Dual mode: JWT tokens (standalone) or Authelia headers (SSO) - LDAP users have `password_hash = None` - Check pattern: `config.AUTHELIA_ENABLED and user.password_hash is None` --- ## Known Issues & Technical Debt ### Critical 1. **Inactive Notification System** - Location: [services/notifications.py](services/notifications.py) - Issue: All code implemented but no scheduler integrated - TODO: Integrate APScheduler or similar 2. **Default SECRET_KEY** - Location: [app/config.py:13](app/config.py#L13) - Issue: Defaults to "change-me-in-production" - Fix: Add startup validation to error if default key used 3. **No CSRF Protection** - Forms use token auth only, vulnerable to CSRF attacks - Fix: Implement CSRF tokens or validate referer header 4. **No Rate Limiting** - Login endpoint has no brute force protection - Fix: Add slowapi or similar middleware ### Performance 1. **N+1 Query Problems** - Location: [app/routes/managers.py:244-259](app/routes/managers.py#L244-L259) - Location: [app/routes/presence.py:336-419](app/routes/presence.py#L336-L419) - Issue: Loops that query database for each item - Fix: Use joins and relationship loading 2. **Inefficient Spot Prefix Lookups** - Location: [services/parking.py:56-64](services/parking.py#L56-L64) - Issue: Repeated DB queries for same data - Fix: Cache in request context ### Code Quality 1. **Duplicated LDAP Check Logic** (4+ locations) ```python # Appears in: users.py:91, 168, 257, 280 is_ldap_user = config.AUTHELIA_ENABLED and user.password_hash is None ``` - Fix: Create `utils.is_ldap_user(user)` helper 2. **Inline JavaScript in HTML** - 500+ lines embedded across pages - Affected: team-rules.html, team-calendar.html, settings.html - Fix: Extract to separate JS files 3. **Inconsistent Response Formats** - Some endpoints return dicts, others Pydantic models - Fix: Standardize on Pydantic response schemas 4. **God Object: User Model** - Location: [database/models.py:11-47](database/models.py#L11-L47) - Issue: 27 columns mixing auth, profile, preferences, manager settings - Fix: Normalize into UserProfile, UserPreferences, ManagerSettings tables 5. **Repetitive CRUD in managers.py** - Location: [app/routes/managers.py](app/routes/managers.py) - Issue: 4 resources × 3 operations with near-identical code - Fix: Create generic CRUD factory or base class 6. **Silent Exception Handling** - Location: [app/routes/presence.py:135-143](app/routes/presence.py#L135-L143) - Issue: Catches all exceptions and only prints - Fix: Log properly and propagate meaningful errors --- ## Areas for Simplification ### 1. Consolidate Response Building The `user_to_response()` pattern is duplicated in [users.py:76-107](app/routes/users.py#L76-L107) and [users.py:254-274](app/routes/users.py#L254-L274). Create single reusable function. ### 2. Generic CRUD Router Factory [managers.py](app/routes/managers.py) has 12 nearly identical endpoints. Create: ```python def create_crud_router(model: Type, schema: Type, parent_key: str): router = APIRouter() # Generate GET, POST, DELETE endpoints return router ``` ### 3. Frontend State Management Each page maintains its own globals (`currentUser`, `currentData`). Consider simple app-level state or Web Components. ### 4. Date Handling All dates stored as TEXT strings. Could use proper DATE columns for better query performance and validation. ### 5. Notification Service Activation Create [services/scheduler.py](services/scheduler.py) with APScheduler: ```python from apscheduler.schedulers.asyncio import AsyncIOScheduler scheduler = AsyncIOScheduler() scheduler.add_job(process_notification_queue, 'interval', minutes=5) ``` --- ## Security Improvements Needed | Priority | Issue | Location | Recommendation | |----------|-------|----------|----------------| | HIGH | Rate limiting | main.py | Add slowapi middleware | | HIGH | CSRF protection | All forms | Implement CSRF tokens | | HIGH | Secret validation | config.py:13 | Error on default key | | MEDIUM | Password validation | auth.py:63-67 | Enforce complexity rules | | MEDIUM | Input sanitization | notification emails | Use template library | | LOW | CORS configuration | compose.yml | Document production settings | --- ## Testing Strategy (Missing) No tests currently exist. Recommended structure: ``` tests/ ├── conftest.py # Fixtures (test DB, client, auth) ├── test_auth.py # JWT and Authelia modes ├── test_parking.py # Fair assignment algorithm ├── test_presence.py # Bulk operations, team calendar ├── test_managers.py # CRUD operations └── integration/ └── test_workflows.py # End-to-end scenarios ``` Key test scenarios: 1. Parking algorithm with varying ratios 2. Manager closing days affect assignments 3. Guarantee and exclusion rules 4. Authelia header authentication flow 5. LDAP vs local user password handling --- ## API Quick Reference ### Authentication - `POST /api/auth/register` - Create user (standalone mode) - `POST /api/auth/login` - Get JWT token - `GET /api/auth/me` - Current user (JWT or Authelia) ### Presence - `POST /api/presence/mark` - Mark single day - `POST /api/presence/mark-bulk` - Mark multiple days - `GET /api/presence/team` - Team calendar with parking ### Parking - `POST /api/parking/manual-assign` - Manager assigns spot - `POST /api/parking/reassign-spot` - Reassign existing spot - `GET /api/parking/eligible-users/{id}` - Users for reassignment ### Manager Settings - `GET/POST/DELETE /api/managers/closing-days` - `GET/POST/DELETE /api/managers/weekly-closing-days` - `GET/POST/DELETE /api/managers/guarantees` - `GET/POST/DELETE /api/managers/exclusions` --- ## Development Notes ### Adding a New Route 1. Create file in `app/routes/` 2. Use `APIRouter(prefix="/api/...", tags=["..."])` 3. Register in `main.py`: `app.include_router(...)` 4. Add auth dependency: `current_user: User = Depends(get_current_user)` ### Database Migrations No migration system (Alembic) configured. Schema changes require: 1. Update [database/models.py](database/models.py) 2. Delete SQLite file or write manual migration 3. Run `create_test_db.py` for fresh database ### Frontend Page Pattern ```html ``` --- ## File Quick Links | Purpose | File | |---------|------| | Main entry | [main.py](main.py) | | Configuration | [app/config.py](app/config.py) | | Database models | [database/models.py](database/models.py) | | Parking algorithm | [services/parking.py](services/parking.py) | | Auth middleware | [utils/auth_middleware.py](utils/auth_middleware.py) | | Frontend API client | [frontend/js/api.js](frontend/js/api.js) | | CSS styles | [frontend/css/styles.css](frontend/css/styles.css) | | Docker config | [compose.yml](compose.yml) |