Files
gems/opal-task/srv
joakim 4c54814eb5 docs: Phase 5 - Comprehensive deployment documentation
- Created detailed srv/README.md with:
  - Quick start guide
  - SystemD service setup instructions
  - Reverse proxy configuration (Caddy & Nginx)
  - Complete API endpoint reference
  - Client configuration examples
  - Troubleshooting guide
  - Security considerations
  - Future enhancement roadmap
- Updated main README.md with server & sync features
- Added sync command quick reference
- Documented offline support and conflict resolution
2026-01-05 16:21:09 +01:00
..

Opal-Task Server

Opal-task server provides a REST API for syncing tasks across multiple devices. This enables household task sharing and access from anywhere.

Features

  • REST API - Chi-based HTTP API for task management
  • API Key Authentication - Secure authentication using bcrypt-hashed keys
  • Bidirectional Sync - Push and pull changes with conflict resolution
  • Offline Support - Queue changes when server is unreachable
  • Change Tracking - Automatic change log with configurable retention
  • Single Database - Shared household task database (v1)

Quick Start

1. Build the Binary

cd opal-task
go build -o opal main.go

2. Generate API Key

On your server (with direct database access):

./opal server keygen --name "My Device" --db /var/lib/opal/opal.db

Output:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
API Key Generated Successfully
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Name: My Device
Key:  oak_abc123...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠️  IMPORTANT: Save this key securely!
   It will not be displayed again.

3. Start the Server

./opal server start --addr :8080 --db /var/lib/opal/opal.db

4. Configure Client

On your local machine or phone:

opal sync init --url https://opal.yourdomain.com --key oak_abc123...

Or use interactive mode:

opal sync init
# Enter server URL: https://opal.yourdomain.com
# Enter API key: oak_abc123...

5. Sync Your Tasks

# Full bidirectional sync
opal sync now

# Push local changes only
opal sync up

# Pull server changes only
opal sync down

# Initial merge (for existing local database)
opal sync merge --prefer-local

Server Deployment

1. Install Binary

# Build
go build -o opal main.go

# Copy to system location
sudo cp opal /usr/local/bin/

# Create data directory
sudo mkdir -p /var/lib/opal
sudo chown $USER:$USER /var/lib/opal

2. Generate First API Key

opal server keygen --name "Admin" --db /var/lib/opal/opal.db
# Save the generated key!

3. Create SystemD Service

Create /etc/systemd/system/opal.service:

[Unit]
Description=Opal Task API Server
After=network.target

[Service]
Type=simple
User=your-user
WorkingDirectory=/var/lib/opal
ExecStart=/usr/local/bin/opal server start --addr :8080 --db /var/lib/opal/opal.db
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

4. Enable and Start Service

sudo systemctl daemon-reload
sudo systemctl enable opal
sudo systemctl start opal
sudo systemctl status opal

Option 2: Direct Execution

# Run in background
nohup ./opal server start --addr :8080 --db /var/lib/opal/opal.db > opal.log 2>&1 &

Reverse Proxy Setup

Add to your Caddyfile:

opal.yourdomain.com {
    reverse_proxy localhost:8080
}

Reload Caddy:

sudo systemctl reload caddy

Nginx

server {
    listen 443 ssl http2;
    server_name opal.yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

API Endpoints

Authentication

All endpoints (except /health) require authentication via API key:

Authorization: Bearer oak_abc123...

Health Check

GET /health

Returns server status.

Tasks

GET    /tasks                  - List tasks (with filters)
GET    /tasks/{uuid}           - Get specific task
POST   /tasks                  - Create task
PUT    /tasks/{uuid}           - Update task
DELETE /tasks/{uuid}           - Delete task
POST   /tasks/{uuid}/complete  - Mark task complete
POST   /tasks/{uuid}/start     - Start task
POST   /tasks/{uuid}/stop      - Stop task

Query Parameters for GET /tasks:

  • status - pending, completed, deleted
  • project - Project name
  • priority - L, M, H, D
  • tag - Tag name (can specify multiple)

Tags

GET    /tasks/{uuid}/tags      - Get task tags
POST   /tasks/{uuid}/tags      - Add tag
DELETE /tasks/{uuid}/tags/{tag} - Remove tag
GET    /tags                   - List all tags

Projects

GET /projects - List all projects

Sync

POST /sync/changes - Get changes since timestamp
POST /sync/push    - Push local changes

API Keys

GET    /auth/keys       - List API keys
DELETE /auth/keys/{id}  - Revoke API key

Client Configuration

Sync settings are stored in ~/.config/jade/opal.yml:

# Task settings
default_filter: status:pending
default_sort: due,priority
color_output: true
week_start_day: monday
default_due_time: ""

# Sync settings
sync_enabled: true
sync_url: https://opal.yourdomain.com
sync_api_key: oak_abc123...
sync_client_id: 550e8400-e29b-41d4-a716-446655440000
sync_strategy: last-write-wins
sync_queue_offline: true

Sync Strategies

  • last-write-wins (default) - Most recently modified version wins
  • server-wins - Server version always wins
  • client-wins - Client version always wins

Change Log Retention

By default, the change log retains entries for 30 days. This can be configured in the database:

UPDATE sync_config SET value = '60' WHERE key = 'change_log_retention_days';

Or programmatically:

engine.SetChangeLogRetentionDays(60)

Cleanup runs manually or can be scheduled:

# In your cron or systemd timer
./opal server cleanup --db /var/lib/opal/opal.db

Troubleshooting

Server won't start

  • Check if port 8080 is already in use: sudo lsof -i :8080
  • Verify database path exists and is writable
  • Check logs: journalctl -u opal -f

Client can't connect

  • Test server health: curl https://opal.yourdomain.com/health
  • Verify API key is correct
  • Check firewall allows traffic on port 8080
  • Ensure reverse proxy is properly configured

Sync conflicts

  • View conflict log: opal sync log
  • Conflicts are automatically resolved based on strategy
  • By default, last-write-wins is used

Offline changes not syncing

  • Check queue status: opal sync status
  • Verify sync_queue_offline: true in config
  • Clear queue if needed: Delete ~/.config/jade/sync_queue.json

Database Schema

Core Tables

  • tasks - Main task storage
  • tags - Task tags (many-to-many)
  • working_set - Display ID mapping (client-local)

Sync Tables

  • users - User accounts (currently single shared user)
  • api_keys - Authentication keys
  • sync_state - Per-client sync state
  • change_log - Change tracking (key:value format)
  • sync_config - Server configuration

Security Considerations

  • API keys are hashed with bcrypt before storage
  • Never log full API keys
  • Use HTTPS in production (via reverse proxy)
  • Implement rate limiting for production use
  • Backup database regularly
  • Rotate API keys periodically

Future Enhancements

  • OAuth2 with Authentik for web/mobile clients
  • Per-user task separation with sharing
  • Real-time sync via WebSockets
  • Web/mobile frontend (SvelteKit PWA)
  • Access control (share specific tags/projects)
  • Audit logging
  • Database backup automation

Support

For issues or questions:

  • Check logs: journalctl -u opal -f
  • View sync status: opal sync status
  • View conflicts: opal sync log
  • Test connectivity: curl https://opal.yourdomain.com/health

License

Same as opal-task main project.