9.7 KiB
9.7 KiB
Refactor 1 - Domain-First Folder Structure
Purpose
Improve reviewability and long-term maintainability by moving from mostly flat frontend folders to a domain-first structure with clear ownership and lower coupling.
Scope
- Frontend structure in
apps/web - Instruction consistency updates
- Incremental migration with compatibility shims
- No behavior changes intended during structure migration
Source Of Truth And Alignment
Use this precedence order when guidance conflicts:
PROJECT_INSTRUCTIONS.md(repo-level source of truth).github/copilot-instructions.md(architecture and coding rules)docs/03_REFACTOR_1.md(this execution tracker and decisions for Refactor 1)
Current refactor-alignment decisions:
- Canonical entry->bucket mutation mechanism:
EntryMutationContext - Domain-first target layout:
apps/web/features/<domain>/...andapps/web/shared/... - Compatibility re-exports removed on 2026-02-12; new imports must use feature-owned paths
Context Compression Guardrails
- At the start of each new session, read this file and the two source-of-truth docs above.
- Before implementation, re-state active decisions from "Current refactor-alignment decisions".
- Add noteworthy changes to "Notes Log" immediately when discovered.
- Do not introduce a second mechanism for any existing concern without logging a decision here first.
Phase 0 - Architecture Alignment (single mechanism rule)
- Decide one canonical entry->bucket mutation mechanism (
contextORevent) - Remove the non-canonical mechanism and all references
- Verify there is no duplicate refresh trigger path
- Document chosen mechanism in instructions
Phase 1 - Instruction and Governance Updates
- Update
.github/copilot-instructions.md - Update
PROJECT_INSTRUCTIONS.md - Add "single mechanism per concern" rule
- Add file-size/complexity refactor thresholds
- Add dead-path cleanup rule
- Add architecture-consistency checklist to PR expectations
Phase 2 - Folder Structure Scaffolding
- Create
apps/web/features/ - Create
apps/web/shared/ - Define domain folders:
features/entriesfeatures/bucketsfeatures/groupsfeatures/tagsfeatures/auth
- Add minimal README/tree notes in new folders (optional but recommended)
Phase 3 - Incremental Domain Migration
Entries + Buckets first (highest coupling)
- Move entries UI/components into
features/entries/components - Move buckets UI/components into
features/buckets/components - Move domain hooks into
features/<domain>/hooks(or keep centralized with strict naming, pick one and stay consistent) - Add temporary compatibility re-exports from old paths
Remaining domains
- Migrate groups
- Migrate tags
- Migrate auth
Phase 4 - Import and Boundary Cleanup
- Replace legacy imports with new feature paths
- Ensure container vs presentational separation in large panels
- Remove obsolete compatibility re-exports once import migration is complete
- Remove dead files and stale helpers
Phase 5 - Validation and Non-Regression
- Run typecheck
- Run lint
- Run relevant unit tests
- Smoke-test key UI flows:
- Entry create/update/delete
- Bucket usage updates
- Edit modal discard behavior
- Group switch behavior
Phase 6 - Consolidation
- Publish final structure map in docs
- Confirm all checklist items closed
- Capture lessons learned and follow-up actions
Notes Log (append as we discover issues)
-
[YYYY-MM-DD] Observation:
- Context:
- Impact:
- Decision:
- Follow-up:
-
[YYYY-MM-DD] Alignment Snapshot:
- Active mechanism:
- Active folder strategy:
- Remaining migration risk:
-
[2026-02-12] Observation:
- Context: Entry->bucket mutation flow had architectural drift (context + custom event mechanism both present).
- Impact: Higher cognitive load and harder debugging/review for regressions.
- Decision: Standardized on
EntryMutationContext; removedentry-mutation-events. - Follow-up: Keep scanning for duplicate state propagation patterns during domain migration.
-
[2026-02-12] Observation:
- Context: During migration edits, a literal
`r`nsequence was accidentally inserted inentries-panel.tsx. - Impact: Broke readability and could have caused compile/runtime issues.
- Decision: Fixed immediately and added note to keep encoding/text clean during scripted edits.
- Follow-up: Keep post-edit grep checks for suspicious escaped literals.
- Context: During migration edits, a literal
-
[2026-02-12] Observation:
- Context:
npx tsc --noEmitstill fails on pre-existing server/test typing issues unrelated to this refactor slice. - Impact: Full type-green gating cannot yet be used as a migration stop condition.
- Decision: Track failures as known baseline until addressed in separate debt fixes.
- Follow-up: Re-run typecheck after each migration phase and confirm no net-new errors.
- Context:
-
[2026-02-12] Observation:
- Context: Alignment details were spread across multiple docs and easy to miss after context compression.
- Impact: Higher risk of inconsistent implementation choices between sessions.
- Decision: Added explicit source-of-truth precedence and context-compression guardrails in this file.
- Follow-up: Keep the "Current refactor-alignment decisions" block updated whenever a major choice changes.
-
[2026-02-12] Observation:
- Context: Hook migration started with entries and buckets domains.
- Impact: Domain ownership is clearer; old import paths still function via compatibility re-exports.
- Decision: Keep compatibility exports in
apps/web/hooksuntil remaining domains are migrated. - Follow-up: Migrate groups/tags/auth hooks and then remove legacy re-exports.
-
[2026-02-12] Observation:
- Context: Migrated auth/groups/tags hooks into
apps/web/features/*/hooksand converted legacyapps/web/hooks/use-*.tsfiles to compatibility re-exports. - Impact: Domain ownership is now explicit while existing imports remain functional during the transition.
- Decision: Keep compatibility shims until Phase 4 import cleanup is complete.
- Follow-up: Remove compatibility shims in Phase 4 after all legacy component path re-exports are retired.
- Context: Migrated auth/groups/tags hooks into
-
[2026-02-12] Alignment Snapshot:
- Active mechanism:
EntryMutationContext - Active folder strategy: domain-first features (
apps/web/features/<domain>/{components,hooks}) - Remaining migration risk: leftover compatibility imports and large mixed-responsibility panels.
- Active mechanism:
-
[2026-02-12] Observation:
- Context: Replaced the final app-level
@/hooks/use-*import (apps/web/components/recurring-entries-panel.tsx) with a feature hook import. - Impact: Runtime code now reads hooks from feature-owned locations;
apps/web/hooks/use-*.tsare compatibility shims only. - Decision: Keep shims temporarily for migration safety.
- Follow-up: Delete hook shims during Phase 4 once no external references remain.
- Context: Replaced the final app-level
-
[2026-02-12] Observation:
- Context: PowerShell write operations introduced BOM and mojibake artifacts in a few migrated files.
- Impact: Increased review noise and risk of accidental text regressions.
- Decision: Normalized touched files to UTF-8 without BOM and replaced unstable glyphs with ASCII-safe equivalents.
- Follow-up: Prefer no-BOM file writes and run a quick mojibake scan after scripted edits.
-
[2026-02-12] Observation:
- Context: Removed obsolete compatibility re-export files under
apps/web/componentsandapps/web/hooks/use-*.ts. - Impact: Reduced duplicate paths and eliminated stale import targets.
- Decision: Treat
apps/web/features/*as the only valid home for migrated component/hook implementations. - Follow-up: Continue Phase 4 by splitting large panels and removing any remaining dead paths.
- Context: Removed obsolete compatibility re-export files under
-
[2026-02-12] Observation:
- Context:
apps/web/components/recurring-entries-panel.tsxandapps/web/hooks/use-recurring-entries.tshad no references and were removed. - Impact: Fewer dead maintenance paths and clearer active surface area.
- Decision: Keep recurring-entry behavior in server/client domain modules only until a routed UI is reintroduced.
- Follow-up: If recurring UI returns, add it directly under
features/entries/components.
- Context:
-
[2026-02-12] Observation:
- Context: Lint validation is currently blocked because
npm run lintcallsnext lint(invalid for current Next setup) and directeslinthas no config file. - Impact: Lint cannot be used yet as a gating signal in this repo state.
- Decision: Keep lint checklist unchecked and treat as tooling debt.
- Follow-up: Add/restore ESLint config and update lint script before enforcing lint gates.
- Context: Lint validation is currently blocked because
-
[2026-02-12] Observation:
- Context: Split
features/entries/components/entries-panel.tsxby extractingEntriesList,EntriesFilterModal, andEntriesDiscardModal. - Impact: Smaller container panel with clearer behavior vs presentation boundaries and simpler review scope.
- Decision: Keep stateful orchestration in
EntriesPaneland move UI-heavy rendering to dedicated presentational components. - Follow-up: Apply the same split pattern to other oversized panels (notably group settings) in a later pass.
- Context: Split
Known Notes (seed)
- Entry->bucket update mechanism currently shows architectural drift (context and event patterns both present in codebase references).
entries-panel.tsxremains large and should be split during migration for reviewability.- Preserve behavior while moving files; avoid functional changes in structure-only PRs.
Exit Criteria
- Single, documented mutation propagation mechanism in use.
- Domain-first structure in place and imports migrated.
- No stale paths or duplicate mechanisms left.
- Validation checks pass (or known pre-existing failures documented separately).