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.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
# 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 A1’s 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)
|
||||
Reference in New Issue
Block a user