Files
org-parking/CLAUDE.md
Stefano Manfredi ce9e2fdf2a fix landing page
2025-12-02 23:18:43 +00:00

254 lines
7.9 KiB
Markdown

# 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
- **Rate Limiting:** slowapi
### Architecture
```
app/
├── config.py → Configuration with logging and validation
└── 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.py → JWT/Authelia authentication
└── helpers.py → Shared utility functions
```
## Build & Run Commands
```bash
# Development
SECRET_KEY=dev-secret-key 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)
- Use `generate_uuid()` from `utils.helpers` for UUIDs
- Use `config.logger` for logging (not print statements)
- 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`
- Use helper: `is_ldap_user(user)` from `utils.helpers`
### Utility Functions (`utils/helpers.py`)
```python
from utils.helpers import (
generate_uuid, # Use instead of str(uuid.uuid4())
is_ldap_user, # Check if user is LDAP-managed
is_ldap_admin, # Check if user is LDAP admin
validate_password, # Returns list of validation errors
format_password_errors, # Format errors into user message
get_notification_default # Get setting value with default
)
```
---
## Configuration (`app/config.py`)
Configuration is environment-based with required validation:
### Required
- `SECRET_KEY` - **MUST** be set (app exits if missing)
### Security
- `RATE_LIMIT_REQUESTS` - Requests per window (default: 5)
- `RATE_LIMIT_WINDOW` - Window in seconds (default: 60)
### Email (org-stack pattern)
- `SMTP_ENABLED` - Set to `true` to enable SMTP sending
- When disabled, emails are logged to `EMAIL_LOG_FILE`
- Follows org-stack pattern: direct send with file fallback
### Logging
- `LOG_LEVEL` - DEBUG, INFO, WARNING, ERROR (default: INFO)
- Use `config.logger` for all logging
---
## Notifications (`services/notifications.py`)
Simplified notification service following org-stack pattern:
```python
from services.notifications import (
send_email, # Direct send or file fallback
notify_parking_assigned, # When spot assigned
notify_parking_released, # When spot released
notify_parking_reassigned, # When spot reassigned
send_presence_reminder, # Weekly presence reminder
send_weekly_parking_summary, # Friday parking summary
send_daily_parking_reminder, # Daily parking reminder
run_scheduled_notifications # Called by cron/scheduler
)
```
### Email Behavior
1. If `SMTP_ENABLED=true`: Send via SMTP
2. If SMTP fails or disabled: Log to `EMAIL_LOG_FILE`
3. Never throws - always returns success/failure
---
## Recent Improvements
### Security Enhancements
- **Required SECRET_KEY**: App exits if not set
- **Rate limiting**: Login/register endpoints limited to 5 req/min
- **Password validation**: Requires uppercase, lowercase, number, 8+ chars
- **Proper logging**: All security events logged
### Performance Optimizations
- **Fixed N+1 queries** in:
- `list_users()` - Batch query for manager names and counts
- `list_managers()` - Batch query for managed user counts
- `get_manager_guarantees()` - Batch query for user names
- `get_manager_exclusions()` - Batch query for user names
### Code Consolidation
- **Utility functions** (`utils/helpers.py`):
- `generate_uuid()` - Replaces 50+ `str(uuid.uuid4())` calls
- `is_ldap_user()` - Replaces 4+ duplicated checks
- `validate_password()` - Consistent password validation
- **Simplified notifications** - Removed queue system, direct send
### Logging Improvements
- Centralized logging via `config.logger`
- Replaced `print()` with proper logging
- Security events logged (login, password change, etc.)
---
## API Quick Reference
### Authentication
- `POST /api/auth/register` - Create user (rate limited)
- `POST /api/auth/login` - Get JWT token (rate limited)
- `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)`
5. Use `config.logger` for logging
6. Use `generate_uuid()` for new records
### Database Changes
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
### Email Testing
With `SMTP_ENABLED=false`, check email log:
```bash
tail -f /tmp/parking-emails.log
```
### Running Scheduled Notifications
Add to cron or systemd timer:
```bash
# Every 5 minutes
*/5 * * * * cd /path/to/org-parking && python -c "
from database.connection import get_db
from services.notifications import run_scheduled_notifications
db = next(get_db())
run_scheduled_notifications(db)
"
```
---
## 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) |
| Notifications | [services/notifications.py](services/notifications.py) |
| Auth middleware | [utils/auth_middleware.py](utils/auth_middleware.py) |
| Utility helpers | [utils/helpers.py](utils/helpers.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) |
| Environment template | [.env.example](.env.example) |
---
## Deployment Notes
### Remote Server
- Host: `rocketscale.it`
- User: `rocky`
- SSH: `ssh rocky@rocketscale.it`
- Project path: `/home/rocky/org-parking`
- Related project: `/home/rocky/org-stack` (LLDAP, Authelia, etc.)
### Environment Variables
Copy `.env.example` to `.env` and configure:
```bash
# Generate secure key
openssl rand -hex 32
```
### Production Checklist
- [ ] Set strong `SECRET_KEY`
- [ ] Configure `ALLOWED_ORIGINS` (not `*`)
- [ ] Set `AUTHELIA_ENABLED=true` if using SSO
- [ ] Configure SMTP or check email log file
- [ ] Set up notification scheduler (cron/systemd)