Files
org-parking/CLAUDE.md
Stefano Manfredi 7168fa4b72 Refactor to manager-centric model, add team calendar for all users
Key changes:
- Removed office-centric model (deleted offices.py, office-rules)
- Renamed to team-rules, managers are part of their own team
- Team calendar visible to all (read-only for employees)
- Admins can have a manager assigned
2025-12-02 13:30:04 +00:00

8.5 KiB
Raw Blame History

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

# 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
    • Issue: All code implemented but no scheduler integrated
    • TODO: Integrate APScheduler or similar
  2. Default SECRET_KEY

    • Location: app/config.py:13
    • 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

  2. Inefficient Spot Prefix Lookups

Code Quality

  1. Duplicated LDAP Check Logic (4+ locations)

    # 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
    • 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
    • Issue: 4 resources × 3 operations with near-identical code
    • Fix: Create generic CRUD factory or base class
  6. Silent Exception Handling


Areas for Simplification

1. Consolidate Response Building

The user_to_response() pattern is duplicated in users.py:76-107 and users.py:254-274. Create single reusable function.

2. Generic CRUD Router Factory

managers.py has 12 nearly identical endpoints. Create:

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 with APScheduler:

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
  2. Delete SQLite file or write manual migration
  3. Run create_test_db.py for fresh database

Frontend Page Pattern

<script type="module">
import api from '/js/api.js';
import { initNav } from '/js/nav.js';

document.addEventListener('DOMContentLoaded', async () => {
    await api.checkAuth(true);  // Redirect to login if not auth'd
    initNav();
    // Page-specific logic
});
</script>

Purpose File
Main entry main.py
Configuration app/config.py
Database models database/models.py
Parking algorithm services/parking.py
Auth middleware utils/auth_middleware.py
Frontend API client frontend/js/api.js
CSS styles frontend/css/styles.css
Docker config compose.yml