Removes vitest, React Testing Library, the config, the setup file and all
eleven test files, plus the test scripts and dev dependencies. Done at the
user's direction; it matches the rest of the repo, which has no automated
tests in any language.
All eleven were observed passing before removal, and their assertions are
kept in the plan as acceptance criteria to check by hand rather than deleted
outright -- they are the clearest statement of what each component has to do.
Consequence worth stating: Task 16's manual pass is now the only verification
that exists for spec 4. Four behaviours it must cover carefully, because each
is easy to break invisibly: 404-not-403 scoping, the expired card naming what
still works, relink disabling at zero, and the blob fallback when a download
fails.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Closes the rest of what spec 4's screens need. Account search now also
matches a Paddle customer ID and resolves an instance UUID to its owning
account -- a support email often contains a UUID and nothing else, and the
old search returned nothing for it.
GET /api/staff/instances/:id is the "why did this stop working" screen's
data: the instance, its account, its whole licence history newest first, and
whether the control plane currently holds the blob we think it holds.
Injection state is reported only for cloud, because for self-hosted the
customer holds the blob and there is nothing for us to have written.
Account detail gains subscriptions, customer users and its own audit trail.
No secret leaves: the password hash and both verify-token fields are json:"-".
The control-plane write surface is unchanged -- still exactly one UpdateOne
of three licence fields in inject.go, with reads everywhere else.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds GET /auth/me so the admin site's route guards can know who is signed
in, POST /auth/signup for self-hosted customers, and max_relinks on the
account payload so the UI never hardcodes a rule the backend enforces.
Signup follows sitesvc's proven shape: honeypot answered as success, a
generic 201 when the address already exists, and nothing usable until the
emailed link is opened.
Also fixes a lockout found while verifying it. When the verification email
failed, the account was rolled back but the customer_users row survived --
an orphan that can never be signed in to and that holds the unique index on
email, so every later signup with that address got a cheerful 201 and the
customer was locked out of their own address with no visible error.
CreateCustomerUser now undoes its own insert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replaces the petrol-and-serif direction with site/app/globals.css's token
set copied verbatim: brand navy accent, the same neutrals, the same clamp
type scale, 1200px rail, 4px radii, and site/'s heading treatment of the
sans at weight 800 rather than a serif display face.
The semantic three are aliased rather than renamed -- globals.css carries
site/'s --up/--pend/--down, and Tailwind exposes them as valid/warn/expired
so each app names them for what it actually shows. Same colours either way.
Tailwind now holds var() references only, so no component or config can
carry a hex value and drift. Buttons match site/'s .btn--solid and
.btn--line, including the neutral border on the secondary variant.
Records the caveat this creates: site/'s dark accent (#5b9be8) sits nearer
web/'s indigo than the light navy does, so the "which app am I in" cue rests
on the light ground and dark must not become the default.
Drops the guilloche ornament -- site/ carries nothing like it. The ledger
stays, because it is information design rather than decoration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sixteen tasks: two that close gaps in admin's API, thirteen frontend, one
verification pass.
Auditing spec 4's screens against what spec 3 actually shipped turned up
eight things the UI needs and the backend does not expose -- including no
GET /auth/me at all, which no route guard can work without, and no signup
endpoint for the self-hosted flow the spec's app/signup/ implies. Those are
tasks 1 and 2 rather than frontend improvisation.
Records the approved design direction as fixed constraints: light ground
because web/ is dark-locked and telling the two apart is what stops a
Reissue landing in the wrong tab, petrol accent because green, amber and red
are spoken for by licence state and indigo belongs to web/, and the licence
ledger as the one screen that earns ornament.
Serves vantage-hq.hostxtra.co.uk on 3004 -- 3002 is the marketing site now,
and the host stays outside *.vantage.hostxtra.co.uk because that namespace
is per-tenant instance subdomains.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ticks all 66 plan steps and records spec 3 as shipped.
Also corrects a stale line that still claimed existing cloud tenants are
grandfathered by migration 0005. That migration was reverted before plan 2
shipped; those instances are read-only until licensed by hand, and the same
file already said so one table above.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Existing cloud instances get licensed by hand through the admin UI instead of
an automated backfill. That needs POST /api/staff/instances, which nothing else
provided — without it there is no way to attach an existing cloud instance to
an account.
hyperboloide/lk signs with ECDSA P-384 and SHA-256, not ed25519, and encodes
keys as base32 rather than hex. Probed in task 1 of the licensing-core plan.
Design is unaffected — only the prose was wrong.
- 2026-07-24-licensing-core.md: 7 tasks. lk payload, offline verify, the
trusted key slice, the noSign build tag, and lkctl for issuing by hand.
- 2026-07-24-instance-licensing.md: 10 tasks. Licence on the instance
document, cached runtime state, deny-by-default mutation gate, feature
gates, service-layer limits, settings UI, and migration 0005 to
grandfather existing cloud instances.
Plan 2 opens by finishing the Org to Instance rename: 18 private identifiers
survived plan 0b's sweep. Nothing functional, but the file that gains the
licence cache is one of the two still carrying the old names.
Spec index updated with plan links and shipped status.
- 2026-07-24-shared-module.md: 8 tasks, extract the shared Go module
- 2026-07-24-instance-rename.md: 9 tasks, Org -> Instance including the
database field, with migration 0004 and a rollback command
No automated tests per instruction; verification is by compiler, grep, and
manual end-to-end plus production-snapshot rehearsal. Spec testing sections
updated to match.