Second of two changes for #186; closes it. Each kind of object the console serializes on now has a family, and every advisory key is built one way: hashtextextended('<family>:<id>', 0), with a UUID written in canonical form. db.Lock and db.LockShared (internal/db/locks.go) build the key and take the lock on a *sql.Tx only, and each family's statement begins with a name line, so pg_stat_activity and the test traces show which family a backend waits on. Families, in the order a transaction takes them: materialization, domains-registry, fedwiki-workspace, lifecycle, stripe-subscription, stripe-invoice, stripe-product-sync, desired-state. The lifecycle and desired-state keys are unchanged byte for byte; the other six change. Migration 00040 replaces core.assert_rendezvous to look for the new materialization key (owner, grants, SECURITY DEFINER and search_path kept; Down restores migration 18's body), and both seeds take the new key right after BEGIN. docs/database-locks.md lists the families in a table and writes one order every path keeps: the materialization lock first, then the families in table order, then rows. The project lint gains advisory-lock-site (an advisory lock function named in a Go string or in SQL or shell code outside the helpers, the test kit's probe, the migrations that name the rendezvous and the rule's own tests; a seed taking any other key, or the rendezvous anywhere but first after BEGIN), pool-lock-site (a core.resource_pools row lock outside LockResourcePool and LockGrantPool, or a call or method value of those outside entitlements/tx.go) and lock-families (the doc's table against the code). The walk covers cmd/, scripts/, internal/, test/ and the root's Go files, and skips testdata and directories whose name begins with a dot, as the go tool does. Tests take a family's lock through the same helpers and probe one with dbtest.TryLock. Recording a lifecycle request comes in two forms: RecordLifecycleRequest opens its own transaction on a database or a pinned connection, and RecordLifecycleRequestInTx runs in the caller's *sql.Tx, so a connection is never used outside a transaction (which released the instance lock at once) and does not compile in the second. The same holds for RecordFirstLifecycleRequest. docs/production-deployment.md now states the upgrade order for every upgrade: stop every process of the running release, run migrate up if migrations run separately, then start the new release; two releases running at once can build different keys for one lock and share none. docs/go-conventions.md, docs/testing.md and docs/building-an-integration.md follow the code. The lint command's help text names the files the lock rules read. 202 golden lines in 109 files change their statement text. Deploy: stop every process of the previous release first. Rollback: stop this release; as the migration user, in one transaction, run 00040's Down section and DELETE FROM goose_db_version_core WHERE version_id = 40; start the previous release (migrate down rolls back the last integration stream first). A deployment using console_reader re-runs scripts/db-reader-role.sql. Break list: 35 records, 35 CAUGHT. Named without a record: the *sql.Tx parameters of the helpers and the -InTx forms (a break that passes a connection does not compile, and the build is the check), and the comments. Full suite on reset databases: 5727 passed, 16 skipped, none failed.
title, audience, summary
| title | audience | summary | |||
|---|---|---|---|---|---|
| Documentation index |
|
Index of member-console documentation, grouped by audience, plus the front-matter convention every doc follows. |
Documentation
Every document in this directory carries YAML front matter declaring its audience, so readers can find what's for them and contributors know who they're writing for.
Front-matter convention
Start each doc with a front-matter block:
---
title: "Human-readable title"
audience: [admin, developer] # one or more of: developer, admin, user (primary first)
summary: "One sentence describing what the doc covers."
---
The three audiences:
- developer — contributing to or understanding the codebase: architecture, design decisions, dev setup, testing, UX research and conventions, the provider-extension contract.
- admin — hosting and operating an instance: installing, configuring an identity provider, building the image, generating secrets, running the service.
- user — the general public or a member using a running service. (None yet — the tag is reserved for member-facing docs.)
List the primary audience first; a doc may name more than one.
For administrators — hosting & operating
- Production Deployment — the sequenced path from a fresh host to a running instance; start here.
- Environment Reference — every configuration key with its default and
MC_*override. - Settings and Configuration — why software uses two words for what a program is told, and how this console applies the rule.
- Hosting member-console — build the image and generate secrets.
- Deployment Architecture — how the console fits alongside a public site and an identity provider.
- Identity Provider Setup — configure an OIDC IdP for login.
- Temporal Authorization Setup — emit the
permissionsclaim Temporal's JWT authorizer expects. - Plan Management — operator guide to plan ladders and grants.
- Stripe Integration — flags, secrets, webhooks, and purchasability.
For developers — contributing & internals
- Database Management — goose migrations and sqlc.
- Database Locks — every advisory and serializing row lock, how each key is built, and the order each path takes them in.
- Design System — UI conventions.
- Domain Model Cards — the model catalog: one card per domain model with invariants, dimensions, and traps.
- FedWiki Integration — provisioning via the FarmManager API.
- Go Conventions — where a rule and an act live, transactions and locks, services that answer after the listener opens, output order, error handling, and dead code.
- HTMX Setup — HTMX under a strict CSP.
- Identifiers — IDs, names, and keys: which entities carry a key, its grammar and scope, and how seeds and lookups use it.
- Operator Information Architecture — the operator panel's IA contract.
- Operator UX Conventions — form and action conventions.
- First-Contact UX Walk Process — the repeatable method for walking the console as a stranger.
- First-Contact UX Rubric — the instrument that method scores with: the A–G question bank, the walker protocol, and the screen coverage checklist.
- Agent Runner — how an agent from another model family reviews or ideates on the code inside a disposable copy: what contains it, how a task is shaped, and what a finding must carry before it counts.
- Operator UI Accessibility Baseline — what operator-UI changes are diffed against.
- Building an Integration — adding a new integration.
- Testing — the test taxonomy and how to run each kind, plus the gates:
make lint(page-anatomy rules and the Go static checks) andmake screens(contact sheets at two widths).
For users
No member-facing documentation yet.
One page per rule
A rule is written on the one page that owns it. Another page that needs the rule links to that page instead of restating it, because two copies of a rule are edited separately and drift apart.
Where things are not
Research, drafts, audits, walkthrough evidence, and other records of how a
decision was reached are not documentation; they stay in a local notebook
that git ignores, so a clone never carries them. When a decision lands,
whatever a reader still needs is written into this directory, which holds
the result without the history. The rule for every kind of file is in
status/MAINTAINING.md.