Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
81 lines
4.1 KiB
Markdown
81 lines
4.1 KiB
Markdown
# 10 — Backend enforcement + integration (agent 10/10)
|
||
|
||
## Status
|
||
|
||
**Enforcement wired** for the highest-risk mutating surfaces. Focused resolve/default/custom/global tests added. Docs index: [README.md](./README.md).
|
||
|
||
Claim gate: run `verify` / `finish_check` after tests in this session.
|
||
|
||
---
|
||
|
||
## What was enforced
|
||
|
||
| Surface | Keys checked | Where |
|
||
|---------|--------------|--------|
|
||
| Processing `StartJob` | `FeatureKeysForProcessingType` (AI / EPREL / normalize / campaign AI) | `processing/pipeline.go` → `AssertProcessingFeatures` |
|
||
| Campaign AI generate | `capability.campaign_ai`, `marketing.campaigns.generate_ai` | `campaigns/generate_send.go` |
|
||
| Campaign live send | `capability.email_live_send`, `marketing.campaigns.send` | `campaigns/generate_send.go` (non–dry-run) |
|
||
| SEO AI apply | `capability.seo_ai_rewrite`, `marketing.seo.ai_rewrite` | `seo/service.go` |
|
||
| API key create | `settings.api_keys`, `capability.api_access` | `httpapi/apikey_handlers.go` |
|
||
| Email blast send | `capability.email_live_send`, `integrations.email.blast` | `httpapi/email_handlers.go` |
|
||
| Brand AI inject | `capability.brand_ai_apply`, `marketing.brand_ai_apply` | `AIBrandApplyAllowed` |
|
||
|
||
HTTP: `writePlanGate` + `RequireFeature` middleware (`httpapi/plan_gate.go`). Processing / SEO / campaigns / v1 process map `ErrFeatureDisabled` → **402** with `code=plan_gate`, `error=feature_disabled`, optional `feature`.
|
||
|
||
Helpers: `FeatureKeyFromError`, `AssertFeatures`, `FeatureKeysForProcessingType` in `billing/feature_enforcement.go`.
|
||
|
||
---
|
||
|
||
## Tests added
|
||
|
||
`apps/api/internal/billing/feature_enforcement_test.go`:
|
||
|
||
- Free defaults deny AI / API keys
|
||
- Custom / Enterprise enable-all
|
||
- Global section disable-all (marketing off)
|
||
- Custom override false wins
|
||
- Capability resolution Starter vs Growth BYOK
|
||
- Feature key extraction + processing-type map
|
||
|
||
Existing: `features_api_test.go`, `custom_package_features_test.go`, `plan_features_handlers_test.go`.
|
||
|
||
---
|
||
|
||
## Glue confirmed from siblings
|
||
|
||
- Migration `026_plan_features.sql`
|
||
- Routes mounted in `server.go` (capabilities, plan features, feature-gates, enable/disable-all)
|
||
- `EnsureDefaultFeatureSeeds` called from `EnsureDefaultPlans`
|
||
- CreditsOverview /auth/me embed effective features
|
||
- Admin Permissions UI + dashboard gating docs present
|
||
|
||
---
|
||
|
||
## Remaining blockers
|
||
|
||
1. **Migrate required** — writes to `plans.features` / `platform_feature_gates` need `026` applied (`.\scripts\migrate.ps1`). Resolve falls back without column but admin PUT fails closed with a clear error.
|
||
2. **Not every route is AssertFeature'd** — list/read endpoints and many store/feed mutations are still UI-gated only. Extend using `RequireFeature` or `AssertFeature` when a section is product-critical.
|
||
3. **OpenAPI** — session fragment lives in `05-openapi-fragment.yaml`; public `/api/v1/openapi.yaml` intentionally unchanged. Optional: merge fragment into internal docs.
|
||
4. **Numeric marketing limits** (feed source count, export count, storage GB) remain documentation-only — not feature keys with counters.
|
||
5. **Agent 9 UI** — confirm live that nav hides after capabilities load; stub mode in admin UI should clear once APIs return 200.
|
||
6. **EPREL** — `capability.eprel` is ON for Free in the matrix; product docs historically disagreed with code (`CanUseEPREL` always true). Align product copy separately.
|
||
|
||
---
|
||
|
||
## Files touched (agent 10)
|
||
|
||
| File | Intent |
|
||
|------|--------|
|
||
| `billing/feature_enforcement.go` | Assert helpers + processing key map |
|
||
| `billing/feature_enforcement_test.go` | Defaults / custom / global / resolve tests |
|
||
| `billing/service.go` | Brand AI feature check |
|
||
| `processing/pipeline.go` | Assert before meter gate |
|
||
| `campaigns/generate_send.go` | Generate AI + live send |
|
||
| `seo/service.go` | SEO AI apply |
|
||
| `httpapi/plan_gate.go` | 402 writer + `RequireFeature` |
|
||
| `httpapi/processing_handlers.go` / `v1_process_handlers.go` | Feature 402 |
|
||
| `httpapi/seo_handlers.go` / `campaigns_handlers.go` | Feature 402 |
|
||
| `httpapi/apikey_handlers.go` / `email_handlers.go` | Create/send gates |
|
||
| `docs/plan-permissions/README.md` | System index |
|
||
| `docs/plan-permissions/10-enforcement.md` | This note |
|