# vantage-shared The private Go module every Vantage service imports. Extracted from the `vantage` monorepo with its history. ``` vantage-shared/ ├── grpc/pb/ # the agent↔control-plane wire types, hand-written ├── grpc/codec/ # the JSON codec they travel over ├── proto/vantage/v1/ # vantage.proto - documentation for the above ├── mail/ # the one email system: transport + templates ├── license/ # payload, sign, verify, trusted keys, plans ├── models/ # Instance, User, Settings ├── provision/ # slug rules, reserved names, instance/user creation ├── backup/ # dump, restore, verify, manifest, fingerprint ├── cryptobox/ # the single AES-256-GCM implementation ├── indexes/ # users.email and instances.slug └── cmd/lkctl/ # issue and inspect licences by hand ``` Module path is `gitea.hostxtra.co.uk/vantage/vantage-shared` - **lowercase `vantage`**, though the Gitea org is canonically `Vantage`. Gitea serves both spellings; Go module paths are case-sensitive strings, and two spellings would cache as two modules. Keep the lowercase one. ## Who depends on this, and when they find out | Repository | Modules | A change here reaches them | | ---------------- | ---------------------------------------- | ---------------------------------------------------- | | `vantage` | `server`, `agent`, `vantagectl` | `server` at the next push to main after a pin bump; `agent` and `vantagectl` only at their next release tag | | `vantage-admin` | `server` | at the next push to main after a pin bump | | `vantage-site` | `server` | at the next push to main after a pin bump | **Nothing bumps a pin automatically.** A fix here is live nowhere until each consumer's `go.mod` moves, and nothing in any of those repositories will remind you. That is the trade this split made: a service can no longer be shipped against a version of this module it was never built against, and in exchange the staleness is now silent rather than impossible. Tag a release when you change anything: `git tag v0.2.0 && git push origin v0.2.0`. Consumers pin exact versions. ## `proto/` is documentation, not a generator input `grpc/pb` is **hand-written** JSON-tagged structs over the codec in `grpc/codec`. Nothing generates them, and `vantage.proto` is not compiled by any build. It is the readable statement of the wire contract, and it lives in the same repository as the Go types precisely so that a message added to one can be added to the other **in the same commit** - that co-location is the only thing enforcing the match, so do not split them again. There used to be two copies of `pb`, in the agent and the server, and they had already drifted: the agent's `UnimplementedVantageServer` was three methods stale and carried no `ReportWorkloads` at all. One package now serves both sides. The agent links the server half as dead code, which the linker drops. **A wire change lands in three steps, in this order**: release this module, bump the pin in `vantage/server` (live at the next push to main), bump the pin in `vantage/agent` (live only at the next `agent/v*` tag). The control plane will be ahead of the fleet in between, which was true before too - it is just written down in two `go.mod` files now instead of implied by a shared directory. ## Things that mirror something outside this repository These cannot be enforced by the compiler and must be changed by hand, in step with a file in another repository: - **`backup.ciphertextFields`** names each collection's `*_enc` fields and mirrors `server/internal/models` in the `vantage` repository, which this module cannot import. Wrong field names fail **silently**: `verify`'s live probe finds no ciphertext and reports "this database stores no ciphertext yet", so the one gate that catches what a key fingerprint cannot becomes a no-op. `settings` is deliberately in neither that map nor `CiphertextCollections()` - its ESO read token is a SHA-256 hash, not ciphertext. - **`mail/templates/layout.html.tmpl`** carries the control plane's dark theme values as **literal hex**. Email clients support neither `var()` nor a reliable `prefers-color-scheme`, so the token indirection the four front ends use is not available here. Every colour in the email system is in that one file. The tokens it mirrors live in `vantage-site`. - **`provision`** is the single implementation of the slug rules that both the control plane and Vantage HQ depend on. It is the one place those two repositories must agree on behaviour, which is why it is here rather than copied - but it now also means a change to it is a release and two pin bumps. `mail/render_test.go` renders every template and fails if one exists that no case covers. The templates are parsed in `init()`, so without that test a mistyped field is a boot-time panic in three services. ## Writing style Never use em dashes (the long dash character) anywhere: code, comments, UI copy, docs, commit messages. Use a plain hyphen ` - `, a comma, a colon, or split the sentence instead.