# 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//` - Task detail operations - `POST /api/tasks//start-timer/` - Start time tracking - `POST /api/tasks/time-entries//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//resolve/` - Resolve conflict **Notifications:** - `GET /api/notifications/` - List notifications - `POST /api/notifications//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//start-timer/` creates TimeEntry with start_time 2. Running timer tracked in UI 3. `POST /api/time-entries//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 ```