103 Commits
Author SHA1 Message Date
saltboandClaude Opus 4.8 53ca110218 feat(about): split runtime into runtime engine + deployment platform
Flatten the instance `runtime` object into two fields: `runtime` (the JS engine,
node | workerd) and `platform` (the deployment host). The About page shows each
as its own row with friendly labels (e.g. "workerd" + "Cloudflare Workers",
"Node.js" + "Docker").

- Detect the platform from the entry file (entry === target): each serverless
  entry declares it; entry-node sniffs Cloud Run (K_SERVICE) / Docker
  (ZPAN_RUNTIME, set in the Dockerfile) / bare node. Cloudflare is detected from
  the D1 binding.
- Decouple the cloud payload: zpan-cloud-sdk fixes runtime { provider, target },
  so CloudInstanceInfo keeps that shape and buildCloudInstanceInfo maps to it;
  buildInstanceInfo serves the richer flat shape to the About API.
- Migrate PostHog instance telemetry to the runtime/platform shape and merge the
  duplicate runtimeInfo in licensing-admin into the shared one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 14:56:29 -04:00
saltboandClaude Opus 4.8 6aa5257f01 feat(about): take latest version from GitHub Releases, keep CHANGELOG drawer
The latest-version indicator now reads the newest published GitHub Release's
tag_name (the source of truth for "what shipped") instead of parsing the
changelog file. The drawer still renders the hand-maintained, product-facing
CHANGELOG.md — the auto-generated release notes are too technical for end users.

- Release lookup is best-effort: a rate-limited/unreachable GitHub API hides the
  version badge but never breaks the drawer (CHANGELOG.md drives the markdown).
- Drop parseLatestVersion; fetch the two sources concurrently behind the cache.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 13:57:05 -04:00
saltboandClaude Opus 4.8 e700fd4977 feat(about): add changelog drawer, latest-version check, and commit hash
Maintain a CHANGELOG.md (Keep a Changelog format) at the repo root and surface
it on the admin About page:

- The page now shows the running build's short commit hash next to the version,
  linked to the GitHub commit. Commit is injected at build time via a new
  resolveAppCommit() (ZPAN_APP_COMMIT -> WORKERS_CI_COMMIT_SHA -> git rev-parse),
  wired through vite/tsup defines, the node entry, Docker, and CI.
- A new admin-only GET /api/system/changelog endpoint fetches CHANGELOG.md from
  master on GitHub, caches it, parses the latest released version, and reports
  whether an update is available (semver compare against the running version).
- The About page renders a "latest version" row with an update-available badge
  and a side drawer that displays the changelog markdown.

Tests cover the semver compare, changelog parse/fetch caching, the API wrapper,
and the route (admin-gated, parsed payload).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 13:38:29 -04:00
Jasper VanandClaude Opus 4.8 5a5583b4ed feat(licensing): regroup comparison table by capability and add social-login/downloader gates (#423)
* feat(licensing): regroup comparison table by capability and add social-login/downloader gates

Decouple the feature comparison table's grouping axis from the pricing tier:
features are now grouped by capability (core/advanced) while edition
availability is expressed purely by the per-edition cells. Coming-soon
features show a badge next to the name with a muted check in the target
edition column, so it's clear which edition they will land in.

Tier reclassification (per product decision):
- Social login & OIDC: free = 1 provider, Pro/Business = unlimited
- Downloaders: free = 1, Pro/Business = unlimited
- Site announcements, Multi-IdP SSO, LDAP/SCIM, Analytics: Business-only

New runtime gates (enforced, mirroring the storages count-gate):
- social_login_unlimited in POST /api/admin/auth-providers (402 on 2nd)
- downloaders_unlimited in POST /api/admin/downloaders (402 on 2nd)
- site_announcements added to BUSINESS_ONLY_FEATURES

Copy cleanup:
- Rename rows that embedded a limit word: "Unlimited Team Workspaces"
  -> "Team Workspaces", "Storage Backends" -> "Storages"
- Clarify "Storage Plans" -> "Sell Storage & Traffic" (the quota_store feature)
- Make the Licensing page intro edition-neutral (Pro + Business) instead of
  the leftover Pro-only copy

Tests: add gate tests for both new limits; seed licenses in the existing
multi-provider/multi-downloader tests; switch announcement tests to a
Business license.

Note: site_announcements moving to Business takes full effect for real
licenses only once zpan-cloud stops listing it in Pro certificates; the
local edition-derived path is already updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(licensing): drop unused per-cert feature override, derive from edition

The optional `features[]` override on the license certificate was added with
the Pro/Business split but was never exercised: real certs carry only
`edition`, and entitlements are derived from it via the feature registry
(PRO_GATE_KEYS minus BUSINESS_ONLY_FEATURES). The override was dead in the
normal flow and duplicated the edition→feature mapping in two places.

Remove it so edition is the single source of truth:
- Drop `LicenseAssertion.features` and `normalizeFeatures` (verify.ts)
- `effectiveFeatures(edition)` no longer takes/honors an override list
- Simplify the test seed helpers (no `features` arg, no test-side
  business-only set) and update licensing tests to assert edition-derived
  entitlements

`BindingState.features` (the resolved list exposed to the client) is kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(downloader): regenerate OpenAPI spec and Go client for new 402 response

The downloaders create route gained a 402 (feature_not_available) response
for the free-plan limit; regenerate the committed OpenAPI document and Go
client so openapi:downloader:check passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 13:32:59 -04:00
Jasper VanandClaude Opus 4.8 891e331ca8 feat(admin): add About page with instance info and edition-aware cloud links (#422)
Add an admin About page (/admin/about) showing version, instance metadata
(id/name/url/runtime/server OS/Node version) and edition status, plus two
CTAs: GitHub (star) and ZPan Cloud. When the instance holds a valid license
the cloud CTA deep-links to the certificate detail page.

- server: expose GET /api/system/instance (admin-only); extract shared
  runtimeInfo() helper; move InstanceInfo to shared types
- ribbon: link to the About page, relabel Community -> Free, recolor
  Pro (gold) / Business (indigo) to match the cloud certificate palette
- licensing: BoundStatusCard "Manage" deep-links to the certificate detail
  page when active with a license_id
- useEntitlement: expose licenseId
- tests: api wrapper + system endpoint + ribbon coverage

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 10:40:54 -04:00
Jasper Van 9d70acfdea feat(licensing): support independent business authorization
Support independent Pro and Business licensing, migrate Cloud store integration through the SDK, gate Business-only credit billing features, and validate the Cloud store E2E flow.
2026-06-08 01:42:23 -04:00
saltbo d1c83ccece refactor(objects): run file operations sequentially 2026-06-06 12:46:18 -04:00
saltbo 65eb5d9738 fix(downloader): reset runtime on task restart 2026-06-06 00:54:26 -04:00
saltbo 6aa711bfb6 refactor(downloads): reshape download task status model 2026-06-06 00:07:21 -04:00
saltbo 8f272b8a41 refactor(downloader): clarify task states and restart action 2026-06-05 21:51:32 -04:00
saltbo 9dd3ca0105 fix(downloader): separate interrupted task recovery 2026-06-05 21:34:57 -04:00
saltbo 3f7a859e73 refactor(downloader): consolidate api contract generation 2026-06-05 15:24:56 -04:00
saltbo b05bf4f07e fix(downloads): normalize target folder paths 2026-06-05 10:10:44 -04:00
saltbo 4dcbab55b1 feat(downloads): improve task controls and metadata 2026-06-04 14:57:44 -04:00
saltbo 94dada75ba feat(downloads): add task actions and classification 2026-06-04 14:08:39 -04:00
saltbo 6276530476 feat(auth): unify api key management 2026-06-04 12:39:59 -04:00
saltbo 1b4f149d05 feat(downloads): stream normalized task details 2026-06-03 13:08:14 -04:00
saltbo 754d1aaa3d fix(downloads): separate storage and peer upload metrics 2026-06-03 12:23:31 -04:00
saltbo cf3324b4a2 feat(downloads): preserve directory uploads 2026-06-03 12:05:55 -04:00
saltbo f698e5a8a9 feat(downloads): show normalized task details 2026-06-03 11:12:56 -04:00
saltbo 53076d7873 feat(downloads): add remote download workers 2026-06-03 02:21:50 -04:00
saltbo 1ff6d13998 feat(billing): meter storage egress with credits 2026-06-02 22:22:40 -04:00
saltbo 7f85da222f feat(quota): consolidate storage entitlements 2026-06-02 20:12:59 -04:00
saltbo dd1d237945 feat(store): add credits package management 2026-06-02 13:38:11 -04:00
Jasper Van 650f209fe8 docs: clarify cloud credit billing boundaries
Clarify ZPAN's Cloud Credits boundaries and keep gift-card creation on the Credits-only contract.
2026-06-02 03:41:07 -04:00
Jasper Van 908786837d fix: align store pricing with USD contract
* fix: align store pricing with usd contract

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: align gift card cloud payload

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: normalize cloud gift card credits

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* test: cover gift card payload without expiry

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: keep gift card payload mapping executable

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: map credits to cloud wallets

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* test: align credits e2e selector

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: keep store credits on credits contract

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98
2026-06-02 01:44:00 -04:00
Jasper Van f45e8732fc feat: integrate cloud credits store flow
Replace ZPAN Store Wallet semantics with Credits-only APIs and UI.

Proxy Cloud credits through credit-account routes, send unitless gift-card credits, and block metered downloads on insufficient Cloud credits before presign while rolling back local counters.

Verification waiver: E2E fails only because the hosted Cloud target rejects the merged Credits gift-card payload; AK follow-up kxel47x6x6l3 tracks that target gap.
2026-06-01 22:31:46 -04:00
Jasper Van 8b45c6218a fix: use better auth captcha providers (#401)
Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98
2026-05-13 16:39:09 -04:00
Jasper Van fdb61c2a14 feat: add captcha protection for authentication (#400)
* feat: add captcha protection for authentication

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* test: guard captcha option key literal

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* test: avoid captcha placeholder literal

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: pin captcha secret option literal

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* fix: block oauth when captcha is enabled

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* test: cover captcha social pass-through

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98

* test: cover settings identity and registration saves

Agent-Profile: https://agent-kanban.dev/agents/a318237412dd8b98
2026-05-13 15:20:28 -04:00
Jasper Van 0694d5511a feat: add local archive background jobs 2026-05-11 20:42:01 -04:00
Jasper Van 2053b84c1a feat: add background job foundation (#388)
* feat: add background job foundation

Agent-Profile: https://agent-kanban.dev/agents/1dc839c09b5ee5e5

* fix: normalize cloud gift card create responses

Agent-Profile: https://agent-kanban.dev/agents/1dc839c09b5ee5e5
2026-05-11 19:24:54 -04:00
saltbo e82f868568 fix(cloud-store): read order deliverable quotas 2026-05-11 15:34:02 -04:00
saltbo 9efdcbb424 refactor(cloud-store): use cloud sdk contracts 2026-05-11 15:03:34 -04:00
saltbo 0795867993 fix(cloud-store): read order item deliverables 2026-05-11 11:49:45 -04:00
saltbo 0c070d8a83 fix(cloud-store): align gift cards with cloud model 2026-05-11 10:10:04 -04:00
saltbo 8c9dcfd928 fix(cloud-store): use wallet balances endpoint 2026-05-10 14:05:21 -04:00
saltbo 0de620d021 fix(cloud-store): align customer fields with cloud 2026-05-10 13:41:43 -04:00
saltbo acc2e81b98 refactor(cloud-store): rename end user fields to consumer 2026-05-10 12:29:58 -04:00
saltbo 73a592c8d9 feat(pro): tighten gates and unify upgrade prompts 2026-05-10 01:58:49 -04:00
saltbo 0f0ea65cb1 feat(storage): allow metered traffic overage 2026-05-09 15:27:54 -04:00
saltbo 46cacc011c feat(storage): redesign plan catalog 2026-05-09 15:10:48 -04:00
saltbo ae3f368335 feat(billing): configure per-currency metered plan pricing 2026-05-09 13:02:41 -04:00
saltbo 25c4a3c3ac feat(billing): configure traffic overage price on plans 2026-05-09 12:24:10 -04:00
saltbo 1ebc46fac0 feat(store): manage workspace subscription plans 2026-05-09 09:25:39 -04:00
saltbo 0b2e7d40cc feat(store): support subscription and fixed quota packages 2026-05-09 08:28:38 -04:00
saltbo 58d94c3df6 feat(cloud-store): accept opaque store deliveries 2026-05-09 00:07:37 -04:00
saltbo 25416a5f18 feat(quota): support plan and extra entitlement quotas 2026-05-08 23:34:15 -04:00
Jasper Van bf8a4f5877 feat: add quota entitlements (#383)
Agent-Profile: https://agent-kanban.dev/agents/1dc839c09b5ee5e5
2026-05-08 19:21:34 -04:00
Jasper Van 0b65e2dc15 [v2.6] Integrate zpan with new cloud order flow and complete migration cleanup
fix(store): guard cloud order actions by org
2026-05-08 15:42:05 -04:00
Jasper Van 11ab430493 refactor(quota-store): unify orders and gift cards
* refactor(quota-store): unify orders and gift cards

* test(quota-store): cover helper paths

* test(quota-store): cover webhook idempotency

* test(quota-store): cover cloud response normalization
2026-05-07 09:03:55 -04:00