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
This commit is contained in:
+365
-9
@@ -1,12 +1,368 @@
|
||||
# Server
|
||||
Opal-task is now a great task CLI management tool, however I need my task list available elsewhere. For reading, yes, but also modification.
|
||||
# Opal-Task Server
|
||||
|
||||
## Current infrastructure
|
||||
I host a VPS behind a Caddy reverse proxy. It hosts an authentik instance for SSO to my services.
|
||||
Opal-task server provides a REST API for syncing tasks across multiple devices. This enables household task sharing and access from anywhere.
|
||||
|
||||
## Usecase
|
||||
- Use within household to share tasks or filters. For our first version we should use one task database and share all data. This might branch off to sharing with access control (sharing specific tags/projects for instance)
|
||||
- CRUD tasks on the go
|
||||
## Features
|
||||
|
||||
## Implementation
|
||||
I was thinking of hosting an api, then building a minimal svelte-kit frontend that could be used as a PWA on our devices. What are your thoughts? We could use oauth for authentication through authentik. for now disregard the front-end implementation.
|
||||
- **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.
|
||||
|
||||
Reference in New Issue
Block a user