Files
headquarter/openspec/changes/backend-frontend-refactoring/tasks.md
T
alex 2757ef3b4f docs: add OpenSpec change for backend-frontend refactoring
Recovers and adapts the structural refactoring from overwritten
main merge (b6f89f9) to current dev reality.

Scope:
- Schema extraction into apps/api/src/schemas/
- Docker service split into services/docker/ package
- Instance lifecycle extraction from api/tool_instances.py
- Config profile service extraction from api/config_profiles.py
- Auth dependency refactor (get_current_user)
- Frontend reorganization into features/ dirs + kebab-case naming

Exclusions (already in dev): seeding, defaults, unique constraint,
SSH key mounting, terminal backend, tunnel regex, session auto-numbering.
2026-06-04 09:42:03 +02:00

7.5 KiB

1. Backend Schema Extraction

  • 1.1 Create apps/api/src/schemas/__init__.py with re-exports
  • 1.2 Extract schemas/tool_type.py from api/tool_types.py (ToolTypeCreate, ToolTypeUpdate, validation schemas)
  • 1.3 Extract schemas/tool_instance.py from api/tool_instances.py (CreateInstanceRequest, StartInstanceRequest, SessionItemResponse, SessionListResponse)
  • 1.4 Extract schemas/config_profile.py from api/config_profiles.py (ConfigProfileCreate, ConfigProfileUpdate, ConfigProfileResponse, DefaultProfilesUpdate, ValidateGitUrlRequest, ValidateGitUrlResponse, GitMountItem, MountItem)
  • 1.5 Extract schemas/health.py from api/health.py (DatabaseHealth, DiskHealth, HealthChecks, HealthResponse, DatabaseHealthResponse)
  • 1.6 Extract schemas/user.py from api/users.py (UserProfileResponse, UserProfileUpdate)
  • 1.7 Extract schemas/user_config.py from api/user_config.py (any request/response schemas)
  • 1.8 Extract schemas/project.py from api/projects.py (any request/response schemas)
  • 1.9 Extract schemas/ssh_key.py from api/ssh_keys.py (any request/response schemas)
  • 1.10 Extract schemas/git_repository.py from api/git_repositories.py (any request/response schemas)
  • 1.11 Update all API routers to import schemas from src.schemas.* instead of defining inline
  • 1.12 Verify py_compile and ruff pass on all schema files

2. Docker Service Package Split

  • 2.1 Create apps/api/src/services/docker/__init__.py with re-exports for backward compatibility
  • 2.2 Create apps/api/src/services/docker/compose.py from services/docker.py:
    • render_compose_template, write_compose_file, _modify_compose_file, _ensure_container_name_in_compose, _ensure_web_bind_address, _ensure_backend_network_in_compose, _sanitize_compose_file, sort_volumes_by_specificity
  • 2.3 Create apps/api/src/services/docker/container.py from services/docker.py:
    • get_container_status, get_container_logs, get_container_id, wait_for_container_running, get_container_ip_on_network, is_container_on_network, connect_container_to_network, get_backend_network_name
  • 2.4 Create apps/api/src/services/docker/config_staging.py from services/docker.py:
    • write_env_file, write_config_files, ensure_instance_directory
  • 2.5 Create apps/api/src/services/docker/tunnel.py from services/tunnel.py:
    • extract_tunnel_url (move tunnel URL regex extraction here), start_tunnel, stop_tunnel, check_tunnel_health, recreate_tunnel
  • 2.6 Remove apps/api/src/services/docker.py after verifying all imports updated
  • 2.7 Update services/tunnel.py to delegate URL extraction to docker/tunnel.py or remove if fully subsumed
  • 2.8 Update all consumers (api/tool_instances.py, services/instance_lifecycle.py, etc.) to import from services.docker package
  • 2.9 Verify py_compile and ruff pass

3. Instance Lifecycle Extraction

  • 3.1 Create apps/api/src/services/instance_lifecycle.py:
    • Extract create_new_instance, start_existing_instance, stop_existing_instance, restart_existing_instance, delete_existing_instance from api/tool_instances.py
    • Extract helper functions: _prepare_manifest_instance, _modify_compose_file, _ensure_container_name_in_compose, _ensure_web_bind_address, _ensure_backend_network_in_compose, _sanitize_compose_file, _resolve_git_mounts, _clone_git_repo, etc.
  • 3.2 Thin api/tool_instances.py to ~300 lines:
    • HTTP routing, auth validation, request parsing
    • Delegate to instance_lifecycle.py service functions
  • 3.3 Move sessions_router from api/tool_instances.py to api/users.py or keep as separate api/sessions.py (align with b6f89f9 pattern)
  • 3.4 Verify all instance endpoints (create, start, stop, restart, delete, list, get) still work
  • 3.5 Verify py_compile and ruff pass

4. Config Profile Service Extraction

  • 4.1 Create apps/api/src/services/config_profiles.py:
    • Extract get_owned_profile, check_duplicate_name, profile_to_dict, _validate_default_profiles, get_default_profiles, set_default_profiles, get_default_profile_for_tool_type, get_or_create_user_config, list_includes_for_profile, list_mounts_for_profile from api/config_profiles.py
    • Add cycle detection helpers (_detect_cycle, validate_includes_no_cycle)
  • 4.2 Thin api/config_profiles.py to ~200 lines:
    • HTTP routing, request parsing
    • Delegate to services/config_profiles.py
  • 4.3 Verify all config profile endpoints (CRUD, includes, defaults, preview, validate-git-url) still work
  • 4.4 Verify py_compile and ruff pass

5. Auth Dependency Refactor

  • 5.1 Add get_current_user to apps/api/src/auth/dependencies.py:
    • Decode session cookie, look up user in DB, return User model
    • Raise 401 if missing/invalid session or user not found
  • 5.2 Migrate api/users.py to use get_current_user instead of get_current_user_id + _get_user
  • 5.3 Migrate api/tool_instances.py sessions_router to use get_current_user where appropriate
  • 5.4 Migrate other routers incrementally (dashboard, projects, etc.) where the full user object is needed
  • 5.5 Keep get_current_user_id for endpoints that only need the ID
  • 5.6 Verify py_compile and ruff pass

6. Frontend Reorganization

  • 6.1 Rename API files to kebab-case:
    • tool_types.tstool-types.ts
    • ssh_keys.tsssh-keys.ts
    • git_repositories.tsgit-repositories.ts
    • Update all imports in pages and components
  • 6.2 Rename page files to *Page.tsx:
    • dashboard.tsxDashboardPage.tsx
    • projects.tsxProjectsPage.tsx
    • sessions.tsxSessionsPage.tsx
    • settings.tsxSettingsPage.tsx
    • ssh-keys.tsxSshKeysPage.tsx
    • terminal.tsxTerminalPage.tsx
    • tool-workshop.tsxToolWorkshopPage.tsx
    • config-profiles.tsxConfigProfilesPage.tsx
    • git-repositories.tsxGitRepositoriesPage.tsx
    • repo-workspace.tsxRepoWorkspacePage.tsx
    • workspaces.tsxWorkspacesPage.tsx
    • workspace-detail.tsxWorkspaceDetailPage.tsx
    • profile.tsxProfilePage.tsx
    • project-settings.tsxProjectSettingsPage.tsx
    • git-history.tsxGitHistoryPage.tsx
    • Update router.tsx imports
  • 6.3 Move components into features/ directories:
    • Create components/features/git/ and move git-related components
    • Create components/features/dashboard/ and move dashboard components
    • Create components/features/project/ and move project components
    • Update all imports
  • 6.4 Verify npm run typecheck passes
  • 6.5 Verify npm run build passes

7. Integration and Verification

  • 7.1 Run backend tests: docker exec hq-api pytest
  • 7.2 Run backend typecheck: pyright or equivalent
  • 7.3 Run backend lint: ruff check
  • 7.4 Run frontend typecheck: npm run typecheck
  • 7.5 Run frontend build: npm run build
  • 7.6 Run docker compose up --build and verify API starts
  • 7.7 Verify key user flows manually:
    • Create a tool instance
    • Start/stop an instance
    • Create a config profile
    • Set a default config profile
    • View sessions list
    • Open terminal
  • 7.8 Verify no 404s or import errors in browser console

8. Documentation

  • 8.1 Update AGENTS.md or backend README with new module structure
  • 8.2 Document the get_current_user vs get_current_user_id pattern for future contributors