Files
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

79 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Free tier enforcement (Descrybe v2)
How the forever-Free plan is packaged and gated versus paid plans.
## Packaging (EnsureDefaultPlans / ProvisionFreePlan)
| Plan | Price | Max products | Monthly AI credits | Notes |
|------|-------|-------------:|-------------------:|-------|
| **Free** | $0 | 50 | **0** | New signups via `ProvisionFreePlan` |
| Starter | $49/mo | 1,000 | 1,000 | ~50% cover; entry “lower fish” |
| Plus | $199/mo | 5,000 | 5,000 | ~50% cover; Woo+Shopify |
| Growth | $299/mo | 25,000 | 25,000 | Hero; near A1 absolute $; full stores + BYOK |
| Business | $499/mo | 50,000 | 50,000 | Plytix-class SKUs; ~50% cover |
| Scale | $999/mo | 150,000 | 120,000 | ~40% cover |
| Enterprise | Custom | Unlimited (`null`) | 1,000,000 | `is_custom`; large managed grant + BYOK |
**A1 legacy** stays dump-faithful (PAYG, ~100 products in practice, Stores/AI integrations off) — not overwritten by `EnsureDefaultPlans`. Public plans are intentionally richer so A1s deal is not “better” than what new customers get.
Extra AI beyond the monthly grant: buyable one-time **credit packs** (`GET /api/billing/credit-packs`, Checkout `{ "pack": "…" }`). See [stripe-setup.md](stripe-setup.md).
`EnsureDefaultPlans` upserts public plans by name (idempotent). Free intentionally grants **no** AI credits so signup never burns LLM cost. SKU/feed packaging follows the public ladder (50 SKUs on Free, etc.).
Existing Free wallets are not wiped on plan sync; only the `plans.monthly_credits` row is corrected. New cycles / `AssignPlan` allocate from the plan row.
## Entitlements
Exposed on `/api/auth/me` → `credits` and `/api/billing/credits`:
| Field | Meaning |
|-------|---------|
| `can_use_ai` | `remaining_credits > 0` **OR** paid plan (not Free) |
| `can_use_eprel` | **Always true** — EU EPREL is public free data on every plan (no credits). Platform may still disable the enricher via `eprel.enabled`. |
| `is_free_plan` / `is_paid_plan` | Derived from active plan name |
`billing.AIBrandApplyAllowed` already blocks brand-kit injection into AI prompts on Free.
## Free vs paid matrix
| Capability | Free | Paid (Starter+) |
|------------|------|-----------------|
| Signup / map feed / view products | Yes | Yes |
| Normalize / parse_specs / fill_fields | Yes (no credit debit) | Yes |
| `ai_enhance` (titles / descriptions / SEO copy) | **Skipped** (`can_use_ai=false`) | Yes (credits) |
| EPREL enrichment | **Yes (all plans)** | Yes |
| AI-only job (`title`, `description`, `enhance_*`) | **402** `ai_requires_upgrade` | Credits gate |
| EPREL-only job | **Yes** (no upgrade) | Yes |
| Email campaign AI generate | **402** via `can_use_ai` / `ErrAIRequiresUpgrade` | Credits / paid |
| SEO formula editors (config) | Editable | Editable |
| SEO AI apply (`/api/seo/apply`) | **402** via `can_use_ai` | Credits / paid |
| Email campaign AI generate | **402** on Free (`/api/campaigns/:id/generate` AI mode) | Credits / paid |
| Product SKU cap | 100 | Per plan |
| Upgrade banners | Dashboard + Products | Low-credit / limit banners |
## Processing behavior
1. **Start job** — `AssertCanStartProcessing` always checks SKU cap. Credit wallet is checked only when `RequiresAI` / `RequiresEPREL` (AI-only or EPREL-only types).
2. **Full / attributes jobs on Free** — allowed; pipeline `StepPolicy` sets `AllowAI=false`, `AllowEPREL=false` and appends clear notes (`ai_enhance: skipped (Free plan…)`, `eprel: skipped (paid plan…)`).
3. **ConsumeCredits** — no debit when `!CanUseAI && tokenCount==0` (free normalize path).
## Demo user
`cmd/seed-demo` ensures a standalone **Platform Demo** company (never renames A1), upserts `demo@descrybe.test` + `demo@descrybe.local`, binds them **only** to Platform Demo, and assigns the custom **Platform Demo** plan (~1,000,000 monthly AI credits, unlimited SKUs, all feature gates ON). Free plan definition for new signups remains `monthly_credits=0`. See [demo-user.md](demo-user.md) and [safe-test-fixtures.md](safe-test-fixtures.md).
## UI
- Products: Free info banner; AI options disabled with upgrade hint; process toast notes AI skip.
- Dashboard: Free-specific banner (not “out of credits”).
- Marketing pricing: Free lists 0 AI credits; EPREL included on all plans.
## Related
- [free-tier-verify.md](free-tier-verify.md) — live smoke while demo is Enterprise
- [eprel.md](eprel.md) — EPREL step details
- [demo-user.md](demo-user.md) — Enterprise credits for demo
- Repo sibling `PRICING-AND-USER-GROWTH.md` (v1 docs) — commercial ladder; Free AI pack in that doc is overridden here to **0** for cost control
- SEO apply: `apps/api/internal/seo` (`can_use_ai`)
- Campaign AI: `apps/api/internal/campaigns` (`ErrAIRequiresUpgrade` on AI generate)