Add zh-CN, ja, ko, ru, es, pt-BR translations under docs/i18n/, keeping
the canonical English README/CHANGELOG at the repo root. Each file gets a
language switcher bar with the current language bolded.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 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>
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.
* feat: v2.6 Z11 — prod public key, Docker cron docs, release notes
- Replace DEV placeholder in public-keys.ts with cloud.zpan.space
production Ed25519 key (k4.public.sphdaogcyIh2_6_yZnO4_xQsi2m52HH9j2CPHcKlGGw)
from cloud C5 cross-repo PR
- Add external cron section to docs/deploy/docker.md for the
POST /api/licensing/refresh-cron endpoint (Z6)
- Create docs/v2.6-release-notes.md with what's new, retroactive gate
notice (open_registration, teams_unlimited, team_quotas), upgrade guide
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* test(licensing): decouple verify/entitlement tests from DEV secret key
Tests were hardcoded to the old DEV placeholder key. Now they generate
a fresh throwaway keypair per suite (beforeAll/afterAll), inject the
public key into PUBLIC_KEYS, and restore the original on teardown.
This keeps the tests independent of whichever production key is in
PUBLIC_KEYS, so rotating the key never breaks the test suite.
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
zpan-cloud renumbered from v0.x to v1.x (SemVer: first stable
= 1.0). v2.6 Pro Launch now depends on cloud v1.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- v2.6 becomes Pro Launch: cloud-account binding activation,
Ed25519 entitlement certificates, white-label as first Pro
feature, retroactive Pro gates (open registration, team count
≤3, per-team storage quota)
- v2.7 becomes Pro Operator: audit log, webhooks, anti-abuse
stack for the Pro-gated open registration mode
- v2.8 becomes Pro Analytics & Identity: analytics dashboard,
multi-IdP SSO + SAML, LDAP / SCIM
- Original Backup (v2.6) content moved to v2.9; Sync & Desktop
(v2.7) content moved to new v2.10
- Managed Cloud Services extracted to a separate closed-source
zpan-cloud repo (content moderation, server-side processing,
managed custom domains)
- Community vs Pro split rewritten around the operator rule
("features that help you use ZPan are free; features that
help you operate ZPan for others are Pro")
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add Azure Functions deployment target (v4, Node 22)
- server/entry-azure.ts: Azure Functions v4 handler wrapping the Hono
app via app.http(); uses createLibsqlPlatform for Turso and serves
the SPA from ./dist via @hono/node-server/serve-static
- server/azure-host.json: runtime manifest (extensionBundle v4)
- deploy/azure-functions/main.bicep: idempotent Bicep template
provisioning Storage Account, Consumption plan and Function App;
BETTER_AUTH_SECRET handled separately by the workflow
- .github/workflows/deploy-azure.yml: 8-step workflow (secret check,
checkout, Node setup, az login, Bicep deploy, build, db:migrate,
func publish) with BETTER_AUTH_SECRET generate-if-missing logic
- package.json: build:azure script + @azure/functions dependency
- docs/deploy/azure-functions.md: setup guide covering SP JSON format,
required secrets, and local emulation with func start
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* fix: address review issues in Azure Functions deploy
- Move BETTER_AUTH_SECRET and APP_URL setup to before func publish
(bootstrap.ts throws on missing secret; any request between publish
and the old secret-set step would have returned 500)
- Remove placeholder appUrl Bicep param; workflow sets APP_URL and
BETTER_AUTH_URL via appsettings after Bicep, before publish
- Fix HttpRequest→Request body handling: construct a proper Web API
Request with body cast and duplex option instead of double-casting
HttpRequest, ensuring POST/PUT/PATCH body-reading routes work
- Add push: branches: [master] trigger + upstream guard to match other
deploy workflow conventions; document the auto-deploy behaviour
- Update docs/deploy/azure-functions.md to reflect the push trigger
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* ci: re-trigger CI for review fixes
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
* feat: v2.5.0 T6 — Google Cloud Run deployment (service.yaml + workflow + docs)
Add Cloud Run as a first-class deploy target. Reuses the existing root
Dockerfile via gcloud run deploy --source (Cloud Build). Turso for DB,
external S3-compatible storage. Follows the standard 8-step workflow
contract: secret check, release resolution, GCloud auth, Turso migration,
Secret Manager upsert, deploy. min-instances=0 for free-tier eligibility
with cold-start callout in docs.
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* fix: resolve first-deploy failure and drive deploy from service.yaml
BLOCKER: BETTER_AUTH_URL and TURSO_AUTH_TOKEN were passed to --set-secrets
even when the corresponding Secret Manager entries didn't exist yet.
BETTER_AUTH_URL isn't known until after the first deploy (it IS the Cloud
Run service URL). TURSO_AUTH_TOKEN is optional. Both caused 'secret not
found' aborts.
Fix: separate deploy into two phases.
Phase 1 — gcloud run services replace with service.yaml, which only
references the guaranteed secrets (turso-database-url, better-auth-secret).
Phase 2 — post-deploy step captures the service URL, upserts better-auth-url
and (if provided) turso-auth-token in Secret Manager, then wires them into
the running service via gcloud run services update --update-secrets.
MINOR: service.yaml was orphaned — the workflow used gcloud run deploy
--source . with inline flags instead. Rebuilt workflow to use gcloud builds
submit to build the image, then gcloud run services replace to drive the
deploy from the manifest. PROJECT_ID is substituted at deploy time.
Also demote BETTER_AUTH_URL from required to optional GitHub secret
(auto-derived from Cloud Run service URL on first deploy) and update docs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: v2.5.0 T4 — Netlify deployment target
- server/entry-netlify.ts: Netlify Functions v2 (ESM) handler using hono/netlify
adapter; connects to Turso via @libsql/client; skips in-process migrations
(workflow applies them before deploy via drizzle-kit)
- deploy/netlify/netlify.toml: build command, functions directory, SPA fallback redirect
- .github/workflows/deploy-netlify.yml: 8-step workflow — secret guard, tag resolve,
Turso migrations, build, netlify deploy --prod, BETTER_AUTH_SECRET first-deploy, summary
- package.json: add build:netlify script (tsup ESM → netlify/functions)
- docs/deploy/netlify.md: 5-section setup guide covering Turso, site creation,
secrets, deploy trigger, first-boot storage setup, and cost breakdown
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* fix: address Netlify deploy review blockers
BLOCKER 1 — move BETTER_AUTH_SECRET step before Deploy in workflow so
the function always has the secret set before its first cold start.
BLOCKER 2 — replace inline platform construction in entry-netlify.ts
with createLibsqlPlatform(); removes duplicated db/schema wiring and
re-unifies with the shared factory. migrate() runs at cold start and
is idempotent (~50–100ms) per the workflow's prior drizzle-kit migrate.
BLOCKER 3 — add --external @libsql/client to build:netlify so tsup
leaves the native-binding package for Netlify to resolve; switch
netlify.toml to node_bundler=esbuild so Netlify bundles @libsql/client
from node_modules. Add included_files=["migrations/**"] so the
migrations folder is available in the function zip for migrate().
Minor — replace 2>/dev/null with 2>&1 in deploy step so netlify-cli
errors surface in CI logs instead of being silently swallowed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add Vercel deployment target (Node runtime + Turso)
Adds first-class Vercel support: server/entry-vercel.ts using hono/vercel
handler, deploy/vercel/vercel.json with nodejs22.x function config and SPA
rewrites, build:vercel npm script producing api/entry-vercel.js + dist/,
deploy-vercel GitHub Actions workflow (8-step: secrets check, tag resolve,
checkout, install, migrate, build, link, deploy), and docs/deploy/vercel.md
documenting secrets, quick-start, local dev, and pricing notes.
Edge runtime is explicitly not used — @aws-sdk/client-s3 requires Node APIs.
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* fix: auto-generate BETTER_AUTH_SECRET on first Vercel deploy
Remove BETTER_AUTH_SECRET from the required secrets check. Add a
dedicated step that detects whether the secret already exists in the
Vercel project env via `vercel env ls production`, then either upserts
the user-supplied GitHub secret, auto-generates one with openssl on
first deploy, or skips if already present. Auto-generation case appends
a backup warning to GITHUB_STEP_SUMMARY. Docs move BETTER_AUTH_SECRET
to Optional Secrets with a note about the auto-gen behaviour.
Matches the existing CF Workers deploy.yml pattern (step 8 contract).
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
* feat: add libSQL (Turso) platform adapter and Docker opt-in
- server/platform/libsql.ts: createLibsqlPlatform() using @libsql/client +
drizzle-orm/libsql; accepts plain env record; async migrate at boot;
authToken optional for file:// URLs
- server/entry-node.ts: select platform at startup — libsql when
TURSO_DATABASE_URL is set, otherwise existing SQLite via createNodePlatform()
- drizzle.config.ts: switch to turso dialect when TURSO_DATABASE_URL is set
- vitest.libsql.config.ts + server/platform/libsql.libsql-test.ts: smoke suite
covering connect, migrations, insert/select against users + storages tables
- package.json: add @libsql/client dependency; add test:libsql script;
externalize @libsql/client in build:node tsup command
- vitest.config.ts: exclude *.libsql-test.ts from coverage
- docs/deploy/docker.md: document Turso opt-in with copy-pasteable
docker-compose snippet
- CONTRIBUTING.md: add Turso migrate path paragraph under Database Migrations
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* refactor: turn bootstrap.ts into a Platform-accepting factory
- server/bootstrap.ts: replace singleton module-scope script with
exportable createBootstrap(platform) async factory; reads
BETTER_AUTH_SECRET/BETTER_AUTH_URL/TRUSTED_ORIGINS from platform.getEnv
so every future entry (Lambda, Vercel, Netlify, Azure) can reuse it
- server/entry-node.ts: slim down to platform selection + createBootstrap
call; no more duplicate auth/app wiring
- server/dev.ts: thin vite-dev-server entry that creates NodePlatform and
calls createBootstrap; replaces the former default export in bootstrap.ts
- vite.config.ts: update node dev server entry to server/dev.ts
- server/platform/libsql.ts: fix getEnv to check env record before
falling back to process.env, matching the cloudflare.ts pattern
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
* style: apply biome auto-fixes for pre-existing lint issues
Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f
---------
Co-authored-by: Bob <aibob@mails.agent-kanban.dev>
v2.5 originally covered branding polish. Shift it to unlock
multi-platform deployment — seven first-class targets (CF Workers,
Docker, AWS Lambda, Vercel, Netlify, Azure Functions, Google Cloud
Run) using Turso libSQL as the universal non-CF database. Zero
SQLite-dialect work, generous free tier, HTTP protocol sidesteps
serverless connection-pool issues.
GitHub Actions workflows drive each deploy, mirroring the existing
CF deploy.yml pattern (self-healing resources, auto-generated
secrets, upstream release tracking). Object storage credentials
stay in the admin UI storages table, not GitHub Secrets.
Site branding (custom logo, favicon) moves to v2.8 as a managed-
only white-label feature. User avatar upload remains in v2.5 as
the sole carry-over from the original scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add tool integration config generators for PicGo/uPic/ShareX/Flameshot
Implements T9 of the v2.4.0 roadmap. Adds a "Tool Integration" section to the
Image Hosting settings page that generates ready-to-use configuration for four
popular screenshot/upload tools from the user's API key.
- src/lib/tool-configs.ts: pure generator functions (PicGo, uPic, ShareX, Flameshot)
- src/lib/tool-configs.test.ts: 15 snapshot + unit tests, all passing
- src/components/image-host-settings/tool-integration-panel.tsx: panel root with
API key selector and tool tab switcher
- src/components/image-host-settings/tool-generators/: per-tool generator components
with Copy buttons; ShareX includes a .sxcu file download
- i18n en.json + zh.json: settings.ihost.tools.* keys added
- docs/tool-integrations.md: step-by-step setup docs for all four tools
All configs use window.location.origin for appHost. Pasted key is ephemeral —
never persisted to localStorage or sent to the server.
Agent-Profile: https://agent-kanban.dev/agents/b724a773425e397c
* refactor: remove unused defaultParams helper from tool-configs
The function was never called by any component or test. Removing it
eliminates a dead-code coverage gap that caused codecov/patch to fail.
Agent-Profile: https://agent-kanban.dev/agents/b724a773425e397c