Billit — Ops
Deploy, restart, troubleshoot. Pro overview viz INDEX.md.
Deploy
cd /root/projects/sentinel
bash deploy/deploy.sh billit hub <commit> # nejdřív hub
# HC + sanity check (1-2 min)
bash deploy/deploy.sh billit prod <commit> # pak prod
⚠️ Vždy DEPLOY OK od Libora předem (orthogonal: feedback_deploy_authorization.md).
Selektivní deploy
Pokud commit mění jen billit-web/ nebo jen billit-api/, deploy.sh restartuje pouze ten container s --no-deps (od commit c6f980c). Vidíš v deploy.sh logu jako SELECTIVE_SERVICES=....
Migration
deploy.yml má database.migration: typeorm. Migration command:
Spouští se v billit-billit-api-1 containeru.
⚠️ Při deploy s migrací → ověřit, že deploy.yml nemá top-level migration: yes flag (to deploy.sh blokuje od commit fd378b4).
Health check po deployi
Sanity:
ssh root@100.68.138.14 "docker ps | grep billit"
ssh root@100.68.138.14 "docker logs s60-billit-api --tail 50"
Restart (bez deploye)
ssh root@100.68.138.14 "cd /opt/billit && docker compose restart billit-api"
ssh root@100.78.87.88 "cd /opt/billit && docker compose restart billit-web"
⚠️ Deploy guard hook blokuje přímé docker compose restart přes Bash tool. Pokud potřebuješ restart, jdi přes deploy.sh nebo požádej Libora o explicitní RESTART OK.
Integrace nové aplikace
Detail: runbooks/billit-integration.md.
Krátká verze:
- JWT — generovat HS256 token signed s
SENTINEL_JWT_SECRETz/root/secrets/billit/.env.prod,iss: https://auth.studio60.cz, owner user ID ztenant_userskdetenant.slug = 'studio-60' - API key —
POST /v1/accounts/studio-60/api-keyss{name, scopes}. Předat token přes dočasný soubor (SSH quoting!) - Webhook —
POST /v1/accounts/studio-60/webhookss{url, events: ["order.paid", "order.cancelled"]}. Vrátísecret(whsec_…) - Env vars v cílové app —
BILLIT_API_URL,BILLIT_API_KEY,BILLIT_WEBHOOK_SECRET - Secrets uložit do
/root/secrets/<app>/billit-integration-prod.env(chmod 600)
Dostupné scopes
| Scope | Popis |
|---|---|
read:invoices, write:invoices |
Faktury |
read:orders, write:orders |
Objednávky |
read:subjects, write:subjects |
Kontakty |
read:expenses, write:expenses |
Náklady |
read:accounting, write:accounting |
Účetnictví |
export:accounting |
Export do ABRA/Pohoda/Money |
read:webhooks |
Správa webhooků |
Troubleshoot
"401 Unauthorized" při volání billit API
- Ověřit, že JWT byl signed s aktuálním
SENTINEL_JWT_SECRET(může se rotovat při migraci) - Ověřit
issclaim =https://auth.studio60.cz - ForwardAuth headers už nefungují (od 2026-03-12) — používat JWT
Container nestartuje po deployi
docker logs s60-billit-api --tail 100— TypeORM migration error?- Ověřit DB connection:
docker exec s60-billit-api env | grep DB_ - Pokud TypeORM
synchronize:truev logu — je to bug, MUSÍ býtfalse(orthogonal:feedback_no_synchronize.md) - Pre-deploy snapshot:
/var/backups/deploy-snapshots/billit/<timestamp>/ - Rollback: viz
runbooks/rollback.md
Slow query / DB pool exhausted
- Check pgBouncer pool:
psql -h 100.125.3.121 -p 6432 -U pgbouncer pgbouncer -c "SHOW POOLS" - Default pool size = 30, max client conn = 1000 (viz
infra/postgres.md) - Při blokujících queries — povolit debug user (RO):
Použít
/root/secrets/billit/.env.prod.debugproSELECT * FROM pg_stat_activity WHERE datname = 's60_billit_prod' - Po debug ihned zablokovat:
ALTER ROLE s60_billit_debug NOLOGIN
Webhook nedoručuje
- Ověřit billit-api logs:
docker logs s60-billit-api 2>&1 | grep webhook - Cíl URL dostupný z prod-alfa?
curl -I https://<app-domain>/webhooks/billit - Webhook secret rotován? — porovnat
BILLIT_WEBHOOK_SECRETv cílové app vs to, co je v DBwebhooks.secret
Oblíbené příkazy
# Stav kontejnerů
ssh root@100.78.87.88 "docker ps --filter name=billit"
# Logy posledních 100 řádků
ssh root@100.78.87.88 "docker logs s60-billit-api --tail 100"
# DB connection check uvnitř containeru
ssh root@100.78.87.88 "docker exec s60-billit-api env | grep -E '^(DB_|REDIS_)'"
# DB query (přes one-off postgres container kvůli neabsenci psql v containeru)
ssh root@100.78.87.88 'PWD_VAL=$(docker exec s60-billit-api printenv DB_PASSWORD); \
docker run --rm --network s60-network -e PGPASSWORD="$PWD_VAL" postgres:17-alpine \
psql -h 100.125.3.121 -p 6432 -U s60_billit_prod_user -d s60_billit_prod -c "SELECT count(*) FROM tenants"'
# Manuální health check
curl https://billit.s60hub.cz/health
curl https://billit.cz/health