- 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
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
Option 1: SystemD Service (Recommended)
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
Caddy (Recommended)
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, deletedproject- Project namepriority- L, M, H, Dtag- 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: truein config - Clear queue if needed: Delete
~/.config/jade/sync_queue.json
Database Schema
Core Tables
tasks- Main task storagetags- Task tags (many-to-many)working_set- Display ID mapping (client-local)
Sync Tables
users- User accounts (currently single shared user)api_keys- Authentication keyssync_state- Per-client sync statechange_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.