Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2.8 KiB
2.8 KiB
07 — Custom packages: enable-all / disable-all / global sections (agent 7/10)
Behavior
Custom detection (IsCustomPackage)
Matches existing product semantics — not is_custom alone:
| Case | Result |
|---|---|
plans.is_custom = true (includes seeded Enterprise) |
custom |
Plan name not in public ladder (IsPublicProductPlan = false: A1, Merkur, admin deals, …) |
custom |
Free / Starter / Growth / Business with is_custom=false |
standard |
Public listing still uses IsPublicProductPlan / ListPublicPlans. Feature defaults use IsCustomPackage.
On custom package create (UpsertPlan, id == 0)
- Non-public names force
is_custom = true(client-deal alignment). - If the request omits
features, materialize all registry keys = true (AllRegistryFeatures(true)). - If the request provides
features(even{}), that map is respected (replace semantics).
Updates (id > 0) do not auto-rewrite features when features is omitted.
Per-plan helpers
| Service | HTTP |
|---|---|
EnableAllPlanFeatures(planID) |
POST /api/admin/plans/{planID}/features/enable-all |
DisableAllPlanFeatures(planID) |
POST /api/admin/plans/{planID}/features/disable-all |
Both write the full registry into plans.features (all true / all false).
Global section helpers (all plans)
| Service | HTTP |
|---|---|
EnableSectionForAllPlans(section) / DisableSectionForAllPlans(section) |
wrappers around SetSectionGate |
SetSectionGate(section, enabled) |
PUT /api/admin/feature-gates/sections/{section} body { "enabled": bool } |
Runtime: effective = plan_allows ∩ global_section ∩ global_feature (see 03-permission-contract.md).
Resolve note
Even with empty features {}, PlanAllowsFeature returns true for every key when IsCustomPackage — create-time materialization is for explicit admin UI state / enable-all parity.
Files touched (agent 7)
apps/api/internal/billing/custom_package_features.go—IsCustomPackage,AllRegistryFeatures, section wrappers, create prepapps/api/internal/billing/custom_package_features_test.goapps/api/internal/billing/plan_features.go— resolve/default useIsCustomPackage;DisableAllPlanFeaturesapps/api/internal/billing/service.go—UpsertPlancreate hookapps/api/internal/billing/default_plan_features_seed.go— sparse defaults useIsCustomPackageapps/api/internal/httpapi/plan_features_handlers.go— disable-all handlerapps/api/internal/httpapi/server.go— route mountapps/api/internal/httpapi/plan_features_handlers_test.go— mount coverage
Shared with agents 4/5: EnableAllPlanFeatures, SetSectionGate, migration 026_plan_features.sql, feature catalog.