Commit Graph
8 Commits
Author SHA1 Message Date
mrhid6andClaude Opus 5 2e8114c41e feat(admin): subscription webhooks promote the entitlement and reissue; cancel and past-due take no licence action
created/updated/activated fold into 'make the world match current state', so
out-of-order delivery is correct by construction. A confirmed subscription
promotes desired->granted and signs from granted only. Cancel and past-due touch
only status; the licence runs to expiry. IssueForInstance backstops a
self-hosted placeholder that is linked after payment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 10:40:06 +01:00
mrhid6andClaude Opus 5 0f5ad1d836 feat(admin): one password change reaches every instance
Best-effort by design: refusing the change because one instance was
unreachable would leave the customer holding the password they were trying
to replace. A failure is flagged and hqsync repairs it.

Also corrects two pieces of copy this makes false — CreateInstance's doc
comment and the instance-ready email both claimed the two passwords
diverge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 16:29:50 +01:00
mrhid6andClaude Opus 5 0c663945ee feat(admin): invite people to an account and give them roles
An invitation carries no password. The HQ password is what signs someone
into every instance they are granted, so a password the inviter chose would
be a shared credential to all of them — the invited row has an empty hash,
which cannot authenticate, until /accept-invite sets one.

Removing a person revokes every projected instance user first, and refuses
outright if any of those is an instance's last owner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 16:26:56 +01:00
mrhid6andClaude Opus 5 aef5811c16 fix(admin): SMTP over implicit TLS, and rollbacks that survive
Server Deploy / deploy (push) Successful in 2m13s
Two bugs, one symptom: signup created an account and a customer_user but
no verification email ever arrived.

net/smtp.SendMail only speaks STARTTLS. Against a port-465 server, which
expects a TLS handshake immediately, it never delivers. The transport now
wraps the connection before speaking SMTP on 465, exactly as
sitesvc/internal/mail already did — the two are duplicated, so change both
or consolidate into shared/. Also adds Date and Message-ID, whose absence
gets a message scored as spam, and a 15s deadline on the conversation.

The rollbacks ran on the HTTP request's context. A stalled mail server
holds the request until the browser gives up, which cancels that context
and turns both rollbacks into silent no-ops — stranding the exact rows
they exist to remove. They now run detached with their own timeout, and
log when they fail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 14:26:34 +01:00
mrhid6andClaude Opus 5 372a8c5ddf feat(admin): lapse sweep and the four renewal notices
Hourly sweep marks expired Free instances lapsed and sends at most one
notice per instance per pass, most urgent first, recorded on the document
so a restart cannot re-send.

Deletion warnings are suppressed when the reaper is off. Promising a
deletion that will never happen is a lie, and a scarier one than silence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:20:00 +01:00
mrhid6andClaude Opus 5 909ddb884e feat(admin): renew a Free instance from the portal
Available from seven days before expiry and, deliberately, at any point
after it up to deletion, so the same button rescues a lapsed instance.

Renewal is manual because it is the entire reclaim signal: an instance
nobody renews is one nobody is using, which is what makes reaping safe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:17:45 +01:00
mrhid6andClaude Opus 5 1836237f82 feat(admin): POST /api/instances creates a Free cloud instance
Provisions the control-plane instance and its owner, records the
admin_instances row, issues and injects a Free licence, and emails the
customer where it is and when it expires.

Licence issuance and email cannot fail the request. The instance exists
and the customer can sign in; rolling back something they can already see
would be worse than shipping it unlicensed for staff to fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:16:12 +01:00
mrhid6andClaude Opus 5 07a3756b18 feat(admin): self-hosted customer accounts with email verification
Mirrors the pattern sitesvc already proves: 32 random bytes, only the
SHA-256 hash stored, a 24-hour expiry, and the token cleared on use -- so a
leaked database yields no working links.

Unverified login returns a distinct "verify your email address first" rather
than the generic error. The address is already known to be theirs, so there
is nothing to disclose and that is the only useful thing to say.

Licence blobs are emailed inline. A blob is signed public data, not a
secret: it is useless on any instance other than the one it names.

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