feat/subscription-gating
needs attentionviewing older commit1fac5ad · incrementalPR #234reviewed 2026-07-07 02:50 UTC0H · 5M · 4L · 2I- Purpose
- Gate the Batu Energy platform to bills + credentials only during soft launch. PR-207 surfaces (Sites, Assets, Tarifas, metrics) ship mounted but stay unreachable until each is ready.
- Goal
- Single SoftLaunchGuard + SSOT (lib/soft-launch.ts) drives both sidebar nav treatment and route-level blocking so they can never drift. Admin bypass (isPlatformAdmin) keeps internal ops working.
- Sub-goals
- SG-1: SSOT + sidebar grey-out (Sites/Tarifas as Pronto, Assets hidden, Bills/Credentials live)
- SG-2: Central SoftLaunchGuard in (dashboard)/layout.tsx; gated → redirect to /bills/contratos
- SG-3: Post-login landing safety — confirmed non-issue
- SG-4: i18n locale config alignment (defaultLocale es + localePrefix always)
- Subscription gating: feature-access decisions + require-active-subscription middleware
- What
- Merge of main into feature branch: SoftLaunchGuard integrated into layout.tsx, 17 new @batu/api exports registered, SNOOZE_REQUIRES_FUTURE_DATE error code added, spec-pointer comments cleaned up, large i18n additions for portfolio + period picker.
- Why
- Keep branch current with main (PR-207 electricity-data-api port) and add remaining export registrations the new domain code requires.
- Areas
- domains/core/src/billing+237−0services/utility/bills/cfe+146−2packages/api+105−3apps/platform/src/components+61−0apps/platform/src/api+74−3apps/platform/src/app+9−2docs/development+209−0
- Blast
- 26 files, +841/−10 across branch. Core: billing decisions + subscription middleware. Platform: layout guard + API exports. No DB migrations, no CDK, no apps/web.
Findings · 10
correctness2
SoftLaunchGuard renders null one frame before redirect — blank flash on hard-nav to gated path
apps/platform/src/components/SoftLaunchGuard.tsx:13
isGated() true → returns null, defers router.replace() to useEffect. On hard-refresh to /sites the dashboard chrome appears with blank main for one commit cycle.
No isPlatformAdmin loading race confirmed
apps/platform/src/app/[locale]/(dashboard)/layout.tsx:91
Layout short-circuits while isLoading; guard only mounts after useAuthUser resolves. isPlatformAdmin is settled.
security1
Client-side gate is acceptable — API enforces auth independently
apps/platform/src/app/[locale]/(dashboard)/layout.tsx
SoftLaunchGuard is a UX reachability gate, not a security boundary. No sensitive data exposed in gated SSR.
conventions4
@batu/metrics-domain devDependency in packages/api inverts canonical type flow
packages/api/package.json
Canonical direction: domains → packages/api → apps. Domain devDep in API layer inverts this. Move AssertEqual check to domain's own type-check.ts.
SNOOZE_REQUIRES_FUTURE_DATE placed under Metrics section with inline sub-comment
packages/api/src/responses/codes.ts:29
Nested '// Triage' sub-comment inside Metrics 400-block fragments the section structure.
i18n drift: 6 dashboard.stats.* keys in en.json missing from es.json
apps/platform/src/messages/en.json
activeRpus, newThisMonth, generationToday, vsYesterday, monthlySavings, vsPreviousMonth absent from es.json.
i18n drift: bills.descargasPage.filters.statusQueued in es.json missing from en.json
apps/platform/src/messages/es.json
'En cola' present in es.json, no counterpart in en.json.
tests2
SoftLaunchGuard component has no behavior test (redirect + null-render)
apps/platform/src/components/SoftLaunchGuard.tsx
Pure-function tests solid; scope.md calls out 'guard unit/behaviour tests pass'. RTL test needed.
DashboardSidebar navState integration untested as a component
apps/platform/src/components/DashboardSidebar.tsx
Scope.md states 'Sidebar test asserts the visible/disabled partition'. navState pure logic tested; component rendering not covered.
improvement1
useEffect dependency should be [gated, router.replace], not [gated, router]
apps/platform/src/components/SoftLaunchGuard.tsx:22
Only router.replace() used inside effect; full router object is an exhaustive-deps lint issue.
History · 7 commits
- c807731needs attentionincremental0H · 6M · 8L2026-07-30 17:24
- 372882bneeds attentionincremental0H · 1M · 2L2026-07-21 17:31
- 1fac5adneeds attentionincremental0H · 5M · 4L2026-07-07 02:50current
- 99bf169safeincremental0H · 0M · 1L2026-07-04 04:01
- 6305b3cneeds attentionincremental0H · 1M · 4L2026-07-04 03:53
- f00e3caneeds attentionincremental0H · 7M · 16L2026-07-04 03:15
- 1ae74bdneeds attentionfull6H · 9M · 8L2026-07-04 02:36