4c54814eb5
- 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
369 lines
7.7 KiB
Markdown
369 lines
7.7 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
cd opal-task
|
|
go build -o opal main.go
|
|
```
|
|
|
|
### 2. Generate API Key
|
|
|
|
On your server (with direct database access):
|
|
|
|
```bash
|
|
./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
|
|
|
|
```bash
|
|
./opal server start --addr :8080 --db /var/lib/opal/opal.db
|
|
```
|
|
|
|
### 4. Configure Client
|
|
|
|
On your local machine or phone:
|
|
|
|
```bash
|
|
opal sync init --url https://opal.yourdomain.com --key oak_abc123...
|
|
```
|
|
|
|
Or use interactive mode:
|
|
|
|
```bash
|
|
opal sync init
|
|
# Enter server URL: https://opal.yourdomain.com
|
|
# Enter API key: oak_abc123...
|
|
```
|
|
|
|
### 5. Sync Your Tasks
|
|
|
|
```bash
|
|
# 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**
|
|
|
|
```bash
|
|
# 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**
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```ini
|
|
[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**
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable opal
|
|
sudo systemctl start opal
|
|
sudo systemctl status opal
|
|
```
|
|
|
|
### Option 2: Direct Execution
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
sudo systemctl reload caddy
|
|
```
|
|
|
|
### Nginx
|
|
|
|
```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`:
|
|
|
|
```yaml
|
|
# 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:
|
|
|
|
```sql
|
|
UPDATE sync_config SET value = '60' WHERE key = 'change_log_retention_days';
|
|
```
|
|
|
|
Or programmatically:
|
|
|
|
```go
|
|
engine.SetChangeLogRetentionDays(60)
|
|
```
|
|
|
|
Cleanup runs manually or can be scheduled:
|
|
|
|
```bash
|
|
# 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.
|