- compose/pgdb/csg-snapshot-v3.sql: 补提交(此前只存在于工作区,未入 git)
- compose/pgdb/csg-snapshot-v5.sql: 新增
· csg_ladder_cost_raw() 无舍入阶梯费用助手
· csg_daily_snapshot() v5: day 费用改累积边际差分 + round(...,2);
p_month 上移 + 跨月守卫;日期与用量同源 latest_day_kwh
· 一次性归一历史 day cost(UPDATE 3 行,总差 -0.01)
· csg_backfill_missing_days() + job 1011(insert-only 断档自愈)
- runbooks/pgdb-health.md: 新增 check 9 CSG 归档新鲜度
- hosts/pgdb.md: v5 事实 + Known issues 2026-09-22
compose/ — repo-owned Compose declarations
Non-secret Compose sources for the Docker hosts. Secrets are never in these
files: every secret is a ${VAR} reference resolved from the server-local
.env (docker compose reads .env from the project directory automatically).
Source-of-truth matrix
| Project | Host | Compose source | Mechanism |
|---|---|---|---|
vaultwarden |
us2 (/opt/vaultwarden) |
compose/vaultwarden/compose.yml |
static file + compose-deploy.yml |
pdns |
hk2 (/opt/pdns) |
compose/pdns/compose.yml |
static file + compose-deploy.yml |
pgdb |
pgdb (/opt/database, 无 ansible) |
compose/pgdb/compose.yml |
static file(手动部署:scp → docker compose config -q → up -d;服务器文件名 docker-compose.yml) |
soft-serve |
us2 (/opt/soft-serve, 已退役停用) |
compose/soft-serve/compose.yml (+ Dockerfile.backup, scripts/) |
static file(参考镜像; 2026-09-18 被 gitea 替换 VPS-94, 数据保留作回滚) |
gitea |
us2 (/opt/gitea) |
compose/gitea/compose.yml (+ Dockerfile.backup, scripts/) |
static file(参考镜像, 未接入 compose-deploy; 服务器文件为准; 2026-09-18 替换 soft-serve, VPS-94) |
adguardhome |
dns.windy.lan (/opt/adguardhome) |
— (待从 LAN 提取) | static file (pending) |
unifi |
ubnt (/home/windy/unifi-9) |
— (待从 LAN 提取) | static file (pending) |
wireguard |
us4 (/opt/wireguard) |
ansible/templates/wireguard-compose.yml.j2 |
role-rendered (inventory vars) |
rustdesk |
hk2 (/opt/rustdesk) |
ansible/roles/rustdesk/templates/compose.yml.j2 |
role-rendered (inventory vars) |
mailcow |
mx2 (/opt/mail) |
— (mailcow update generator owns it) | excluded by design |
Mechanism rule: static compose/<project>/compose.yml for declarations that
do not vary per host; role-rendered j2 for declarations driven by inventory
vars (image pins, relay host). One mechanism per project; do not duplicate a
project in both.
Deploying a static project
cd ansible
# Read-only diff + validation against the server .env (no writes)
ansible-playbook playbooks/compose-deploy.yml --limit vaultwarden --check --diff
# Apply: stage repo file → validate `docker compose config -q` → backup current
# file → promote → `docker compose up -d` (gated)
ansible-playbook playbooks/compose-deploy.yml --limit vaultwarden \
-e '{"compose_deploy_confirm": true}'
See ../runbooks/ansible-operations.md.
Adding a project
- Sanitize the live compose so every secret is
${VAR}from.env(prefer${VAR:?missing VAR}for required keys). - Commit
compose/<project>/compose.yml+.env.example(key names only). - Add
compose_repo_project(+compose_remote_fileif notcompose.yml) to the host inansible/inventory/hosts.yml, and allowlist the project inansible/roles/compose_deploy/defaults/main.yml. - Verify with
--check --diff(zero diff) then a gated apply.