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
8.5 KiB
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
-
Inactive Notification System
- Location: services/notifications.py
- Issue: All code implemented but no scheduler integrated
- TODO: Integrate APScheduler or similar
-
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
-
No CSRF Protection
- Forms use token auth only, vulnerable to CSRF attacks
- Fix: Implement CSRF tokens or validate referer header
-
No Rate Limiting
- Login endpoint has no brute force protection
- Fix: Add slowapi or similar middleware
Performance
-
N+1 Query Problems
- Location: app/routes/managers.py:244-259
- Location: app/routes/presence.py:336-419
- Issue: Loops that query database for each item
- Fix: Use joins and relationship loading
-
Inefficient Spot Prefix Lookups
- Location: services/parking.py:56-64
- Issue: Repeated DB queries for same data
- Fix: Cache in request context
Code Quality
-
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
- Fix: Create
-
Inline JavaScript in HTML
- 500+ lines embedded across pages
- Affected: team-rules.html, team-calendar.html, settings.html
- Fix: Extract to separate JS files
-
Inconsistent Response Formats
- Some endpoints return dicts, others Pydantic models
- Fix: Standardize on Pydantic response schemas
-
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
-
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
-
Silent Exception Handling
- Location: app/routes/presence.py:135-143
- 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 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:
- Parking algorithm with varying ratios
- Manager closing days affect assignments
- Guarantee and exclusion rules
- Authelia header authentication flow
- LDAP vs local user password handling
API Quick Reference
Authentication
POST /api/auth/register- Create user (standalone mode)POST /api/auth/login- Get JWT tokenGET /api/auth/me- Current user (JWT or Authelia)
Presence
POST /api/presence/mark- Mark single dayPOST /api/presence/mark-bulk- Mark multiple daysGET /api/presence/team- Team calendar with parking
Parking
POST /api/parking/manual-assign- Manager assigns spotPOST /api/parking/reassign-spot- Reassign existing spotGET /api/parking/eligible-users/{id}- Users for reassignment
Manager Settings
GET/POST/DELETE /api/managers/closing-daysGET/POST/DELETE /api/managers/weekly-closing-daysGET/POST/DELETE /api/managers/guaranteesGET/POST/DELETE /api/managers/exclusions
Development Notes
Adding a New Route
- Create file in
app/routes/ - Use
APIRouter(prefix="/api/...", tags=["..."]) - Register in
main.py:app.include_router(...) - Add auth dependency:
current_user: User = Depends(get_current_user)
Database Migrations
No migration system (Alembic) configured. Schema changes require:
- Update database/models.py
- Delete SQLite file or write manual migration
- Run
create_test_db.pyfor 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>
File Quick Links
| 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 |