WZ: Restructure the three apps for code quality - #56
Merged
Merged
Conversation
✅ Deploy Preview for westeroz ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
- run the root oxfmt pass with --disable-nested-config so the admin-portal config no longer pulls that app's files into the root check - reformat the income hero change line by deriving one change object instead of a two-part guard with a comment inside the expression - add lib/guards.ts as the one home for the runtime type guards every API module was declaring locally
- split plays.py (1668 lines) into a plays package: base, ledger, views and never_played, with __init__ re-exporting the public surface so no call site changes - materialise the shared query as a temp table once per request instead of naming a window-function CTE in up to seven statements - share one paged-plays query between user history and title history - generate the quality CASE expressions from QUALITY_RANK so the ladder is written once - move fleet judgement out of api.py into fleet.py, and metric history into series.py, cutting api.py from 748 to 381 lines - read every env var through config, including the two auth reads - drop the docker probe fields the parser documented as never populated, and the unreferenced ProbeFailure type
- move the sign-out-on-401 rule into one query client cache handler, deleting thirteen per-call guards, four load effects and the useAdminAuth hook - split User.tsx from 1033 lines to 134 across MemberDetails, MemberControls, MemberHistory, PendingActionModal and a useMemberActions hook, with the stylesheet split the same way - replace seven pending-action states and six modal blocks with one PendingAction union and one modal - add lib/memberQueries.ts as the one home for the member query keys, options and optimistic cache patching - extract TierMenuButton, Spinner and InviteResultNotice, each of which existed two or three times - make the invite label rule one helper so the member page and the table agree that a member in dunning reads Re-invite - route fetchMember through requestJson via a NotFoundError so it keeps the shared response guards - derive the design reference status and tag lists from the model instead of hardcoding stale counts
- replace the two copies of AsyncSection and the three error helpers with one shared component, and let the fleet charts block be a plain section again - merge ChartTabs into one ViewTabs component with an optional action, so the two tab strips stop duplicating their keyboard handling - add components/Chart: one stylesheet, one tooltip, one legend, one frame and one scale, replacing four tooltips, three stylesheets and three margin constants - split MetricChart from 690 lines to 283 by extracting metricFrame and timeAxis, and drop the while loop from the carry-forward pass - collapse ten fetch-validate-throw blocks into one typed readMonitor reader, and import the shared guards - narrow the history row kind to the union the monitor already sends, so the hand-written re-narrowing goes away - derive the default play range from the range table, and write the url params from a table instead of a mutating closure - share the page-count helper and the pager sandwich across the three paged panels
- replace the 190-line webhook if/elif with a table of one handler per Stripe event type, leaving the idempotency ordering untouched - add config.py so the six env vars and the Wizarr client are read and built once, instead of four modules each doing it with different strictness - add invites.py for the scope-then-mint pipeline the webhook, the admin reissue and the baseline sweep each had their own copy of - move the pure member assembly into roster.py and reuse it in get_member, cutting admin.py from 750 to 523 lines - collect every operator alert subject and body in alerts.py so the copy audit has one file to read - fold the four ensure-column helpers and the three update-or-placeholder blocks in store.py into one of each, and close connections through a context manager - type customer and member rows instead of reading them through get-or-empty chains - share one scripts/py-tool.sh between both Python apps, and declare it as a cache input for lint:py and test - update CLAUDE.md, the reconcile skill, the sales-agent comment and the billing doc to the modules that now own this logic
codebend3r
force-pushed
the
code-quality-restructure
branch
from
September 21, 2026 13:12
cf8c3b5 to
2aec3ff
Compare
codebend3r
added a commit
that referenced
this pull request
Sep 21, 2026
A behaviour-preserving restructure across all three apps, from a full review of `main`. 43 findings, 40 applied, 3 deliberately skipped. **Baseline** - the root format gate was failing on `main`: oxfmt discovered the admin-portal config as a nested root and formatted that app under the root pass, so the documented `apps` ignore was never in effect. The pass now runs with `--disable-nested-config`. **admin-portal** - the sign-out-on-401 rule moved into one query client cache handler, deleting thirteen per-call guards, four load effects and the `useAdminAuth` hook - `User.tsx` went from 1033 lines to 134, split into `MemberDetails`, `MemberControls`, `MemberHistory`, `PendingActionModal` and a `useMemberActions` hook, with its stylesheet split the same way - seven pending-action states and six modal blocks became one `PendingAction` union and one modal - `TierMenuButton`, `Spinner`, `InviteResultNotice`, `AsyncSection`, `ViewTabs` and a shared `Chart` set each replace two to four copies - `MetricChart.tsx` went from 690 lines to 283 by extracting `metricFrame.ts` and `timeAxis.ts` - ten fetch-validate-throw blocks collapsed into one typed `readMonitor` reader, and the runtime guards live in `lib/guards.ts` **stripe-bridge** - the 190-line webhook if/elif became a table of one handler per event type, with the idempotency ordering lifted unchanged - new `config.py`, `invites.py`, `roster.py` and `alerts.py`; `admin.py` went from 750 lines to 523 - `store.py` migrations, placeholder writes and connection closing each happen in one place now **fleet-monitor** - `plays.py` (1668 lines) is now a package of four modules plus a re-exporting `__init__`, so no call site changed - the shared query is materialised once per request instead of being re-evaluated in up to seven statements - fleet judgement moved out of `api.py` into `fleet.py`, cutting it from 748 lines to 381 **Skipped, with reasons** - deleting the unlinked `ResetUser` page: dead by every static signal but reachable by URL, so it wants your sign-off - moving the webhook off the event loop: correct in isolation, but it lets two deliveries of one event race past the idempotency check, so it belongs in its own PR with claim-first idempotency - parallelising in-host Plex reads: the sequencing is a documented load constraint, not an oversight **Verification** - `bun run verify` green with 0/9 cache hits: root oxlint and oxfmt, then lint, SCSS lint, ruff, format check, typecheck and tests for all three projects - 526 admin-portal tests, 338 bridge tests, 432 monitor tests - the CI sanity-check import passes and both webhook routes are still registered
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A behaviour-preserving restructure across all three apps, from a full review of
main. 43 findings, 40 applied, 3 deliberately skipped.Baseline
main: oxfmt discovered the admin-portal config as a nested root and formatted that app under the root pass, so the documentedappsignore was never in effect. The pass now runs with--disable-nested-config.admin-portal
useAdminAuthhookUser.tsxwent from 1033 lines to 134, split intoMemberDetails,MemberControls,MemberHistory,PendingActionModaland auseMemberActionshook, with its stylesheet split the same wayPendingActionunion and one modalTierMenuButton,Spinner,InviteResultNotice,AsyncSection,ViewTabsand a sharedChartset each replace two to four copiesMetricChart.tsxwent from 690 lines to 283 by extractingmetricFrame.tsandtimeAxis.tsreadMonitorreader, and the runtime guards live inlib/guards.tsstripe-bridge
config.py,invites.py,roster.pyandalerts.py;admin.pywent from 750 lines to 523store.pymigrations, placeholder writes and connection closing each happen in one place nowfleet-monitor
plays.py(1668 lines) is now a package of four modules plus a re-exporting__init__, so no call site changedapi.pyintofleet.py, cutting it from 748 lines to 381Skipped, with reasons
ResetUserpage: dead by every static signal but reachable by URL, so it wants your sign-offVerification
bun run verifygreen with 0/9 cache hits: root oxlint and oxfmt, then lint, SCSS lint, ruff, format check, typecheck and tests for all three projects