Without -R, a manual uv sync or git operation run as root would create
files under /opt/padelnomics owned by root, breaking uv for the service
user (Permission denied on .venv/bin/python3).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- setup_server.sh now requires root, creates padelnomics_service user,
adds to docker group, generates deploy key in service user's home,
owns /opt/padelnomics and /data/padelnomics to service user
- supervisor service: User=padelnomics_service, updated PATH
- landing-backup service: User=padelnomics_service
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On first deploy to a new server, deploy.sh:
1. Installs age and sops binaries if missing
2. Generates an age keypair if missing
3. Prints the public key and exits with instructions
All checks are idempotent — subsequent deploys skip to decryption.
Removed duplicate sops/age setup from setup_server.sh (deploy.sh handles it).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Installs age and sops binaries, generates an age keypair at
/opt/padelnomics/age-key.txt, and prints the public key in next
steps so it can be added to .sops.yaml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Landing files (append-only JSON.gz) synced to R2 every 30 min via
systemd timer + rclone. Extraction state DB (.state.sqlite) continuously
replicated via Litestream (second DB entry). Auto-restore on container
startup for both app.db and .state.sqlite. Reuses existing R2 bucket
and credentials — no new env vars needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pulls in template changes: export_serving.py for atomic DuckDB swap,
supervisor export step, SQLMesh glob macro, server provisioning script,
imprint template, and formatting improvements.
Template scaffold SQL models excluded (padelnomics has real models).
Web app routes/analytics unchanged (padelnomics-specific customizations).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>