Internal
Public Access
Add CLAUDE.md documentation for Claude Code
Provides comprehensive guidance for future Claude Code instances including development commands, architecture overview, and common patterns. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
7b4d024334
commit
cdcae378b7
@@ -0,0 +1,446 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Local Development (Non-Docker)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set environment for development
|
||||||
|
export DJANGO_SETTINGS_MODULE=config.settings.development
|
||||||
|
|
||||||
|
# Create and activate virtual environment
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Database operations
|
||||||
|
python manage.py migrate
|
||||||
|
python manage.py makemigrations
|
||||||
|
python manage.py createsuperuser
|
||||||
|
|
||||||
|
# Run development server
|
||||||
|
python manage.py runserver
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
python manage.py test
|
||||||
|
|
||||||
|
# Django shell
|
||||||
|
python manage.py shell
|
||||||
|
|
||||||
|
# Collect static files (for production)
|
||||||
|
python manage.py collectstatic --noinput
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development with live reload
|
||||||
|
make dev
|
||||||
|
make dev-build # Rebuild containers
|
||||||
|
|
||||||
|
# Production mode
|
||||||
|
make prod
|
||||||
|
make build # Build production containers
|
||||||
|
make deploy # Full deployment (pull, build, migrate, restart)
|
||||||
|
|
||||||
|
# Database operations
|
||||||
|
make migrate
|
||||||
|
make makemigrations
|
||||||
|
make createsuperuser
|
||||||
|
make dbshell # Access database shell
|
||||||
|
make backup # Backup database
|
||||||
|
|
||||||
|
# Monitoring
|
||||||
|
make logs # All container logs
|
||||||
|
make logs-web # Web container logs only
|
||||||
|
make logs-celery # Celery worker logs
|
||||||
|
make status # Container status
|
||||||
|
|
||||||
|
# Control
|
||||||
|
make stop
|
||||||
|
make restart
|
||||||
|
make clean # Stop and remove all containers/volumes
|
||||||
|
|
||||||
|
# Shell access
|
||||||
|
make shell # Django shell
|
||||||
|
make test # Run tests in container
|
||||||
|
```
|
||||||
|
|
||||||
|
### Celery (Background Tasks)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Local development (non-Docker)
|
||||||
|
# Terminal 1: Run Celery worker
|
||||||
|
celery -A config worker -l info
|
||||||
|
|
||||||
|
# Terminal 2: Run Celery beat (scheduled tasks)
|
||||||
|
celery -A config beat -l info
|
||||||
|
|
||||||
|
# In Docker, Celery runs automatically as separate services
|
||||||
|
```
|
||||||
|
|
||||||
|
## High-Level Architecture
|
||||||
|
|
||||||
|
### Django Apps
|
||||||
|
|
||||||
|
**users/** - User authentication and management
|
||||||
|
- Custom User model with email-based authentication (no username)
|
||||||
|
- Three-tier verification: email verification → admin approval → login
|
||||||
|
- JWT token authentication with refresh tokens
|
||||||
|
- Device token management for push notifications
|
||||||
|
- Rate-limited registration (5/hour) and login (10/hour)
|
||||||
|
|
||||||
|
**tasks/** - Core task management
|
||||||
|
- Hierarchical tasks with parent/subtask relationships
|
||||||
|
- Task status (pending, in_progress, completed, cancelled) and priority (low, medium, high, urgent)
|
||||||
|
- Recurrence patterns (daily, weekly, monthly, yearly, custom RRULE)
|
||||||
|
- Time tracking with start/stop timer functionality
|
||||||
|
- Tag system with colors and icons for organization
|
||||||
|
- Task sharing with permission levels (viewer/editor)
|
||||||
|
- Soft-delete architecture (is_deleted flag) for sync compatibility
|
||||||
|
|
||||||
|
**sync/** - Mobile app synchronization
|
||||||
|
- Offline-first bidirectional sync protocol
|
||||||
|
- Timestamp-based conflict detection with three resolution strategies (local, server, merged)
|
||||||
|
- Multi-device support with independent sync tokens per device
|
||||||
|
- Incremental sync (delta updates) and full sync support
|
||||||
|
- Uses sync_id (UUID) separate from Django id for mobile compatibility
|
||||||
|
- Soft-delete propagation to enable client-side deletion
|
||||||
|
|
||||||
|
**notifications/** - Email notifications and reminders
|
||||||
|
- Daily email digest (overdue + due today tasks)
|
||||||
|
- Timezone-aware scheduling (6-7 AM in user's local time)
|
||||||
|
- Deduplication (one email per user per day)
|
||||||
|
- Celery-based background processing
|
||||||
|
- Recurring task safety net (creates missed recurrences)
|
||||||
|
|
||||||
|
### Key Architectural Patterns
|
||||||
|
|
||||||
|
**UUID Primary Keys** - All models use UUID as primary key for distributed system compatibility and security.
|
||||||
|
|
||||||
|
**Dual ID System** - Each entity has both `id` (Django PK) and `sync_id` (for mobile sync). Sync protocol uses `sync_id` to maintain consistency across devices.
|
||||||
|
|
||||||
|
**Soft Delete Pattern** - All entities have `is_deleted` boolean instead of hard deletes. Dual managers enable filtering:
|
||||||
|
- `objects` - Default manager (excludes deleted)
|
||||||
|
- `all_objects` - Includes deleted items (used in sync)
|
||||||
|
|
||||||
|
**Multiple Serializers Per Context** - Different serializers for list/detail/sync endpoints to optimize performance:
|
||||||
|
- `TaskListSerializer` - Lightweight for list views
|
||||||
|
- `TaskSerializer` - Full details with nested subtasks
|
||||||
|
- `TaskSyncSerializer` - Uses sync_id, includes is_deleted
|
||||||
|
|
||||||
|
**Permission System** - Custom `IsOwnerOrReadOnlyIfShared` permission:
|
||||||
|
- Read access: Owner OR users with shared access
|
||||||
|
- Write access: Owner only
|
||||||
|
- Security filtering in serializers prevents tag/task leakage
|
||||||
|
|
||||||
|
**Custom Authentication Backend** - `EmailVerifiedApprovedBackend` enforces:
|
||||||
|
1. Email verification check
|
||||||
|
2. Admin approval check
|
||||||
|
3. Superusers bypass both checks
|
||||||
|
4. Stores error state in session for web UI
|
||||||
|
|
||||||
|
**Timezone-Aware Operations** - All time calculations use user's timezone:
|
||||||
|
- Daily emails scheduled in user's local 6-7 AM
|
||||||
|
- Overdue calculation relative to user's local date
|
||||||
|
- UTC storage, converted for display and logic
|
||||||
|
|
||||||
|
**Mobile App Support** - `AllowMobileAppFramingMiddleware` detects mobile app via User-Agent and removes X-Frame-Options to allow WebView embedding while maintaining security for web browsers.
|
||||||
|
|
||||||
|
### Sync Protocol Details
|
||||||
|
|
||||||
|
The sync endpoint (`POST /api/sync/`) handles offline-first synchronization:
|
||||||
|
|
||||||
|
**Request Format:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"device_id": "unique-device-id",
|
||||||
|
"last_sync_token": "previous-token-or-null",
|
||||||
|
"changes": {
|
||||||
|
"tasks": [...],
|
||||||
|
"tags": [...],
|
||||||
|
"time_entries": [...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response Format:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sync_token": "new-sync-token",
|
||||||
|
"server_time": "2025-01-10T12:00:00Z",
|
||||||
|
"server_changes": {
|
||||||
|
"tasks": [...],
|
||||||
|
"tags": [...],
|
||||||
|
"time_entries": [...]
|
||||||
|
},
|
||||||
|
"conflicts": [...]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Conflict Detection:** Compares `updated_at` timestamp between client's last sync and server's current state. If server modified entity since last sync, conflict is flagged.
|
||||||
|
|
||||||
|
**Conflict Resolution Strategies:**
|
||||||
|
- **local** - Apply client changes (overwrite server)
|
||||||
|
- **server** - Keep server version (discard client)
|
||||||
|
- **merged** - Accept manually merged data
|
||||||
|
|
||||||
|
### Celery Task Schedule
|
||||||
|
|
||||||
|
Configured in `config/celery.py`:
|
||||||
|
|
||||||
|
**send_daily_task_email** - Runs every hour
|
||||||
|
- Fetches users with email notifications enabled
|
||||||
|
- Converts UTC to user's timezone
|
||||||
|
- Sends email only if user's local time is 6-7 AM
|
||||||
|
- Checks for existing notification to prevent duplicates
|
||||||
|
- Groups tasks: overdue + due today (pending/in_progress only)
|
||||||
|
|
||||||
|
**process_recurring_tasks** - Runs daily at midnight
|
||||||
|
- Safety net for recurring task creation
|
||||||
|
- Processes completions from last 48 hours
|
||||||
|
- Creates next recurrence if missing
|
||||||
|
- Prevents duplicate recurrences
|
||||||
|
|
||||||
|
### Settings Modules
|
||||||
|
|
||||||
|
**config.settings.development** - Local development
|
||||||
|
- DEBUG=True
|
||||||
|
- SQLite database
|
||||||
|
- Console email backend
|
||||||
|
- Minimal security
|
||||||
|
|
||||||
|
**config.settings.production** - Production deployment
|
||||||
|
- DEBUG=False
|
||||||
|
- PostgreSQL required
|
||||||
|
- SMTP email backend
|
||||||
|
- Full security (HTTPS, CSP, HSTS)
|
||||||
|
- Gunicorn with multiple workers
|
||||||
|
|
||||||
|
**config.settings.selfhosted** - Docker/self-hosted
|
||||||
|
- Environment-based configuration
|
||||||
|
- PostgreSQL with health checks
|
||||||
|
- Redis for Celery
|
||||||
|
- Configurable workers and timeout
|
||||||
|
- WhiteNoise for static files
|
||||||
|
|
||||||
|
### Database Models Reference
|
||||||
|
|
||||||
|
**Task Model Fields:**
|
||||||
|
- Hierarchy: `parent` (ForeignKey to self)
|
||||||
|
- Status: pending, in_progress, completed, cancelled
|
||||||
|
- Priority: low, medium, high, urgent
|
||||||
|
- Recurrence: `recurrence_type`, `recurrence_interval`, `recurrence_rule` (RRULE)
|
||||||
|
- Timing: `due_date`, `due_time`, `completed_at`, `created_at`, `updated_at`
|
||||||
|
- Soft delete: `is_deleted` (filters via `SoftDeleteManager`)
|
||||||
|
- Sync: `sync_id` (UUID for mobile sync)
|
||||||
|
- Relationships: `tags` (ManyToMany), `time_entries` (reverse FK)
|
||||||
|
|
||||||
|
**User Model Fields:**
|
||||||
|
- Authentication: `email` (unique), `password`, `first_name`, `last_name`
|
||||||
|
- Verification: `email_verified`, `is_approved`, `approved_by`
|
||||||
|
- Preferences: `timezone`, `reminder_minutes_before`, `notifications_enabled`, `email_notifications_enabled`
|
||||||
|
- UUID primary key for security
|
||||||
|
|
||||||
|
**TimeEntry Model:**
|
||||||
|
- `start_time`, `end_time`, `duration` (auto-calculated)
|
||||||
|
- Foreign keys: `task`, `user`
|
||||||
|
- Soft delete: `is_deleted`
|
||||||
|
|
||||||
|
**TaskShare Model:**
|
||||||
|
- `shared_by`, `shared_with` (User FKs)
|
||||||
|
- `permission_level`: viewer, editor
|
||||||
|
- Can share tasks or tags
|
||||||
|
- Generic relation pattern
|
||||||
|
|
||||||
|
### API Endpoint Overview
|
||||||
|
|
||||||
|
**Authentication:**
|
||||||
|
- `POST /api/users/register/` - Create account (rate limited 5/hour)
|
||||||
|
- `POST /api/users/token/` - Login (rate limited 10/hour)
|
||||||
|
- `POST /api/users/token/refresh/` - Refresh JWT
|
||||||
|
- `POST /api/users/verify-email/` - Verify email token
|
||||||
|
- `POST /api/users/resend-verification/` - Resend verification email
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- `GET/POST /api/tasks/` - List/create tasks (supports filtering by status, priority, tags, search)
|
||||||
|
- `GET/PUT/DELETE /api/tasks/<id>/` - Task detail operations
|
||||||
|
- `POST /api/tasks/<id>/start-timer/` - Start time tracking
|
||||||
|
- `POST /api/tasks/time-entries/<id>/stop/` - Stop timer
|
||||||
|
- `GET/POST /api/tasks/tags/` - Tag management
|
||||||
|
- `GET/POST /api/tasks/shares/` - Share management
|
||||||
|
|
||||||
|
**Sync:**
|
||||||
|
- `POST /api/sync/` - Main sync endpoint (rate limited 100/hour)
|
||||||
|
- `GET /api/sync/conflicts/` - List pending conflicts
|
||||||
|
- `POST /api/sync/conflicts/<id>/resolve/` - Resolve conflict
|
||||||
|
|
||||||
|
**Notifications:**
|
||||||
|
- `GET /api/notifications/` - List notifications
|
||||||
|
- `POST /api/notifications/<id>/read/` - Mark as read
|
||||||
|
- `POST /api/notifications/mark-all-read/` - Mark all read
|
||||||
|
- `GET /api/notifications/unread-count/` - Get unread count
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
Key variables (see `.env.example` and `stack.env.example`):
|
||||||
|
|
||||||
|
**Django Core:**
|
||||||
|
- `SECRET_KEY` - Django secret (generate with `python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"`)
|
||||||
|
- `DEBUG` - Debug mode (False in production)
|
||||||
|
- `ALLOWED_HOSTS` - Comma-separated hosts
|
||||||
|
- `CSRF_TRUSTED_ORIGINS` - HTTPS origins
|
||||||
|
- `SITE_DOMAIN` - Domain for email links
|
||||||
|
|
||||||
|
**Database:**
|
||||||
|
- `DATABASE_URL` - Connection string (e.g., `postgresql://user:pass@host:5432/db`)
|
||||||
|
|
||||||
|
**Redis & Celery:**
|
||||||
|
- `REDIS_URL` - Redis connection (e.g., `redis://localhost:6379/0`)
|
||||||
|
|
||||||
|
**Email:**
|
||||||
|
- `EMAIL_HOST`, `EMAIL_PORT`, `EMAIL_USE_TLS`
|
||||||
|
- `EMAIL_HOST_USER`, `EMAIL_HOST_PASSWORD`
|
||||||
|
- `DEFAULT_FROM_EMAIL` - Sender address
|
||||||
|
- `EMAIL_VERIFICATION_TOKEN_EXPIRY_HOURS` - Token validity (default: 24)
|
||||||
|
|
||||||
|
**Docker/Gunicorn:**
|
||||||
|
- `GUNICORN_WORKERS` - Worker processes (default: 3)
|
||||||
|
- `GUNICORN_TIMEOUT` - Request timeout (default: 60)
|
||||||
|
- `WEB_PORT` - External port (default: 8000)
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Tests located in each app's `tests.py`. Run with:
|
||||||
|
```bash
|
||||||
|
python manage.py test # All tests
|
||||||
|
python manage.py test users # Specific app
|
||||||
|
python manage.py test users.tests.TestUserModel # Specific test
|
||||||
|
```
|
||||||
|
|
||||||
|
Docker:
|
||||||
|
```bash
|
||||||
|
make test # Run tests in container
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deployment Notes
|
||||||
|
|
||||||
|
**Docker Deployment:**
|
||||||
|
- Production uses PostgreSQL (postgres:16-alpine)
|
||||||
|
- Redis for Celery message broker (redis:7-alpine)
|
||||||
|
- Web service runs Gunicorn with configurable workers
|
||||||
|
- Celery worker and beat run as separate services
|
||||||
|
- Health checks on all services
|
||||||
|
- Named volumes for persistence (db_data, redis_data, static_files)
|
||||||
|
- Networks: frontend (web-facing), backend (internal services)
|
||||||
|
|
||||||
|
**Manual Deployment:**
|
||||||
|
- Use `config.settings.production` settings module
|
||||||
|
- Requires PostgreSQL (not SQLite)
|
||||||
|
- Configure SMTP for email
|
||||||
|
- Use Gunicorn behind Nginx reverse proxy
|
||||||
|
- Set up systemd services for Gunicorn, Celery worker, Celery beat
|
||||||
|
- Configure SSL/TLS certificates (Let's Encrypt recommended)
|
||||||
|
- Enable firewall (UFW) with SSH, HTTP, HTTPS only
|
||||||
|
|
||||||
|
**Production Checklist:**
|
||||||
|
- Set DEBUG=False
|
||||||
|
- Use strong SECRET_KEY
|
||||||
|
- Configure ALLOWED_HOSTS (no wildcards)
|
||||||
|
- Set CSRF_TRUSTED_ORIGINS for HTTPS
|
||||||
|
- Use PostgreSQL (not SQLite)
|
||||||
|
- Configure email backend (SMTP)
|
||||||
|
- Enable security headers (in settings)
|
||||||
|
- Set up SSL/TLS certificates
|
||||||
|
- Configure database backups
|
||||||
|
- Set up log rotation
|
||||||
|
- Monitor error logs and uptime
|
||||||
|
|
||||||
|
### Common Development Patterns
|
||||||
|
|
||||||
|
**Creating Recurring Tasks:** When a recurring task is marked complete, the next recurrence is automatically created in `tasks/models.py` `create_next_recurrence()` method. Celery task `process_recurring_tasks()` runs as safety net.
|
||||||
|
|
||||||
|
**Time Entry Workflow:**
|
||||||
|
1. `POST /api/tasks/<id>/start-timer/` creates TimeEntry with start_time
|
||||||
|
2. Running timer tracked in UI
|
||||||
|
3. `POST /api/time-entries/<id>/stop/` sets end_time and calculates duration
|
||||||
|
|
||||||
|
**Email Verification Flow:**
|
||||||
|
1. User registers → `email_verified=False`, `is_approved=False`
|
||||||
|
2. EmailVerificationToken created with 24-hour expiry
|
||||||
|
3. User clicks link → `email_verified=True`, token marked used
|
||||||
|
4. Admins notified via email
|
||||||
|
5. Admin approves in Django admin → `is_approved=True`
|
||||||
|
6. User notified and can now login
|
||||||
|
|
||||||
|
**Adding New Celery Tasks:**
|
||||||
|
1. Create task function in app's `tasks.py` with `@shared_task` decorator
|
||||||
|
2. Add to beat schedule in `config/celery.py` if periodic
|
||||||
|
3. Import in app's `__init__.py` to ensure task registration
|
||||||
|
4. Restart Celery worker and beat services
|
||||||
|
|
||||||
|
**Extending User Model:** The User model is in `users/models.py`. Add fields there, create migration, update serializers and admin if needed.
|
||||||
|
|
||||||
|
**Security Filtering:** When adding new endpoints that query related objects, filter by user in viewset's `get_queryset()`. Example from TaskViewSet:
|
||||||
|
```python
|
||||||
|
def get_queryset(self):
|
||||||
|
return Task.objects.filter(user=self.request.user)
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Structure Reference
|
||||||
|
|
||||||
|
```
|
||||||
|
config/ # Django project configuration
|
||||||
|
settings/ # Environment-specific settings
|
||||||
|
base.py # Shared settings
|
||||||
|
development.py # Local development
|
||||||
|
production.py # Production deployment
|
||||||
|
selfhosted.py # Docker/self-hosted
|
||||||
|
celery.py # Celery configuration
|
||||||
|
urls.py # Root URL configuration
|
||||||
|
wsgi.py # WSGI entry point
|
||||||
|
|
||||||
|
users/ # User management app
|
||||||
|
models.py # User, DeviceToken, EmailVerificationToken
|
||||||
|
views.py # Registration, login, profile
|
||||||
|
serializers.py # User serializers
|
||||||
|
backends.py # EmailVerifiedApprovedBackend
|
||||||
|
utils.py # Email utilities
|
||||||
|
|
||||||
|
tasks/ # Task management app
|
||||||
|
models.py # Task, Tag, TimeEntry, TaskShare
|
||||||
|
views.py # Task CRUD, filtering, timers
|
||||||
|
serializers.py # Multiple serializers per context
|
||||||
|
middleware.py # AllowMobileAppFramingMiddleware
|
||||||
|
permissions.py # IsOwnerOrReadOnlyIfShared
|
||||||
|
|
||||||
|
sync/ # Mobile sync app
|
||||||
|
models.py # SyncLog, SyncConflict
|
||||||
|
views.py # Sync endpoint, conflict resolution
|
||||||
|
serializers.py # SyncSerializer with sync_id
|
||||||
|
|
||||||
|
notifications/ # Notifications app
|
||||||
|
models.py # Notification, ScheduledReminder
|
||||||
|
views.py # Notification CRUD
|
||||||
|
tasks.py # Celery tasks (daily email, recurring tasks)
|
||||||
|
|
||||||
|
templates/ # Django templates
|
||||||
|
base.html # Base template with dark mode
|
||||||
|
tasks/ # Task-related templates
|
||||||
|
users/ # User-related templates
|
||||||
|
|
||||||
|
static/ # Static assets
|
||||||
|
css/ # Stylesheets
|
||||||
|
js/ # JavaScript
|
||||||
|
|
||||||
|
docker/ # Docker-related files
|
||||||
|
docker-compose.yml # Production Docker setup
|
||||||
|
docker-compose.dev.yml # Development overrides
|
||||||
|
Dockerfile # Production image
|
||||||
|
Dockerfile.dev # Development image
|
||||||
|
Makefile # Docker command shortcuts
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user