Commit Graph

3 Commits (2b2bb439a5efe330cd9c7a9f2de660c367c034e0)

Author SHA1 Message Date
nexxo 87c49de6e5 Move the console's identity out of the customer table 2026-07-28 10:31:43 +02:00
nexxo 2b70c9226a fix(traffic): release the throttle at month end; close the Livewire bypass
Two from Codex:

- A throttled instance kept its NIC limit into the new month: the new period
  row starts unthrottled, so neither branch of enforce() fired and nothing ever
  took the limit off. A customer would have stayed slow through a month they
  had already paid for.
- PublicSiteGate exempted livewire/* wholesale. That endpoint is shared by the
  console and the portal, so a signed-in customer could keep driving portal
  components — billing included — while the portal was supposed to be offline.
  Operators pass the normal check anyway, which is all the console needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 23:36:38 +02:00
nexxo e2b4cdbac4 feat(site): switch the public website and portal off from the console
While the product is still being built, the marketing site and the customer
portal should not be reachable — but they must stay reachable for us.

- A toggle in the console (site.manage, Owner/Admin) stored in a new
  app_settings table, because this has to be flippable without a deploy.
- Outsiders get a placeholder with 503 + noindex, not 200: a 200 invites search
  engines to index the placeholder as the site's content, which is far harder
  to undo than to prevent.
- Anyone on the management VPN, and any signed-in operator, sees the real site.
  The console, Livewire's endpoint, the Stripe webhook and the health check are
  always reachable — otherwise the switch could only be flipped once.
- robots.txt is generated by the app and follows the switch. It had to stop
  being a static file: nginx short-circuited it and Laravel's stock file said
  'Disallow:' with an empty value, so crawlers were never told anything.
- Settings reads fall back to the default when the table is unavailable. The
  gate reads one on every request, so a deploy running new code before migrate
  would otherwise answer the entire site with a 500.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 23:10:27 +02:00