Files
KeepItGoingServer/CLAUDE.md
T
Keith SmithandClaude Sonnet 5 a23600a486 Document custom recurrence RRULE patterns and fix stale field names
API.md now lists the supported custom RRULE patterns (every Wednesday,
every other Wednesday, every second Tuesday, every 15th, etc.) matching
the newly implemented dateutil.rrule evaluation. CLAUDE.md's Task model
reference also gets corrected: it listed recurrence_type/recurrence_interval
fields that never existed on the model.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 21:21:50 -06:00

16 KiB

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)

# 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

# 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)

# 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, biweekly, monthly, yearly, or custom RRULE for day-of-week/nth-weekday/day-of-month control)
  • 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:

{
  "device_id": "unique-device-id",
  "last_sync_token": "previous-token-or-null",
  "changes": {
    "tasks": [...],
    "tags": [...],
    "time_entries": [...]
  }
}

Response Format:

{
  "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 (none/daily/weekly/biweekly/monthly/yearly/custom), recurrence_rule (RRULE string, used when recurrence='custom', parsed via dateutil.rrule), recurrence_end_date
  • 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:

python manage.py test                # All tests
python manage.py test users          # Specific app
python manage.py test users.tests.TestUserModel  # Specific test

Docker:

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, which calls calculate_next_due_date(). For recurrence='custom', the next date is computed by evaluating recurrence_rule (an RRULE string) via dateutil.rrule; the web UI's Custom recurrence builder (in templates/tasks/_recurrence_fields.html and static/js/app.js) generates these strings for day-of-week, nth-weekday, and day-of-month patterns. 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:

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