254 lines
7.9 KiB
Markdown
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)
|