10 KiB
Agents
This codebase powers the born-digital edition of Johann Jacob Lenz’s correspondence. Every package acts like an agent in the editorial pipeline: ingesting the XML corpus, enriching it with scholarly context, and presenting the material on the public website. This document inventories those agents, how they cooperate, and where to extend them.
System lineage
- Entry point (
lenz.go) – boots withconfig, clones or reuses the corpus Git repo viagit/, parses TEI-like XML into memory (xmlmodels), wires the templating engine and cache, then starts the Fiber server. - Data origin – XML, references, and tradition files live inside the checked-out repository (
config.BaseDIR+config.GITPath). Changes arrive either through CLI restarts, filesystem watchers (dev), or GitHub webhooks (controllers/webhook.go). - Request flow – Fiber receives HTTP traffic (
server/), routes it through the controllers (controllers/*.go), pulls structured data fromxmlmodels, renders Go templates (templating/,views/), and serves static assets through the custom filesystem middleware.
Agent catalog
1. Configuration & boot agent
- Scope –
config/,lenz.go. - Responsibilities
- Merge
config.dev.json,config.json, andKGPZ_*env vars, then enforce defaults for cache directories, bind address, webhook endpoint, etc. - Shape the runtime: debug mode flips Fiber logging on, turns on hot reloaders, and exposes the WebSocket live-reload port.
- Stage the working directories (
_cache/git,_cache/gnd,_cache/geo,_cache/search,data_bilder).
- Merge
- Extension hooks
- Add new configuration knobs to
config.Config, plumb them throughConfigProvider, then surface them insidecontrollersviactx.Locals("cfg", cfg). - Update
Dockerfileordocker-compose.*when the runtime contract changes (ports, binaries, base path).
- Add new configuration knobs to
2. Corpus sync agent
- Scope –
git/git.go,_cache/git,controllers/webhook.go. - Responsibilities
- Clone, validate, and update the corpus repository (default
https://github.com/Theodor-Springmann-Stiftung/lenz-briefe) while keeping branch and hash bookkeeping (gitprovider.Commit). - Expose two lifecycle calls:
OpenOrClone(during boot) andPull(during webhook), each guarded by a global mutex to avoid concurrent git state. - On webhook delivery, verify
X-Hub-Signature-256, pull the branch, triggerxmlmodels.Parse, and reset the cache store so visitors immediately see the update.
- Clone, validate, and update the corpus repository (default
- Extension hooks
- Add new repo validation rules by extending
ValidateBranchor the webhook handler (e.g., topic filtering). - Emit observability metrics or notifications after
Pulland parse success.
- Add new repo validation rules by extending
3. XML modeling agent
- Scope –
xmlmodels/,xmlparsing/. - Responsibilities
- Parse
data/xml/meta.xml,briefe.xml,references.xml, andtraditions.xmlconcurrently into strongly typed structs (Meta,Letter,Tradition,PersonDef,LocationDef, etc.). - Provide a singleton
Library(xmlmodels.Set/Get) that caches derived artefacts (sync.Mapfor year groupings, person/place lookups) and exposes helpers likeNextPrev,Years, andTradition. - Offload streaming tokenization, entity resolution, optional booleans, and TEI-ish constructs to
xmlparsing(seeparser.go,resolver.go,optionalbool.go,xmlsort.go).
- Parse
- Extension hooks
- Add new TEI registers by amending
xmlmodels/library.goandxmlmodels/roots.go, then plugging in anxmlparsing.XMLParserfor the new structure. - When introducing derived caches, use the built-in
sync.Mapto avoid reprocesing across requests.
- Add new TEI registers by amending
4. Text rendering agent
- Scope –
helpers/functions/textparse.go,helpers/functions/*.go. - Responsibilities
- Convert
Letter.Content(inner XML) into semantic HTML fragments consumable by the templates: inline sidenotes, block notes, insertion markers, manuscript hands, printable line/pagination counters, etc. - Offer template-safe utilities (date math, slicing, string helpers, HTML escaping, embedder functions) injected via
templating.Engine.AddFuncandLibrary.FuncMap().
- Convert
- Extension hooks
- Support new TEI tags or editorial conventions by updating the
switchinParseand by introducing helperTokensoperations when needed. - Register the helper with templates through
templating.Engine.AddFunc("NewFunc", fn)to keep the template surface area explicit.
- Support new TEI tags or editorial conventions by updating the
5. Presentation & asset agent
- Scope –
templating/,views/,helpers/middleware. - Responsibilities
- Maintain the custom Go template engine (
templating.Engine): layout registry, route registry, live-reload WebSocket (port 9000), and debug refresh/reset watchers (seewatcher.go). - Deliver static artefacts (
views/assets, fonts, paged.js bundle) through the fiber-aware filesystem middleware with cache-control + optional weak ETags. - Organize the view layer:
views/layouts/default/root.gohtmlfor the shell,views/routes/**/head.gohtml&body.gohtmlpairs for routes,views/routes/componentsfor partials, andviews/publicas embeddable snippets/XSLT. - Ship the CSS/JS toolchain (Tailwind 4, DaisyUI, Vite) via
views/package.json,vite.config.js, andtransform/site.css, producing the compiledassets/bundle that gets embedded at build time (views/embed*.go).
- Maintain the custom Go template engine (
- Extension hooks
- When adding routes, create a new directory under
views/routes/<slug>/withheadandbodytemplates and callc.Render("/<slug>/", data)from the matching controller. - For new global data, use
Engine.Globalsso layouts gain the values without per-controller plumbing. - In dev, use
cfg.Debug=truesoSetupRefreshWatcherreloads templates when files underviews/routesorviews/layoutschange.
- When adding routes, create a new directory under
6. Delivery agent (HTTP server & controllers)
- Scope –
server/,controllers/. - Responsibilities
- Configure Fiber with shared middlewares (compression, cache, logging/recover, custom cache key generator) and expose the
Serverstruct that owns thetemplating.Engineand memory-backed cache store (github.com/gofiber/storage/memory). - Register web routes:
/redirects to/briefe./briefelists letters grouped into historic ranges (seecontrollers/uebersicht.go)./brief/:letterrenders an individual letter with prev/next navigation, parsed body, and tradition apparatus (controllers/brief.go)./datenschutz,/ausgabe/zitation,/ausgabe/edition,/kontaktrender mostly static material via the template partials./assets/**serves CSS/JS/images with compression + ETag (middleware).
- Expose Go structs (e.g.,
DateRange) to the templates so grouping logic stays in Go rather than HTML.
- Configure Fiber with shared middlewares (compression, cache, logging/recover, custom cache key generator) and expose the
- Extension hooks
- Add future APIs (e.g., JSON endpoints) inside
controllerswhile reusingxmlmodelsfor data access. - Extend caching strategy by tweaking
server/cache.goorCacheFunc(e.g., to drop caching for preview routes).
- Add future APIs (e.g., JSON endpoints) inside
7. Update, cache & observability agent
- Scope –
watcher.go,server/cache.go,controllers/webhook.go. - Responsibilities
- Implement hot-reload in debug builds: watchers monitor
./views/assetsfor refreshes and./views/layouts,./views/routesfor full reloads, then callEngine.Refresh()orEngine.Reload()and reset the in-memory cache. - Provide manual cache reset helpers (
ResetFunction,RefreshFunction) that controllers or tooling can reuse. - Support GitHub webhook-triggered cache invalidation (see agent 2).
- Implement hot-reload in debug builds: watchers monitor
- Extension hooks
- Watch additional directories (e.g., content markdown) by appending to
REFRESH_CHANGES/RESET_CHANGES. - Integrate metrics by instrumenting
server.Server.Start/Stopand the webhook handler.
- Watch additional directories (e.g., content markdown) by appending to
Data contracts
| Type | File | Purpose |
|---|---|---|
xmlmodels.Meta |
data/xml/meta.xml |
Chronological metadata per letter (sent/received actions, person/place refs, proofing flags). Supplies the timeline, filters, and prev/next logic. |
xmlmodels.Letter |
data/xml/briefe.xml |
Carries the full textual content, pagination hints, and handwriting markers. Parsed into HTML via the text rendering agent. |
xmlmodels.Tradition |
data/xml/traditions.xml |
Encodes the apparatus (Apps) for each letter so the UI can show textual variants and transmission notes. |
xmlmodels.PersonDef, LocationDef, AppDef |
data/xml/references.xml |
Lookup tables for persons, places, and apparatus definitions, surfaced through the template func map (Person, Place, App). |
All XML parsing goes through xmlparsing.XMLParser[T], so new record types only require defining a struct with xml tags plus a corresponding root type in xmlmodels/roots.go.
Request lifecycle (TL;DR)
- Startup –
config.Get()→gitprovider.OpenOrClone()→xmlmodels.Parse()populates the singleton library and caches. - Serve –
server.New()builds Fiber + templating + cache;controllers.Register()binds routes. - Handle request – Controller retrieves data from
xmlmodels.Get(), optionally transforms it (sorting, grouping), and renders a template. The templating engine merges controller data with globals and layout fragments, optionally injecting the live-reload script in debug mode. - Deliver – Responses are cached in memory (unless
CacheFuncopts out) and static assets flow through the filesystem middleware with compression + weak validators. - Update corpus – GitHub webhook or manual restart pulls new XML content, re-runs
xmlmodels.Parse, clears caches, and future requests see the updated edition.
Development workflow
- Go server –
go run .(orair, etc.). Ensure_cache/gitis writable; config defaults to_cacherelative to repo root. - Frontend assets –
cd views && npm install && npm run devduring template work, ornpm run buildto regenerateviews/assets. The Go build embeds the compiled assets unless built with-tags dev. - Debugging – Set
debugtotrueinconfig.dev.json. That turns on verbose logs, template reloaders, the WebSocket refresher, and disables static caching so CSS/JS changes land instantly. - Deployment –
Dockerfilebuilds a static binary (go build) and exposes port 8085. Mount_cacheas a volume (or bake in) so git clones persist across container restarts.
Together these agents ensure that the scholarly corpus, textual enrichment logic, and presentation layer remain decoupled yet synchronized, making it straightforward to add new editorial features or publish new findings about Lenz’s letters.