Files
descrybe/docs/free-tier-verify.md
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

4.0 KiB

Free tier verification (while demo is Enterprise)

Proof that cmd/seed-demo assigning Enterprise to Local Demo Co does not break forever-Free packaging or gates for new signups.

Date: 2026-08-04
Related: free-tier.md, demo-user.md

Expected matrix

Check Free signup Demo (Enterprise)
Plan name Free Enterprise
monthly_credits 0 1000000
Wallet remaining 0 ≈1M
can_use_ai false true
can_use_eprel false true
AI-only job (title / description / enhance) 402 ai_requires_upgrade Allowed (credits)
EPREL-only job 402 eprel_requires_upgrade Allowed
Full / normalize process 202 → completes; ai_enhance + eprel skipped Full AI path

Live smoke (2026-08-04)

API: http://127.0.0.1:8080 · Postgres: localhost:5433

1. Public plan rows after Enterprise seed

SELECT name, monthly_credits, max_products, is_custom
FROM plans WHERE lower(name) IN ('free','enterprise') ORDER BY name;
name monthly_credits max_products is_custom
Free 0 100 f
Enterprise 1000000 null t

2. New Free signup path

POST /api/auth/register201ProvisionFreePlan.

Observed (/api/auth/mecredits):

  • plan.name=Free, monthly_credits=0
  • remaining_credits=0, can_use_ai=false, can_use_eprel=false, is_free_plan=true

3. 402 on AI (Free company with a raw product)

Request Status Body code
POST /api/processing/jobs processing_type=title 402 ai_requires_upgrade
processing_type=description 402 ai_requires_upgrade
processing_type=enhance 402 ai_requires_upgrade
processing_type=eprel_only 402 eprel_requires_upgrade

Example body:

{
  "code": "ai_requires_upgrade",
  "error": "ai features require a paid plan or AI credits — upgrade your plan or add AI credits",
  "upgrade_url": "/pricing"
}

4. Non-AI process works

POST /api/processing/jobs processing_type=full202, job completed:

  • normalize / parse_specs / fill_fieldsdone
  • eprelskipped (entitlement_can_use_eprel)
  • ai_enhanceskipped (entitlement_can_use_ai)

5. Demo still Enterprise

demo@descrybe.local/api/billing/credits: plan.name=Enterprise, can_use_ai=true, remaining ≈ 1M.

Regression fixed

ProvisionFreePlan previously fell back to SELECT id FROM plans ORDER BY id LIMIT 1 when Free was missing. After migration + seed-demo, Enterprise can have a lower id than Free, so that fallback could assign Enterprise to a new signup. Fallback removed — only the Free row is assigned (best-effort no-op if Free is absent after EnsureDefaultPlans).

seed-demo now fails closed if Free monthly_credits ≠ 0 or max_products ≠ 100 after EnsureDefaultPlans.

Automated checks

cd apps/api
go test ./internal/billing/ ./internal/processing/ -count=1
go build ./...

# Optional DB smokes (requires migrated + seed-demo DB):
$env:DATABASE_URL = "postgres://descrybe:descrybe@localhost:5433/descrybe?sslmode=disable"
go test ./cmd/seed-demo/ -count=1 -v

Unit coverage:

  • TestComputeEntitlements — Free 0 credits → no AI/EPREL
  • TestDefaultPublicPlansFreeZeroCredits — Free packaging locked at 0 / 100 SKUs
  • TestDefaultPublicPlansEnterpriseUnlimited — Enterprise 1M / unlimited SKUs
  • TestFreePlanUnaffectedByEnterpriseSeed — live Free row after demo seed
  • TestLocalDemoCoEnterpriseCredits — demo company still Enterprise

Re-run checklist

  1. go run ./cmd/seed-demo (demo → Enterprise; Free row still 0 credits)
  2. Register a fresh user → Free / 0 credits / can_use_ai=false
  3. Start title job → 402 ai_requires_upgrade
  4. Start full job → 202; AI/EPREL steps skipped
  5. Login as demo → Enterprise credits unchanged