Skip to content

feat(release): v7.7.0 — V1 Plugin Pro paid tier + recovery + GDPR#385

Closed
saurabhjain1592 wants to merge 1 commit into
mainfrom
sync/enterprise-20260506-120725-25434245469
Closed

feat(release): v7.7.0 — V1 Plugin Pro paid tier + recovery + GDPR#385
saurabhjain1592 wants to merge 1 commit into
mainfrom
sync/enterprise-20260506-120725-25434245469

Conversation

@saurabhjain1592

Copy link
Copy Markdown
Member

v7.7.0 — V1 launch release

First public release of the paid Pro tier and credential recovery for AxonFlow Community SaaS, alongside the unified license matrix from ADR-050. Self-hosted Enterprise deployments are unaffected; existing Self-Hosted license tokens continue to validate via the missing-aud fallback documented in ADR-050.

Note: companion plugin and SDK changes (the new X-Axonflow-Client header read path, scope-aware license validation) are present on enterprise main but the corresponding plugin and SDK releases will follow on their own cadence. Clients without the new header continue to work and receive a one-time upgrade hint.

Added — paid Pro tier

  • POST /api/v1/billing/stripe-webhook receives Stripe webhook deliveries for the V1 SaaS Plugin Pro tier. Subscribes to checkout.session.completed (issues the license) and charge.refunded (revokes on full refund). Defended by Stripe-Signature HMAC + IP allowlist (Stripe's published webhook CIDRs, env-overridable) + per-source rate limit. Idempotent over stripe_session_id — Stripe at-least-once delivery returns the original token byte-identically on retry, never a new one.

  • License token validation on every governed request. validateCommunitySaasAuth now reads X-License-Token, validates the Ed25519 signature, checks the token's audience claim against the SaaS Plugin accept list, verifies the tenant binding, and looks up the active row in plugin_user_licenses. Free tier (no header) passes through unmodified; Pro / Premium tier promotes the request when both token and row are valid. Per-request DB lookup keeps revocation effective within ~60s of a chargeback or dispute.

  • Per-tenant daily request quota and audit retention follow the resolved tier from the license token: Free 200/day with 3-day rolling retention; Pro 1,000/day with 30-day retention; Premium 5,000/day with 90-day retention (reserved, not yet sold). Fires on both admin routes (apiAuthMiddleware) and plugin/SDK governed routes.

  • Auto-revoke on full refund. A charge.refunded event whose amount_refunded == amount and whose latest refund status == "succeeded" triggers a revoked_at UPDATE on the matching license row, looked up by stripe_payment_intent_id. Partial refunds are an explicit no-op. Replays / already-revoked rows take an idempotent no-op path.

Added — free-tier credential recovery

  • POST /api/v1/recover and POST /api/v1/recover/verify allow Community SaaS tenants who opted in at sign-up time to self-recover a lost secret via emailed magic link. Capped at 3 active tenants per email; per-IP rate limit prevents enumeration probes. Tokens stored as HMAC-SHA256 with optional server pepper; single-use; 1-hour TTL.

Added — GDPR right-to-erasure

  • POST /api/v1/tenant/{id}/delete-{request,confirm} — two-step email-verified tenant deletion. delete-request accepts the email-on-file and emails a single-use 1-hour confirmation token; delete-confirm consumes the token and atomically scrubs the tenant from community_saas_registrations, plugin_user_licenses, audit_logs, community_saas_daily_usage, and usage_events. Stripe customer archive runs best-effort post-commit (DB-side erasure completes regardless of Stripe reachability). New tenant_deletion_log table is the immutable audit trail of completed erasures — survives the deletion of the tenant's own audit_logs, which is precisely what GDPR Article 30 requires. Anti-enumeration: delete-request always returns 202 with the same generic message regardless of whether the (tenant_id, email) pair matches.

Added — license matrix (ADR-050)

  • -aud flag on the keygen CLI for self-hosted operators. Issuers can now generate licenses with an explicit aud claim from the canonical set: axonflow.self_hosted.full (default — no behavior change), axonflow.self_hosted.plugin and axonflow.self_hosted.sdk (both forward-looking, not yet sold). Cross-quadrant aud values (axonflow.saas.*) are rejected at issuance.

Changed

  • SaaS Plugin tier names unified to Pro / Premium. The plugin_user_licenses.entitlements JSONB scaffolding shipped in v7.6.1 has been superseded by the unified tier ladder. Migration 080 drops the column and renames any pre-existing 'plugin-claimed' rows to 'Pro' and 'plugin-subscription' rows to 'Premium'. No production tokens existed for the v7.6.1 design — the row writer was inert scaffolding without a downstream reader.

Bug fixes

  • csaas register/recovery rate limit now trusts the LAST X-Forwarded-For entry (the AWS ALB-appended client IP) instead of the first, which is client-spoofable. Real per-IP rate limiting now actually fires on real attacker IPs behind the ALB.

  • AWS Secrets-Manager-derived secret env vars are trimmed to prevent silent fail-closed on trailing newlines. The Resend API rejects Authorization headers with embedded newlines, which previously caused every paid-tier license email to fail without any obvious cause.

  • tierRank fails closed on unknown tier strings. Defense in depth against a corrupt or future-version row evaluating to a permissive tier.

Migrations

  • 080 — drops the dormant entitlements JSONB column from v7.6.1 (idempotent, replay safe)
  • 081 — promotes usage_metering schema from migrations/enterprise/ to migrations/core/ so community-saas runs it (idempotent IF NOT EXISTS — replay safe on existing SaaS prod where the original migration 104 already applied)
  • 082tenant_deletion_log audit table for GDPR Article 30
  • 083stripe_payment_intent_id on plugin_user_licenses (nullable + partial-indexed) for charge.refunded reverse lookup

V1 launch release for AxonFlow Community SaaS. First public release of
the paid Pro tier, free-tier credential recovery, GDPR right-to-erasure,
and the unified license matrix from ADR-050. Self-hosted Enterprise
deployments are unaffected; existing Self-Hosted license tokens
continue to validate via the missing-aud fallback.

Customer-facing surfaces:

- Paid Pro tier ($9.99 one-time, 90 days). Stripe Checkout completion
  mints an Ed25519-signed plugin license token, persists it on the
  tenant, and emails it to the buyer. Full Stripe refunds within the
  14-day refund window auto-revoke the license; partial refunds are an
  explicit no-op so a partial credit doesn't cancel the buyer's tier.
  New POST /api/v1/billing/stripe-webhook (Stripe-Signature HMAC + IP
  allowlist + per-source rate limit; idempotent over stripe_session_id;
  charge.refunded reverse lookup via stripe_payment_intent_id).

- Free-tier credential recovery for Community SaaS tenants who opt in
  at sign-up. Lost secret recovered via emailed magic link; capped at 3
  active tenants per email with per-IP rate limit. New endpoints:
  POST /api/v1/recover and POST /api/v1/recover/verify.

- GDPR right-to-erasure (Article 17). Two-step email-verified tenant
  deletion atomically scrubs registration, plugin license, audit
  history, daily-usage counters, and per-tenant usage records.
  Anti-enumeration: delete-request always returns 202 with a generic
  message regardless of (tenant_id, email) match. New endpoints
  POST /api/v1/tenant/{id}/delete-request + .../delete-confirm. New
  immutable tenant_deletion_log table for Article 30 records-of-
  processing-activities compliance.

- Per-tenant tier resolution from the license token's aud claim on
  every governed request. Per-tier daily quota + audit retention now
  fire on both admin and plugin/SDK governed routes (Free 200/day/3d;
  Pro 1000/day/30d; Premium 5000/day/90d reserved). Token tenant_id
  mismatch returns 403; missing or revoked row returns 401.

- -aud flag on the keygen CLI for explicit aud claim selection from the
  canonical ADR-050 set (self_hosted.{full,plugin,sdk}). Cross-quadrant
  aud values rejected at issuance.

Internals:

- SaaS Plugin tier names unified to Pro / Premium. The entitlements
  JSONB scaffolding shipped in v7.6.1 has been superseded; migration
  080 drops the column and renames pre-existing 'plugin-claimed' rows
  to 'Pro'.

- csaas register/recovery rate limit now trusts the LAST X-Forwarded-For
  entry (the AWS ALB-appended client IP), not the first.

- AWS Secrets-Manager-derived secret env vars trimmed to prevent silent
  fail-closed on trailing newlines (Resend API was rejecting authorization
  headers, breaking license email delivery).

- tierRank fails closed on unknown tier strings.

Migrations:
- 080: drops dormant entitlements_jsonb from v7.6.1 (replay safe)
- 081: promotes usage_metering schema to migrations/core/ for csaas
- 082: tenant_deletion_log audit table (GDPR Article 30)
- 083: stripe_payment_intent_id on plugin_user_licenses (nullable +
       partial-indexed) for charge.refunded reverse lookup

See CHANGELOG.md v7.7.0 entry for the full per-edition breakdown.

Source Commits: fd2655d27,db2b1d085,40058c5dd,2dce10aa4,ad3315259,ad8664c10,399cdb0b2,8ed60c5db,22e3f0392,9cc93f800,c308f137a,ce9b12876,6eef94b38,5170ec572,67a037306,d7edaa28a,01bf36c3c,6241c41ff,6c3fa86c2,32577298f,2daff63d4,b753ff09e,fbe615af0,d7c47e926,f591d604a,8a7d078a3,ff2556ea8,62d26dbb7,b323c4052,748e61197,4e12c5de3,baef468c7,ae8e72b2e,a7b96dff1,a56575d03,82c645db2,a06ac666b,c7434321e,8b215edbe,9f83e53c9,e4558f7d0,28f10539c,195a4f358,e45886ee4,a20684a98,3831359d4,b72deb8de,c3bc52207,3a7345c5a,54dbf8176,1802845a7,9d0df6b98,c0b8402f5,70489286a,ca77ea1a3,ba07707fb,3c5816882,870111f47,db6a2c3a3,a25805e28,e6a92a181,cacb72018,6642c9813,3207b9fb1,810cee570,3068105cd,d94621e18,3f0252290,e87263306,0f92b2f99,d52847129,bb02aa9bc,2ab8322ae,5d9d06fdd,a80ec1d86,0899e744e,673104be7,cdb733be8

Signed-off-by: AxonFlow Team <bot@getaxonflow.com>
@saurabhjain1592 saurabhjain1592 added the community-sync Sync from enterprise repository label May 6, 2026
@saurabhjain1592

Copy link
Copy Markdown
Member Author

Closing — sync filter let through files that should have been excluded. Reopening will follow once filter excludes are corrected.

@saurabhjain1592 saurabhjain1592 deleted the sync/enterprise-20260506-120725-25434245469 branch May 6, 2026 12:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-sync Sync from enterprise repository

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants