Commit Graph
3 Commits
Author SHA1 Message Date
mrhid6andClaude Opus 5 4bb7400b8e feat(admin): session probe, self-hosted signup and the relink cap
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>
2026-07-25 20:48:09 +01:00
mrhid6andClaude Opus 5 268134d821 feat(admin): staff API and the route table
Completes the service -- this is the first commit where the whole thing
compiles and serves.

staffCreateInstance adopts a cloud instance that already exists in the
control plane, taking its name and slug from there and refusing when no
such instance exists: an admin row pointing at nothing would issue licences
nobody can use. Adopt then issue is how the existing read-only cloud
instances get licensed.

staffRelink has no attempt cap. The customer-facing limit exists to put a
human in front of the fourth attempt, and this is that human.

Editing a plan changes what a tier grants from now on only; existing
licences snapshotted theirs at issue time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:11:04 +01:00
mrhid6andClaude Opus 5 c829cc41d9 feat(admin): linking, relink and the scoped customer API
Every customer handler that names an instance resolves it through
ownedInstance, which returns 404 rather than 403 for another account's
instance -- a 403 confirms the instance exists, which is an existence
oracle over customer data.

The unique index on admin_instances.instance_id, not the pre-check, is what
actually prevents two accounts owning one instance. Relink issues a
replacement covering the REMAINING term, so it cannot be used to extend a
subscription, and the old licence is not revoked because offline
verification has no revocation -- its instance binding is what stops it.

The route table lands with the staff handlers in the next commit so every
commit builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:09:13 +01:00