Skip to content

Land community fixes: setup wizard, postgres volume, favicon, license expiry - #12

Merged
alanisme merged 15 commits into
mainfrom
integrate-prs
Aug 15, 2026
Merged

Land community fixes: setup wizard, postgres volume, favicon, license expiry#12
alanisme merged 15 commits into
mainfrom
integrate-prs

Conversation

@alanisme

Copy link
Copy Markdown
Contributor

Lands the four open community PRs together, plus follow-up hardening on the expiry endpoint.

Merging as one branch so CI validates the actual combined result — none of the four PRs had ever run CI, since fork PRs from first-time contributors sit behind the approval gate.

Included

Added on top of #6

  • Reject expiry edits on Stripe-billed licenses (409). The dashboard already hid the control, but the endpoint is also reachable by licenses:write API keys, and the next renewal overwrites whatever gets set.
  • Reject past dates, matching POST /admin/licenses. Back-dating is not an "expire now" shortcut — the grace sweep picks the license up and emails the customer that it expired, so a mistyped year turns into customer-facing mail.
  • Emit license.expiry_changed. Every other lifecycle action dispatches a webhook; this one only wrote an audit entry. Clearing the date sends JSON null so an integration can tell "perpetual now" from "field omitted".
  • Note in the UI that a new date alone won't revive an expired license — assertUsable short-circuits on the status before it reads valid_until.

Unrelated fix that rode along

WEBHOOK_EVENTS in the dashboard listed 5 of the 10 license.* events the backend dispatches. Since FindWebhooksForEvent filters by subscription, the missing ones — including license.expired — could never be subscribed to and were effectively undeliverable for anyone configuring from the UI.

Verified

Full CI locally (vet, unit, Atomic integration against real postgres, build; frontend lint/typecheck/build) and end-to-end in containers on a fresh volume: wizard returns 201 with a populated checkout_id, data survives container recreation, expiry guards return 400/409, webhook deliveries carry the right payload.

KurtJacobson and others added 15 commits July 15, 2026 20:52
Allows manually issued licenses to carry a fixed expiry date
(e.g. invoice-based one-year licenses). Empty keeps the existing
behavior: trial plans expire after trial_days, others are perpetual.
POST /admin/licenses/:id/valid-until with an RFC 3339 timestamp
sets the expiry; an empty value clears it (perpetual). Status is
deliberately untouched — reinstating an expired license remains an
explicit separate action.
The issue dialog gains an optional date field (empty = perpetual;
trial plans keep their trial_days default). The detail view shows a
pencil next to Valid Until for non-Stripe licenses — Stripe-billed
expiry is renewal-managed, so editing it there stays hidden. Dates
are sent as end-of-day UTC.
Previously the picked date became 23:59:59 UTC, which renders as a
confusing mid-evening time for admins west of Greenwich. The date
input's prefill is converted back the same way so editing doesn't
shift the day.
…irst

index.html ships two icon links (svg + sizes=32x32) and browsers
often prefer the sized one, so rewriting only the first link never
visibly changed the tab icon.
Migration 20260401_plan_checkout_id made plans.checkout_id NOT NULL,
and store.CreatePlan fills it via shortID() — but the setup wizard's
raw INSERT was never updated, so POST /api/v1/setup/initialize fails
with a not-null violation on every fresh install (surfaced to the
client as an opaque 500 INTERNAL_ERROR).

Export the existing shortID() helper as store.ShortID() (same pattern
as store.NewID(), which was exported for this handler) and include
checkout_id in the wizard's plan INSERT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
postgres:18+ official images moved the data directory into a versioned
subdirectory and expect the volume to be mounted at /var/lib/postgresql
instead of /var/lib/postgresql/data. With the old mount point a fresh
`docker compose up` fails: the postgres container loops with "There
appears to be PostgreSQL data in /var/lib/postgresql/data (unused
mount/volume)" and never becomes healthy, so the keygate container
never starts.

See docker-library/postgres#37

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alanisme
alanisme merged commit fe31ca8 into main Aug 15, 2026
2 checks passed
@alanisme alanisme mentioned this pull request Aug 15, 2026
4 tasks
@alanisme
alanisme deleted the integrate-prs branch August 15, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants