No description
  • Dart 65%
  • JavaScript 23.6%
  • Python 7.5%
  • Shell 2%
  • Typst 1.1%
  • Other 0.8%
Find a file
Jan-Henrik Bruhn 6f5ef44dc0 feat(audit): the correlation columns come from the registry
`withRegistry` already let an app say which record its log correlates
under — which collection is the centre, which field reaches it, which
children reach it only through a parent. The row that resolution produced
was then written to `case_id` and `case_label` regardless.

That is federfall's vocabulary, and a stored column name is the one thing
an app cannot rename later: audit_events has no update rule by design, so
the spelling chosen on the first write is the spelling those rows keep.
eiermann's centre is a Spot, which left it two options, both bad — carry
"case" in its database permanently, or fork this file.

So `correlation.column` and `correlation.labelColumn`, defaulting to the
old pair so federfall does not move, and `correlationId`/`correlationLabel`
as the neutral spelling of the emit options. `caseId`/`caseLabel` are still
honoured: six federfall call sites pass them.

`correlationColumns` is exposed on the bound API so an app can check its
schema against its own registry. emit() never throws, so a column name
that does not exist is otherwise a warning in a log nobody reads and a
correlation that is quietly always empty.

The unit harness stubs no `app` on purpose, so what the tests cover is the
resolution, not the write — canaried by pinning the column back to the
literal and watching the registry case fail. The write itself is asserted
live in eiermann-30w.8, against a real schema.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 10:37:22 +02:00
.github/workflows build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
backend/pocketbase feat(audit): the correlation columns come from the registry 2026-08-24 10:37:22 +02:00
packages build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
.gitignore feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
.release-please-manifest.json feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
AGENTS.md docs: the injection-boundary write-up CLAUDE.md was pointing at 2026-08-21 01:58:55 +02:00
analysis_options.yaml build: keep the analyzer excludes flutter pub get writes itself 2026-08-21 15:59:55 +02:00
CLAUDE.md build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
Dockerfile feat(docker): publish zugvogel-pb-base to GHCR 2026-08-21 08:03:09 +02:00
LICENSE feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
pubspec.yaml feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
README.md build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
release-please-config.json feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00

Zugvogel

The shared library behind federfall and eiermann: the part of both apps that carries no product vocabulary. Four Dart packages plus the PocketBase and Typst assets that go with them.

Zugvogel is not an app and is not published to pub.dev. Both apps consume it through a pinned git ref, so neither one moves until it is moved deliberately.

Layout

packages/
  zugvogel_core/       pure Dart — GeoPoint, converters, wire-value enums,
                       Result, ErrorMessage, logger
  zugvogel_data/       pure Dart — generic PocketBase repository, PbFilter,
                       keyset paging, multipart, idempotency
  zugvogel_pb_client/  Flutter — client, auth token, server URL, reachability
                       probe, /info, version compatibility, realtime
  zugvogel_ui/         Flutter — widgets, charts, map layers, bundled fonts
backend/pocketbase/
  pb_hooks/            shared hooks in the reserved zv_* namespace
  typst/               report_common.typ and the vendored Typst packages
  tests/               the rule/hook harness templates

Dependency direction is one-way: ui/pb_clientdatacore. Nothing depends upwards, and nothing in this repo depends on either app.

Consuming it

Pin a commit hash, never a branch and never a tag:

dependencies:
  zugvogel_ui:
    git:
      url: https://github.com/jhbruhn/zugvogel.git
      ref: 0000000000000000000000000000000000000000  # a full 40-char SHA
      path: packages/zugvogel_ui

A commit hash is the only ref that cannot move. A branch obviously moves; a tag can be re-pointed, and pub caches by ref, so a moved tag means two machines resolve the same declaration to different code and only one of them can reproduce the bug. Nothing here is released — there are no tags at all — so the hash is also the only ref there is.

Use the full 40 characters. pub accepts a short one, but a short hash is ambiguous in principle and unhelpful in practice: it cannot be pasted into a compare URL, and git log <short>..<short> is exactly what you want when a version bump breaks something.

The https URL, not git@github.com: — a CI runner has no SSH key, and a dependency that only resolves on a developer's laptop is a dependency that breaks the build. The repo is public, so https needs no credentials at all. Push over SSH (git@github.com:jhbruhn/zugvogel.git); that is the remote configured here.

The members declare resolution: workspace for local development, which does not stand in the way of git consumption — verified: a consuming app that pins zugvogel_data and zugvogel_ui resolves their relative path dependencies inside the same checkout and ends up with exactly one copy of zugvogel_core.

pubspec.lock is deliberately not committed here. This repo ships libraries; the consuming app's lockfile is the one that pins versions.

Versioning

Nothing is released yet, on purpose. Both apps pin a commit hash (see above), so a version number would be decoration — and a tag that exists is a tag somebody can pin by accident.

The machinery is in place for when that changes: release-please watches conventional-commit history and maintains a standing release PR with the next bump and a CHANGELOG. Merging that PR is what would cut a release; leaving it open costs nothing and creates nothing. Pre-1.0 the config bumps a minor for a breaking change and a patch for a feature.

There is no bootstrap-sha in release-please-config.json: the repo starts here, so reading the full history is correct.

The rules

Three injection boundaries keep a wide shared package from welding two product designs together — no strings, no colours, no configuration inside the package. And PocketBase migrations cannot be shared, only copied as templates. Both are spelled out in CLAUDE.md.

Toolchain

Flutter 3.44.3 / Dart 3.12. This library is compiled by the consuming apps' toolchain, so the version in .github/workflows/ci.yml must stay in lockstep with theirs. 3.47.x is skipped deliberately — see CLAUDE.md.

Licence

AGPL-3.0, same as the apps that consume it. See LICENSE.