refactor: architectural cleanup -- God object, data layer, dispatch#567
Merged
refactor: architectural cleanup -- God object, data layer, dispatch#567
Conversation
064e69e to
d562e98
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #567 +/- ##
==========================================
+ Coverage 74.24% 75.21% +0.97%
==========================================
Files 58 60 +2
Lines 17902 17575 -327
==========================================
- Hits 13291 13219 -72
+ Misses 3912 3710 -202
+ Partials 699 646 -53 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- countStr: replace 12 inline count-to-string blocks in tables.go - idColumnSpec: replace 9 identical ID column spec literals - formDataAs[T]: generic type assertion replacing 10 form data casts - fuzzy.go: consolidate fuzzyMatch, sortFuzzyScored, and highlightFuzzyPositions from column_finder.go and chat.go - stream.go: generic waitForStream replacing 4 near-identical channel-wait functions across chat.go and extraction.go - transformCells: shared cell-grid copy loop used by compactMoneyCells and magTransformCells - quoteRowSpec: single builder for quote rows with includeProject / includeVendor flags, replacing 3 copy-pasted functions
- overlayMaxHeight: extract shared overlay height clamping from buildDashboardOverlay and buildNotePreviewOverlay - topLevelEmptyHint: replace 8-case switch with map + TabKind.plural() - computeNaturalWidths: consolidate naturalWidths and naturalWidthsIndirect via a column-index mapper function - replaceAssistantWithError: extract duplicated "remove assistant message, append error, refresh" pattern from 3 chat stream handlers
Cover the patch gaps from the refactoring PR: formDataAs error path, waitForStream open/closed channel, replaceAssistantWithError, overlayMaxHeight clamp, computeNaturalWidths indirect path and short-row guard, and the missing tabIncidents/tabDocuments branches in TestEmptyHintPerTab.
…pers Exercise the formDataAs error path at every call site by passing the wrong formData type. Add direct plural() test covering tabQuotes and tabDocuments (bypassed by emptyHintOverrides). Test waitForExtractProgress, waitForLLMChunk, waitForSQLChunk, and waitForChunk wrappers with both open and closed channels.
Move 13 form-related fields into a formState struct held as a value field (fs) on Model. All references updated from m.fieldName to m.fs.fieldName. No logic changes -- purely structural reorganization to reduce the God object surface area. Part of #568.
Move 9 extraction-related fields into an extractState struct held as a value field (ex) on Model. pull stays on Model since it is shared between chat and extraction. All references updated from m.fieldName to m.ex.fieldName. No logic changes. Part of #568.
…cation
Replace 16 identical func(q *gorm.DB) *gorm.DB { return q.Unscoped() }
closures in Preload calls with a single package-level var. The 2 special
cases with chained .Preload("ProjectType") are left as-is.
Part of #568.
Introduce buildOptions[T] that takes a label+id extractor closure and handles the make/append/withOrdinals boilerplate. projectTypeOptions, maintenanceOptions, projectOptions, and applianceOptions now delegate to it. Part of #568. Made-with: Cursor
Add a createOrUpdate helper that handles the repeated pattern of setting the entity ID from editID on update, or persisting the new ID back to editID on create. 9 submit methods now delegate to it (project, quote, maintenance, appliance, vendor, serviceLog, incident, document, scopedDocument). submitHouseForm is left as-is since it is a singleton with unique logic. Also fixes submitIncidentForm which was missing the editID assignment after create, inconsistent with every other entity. Part of #568. Made-with: Cursor
Introduce listQuery[T], getByID[T], and checkDependencies to eliminate the repeated boilerplate across entity CRUD methods: - listQuery[T]: replaces 14 list methods' var/prepare/unscoped/find/return pattern with a single generic that takes a prepare closure - getByID[T]: replaces 8 get methods' var/preload/first/return pattern - checkDependencies: replaces the repeated count-and-fail loop in 4 delete methods (vendor, project, maintenance, appliance) Create/Update/Restore left as-is -- they're already compact one-liners or have too much entity-specific logic (vendor upsert transactions, document blob omission, polymorphic parent checks). Part of #568. Made-with: Cursor
Replace the 7-block overlay guard chain in Update with a single dispatchOverlay method that determines the active overlay (priority order), absorbs non-key messages, and dispatches key messages to the appropriate handler. As part of this, simplify handleChatKey, handleCalendarKey, and handleInlineInputKey to return tea.Cmd instead of (tea.Model, tea.Cmd) since they always return m. Extract helpOverlayKey from the inline switch that was previously in Update. Part of #568. Made-with: Cursor
cpcloud
added a commit
that referenced
this pull request
Mar 19, 2026
…567) ## Summary - Extract `formState` (13 fields) and `extractState` (9 fields) from the 56-field `Model` God object, reducing it to 34 fields - Add generic `listQuery[T]`, `getByID[T]`, and `checkDependencies` helpers in the data layer, deduplicating 14 list methods, 8 get methods, and 4 delete methods - Add `createOrUpdate` helper to deduplicate 9 submit methods in forms - Add `buildOptions[T]` generic to deduplicate 4 option builder functions - Replace `unscopedPreload` lambda duplication (16 copies) with a plain function - Unify the 7-block overlay guard chain in `Update` into a single `dispatchOverlay` method; simplify 3 handler signatures from `(tea.Model, tea.Cmd)` to `tea.Cmd` - Extract shared helpers from earlier in the branch: `fuzzyMatch`/`sortFuzzyScored`, `waitForStream`, `formDataAs[T]`, `replaceAssistantWithError`, `computeNaturalWidths`, `overlayMaxHeight`, `countStr`, `idColumnSpec`, `quoteRowSpec`, `transformCells` - Add coverage tests for all new helpers Net -248 lines of production code, +339 lines of tests. Closes #568. ## Test plan - [x] `go test -shuffle=on ./...` passes (all packages) - [x] `nix run '.#pre-commit'` clean on every commit - [x] CI checks pass
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.
Summary
formState(13 fields) andextractState(9 fields) from the 56-fieldModelGod object, reducing it to 34 fieldslistQuery[T],getByID[T], andcheckDependencieshelpers in the data layer, deduplicating 14 list methods, 8 get methods, and 4 delete methodscreateOrUpdatehelper to deduplicate 9 submit methods in formsbuildOptions[T]generic to deduplicate 4 option builder functionsunscopedPreloadlambda duplication (16 copies) with a plain functionUpdateinto a singledispatchOverlaymethod; simplify 3 handler signatures from(tea.Model, tea.Cmd)totea.CmdfuzzyMatch/sortFuzzyScored,waitForStream,formDataAs[T],replaceAssistantWithError,computeNaturalWidths,overlayMaxHeight,countStr,idColumnSpec,quoteRowSpec,transformCellsNet -248 lines of production code, +339 lines of tests.
Closes #568.
Test plan
go test -shuffle=on ./...passes (all packages)nix run '.#pre-commit'clean on every commit