Skip to content

Super admin panel overview

Source: g2labs-in/billuu-docs@7780d43 · content/admin/overview.md · updated 2026-09-26

What this app is

The repository is g2labs-in/brewlabs-billu-admin, cloned locally as breww-admin and live at superadmin.billuu.com. It moved there on 2026-09-26; the history before that is in anonymousabhi13/breww-admin.

breww-admin is the platform operator console. A SUPER_ADMIN signs in to it and works across every business on the platform. It is the third browser app in the estate, after the POS and the marketing site, and it shares no code with either.

breww-admin/index.html mounts the bundle into #root and loads breww-admin/src/main.jsx, which puts a BrowserRouter around a Redux Provider and renders the route table in breww-admin/src/configs/NavigatedRoutes.jsx.

The app is smaller than the POS and thinner than the docs suggest. 95 files under src/, about 25,000 lines, 45 screens under src/screens/Dashboard/SuperAdmin/, and 30 sidebar entries.

Stack

ConcernChoiceDeclared in
UIReact 19breww-admin/package.json
BuildVite 6breww-admin/package.json
Routingreact-router 7breww-admin/package.json
Client state@reduxjs/toolkit 2.8breww-admin/package.json, breww-admin/src/store/store.js
ComponentsMUI 7 plus Tailwind 3.4breww-admin/package.json
Chartsrecharts 3breww-admin/package.json
HTTPaxios 1.7 in one shared instance, and raw fetch in a second clientbreww-admin/src/configs/axiosInstance.js, breww-admin/src/services/superAdminService.js
Realtimesocket.io-client 4.8breww-admin/package.json, breww-admin/src/hooks/useSocket.js
Testsnonebreww-admin/package.json has no test script

The package name is billu-super-admin, not breww-admin, and there is no test runner, no lint gate in CI, and no lockfile. breww-admin/.npmrc sets package-lock=false, which is why no lockfile is committed.

Build and tooling

ScriptRunsNotes
npm run devviteDev server on port 5174
npm run buildvite buildReads breww-admin/.env.production
npm run previewvite previewServes dist/
npm run linteslint .Config in breww-admin/eslint.config.js
npm run deploy:cfwrangler deployBuilds nothing. Run npm run build first. wrangler is a devDependency, so this works from a clean install

breww-admin/vite.config.js sets the dev server to port 5174 and proxies /api to VITE_BACKEND_URL, defaulting to http://localhost:8000. The proxy is not what production uses: the bundle carries an absolute API host from VITE_API_URL.

Two leftovers sit in the tree. breww-admin/stats.html is a 3.7 MB bundle report committed by hand and read by nothing. breww-admin/public/.htaccess is an Apache-era file that Cloudflare ignores, and Vite copies public/ verbatim, so it ships to the Worker as inert bytes on every deploy.

Routing and screens

Every route is declared in breww-admin/src/configs/NavigatedRoutes.jsx. The public ones are /, /email-login, /signup and /setupPassword/:token. Everything else hangs off /dashboard, which renders breww-admin/src/layouts/Dashboard.jsx and then one screen per route.

The sidebar is breww-admin/src/components/Sidebar.jsx. It lists 31 entries in seven groups, and every one of them is rendered for any signed in user. Every entry pointed at a screen until the Administrators entry was added: AllSubAdmin was routed at /dashboard/sub-admins/all and linked from nowhere, so the only screen that changes who can reach the rest was itself unreachable. There is no per-screen permission check anywhere in the app. The POS in brewlabs-billu-frontend gates every route on menuKey through brewlabs-billu-frontend/src/components/shared/ProtectedRoute.jsx; this panel has no equivalent.

Several route names do not describe the screen behind them. lifecycle renders the same TenantsManagement component as tenants, and four separate /dashboard/partner-master/* paths render PartnerMasterWrapper.

Authentication

Sign in is email and password. loginWithPassword in breww-admin/src/store/slices/authSlice.js posts { identifier, password } to /auth/login, reads the user and the two tokens out of data.user and data.tokens, and refuses any role outside SUPER_ADMIN, PLATFORM_OWNER, PLATFORM_ADMIN, SUPPORT, OPERATIONS, FINANCE and READ_ONLY.

The tokens go to localStorage, not to a cookie. breww-admin/src/configs/axiosInstance.js then sends Authorization: Bearer <token> on every request and stamps x-panel-type: ADMIN.

breww-admin/src/App.jsx checks three things before it trusts a stored session, and all three read localStorage: isAuthenticated, user, and token. It then requires a platform role, rejects any panelType that is present and is not "ADMIN", and only after that calls validateToken, which is GET /super-admin/me in breww-admin/src/store/slices/validateTokenSlice.js. Two things follow. The panelType test is conditional, so a user object without the field passes, and that is what the live API returns: data.user carries only id, email and role, while the panelType: ADMIN claim lives in the JWT instead. And a session that exists only as a cookie is never validated, because the first check fails first.

Both login screens used to hardcode the three email addresses the form would accept, which made the client the gate and locked out every platform admin an operator created. That allowlist is gone from breww-admin/src/screens/Login/Login.jsx and breww-admin/src/screens/Login/EmailLogin.jsx; adminOnlyMiddleware and the panel type on the session decide instead. Nothing else in the app checks a permission, so the backend is now the only gate.

The API layer, and the gap

There are two clients, and screens are split across them.

ClientFileWhat it does
axiosInstancebreww-admin/src/configs/axiosInstance.jsx-panel-type, Bearer token, one refresh retry on 401, toasts
SuperAdminServicebreww-admin/src/services/superAdminService.jsRaw fetch with its own header builder. No x-panel-type, no credentials, no refresh, no toast

breww-admin/src/configs/apiEndpoints.js declares 199 endpoint constants under /api/super-admin, plus 7 under /api/auth. SuperAdminService exposes 260 async methods that call them.

The backend implements a fraction of it. brewlabs-billu-backend/src/routes/superAdminRoute.js is the whole /api/super-admin surface. It held eight routes before any of this work; it now holds twenty-one, and every one of them is implemented.

GroupRoutesController
TenantsGET /tenants, /tenants/pending, /tenants/search, /tenants/:tenantId, /tenants/:tenantId/orders, PATCH /tenants/:tenantId/statussuperAdminController.js
Platform sessionGET /mesuperAdminController.js
MetricsGET /metricssuperAdminController.js
PlansGET /plans, POST /plans, PATCH /plans/:planId, DELETE /plans/:planIdsubscriptionAdminController.js
SubscriptionsGET /subscriptions, GET /subscriptions/expiring, PUT /subscriptions/:businessId, PATCH /subscriptions/:businessId/statussubscriptionAdminController.js
Platform adminsGET /platform-admins, POST /platform-admins, POST /platform-admins/:adminId/revoke-sessions, DELETE /platform-admins/:adminIdplatformAdminController.js
Organization permissionsPATCH /organizations/:id/permissionspermissionControlController.js

The larger /api/admin surface in brewlabs-billu-backend/src/routes/adminRoute.js has 40 routes, and 31 of them call superAdminController.notImplemented, which answers 501.

So the gap is still most of the console. The panel declares 199 endpoints and 17 exist, so the 45 screens mostly point at nothing. The subscriptions slice is the first one wired end to end; the rest is a console written against an API that was specified and never built.

The failure used to be quiet in one place and loud in the other, and both were wrong. breww-admin/src/configs/axiosInstance.js swallows 404 with no toast, so a screen wired to an endpoint that does not exist rendered as empty rather than as an error. breww-admin/src/services/superAdminService.js threw, so the same situation raised a red toast and a console error. Either way a screen with no data and a screen with no endpoint looked the same.

Both clients now feed one registry in breww-admin/src/services/endpointAvailability.js, and breww-admin/src/components/NotBuiltNotice.jsx renders above the router outlet naming the endpoints the current page asked for and the backend does not have. A missing route answers an empty list rather than throwing, so the screen shows its own empty state, and the notice explains why that state is empty. A write still throws, because reporting success for a mutation that never happened would be worse than the noise.

Measured by walking all 31 routes in a browser against production, before and after: 26 of 31 screens asked for at least one route the backend does not have, console errors fell from 10 screens to 0, and the notice now appears on exactly the 25 that need it and is absent on the 6 that work. Of those 26 failures, one was a real defect rather than an absent feature.

The subscriptions slice

The first part of the console wired end to end, because it is the job an operator does most often: see who is on what, move a tenant between plans, and change whether it can use the software.

brewlabs-billu-backend/src/controllers/subscriptionAdminController.js holds the handlers. Plans are plain control-plane rows. Subscriptions are not, for three reasons worth writing down.

One row per business. UnifiedTenantMiddleware.getSubscriptionDetails reads a single subscription per business with findOne. A second row for the same business would be invisible to that read, so the table can hold one and the API upserts on the business id rather than inserting.

The status set is load-bearing. brewlabs-billu-backend/src/core/tenant/unifiedTenantMiddleware.js admits a tenant only when the status is in ['active', 'trial'] and current_period_end is null or in the future. That filter is the difference between a tenant that can trade and one that cannot, and it lives in a different file from the controller. The API therefore defines the vocabulary in one place, ['trial', 'active', 'past_due', 'paused', 'cancelled', 'expired'], and validates every write against it.

A status column alone misleads. An active subscription whose period ended reads as active and is locked out. GET /subscriptions therefore returns a derived isGranting alongside the raw status, and the panel shows it as an Access column. That is the operator’s actual question, and it is the one thing the table cannot answer by itself.

Eight lifecycle endpoints were declared for this: activate, renew, cancel, pause, resume, assign, upgrade, downgrade. The table has status, plan_id, billing_cycle and two period dates, so every one of those is a status write or a plan write. They collapse to PUT /subscriptions/:businessId and PATCH /subscriptions/:businessId/status, with six statuses. The other six constants are deleted from breww-admin/src/configs/apiEndpoints.js rather than left pointing at nothing.

The subscriptions table also carries a stamp per lifecycle state, paused_at, resume_at, cancelled_at, cancellation_reason, cancel_at_period_end, trial_start and trial_end. brewlabs-billu-backend/src/control_plane_models/subscriptionModel.js declared none of them, and Sequelize drops attributes it does not know about, so nothing could write them and nothing could read them. A status flip alone cannot answer “when was this cancelled”, so the model now declares all seven, setSubscriptionStatus stamps the one matching the transition, and the list returns them.

Both writes call UnifiedTenantMiddleware.invalidateSubscription(businessId) after committing, so a status change takes effect on the tenant’s next request. Without it the gate serves a stale subscription until its cache entry expires. That cache is per process, so with more than one replica the other replicas stay stale until their TTL. A shared invalidation needs Redis, which this path does not use.

Errors the operator has to read are answered from the controller rather than passed to next(error). brewlabs-billu-backend/app.js replaces every forwarded message with An unexpected error occurred. Please try again. when not in development, which would turn a duplicate slug or a plan still in use into that sentence. The status code survives either way; only the message needs the detour. DELETE /plans/:planId is refused with 409 while subscriptions point at the plan, because Subscription has no plan cascade and deleting it would leave those rows without a price.

On the panel side, breww-admin/src/screens/Dashboard/SuperAdmin/SubscriptionBillingManagement.jsx lists subscriptions with a plan select and a status select in each row, and breww-admin/src/screens/Dashboard/SuperAdmin/SubscriptionPlans.jsx manages plans. Changing a plan sends the current period back so that moving a tenant does not move its renewal date.

Production’s control plane is Supabase, not the local Postgres, and reading its schema settled two questions the local database could not. plans there has no code column, slug is NOT NULL, and features defaults to '[]', so the array-of-keys shape is the intended one and the dialog’s { key: true } map was the outlier. subscriptions has the lifecycle columns above.

The local bootstrap disagrees with both. npm run test:admin resets the control plane through brewlabs-billu-backend/src/scripts/init-database.js, which creates plans with code VARCHAR(50) UNIQUE NOT NULL - a column production does not have - and subscriptions without any lifecycle column. Against that schema POST /plans answered 500 with a NOT NULL violation, because the model does not know about a column the bootstrap invented. Adding code to the model would break production, where the column does not exist, so the bootstrap is the thing that needs fixing. brewlabs-billu-backend/src/migrations/legacy/control-plane/001_init_control_plane.sql has a third shape again, name VARCHAR(255) NOT NULL UNIQUE with max_terminals. Three sources, three schemas, one deployed reality.

Three things were deleted rather than stubbed. The Invoices tab had no payments API behind it. The Settings tab was three hardcoded gateway switches that toggled nothing. The six stat cards read platformRevenue, mrr, churnRate and failedPayments, none of which any endpoint returns, so they always showed zero; the cards now derive from the subscription list.

Plan-level permissions remain decorative. The plans screen can enable feature flags and derive permission keys from them, but there is no table for a plan-to-permission mapping and no endpoint to read one, so enabledPermissions is sent and silently ignored. That needs a product decision and a schema, not a panel change.

Who can sign in

brewlabs-billu-backend/src/controllers/platformAdminController.js manages the rows in super_admin_users, which is the whole of platform access.

Three properties of that table and its guards make platform access binary, and the API is shaped to match rather than to offer controls that do nothing.

authService.js:272 builds the login response as role: isSuperAdmin ? 'SUPER_ADMIN' : rawUser.role. Every row found in super_admin_users therefore signs in as SUPER_ADMIN whatever its role column says. adminOnly in unifiedAuthMiddleware.js admits SUPER_ADMIN, ADMIN and OWNER, but adminDatabaseGuard in brewlabs-billu-backend/src/middlewares/databaseIsolation.js then requires SUPER_ADMIN exactly, so the wider list is unreachable. There is no role to pick, so POST /platform-admins takes no role parameter.

The deployed table has no name and no is_active, so there is no display name to store and no soft disable. DELETE /platform-admins/:adminId is the only way to take access away, and the screen says so rather than showing a status toggle over a column that does not exist.

Revocation was enforced nowhere

This is the finding worth keeping. brewlabs-billu-backend/src/core/middleware/tokenVerification.js contains the only code that compares a token’s tokenVersion against the stored row, and nothing imports it. It is superseded by unifiedAuthMiddleware.js and its exports appear only in two documents under src/docs/. So tokenVersion was read, carried in the JWT, and never checked, which means no session could be revoked and a deleted admin’s token kept working until it expired.

Two things were missing. The comparison, now in UnifiedAuthMiddleware.getValidatedUser, which every authenticated request passes through. And the cache: the resolved user is held in memory for five minutes and in Redis for 24 hours, so a version bump would have been invisible for the rest of the day. UnifiedAuthMiddleware.invalidateUserCache clears both and is called by both the revoke and the remove paths. Without it, removing an admin left their cached row serving requests.

The comparison is scoped to panelType === 'ADMIN' deliberately. Production’s users table holds four rows with a non-zero token_version, and enforcing this on the tenant chain would sign those four out the moment it ships. super_admin_users has none. Extending it to TENANT is a one-word change once someone has looked at those four.

There is no last-admin guard, and that is a decision rather than an omission. Every caller is itself a row in this table, and the self-check stops them removing their own, so the count cannot reach zero through this route.

The ghost-session consequence is worth knowing about. Because the resolved user is cached for 24 hours, a row deleted outside this API, by SQL or by a database reset, keeps its holder signed in until the cache entry expires. The API’s own delete path avoids it by invalidating; anything else does not.

Deployment

The panel is a static bundle, so it deploys the same way as the POS: a Cloudflare Worker with a static assets binding and no script. Four files carry it.

FileRole
breww-admin/wrangler.jsoncWorker billuu-admin, assets from ./dist, not_found_handling: single-page-application
breww-admin/public/_headersone rule, /assets/* immutable for a year. Other paths revalidate because that is the platform default for static assets, not because this file says so
breww-admin/.github/workflows/deploy.ymlbuild and deploy, on a push to the panel branch or by hand
breww-admin/package.jsonthe deploy:cf script

This mirrors the POS hosting in brewlabs-billu-frontend/wrangler.jsonc, brewlabs-billu-frontend/public/_headers and brewlabs-billu-frontend/.github/workflows/deploy.yml. Both Workers use compatibility date 2026-09-18.

The panel is set up to replace Vercel and Netlify, and that cutover has not been executed. Nothing is deployed, the Worker does not exist yet, and brewwlabs-admin.vercel.app still serves the February build described below. Both old configs are gone from the branch: the Vercel rewrites only duplicated the SPA fallback the Worker does with not_found_handling, and the Netlify build block repeated the variables that breww-admin/.env.production already carries. Dropping them means a Vercel preview of this branch no longer rewrites deep links to index.html, which is the intent.

.env.production points the bundle at https://testing.billuu.com/api, the API hostname the infrastructure repo records in /home/codejack/code/linode/CONTEXT.md. The hostname that was there before, brewwlabs.3dpnow.com, is a Linode-era name, and Cloudflare answers it with a block page.

The panel is behind a Cloudflare Access gate

superadmin.billuu.com requires an email one-time code before anything loads. It is a self-hosted Access application of type Public DNS on that hostname, with a single allow policy naming four addresses, and the team domain is long-term-2714.cloudflareaccess.com.

Public DNS rather than the Workers destination type, even though the panel runs on a Worker: the panel is reached through a custom domain on the zone, not a *.workers.dev address, so matching on the hostname is both correct today and independent of how the Worker is deployed.

Verified from outside and unauthenticated: /, a deep link such as /dashboard/billing, /assets/*.js and /favicon.svg all return 302 to the Access login, and none of their bodies contains a reference to the panel bundle. That last detail is the check worth keeping, because an Access application that failed to attach to the hostname returns the panel and looks entirely correct in the dashboard.

The application was created from the dashboard, not the API: the token in ~/.config/billuu/infra.env can read Access but not write it, and its app listing returns zero apps even while the gate is live, so policy contents are not readable from there.

The Worker’s hostname is not a free choice

refreshTokens in brewlabs-billu-backend/src/auth/auth.controller.js reads the refresh token from req.cookies?.refreshToken and from nowhere else. The login response sets both cookies HttpOnly; Secure; SameSite=Strict. SameSite is a site rule, not an origin rule, so a panel on superadmin.billuu.com sends those cookies to testing.billuu.com and a panel on a *.workers.dev name does not. On a workers.dev origin the access token dies after 24 hours with no way back, and POST /auth/refresh answers 401 Refresh token missing.

The host also has to be in the allowlist in brewlabs-billu-backend/src/config/corsConfig.js. That list already carries https://superadmin.billuu.com, and it carries https://brewwlabs-admin.vercel.app but no workers.dev name. superadmin.billuu.com satisfies both constraints with no backend change, which makes it the host to pick.

The workflow needs the CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID repository secrets. Neither is set, and no run of breww-admin/.github/workflows/deploy.yml has executed, so the job is written but unproven.

Where the panel is today

Three separate things are true at once, and untangling them is most of the work.

The repo holds three unrelated histories. The panel branch themeing-and-Updated-code-2026-07-01 has 16 commits and its root is 5569626. main has a different root, 6f1d240. Neither is an ancestor of the other, so git merge-base main themeing-and-Updated-code-2026-07-01 finds nothing to merge.

The live URL serves none of them. The bundle at brewwlabs-admin.vercel.app on 2026-09-24 carries the route table of breww-admin/src/configs/NavigatedRoutes.jsx at commit 4611679, which is the first commit of testing-phase-with-auth-21-feb-2026. It has /dashboard/echo, /dashboard/inbox, /dashboard/teams and /dashboard/cafes; the panel branch and main have neither. Vercel also lists production deployments from main, the last on 2026-05-29, so the domain and the deployments disagree.

The live API refuses every token, and the cause was in the container logs. POST https://testing.billuu.com/api/auth/login returns 200 and a JWT whose claims include "panelType":"ADMIN". Every authenticated call then returns 401. Two handlers make the response body uninformative: brewlabs-billu-backend/src/middlewares/authErrorHandler.js rewrites the message to Authentication required for any error carrying status 401, and the default handler in brewlabs-billu-backend/app.js rewrites everything else to An unexpected error occurred. Please try again. So a rejected token, a malformed token and a failed user lookup all read the same, and no probe from outside can tell them apart. An earlier version of this page read the byte-identical responses as proof that the token never reached verification. That inference was wrong.

The logs answer it. docker service logs billuu-backend-poxd1a on billuu-app shows:

User not found: 15f4e2c1-7fc9-4e40-b1f3-0596e4af042f
UnauthorizedError: User not found
at UnifiedAuthMiddleware.getValidatedUser (src/core/auth/unifiedAuthMiddleware.js:215:13)

The token verified and then the user lookup failed. authService.login searches users and falls back to super_admin_users, so the token it issues can name a row that exists only in the second table. Verification read users alone. A platform admin therefore lost the session on the request after signing in, always.

That was the first of three independent faults in the same API, and the other two are worse. req.readWithTenant and req.executeWithTenant are installed only by setupTenantContext on the tenant chain, while /api/super-admin is mounted with publicChain, so every one of the eight handlers threw req.readWithTenant is not a function. And TenantRegistry had no business association, so the includes failed as well. The routes had never run.

CheckCommandObserved 2026-09-24
Logincurl -s -X POST -H 'Content-Type: application/json' -d '{"identifier":"admin@brewwlabs.com","password":"Admin@123456"}' https://testing.billuu.com/api/auth/login200. data.user is {id, email, role: SUPER_ADMIN} with no panelType; the JWT payload carries panelType: ADMIN
Session readcurl -s -H "Authorization: Bearer <that token>" https://testing.billuu.com/api/auth/me401 Authentication required
A route that answers with data if authentication workscurl -s -H "Authorization: Bearer <that token>" -H 'x-panel-type: ADMIN' https://testing.billuu.com/api/admin/dashboard401 An unexpected error occurred. Please try again.
The causessh codejack@20.235.64.99 'sudo docker service logs --tail 200 billuu-backend-poxd1a'User not found: <the id from the token>
The panel’s own pathsign in against the Worker-served buildPOST /api/auth/login 200, GET /api/auth/me 401, GET /api/super-admin/lifecycle/stats 401

All three faults are fixed, merged to main as 3857ce0 and deployed to production on 2026-09-25. Every route that answered 401 now answers 200 with real rows: seven tenants, five plans, three subscriptions, one platform admin. A sign-in now lands on the dashboard and stays there instead of bouncing back after two seconds.

The faults were fixed on fix/admin-api-auth-and-tenant-routes, verified against a local backend on the Docker Postgres and Redis with a super admin seeded into super_admin_users only, then merged through g2labs-in/brewlabs-billu-backend PR #65 and deployed through Dokploy.

Two things that fix did not settle, both left as findings rather than guessed at:

  • GET /api/super-admin/metrics answered 500. Four parties disagreed about system_metrics: the table is metric_value jsonb with no metadata column, the model declared metricValue as NUMERIC plus a separate metadata column, brewlabs-billu-backend/scripts/update_system_metrics.js writes one row per metric name with a string value, and the handler read a single row named global_summary that nothing writes. Resolved in favour of the writer: the model now types metric_value as JSONB, the invented metadata field is gone, and the handler returns the metric map the script produces, with ?name= for one entry.
  • Status case is asymmetric. PATCH accepts suspended and the model setter stores SUSPENDED, so reads come back uppercase. A panel has to expect that.

That behaviour was the live failure until 2026-09-25: sign in returned 200, GET /api/super-admin/me returned 401, /api/auth/refresh returned 401, and the panel returned the operator to the login page within about two seconds.

The bounce is silent, and that part remains. breww-admin/src/configs/axiosInstance.js deliberately does not clear storage or redirect when a refresh fails, and breww-admin/src/App.jsx only clears it when the local checks or the JSON parse fail, so a failed session check leaves nothing on screen to explain itself. It was only visible as a console line. Worth fixing, because an unexplained bounce reads as a broken panel rather than as a rejected session.

A note on /api/auth/me for the panel. It is a tenant-shaped route: protectedAuthChain in brewlabs-billu-backend/src/auth/auth.routes.js runs tenantContextMiddleware after authentication, so a platform admin with no organization gets 403 even once the lookup works. The panel’s original /api/super-admin/me call was reaching for the right thing and the backend was what was missing; GET /api/super-admin/me now exists and the panel asks for it.

Traps

  • Two HTTP clients, and the raw fetch one in breww-admin/src/services/superAdminService.js skips every interceptor. A screen that uses it gets no x-panel-type, no refresh and no error toast, so its failures are invisible.
  • breww-admin/src/hooks/useSocket.js opens a socket on import.meta.env.VITE_API_URL, which ends in /api. Socket.IO is mounted on the HTTP server root in brewlabs-billu-backend/src/infrastructure/websocket/socketService.js, so this connects to the wrong path.
  • breww-admin/src/App.jsx gates on localStorage before it validates anything, so a signed out tab that still holds a stale token key looks signed in until /auth/me answers.
  • There is no lockfile and no test suite, so a deploy cannot be reproduced from a commit and nothing catches a regression.
  • breww-admin/src/configs/apiEndpoints.js is the specification for an API that does not exist. Reading it as documentation is the fastest way to conclude the backend is broken when the backend simply never had those routes.
  • The deployed API contradicts itself about its own routes. An unknown path returns a hand written availableRoutes list from brewlabs-billu-backend/app.js that names /api/auth/*, /api/admin/* and five others but omits /api/super-admin/*, even though that group is mounted by brewlabs-billu-backend/src/architecture/databaseMiddlewareChain.js. Do not use that list to decide what the API serves.
  • The panel’s host decides whether sessions can be renewed, because the refresh token only travels as a SameSite=Strict cookie. See the deployment section.
  • brewlabs-billu-backend/src/core/middleware/tokenVerification.js is dead code that looks live. It contains the only tokenVersion comparison in the repository and nothing imports it, so reading it as the enforcement point is the fastest way to believe revocation works when it does not.
  • The resolved user is cached for 24 hours in Redis. Any row deleted outside the API keeps working until that entry expires.

Sources

  • breww-admin/package.json
  • breww-admin/vite.config.js
  • breww-admin/index.html
  • breww-admin/.npmrc
  • breww-admin/.env.production
  • breww-admin/wrangler.jsonc
  • breww-admin/public/_headers
  • breww-admin/.github/workflows/deploy.yml
  • breww-admin/src/main.jsx
  • breww-admin/src/App.jsx
  • breww-admin/src/configs/NavigatedRoutes.jsx
  • breww-admin/src/configs/axiosInstance.js
  • breww-admin/src/configs/apiEndpoints.js
  • breww-admin/src/store/store.js
  • breww-admin/src/store/slices/authSlice.js
  • breww-admin/src/store/slices/validateTokenSlice.js
  • breww-admin/src/services/superAdminService.js
  • breww-admin/src/services/endpointAvailability.js
  • breww-admin/src/components/NotBuiltNotice.jsx
  • breww-admin/src/layouts/Dashboard.jsx
  • breww-admin/src/screens/Dashboard/SuperAdmin/SupportHelpdesk.jsx
  • breww-admin/src/components/Sidebar.jsx
  • breww-admin/src/configs/NavigatedRoutes.jsx
  • breww-admin/src/hooks/useSocket.js
  • breww-admin/src/layouts/Dashboard.jsx
  • breww-admin/src/screens/Login/Login.jsx
  • breww-admin/src/screens/Login/EmailLogin.jsx
  • breww-admin/src/screens/Dashboard/SuperAdmin/SubscriptionBillingManagement.jsx
  • breww-admin/src/screens/Dashboard/SuperAdmin/SubscriptionPlans.jsx
  • breww-admin/src/screens/Dashboard/SuperAdmin/AllSubAdmin.jsx
  • breww-admin/src/screens/Dashboard/SuperAdmin/TenantConsole.jsx
  • breww-admin/stats.html
  • breww-admin/public/.htaccess
  • brewlabs-billu-backend/src/routes/superAdminRoute.js
  • brewlabs-billu-backend/src/routes/adminRoute.js
  • brewlabs-billu-backend/src/controllers/superAdminController.js
  • brewlabs-billu-backend/src/controllers/subscriptionAdminController.js
  • brewlabs-billu-backend/src/controllers/platformAdminController.js
  • brewlabs-billu-backend/src/middlewares/databaseIsolation.js
  • brewlabs-billu-backend/src/services/authService.js
  • brewlabs-billu-backend/src/core/tenant/unifiedTenantMiddleware.js
  • brewlabs-billu-backend/src/control_plane_models/systemMetricsModel.js
  • brewlabs-billu-backend/src/control_plane_models/planModel.js
  • brewlabs-billu-backend/src/control_plane_models/subscriptionModel.js
  • brewlabs-billu-backend/src/architecture/databaseMiddlewareChain.js
  • brewlabs-billu-backend/src/auth/auth.routes.js
  • brewlabs-billu-backend/src/middlewares/authValidation.js
  • brewlabs-billu-backend/src/config/corsConfig.js
  • brewlabs-billu-backend/src/middlewares/authErrorHandler.js
  • brewlabs-billu-backend/src/auth/auth.controller.js
  • brewlabs-billu-backend/src/core/auth/unifiedAuthMiddleware.js
  • brewlabs-billu-backend/src/infrastructure/websocket/socketService.js
  • brewlabs-billu-backend/app.js
  • brewlabs-billu-frontend/src/components/shared/ProtectedRoute.jsx
  • /home/codejack/code/linode/CONTEXT.md
  • brewlabs-billu-frontend/wrangler.jsonc
  • brewlabs-billu-frontend/public/_headers
  • brewlabs-billu-frontend/.github/workflows/deploy.yml
  • billuu-docs/docs.manifest.yaml