Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
110 lines
4.0 KiB
Markdown
110 lines
4.0 KiB
Markdown
# 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](free-tier.md), [demo-user.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
|
|
|
|
```sql
|
|
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/register` → `201` → `ProvisionFreePlan`.
|
|
|
|
Observed (`/api/auth/me` → `credits`):
|
|
|
|
- `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:
|
|
|
|
```json
|
|
{
|
|
"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=full` → **202**, job **completed**:
|
|
|
|
- `normalize` / `parse_specs` / `fill_fields` → `done`
|
|
- `eprel` → `skipped` (`entitlement_can_use_eprel`)
|
|
- `ai_enhance` → `skipped` (`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
|
|
|
|
```powershell
|
|
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
|