Sign inSign up

visibilityspots/vonk

By visibilityspots

•Updated about 12 hours ago

Turn the Scouts Tervant vonk PDFs into a CalDAV calendar, with approval before every write

Buildkit cache
Image
0

391

visibilityspots/vonk repository overview

⁠vonk

Turns the monthly vonk PDFs of Scouts en Gidsen Tervant (scoutstervant.be) into events in a family CalDAV calendar, but only after a human has approved the changes.

⁠How it works

  1. vonk poll asks the scoutstervant.be WordPress REST API for new or changed vonk posts, downloads the PDFs, converts them with pdftotext and lets Claude locate the event spans for the configured takken (plus the group-wide key dates from the jaarvonk). Dates, years and event identity are derived by plain code, not by the model.
  2. The poll result is sent to the vonk service, which diffs it against the events it owns in the Baikal calendar (UID prefix vonk-, domain @vonk.visibilityspots).
  3. A non-empty diff is announced through Gotify with a link to an internal approve page.
  4. Only after approval in the browser does the service write the diff over CalDAV.
⁠Architecture (one image, two Nomad jobs)
JobTypeRole
vonk (nomad/vonk.hcl)service, count = 1Approve page, bearer-authenticated internal API, /health, /metrics. Sole owner of SQLite (identity, state, extraction cache, tokens) and of every CalDAV write.
vonk-poll (nomad/vonk-poll.hcl)periodic batch, every 6 hoursStateless. Extracts and sends results to the service API; always reports back via /api/poll-report; exits non-zero on any failure.

Both are served from the same image: vonk serve (default command) and vonk poll. The service is reachable on the internal https entrypoint only. Without secrets it starts degraded: /health still answers 200 and vonk_degraded is 1.

⁠Local development

python -m venv .venv && . .venv/bin/activate
pip install -e '.[dev]'
ruff check .
pytest                  # default markers: no network, no API key, no Baikal

pdftotext (poppler-utils) must be installed. Opt-in test markers:

MarkerNeedsCommand
llmANTHROPIC_API_KEY, costs moneypytest -m llm tests/golden
caldavscratch Baikal calendar vonk-test (never gezin)pytest -m caldav
netread-only calls to the live scoutstervant.bepytest -m net

Image: podman build -t vonk:dev . then dgoss run vonk:dev (see goss.yaml).

⁠Configuration

All configuration is environment based; on the cluster it arrives through a Vault template from kv/data/services/vonk (service) and kv/data/services/vonk-poll (poll job: api_token, anthropic_api_key, takken), one path per job as the Vault policy requires. Empty values and the consul-template string <no value> count as missing.

Env varVault keyUsed byPurpose
BAIKAL_URL, BAIKAL_USER, BAIKAL_PASSWORD, BAIKAL_CALENDARbaikal_*serveCalDAV target
GOTIFY_URL, GOTIFY_TOKENgotify_*servechange notices
VONK_API_TOKENapi_tokenserve, pollbearer token of the internal API
VONK_PUBLIC_URL(in the job)servebase of the approve links
CHILD_NAMESchild_namesserveJSON object {"<tak>": "<name>"}, shown on the approve page
VONK_DB_PATH(in the job)serveSQLite path, /data/vonk.db on the CSI volume
ANTHROPIC_API_KEYanthropic_api_keypollextraction
TAKKENtakkenpolltakken to process, comma separated
VONK_API_URL(in the job)pollservice base URL, without /api

BAIKAL_CALENDAR is the calendar collection name under calendars/<BAIKAL_USER>/, not the display name. For a calendar shared with the vonk user that is the share's UUID, which the Nomad job takes from the Vault key baikal_gezin_uri; baikal_calendar is only the display name and is not used for the path.

⁠Deploy

In short:

  1. Tag a semver release; CI runs ruff and pytest, then the shared github-workflows main.yml (dgoss, multi-arch linux/amd64,linux/arm64 push to Docker Hub). Set the repository variable DOCKERHUB_REPOSITORY to vonk.
  2. Seed the image into the zot registry (see the nomad-visibilityspots skill).
  3. Create /volume4/nomad/data/vonk/ on the NAS, register nomad/vonk-volume.hcl.
  4. Write kv/data/services/vonk and kv/data/services/vonk-poll in Vault; vonk.visibilityspots.net is covered by the internal *.visibilityspots.net wildcard.
  5. Copy nomad/vonk.hcl and nomad/vonk-poll.hcl to jobs/stable/services/, set the image tag, run nomad job run.
  6. Paste nomad/prometheus-vonk.rules.yml into infrastructure/prometheus.hcl as a rule template; redeploy Prometheus and check /api/v1/rules.
  7. Verify with a real call (curl -H 'Host: vonk.visibilityspots.net' .../health, nomad job periodic force vonk-poll), first against vonk-test, then gezin; add the Argus entries.

⁠Privacy

The repository is public. The vonk PDFs contain names and phone numbers of leiding and are never committed (tests/fixtures/pdf/ is ignored; scripts/fetch_fixtures.py verifies sources by URL and sha256). Only redacted pdftotext output is committed. Child names live only in Vault (child_names) and are never logged or echoed in error messages.

Tag summary

Content type

Image

Digest

sha256:aa9be7a54…

Size

87.6 MB

Last updated

about 12 hours ago

docker pull visibilityspots/vonk