89 lines
4.0 KiB
Markdown
89 lines
4.0 KiB
Markdown
# 19 — Plan / role defaults alignment (agent 19/20)
|
|||
|
|
|
||
|
|
**Status:** Implemented end-to-end defaults for public ladder, custom enable-all, Legacy (A1), and staff role ceilings.
|
||
|
|
**Sources:** `03-roles-matrix.md` / `.json`, `docs/plan-permissions/06-defaults-matrix.md`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## PROBLEM
|
||
|
|
|
||
|
|
Public ladder defaults, custom enable-all, and Legacy (A1) limited nav must agree across API resolve, seeds, admin UI profiles, and demo assignment — without treating A1 as custom all-ON.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Effective matrices
|
||
|
|
|
||
|
|
| Profile | Source of truth | Default behavior |
|
||
|
|
|---------|-----------------|------------------|
|
||
|
|
| Free | `freePlanFeatureOff` | AI / API keys / BYOK / campaigns off |
|
||
|
|
| Starter | `starterPlanFeatureOff` | BYOK off |
|
||
|
|
| Growth / Business | all registry ON | empty sparse overrides |
|
||
|
|
| Enterprise | `is_custom=true` ? custom path | all ON |
|
||
|
|
| Custom deals (Merkur, …) | `IsCustomPackage` | all ON (create materializes enable-all) |
|
||
|
|
| **Legacy (A1)** | `legacyFeatureAllowlist` / `03-roles-matrix` | image-nav allow-list only; `processing.monitor` OFF |
|
||
|
|
| Staff `admin` / `developer` | `DefaultStaffRoleAllows` | all feature keys ON; full `/admin` |
|
||
|
|
| Staff `support_staff` | denied set in `staff_role_defaults.go` | support queue + assist; no billing mutation routes |
|
||
|
|
|
||
|
|
Resolve order for plans: **Legacy ? Custom enable-all ? Free/Starter denials ? Growth+**.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## A1 / Local Demo Co
|
||
|
|
|
||
|
|
| Piece | Behavior |
|
||
|
|
|-------|----------|
|
||
|
|
| Plan name patterns | `Legacy`, `A1*`, contains `legacy` / `a1 slovenija` |
|
||
|
|
| Company cohort | `legacy_company_id = 97e1a309-3d23-4aa2-b518-8e8d7afdfec7` or name Local Demo Co / A1 |
|
||
|
|
| Seed | `EnsureLegacyDefaults` upserts plan **Legacy** (Enterprise credit pack, unlimited SKUs, `is_legacy=true`) |
|
||
|
|
| Assignment | A1 cohort companies get Legacy when missing or on non-legacy profile |
|
||
|
|
| Demo | `seed-demo` assigns **Legacy** (not Enterprise) so capabilities match limited nav |
|
||
|
|
| Repair | Full enable-all `plans.features` on legacy-named rows ? `SparseLegacyOverrides` (idempotent) |
|
||
|
|
|
||
|
|
**ASSUMPTION:** Empty `{}` still resolves via `DefaultPlanFeatures` by name; seeder writes sparse false keys so admin UIs show an explicit matrix.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Implementation map
|
||
|
|
|
||
|
|
| Piece | Path |
|
||
|
|
|-------|------|
|
||
|
|
| Legacy detect + allow-list | `apps/api/internal/billing/legacy_plan.go` |
|
||
|
|
| Legacy plan row + A1 assign | `apps/api/internal/billing/legacy_plan_seed.go` (`EnsureLegacyDefaults`) |
|
||
|
|
| Sparse legacy helpers | `apps/api/internal/billing/legacy_plan_features.go` |
|
||
|
|
| Feature seed hook | `EnsureDefaultFeatureSeeds` ? `EnsureLegacyPlanFeatureSeeds`; `EnsureDefaultPlans` ? `EnsureLegacyDefaults` |
|
||
|
|
| Custom vs legacy | `IsCustomPackage` excludes legacy names |
|
||
|
|
| Staff role defaults | `apps/api/internal/auth/staff_role_defaults.go` |
|
||
|
|
| Schema | `apps/api/sql/schema/028_plan_is_legacy.sql` (`plans.is_legacy`) |
|
||
|
|
| Admin UI profiles | `apps/web/src/lib/admin-plan-permissions.ts` (`LEGACY_FEATURE_ALLOWLIST`, profiles) |
|
||
|
|
| Billing display | `isLegacyPlan` in `apps/web/src/lib/billing-display.ts` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Idempotency
|
||
|
|
|
||
|
|
- `EnsureDefaultPlans` / `EnsureLegacyDefaults` / `EnsureLegacyPlanFeatureSeeds` are safe to re-run.
|
||
|
|
- Non-empty **partial** admin feature maps on legacy plans are **not** wiped (only empty or full enable-all).
|
||
|
|
- Global section gates use `ON CONFLICT DO NOTHING`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd apps/api
|
||
|
|
go test ./internal/billing/ ./internal/auth/ -count=1 -run "DefaultPlanFeatures|Legacy|IsCustom|Sparse|StaffRole|Normalize|PlanAllows"
|
||
|
|
```
|
||
|
|
|
||
|
|
Integration (after migrate `028` + `seed-demo`):
|
||
|
|
|
||
|
|
- `TestLocalDemoCoLegacyCredits` — Local Demo Co on Legacy with 1M credits
|
||
|
|
- Capabilities: `processing.monitor` false; `catalog.products` / `feeds.list` true
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Coordination notes
|
||
|
|
|
||
|
|
- Agent 5 owns overlapping legacy seed docs (`05-legacy-seed.md`); this file is the alignment checklist for agent 19/20.
|
||
|
|
- Agent 6 wires `staff_role` schema/middleware; defaults here are the ceiling until that lands (`StaffRoleFromPlatformAdmin` bridges the boolean).
|
||
|
|
- Agent 8 admin profiles should match `LEGACY_FEATURE_ALLOWLIST` ? Go `legacyFeatureAllowlist` (66 ON keys from `03-roles-matrix.json`).
|