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

447 lines
16 KiB
Markdown

# 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, 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:**
```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` (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:
```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, 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:
```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
```