---
phase: 06-deployment
plan: 02
type: execute
wave: 2
depends_on: ["06-01"]
files_modified:
  - src/routes/health/+server.ts
  - .env.example
  - backup.sh
  - README.md
autonomous: true

must_haves:
  truths:
    - "Health endpoint returns 200 when database is accessible"
    - "Health endpoint returns 503 when database fails"
    - "Environment variables are documented with examples"
    - "Backup script creates timestamped archive of data volume"
  artifacts:
    - path: "src/routes/health/+server.ts"
      provides: "Health check endpoint for Docker"
      exports: ["GET"]
    - path: ".env.example"
      provides: "Environment variable documentation"
      contains: "TASKPLANER_DATA_DIR"
    - path: "backup.sh"
      provides: "Volume backup script"
      contains: "tar czf"
  key_links:
    - from: "Dockerfile"
      to: "src/routes/health/+server.ts"
      via: "HEALTHCHECK wget command"
      pattern: "/health"
    - from: "docker-compose.yml"
      to: ".env.example"
      via: "environment variable reference"
      pattern: "ORIGIN"
---

<objective>
Runtime configuration with health checks, environment documentation, and backup tooling

Purpose: Complete the production deployment setup with health monitoring for Docker, clear documentation of configuration options, and a backup script for data preservation.

Output: /health endpoint, .env.example template, backup.sh script, updated README with Docker instructions
</objective>

<execution_context>
@/home/tho/.claude/get-shit-done/workflows/execute-plan.md
@/home/tho/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-deployment/06-RESEARCH.md
@.planning/phases/06-deployment/06-01-SUMMARY.md

Key from Plan 01:
- Dockerfile has HEALTHCHECK pointing to /health
- Data paths use TASKPLANER_DATA_DIR env var
- docker-compose.yml uses named volume taskplaner_data
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create health check endpoint</name>
  <files>src/routes/health/+server.ts</files>
  <action>
Create src/routes/health/+server.ts:

```typescript
import type { RequestHandler } from './$types';
import { db } from '$lib/server/db';
import { entries } from '$lib/server/db/schema';

export const GET: RequestHandler = async () => {
  try {
    // Verify database connectivity with a simple query
    db.select().from(entries).limit(1).all();

    return new Response('ok', {
      status: 200,
      headers: { 'Content-Type': 'text/plain' }
    });
  } catch (error) {
    console.error('Health check failed:', error);

    return new Response('unhealthy', {
      status: 503,
      headers: { 'Content-Type': 'text/plain' }
    });
  }
};
```

The endpoint:
- Returns 200 "ok" when database is accessible
- Returns 503 "unhealthy" when database query fails
- Logs errors for debugging but doesn't expose details
- Uses simple text response (Docker just needs status code)
  </action>
  <verify>
    - `npm run dev` and visit http://localhost:5173/health returns "ok"
    - Health endpoint returns 200 status code
    - Database query is executed (visible in dev server logs on first request)
  </verify>
  <done>/health endpoint returns 200 with database connectivity check</done>
</task>

<task type="auto">
  <name>Task 2: Create environment documentation and backup script</name>
  <files>.env.example, backup.sh</files>
  <action>
1. Create .env.example:
   ```bash
   # TaskPlaner Environment Configuration
   # Copy to .env and customize for your deployment

   # ============================================
   # Server Configuration
   # ============================================

   # Port the server listens on (inside container)
   # Map to host port via docker-compose ports setting
   PORT=3000

   # ============================================
   # Data Storage
   # ============================================

   # Directory for database and uploads
   # Docker: /data (must match volume mount)
   # Local development: ./data
   TASKPLANER_DATA_DIR=/data

   # Optional: Direct database path override
   # DATABASE_PATH=/data/db/taskplaner.db

   # ============================================
   # Production URL (REQUIRED for production)
   # ============================================

   # The full URL where users access the app
   # Used for CSRF validation and generating absolute URLs
   # Example: https://tasks.example.com
   ORIGIN=http://localhost:3000

   # ============================================
   # Request Limits
   # ============================================

   # Maximum request body size
   # Supports K, M, G suffixes
   # Default: 512kb, recommended for images: 10M
   BODY_SIZE_LIMIT=10M

   # ============================================
   # Reverse Proxy Configuration
   # Uncomment when running behind nginx/traefik/etc
   # ============================================

   # Header containing original protocol (http/https)
   # PROTOCOL_HEADER=x-forwarded-proto

   # Header containing original host
   # HOST_HEADER=x-forwarded-host

   # Header containing original client IP
   # ADDRESS_HEADER=x-forwarded-for

   # Number of trusted proxies in front of app
   # XFF_DEPTH=1
   ```

2. Create backup.sh:
   ```bash
   #!/bin/bash
   # TaskPlaner Data Backup Script
   # Creates a timestamped backup of the Docker volume

   set -e

   # Configuration (override via environment)
   BACKUP_DIR="${BACKUP_DIR:-./backups}"
   VOLUME_NAME="${VOLUME_NAME:-taskplaner_taskplaner_data}"
   TIMESTAMP=$(date +%Y%m%d_%H%M%S)
   BACKUP_FILE="${BACKUP_DIR}/taskplaner_backup_${TIMESTAMP}.tar.gz"

   # Create backup directory if needed
   mkdir -p "$BACKUP_DIR"

   echo "========================================="
   echo "TaskPlaner Backup"
   echo "========================================="
   echo "Volume: $VOLUME_NAME"
   echo "Output: $BACKUP_FILE"
   echo ""

   # Check if volume exists
   if ! docker volume inspect "$VOLUME_NAME" > /dev/null 2>&1; then
     echo "Error: Volume '$VOLUME_NAME' not found"
     echo ""
     echo "Available volumes:"
     docker volume ls --format '  - {{.Name}}' | grep -i taskplaner || echo "  (none with 'taskplaner' in name)"
     echo ""
     echo "Tip: Set VOLUME_NAME environment variable to use a different volume"
     exit 1
   fi

   # Create backup using temporary Alpine container
   echo "Creating backup..."
   docker run --rm \
     -v "${VOLUME_NAME}:/data:ro" \
     -v "$(cd "$BACKUP_DIR" && pwd):/backup" \
     alpine:latest \
     tar czf "/backup/taskplaner_backup_${TIMESTAMP}.tar.gz" -C /data .

   echo ""
   echo "Backup complete!"
   echo "File: $BACKUP_FILE"
   echo "Size: $(du -h "$BACKUP_FILE" | cut -f1)"
   echo ""
   echo "To restore: docker run --rm -v ${VOLUME_NAME}:/data -v \$(pwd)/${BACKUP_DIR}:/backup alpine tar xzf /backup/taskplaner_backup_${TIMESTAMP}.tar.gz -C /data"
   ```

3. Make backup.sh executable:
   After creating the file, run: chmod +x backup.sh
  </action>
  <verify>
    - .env.example exists with all documented variables
    - backup.sh exists and is executable: `ls -la backup.sh`
    - backup.sh syntax is valid: `bash -n backup.sh`
  </verify>
  <done>.env.example documents all configuration options, backup.sh creates timestamped archive</done>
</task>

<task type="auto">
  <name>Task 3: Add Docker deployment section to README</name>
  <files>README.md</files>
  <action>
Check if README.md exists. If it does, add a Docker Deployment section. If not, create a minimal README with the Docker section.

Add this section (after any existing content, or as the main content):

```markdown
## Docker Deployment

### Quick Start

```bash
# Build and start the container
docker-compose up -d

# View logs
docker-compose logs -f

# Stop the container
docker-compose down
```

The application will be available at http://localhost:3000

### Configuration

Copy `.env.example` to `.env` and customize:

```bash
cp .env.example .env
```

Key settings:
- `ORIGIN` - Required for production. Set to your public URL (e.g., `https://tasks.example.com`)
- `BODY_SIZE_LIMIT` - Max upload size. Default: `512kb`, recommended: `10M`
- `PORT` - Server port inside container. Default: `3000`

### Behind a Reverse Proxy

When running behind nginx, traefik, or similar, uncomment these in `.env`:

```bash
PROTOCOL_HEADER=x-forwarded-proto
HOST_HEADER=x-forwarded-host
ADDRESS_HEADER=x-forwarded-for
XFF_DEPTH=1
```

### Data Persistence

Data is stored in a Docker named volume (`taskplaner_data`). This includes:
- SQLite database (`/data/db/taskplaner.db`)
- Uploaded images (`/data/uploads/`)

The volume persists across container restarts and updates.

### Backup & Restore

Create a backup:
```bash
./backup.sh
```

Backups are saved to `./backups/` with timestamps.

Restore from backup:
```bash
# Stop the container first
docker-compose down

# Restore (replace TIMESTAMP with actual backup filename)
docker run --rm \
  -v taskplaner_taskplaner_data:/data \
  -v $(pwd)/backups:/backup \
  alpine tar xzf /backup/taskplaner_backup_TIMESTAMP.tar.gz -C /data

# Start the container
docker-compose up -d
```

### Health Check

The container includes a health check at `/health`. View status:

```bash
docker-compose ps
```

A healthy container shows `(healthy)` in the status column.
```

If README.md exists, preserve existing content and add this as a new section.
If README.md doesn't exist, create it with a title "# TaskPlaner" followed by this Docker section.
  </action>
  <verify>
    - README.md exists with Docker Deployment section
    - Section includes Quick Start, Configuration, Backup instructions
    - Commands are correct and copy-pasteable
  </verify>
  <done>README.md documents Docker deployment with quick start, configuration, and backup instructions</done>
</task>

</tasks>

<verification>
1. Health endpoint works: `curl http://localhost:5173/health` returns "ok" (dev mode)
2. Environment documented: `.env.example` has all configuration options
3. Backup script works: `./backup.sh` (requires running container with volume)
4. README complete: Docker section with quick start and backup instructions

Full Docker verification (after both plans):
```bash
# Build and start
docker-compose up -d

# Check health
docker-compose ps  # Should show (healthy)
curl http://localhost:3000/health  # Should return "ok"

# Verify data persistence
# Add an entry via the UI, then:
docker-compose down
docker-compose up -d
# Entry should still exist

# Test backup
./backup.sh
ls -la backups/  # Should show timestamped tar.gz
```
</verification>

<success_criteria>
- /health endpoint returns 200 when database accessible, 503 on failure
- .env.example documents PORT, TASKPLANER_DATA_DIR, ORIGIN, BODY_SIZE_LIMIT, proxy headers
- backup.sh creates timestamped tar.gz of data volume
- README.md has Docker deployment section with quick start and backup instructions
- Container shows "healthy" status in docker-compose ps
</success_criteria>

<output>
After completion, create `.planning/phases/06-deployment/06-02-SUMMARY.md`
</output>
