- Create types/ directory with centralized domain types: session, tool-instance, tool-type, git-repository, config-folder, tool-config, project, user, api-response - Remove inline type definitions from API modules; re-export from types/ for backward compatibility - Update state/sessions.tsx to import Session from types/session.ts - Update all consumer components/pages to import from types/ - Extract seed_builtin_tool_types from main.py to seeds/builtin_tool_types.py - Create types/index.ts barrel export Quality gates: tsc (pass), eslint (pass), Python syntax (pass)
8.5 KiB
SDD Proposal: Repository Restructuring and Modularization
Overview
The Headquarter codebase has grown organically over ~6 months of active development. What began as a lean full-stack application has accumulated structural debt: monolithic files, mixed concerns, duplicated types, inconsistent naming, and a single 2,844-line stylesheet. This proposal plans a phased refactoring to establish clear module boundaries, enforce a ~200-line-per-file target (hard limit 300), and standardize naming conventions across the entire repo.
Motivation:
- Files over 400 lines are difficult to reason about, test, and review
- Pages mix data fetching, state management, form logic, and UI rendering
- A single stylesheet makes theme changes risky and component isolation impossible
- Backend routers contain business logic that should live in services
- Duplicate types (
Session,ToolInstance) create drift between API and state layers - Naming inconsistencies make file discovery harder for new contributors
Desired outcome: A codebase where every file has a single, obvious responsibility; imports follow predictable patterns; and a new developer can locate any functionality within 30 seconds.
Scope
In Scope
-
Frontend type consolidation
- Move all domain types from
api/*.tsintotypes/with clear domain grouping - Remove duplication between
api/sessions.tsandstate/sessions.tsx - Standardize type naming and export patterns
- Move all domain types from
-
Frontend page decomposition
- Extract inline components (e.g.,
FileBrowserfromrepo-workspace.tsx) - Split "list + form + dialog" pages into container + presentational components
- Extract reusable loading/error/retry UI patterns into shared components
- Extract inline components (e.g.,
-
Frontend style system restructure
- Split
styles.cssinto: tokens, global, layout, components, pages, syntax-highlight - Remove unused CSS classes (verified by grep/build)
- Keep visual output pixel-identical (no design changes)
- Split
-
Frontend component organization
- Group domain-specific components under
components/features/{domain}/ - Keep generic UI primitives at
components/ui/ - Rename page component files to match exported names (e.g.,
git-history.tsx→GitHistoryPage.tsxor rename component)
- Group domain-specific components under
-
Backend router decomposition
- Extract business logic from
tool_instances.py,git_repositories.py,config_profiles.py - Move helper functions (
_get_user,_get_owned_project) to shared dependencies - Split large routers by sub-resource (CRUD vs. operations vs. files)
- Extract business logic from
-
Backend service decomposition
- Split
services/docker.pyinto compose, container, tunnel, config-staging modules - Ensure no service module exceeds 300 lines
- Split
-
Backend seed data extraction
- Move hardcoded seed data from
main.pytoseeds/builtin_tool_types.py
- Move hardcoded seed data from
-
Naming convention standardization
- Frontend React components: PascalCase files matching component name
- Frontend hooks: camelCase (
useTheme.ts) - Frontend utilities/api: kebab-case
- Backend modules: snake_case
- Document conventions in
docs/development/naming.md
Out of Scope (Non-Goals)
- No behavior changes — All user-facing functionality stays identical; this is pure restructuring
- No new features — We are not adding capabilities, only reorganizing existing ones
- No technology swaps — Keeping React 18, Vite, FastAPI, SQLAlchemy, xterm as-is
- No test rewrites — Existing tests should pass after path updates; we are not changing test frameworks or strategies
- No database migrations — Model files stay in place; only code organization changes
- No build system changes — Keep existing vite.config.ts, tsconfig.json, pyproject.toml
- No CI/CD changes — Existing quality gates (typecheck, lint, pytest) must continue to pass
- No documentation overhaul — We will add a naming conventions doc, but not rewrite all docs
Risks and Mitigations
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Import path breakage | High | Medium | Use IDE/automated refactor for import rewrites; run full typecheck after every phase |
| CSS regression | Medium | High | Split styles incrementally; verify each page visually after each CSS file split; keep original styles.css as backup during migration |
| Lost git history | Medium | Low | Use git mv for file moves; avoid copy-delete patterns |
| Test failures from path changes | High | Low | Update test imports alongside source imports; run test suite after each phase |
| Scope creep | Medium | High | Strict non-goals list; pause between phases; require explicit approval to expand scope |
| Merge conflicts with active development | Medium | High | Coordinate timing; prefer short phases with quick PRs; avoid refactoring files with active feature branches |
| Reviewer fatigue | Medium | Medium | Auto-forecast at 400 lines; split into chained PRs; each PR limited to one concern |
| Accidental behavior change | Low | High | Pure cut-paste with no logic changes; reviewer checks for any non-import diffs |
High-Level Approach
We will execute in 5 phases, each producing an independent, reviewable PR:
Phase 1: Safe Foundations (est. +200/-150 lines, 1 PR)
- Consolidate types: create
types/index.tswith all domain types - Update imports in all consumers
- Extract
FileBrowserfromrepo-workspace.tsx - Move seed data from
main.pytoseeds/ - Extract shared auth dependencies
Phase 2: Style System Restructure (est. +50/-2,700 lines, 1 PR)
- Split
styles.cssinto 6 files understyles/ - Update
main.tsxto import new style entry point - Verify no visual regressions
Phase 3: Backend Router Decomposition (est. +800/-1,500 lines, 2-3 chained PRs)
- PR 3a: Extract shared dependencies and helpers
- PR 3b: Split
tool_instances.py→ router + services - PR 3c: Split
git_repositories.pyandconfig_profiles.py
Phase 4: Frontend Page Decomposition (est. +600/-1,200 lines, 2-3 chained PRs)
- PR 4a: Split
tool-workshop.tsxinto feature components - PR 4b: Split
sessions.tsx,dashboard.tsx,repo-workspace.tsx - PR 4c: Rename page components and files for consistency
Phase 5: Testing & Polish (est. +300/-50 lines, 1 PR)
- Add tests for extracted components
- Document naming conventions
- Final cleanup: remove dead code, unused exports
Total estimated churn: ~2,000 lines added, ~5,700 lines removed (net: files become smaller and more numerous)
Acceptance Criteria
Overall
- No file in
src/exceeds 300 lines (exceptions: auto-generated migration files) tsc --noEmitpasses with zero errorseslintpasses with zero warnings- All existing tests pass (frontend: vitest; backend: pytest)
- No visual regressions in key pages (verified manually or via existing e2e)
- No behavior changes — all user flows work identically
Per Phase
- Phase 1: All types centralized; zero duplicated type definitions; seed data extracted
- Phase 2:
styles.cssdeleted; styles split by concern; no visual regressions - Phase 3: No router exceeds 300 lines; business logic lives in services; no inline Docker/git ops in routers
- Phase 4: No page exceeds 300 lines; inline components extracted; naming consistent
- Phase 5: Naming convention doc exists; extracted components have basic tests
Review Workload Forecast
| Phase | Est. Changed Lines | PR Strategy |
|---|---|---|
| Phase 1 | ~350 | Single PR |
| Phase 2 | ~2,750 | Single PR (mostly CSS reorganization) |
| Phase 3a | ~400 | Single PR |
| Phase 3b | ~800 | Single PR |
| Phase 3c | ~700 | Single PR |
| Phase 4a | ~500 | Single PR |
| Phase 4b | ~600 | Single PR |
| Phase 4c | ~350 | Single PR |
| Phase 5 | ~350 | Single PR |
All PRs are under the 400-line review budget. Phases 2 and 3/4 may require careful review focus due to file move volume, but each PR stays within the limit.
Open Questions
- Should we adopt CSS Modules for component styles, or keep global CSS with BEM-like naming?
- Should backend routers be versioned under
api/v1/now, or keep flatapi/structure? - Should extracted frontend feature components live in
components/features/orfeatures/at root? - Do we want to introduce barrel exports (
index.ts) for each domain module? - Should we run this refactor in a feature branch, or merge each phase to main immediately?
Proposal prepared for SDD review. Next phase: Spec writing with detailed requirements and scenarios.