Files
kite/.planning/milestones/v0.2-phases/08-stack-upgrade-backend-decomposition/08-02-PLAN.md
T
curo1305andClaude Sonnet 4.6 123ae5b29b chore: archive v0.2 phase directories to milestones/v0.2-phases/
Moves phases 08–11 execution artifacts from .planning/phases/ to
.planning/milestones/v0.2-phases/ to keep .planning/phases/ clean
for the next milestone.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 14:34:52 +02:00

10 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, tags, must_haves
phase plan type wave depends_on files_modified autonomous requirements tags must_haves
08-stack-upgrade-backend-decomposition 02 execute 0
backend/api/schemas.py
backend/api/cloud.py
true
CODE-08
shared-schemas
cross-package
prerequisite
wave-0
truths artifacts key_links
backend/api/schemas.py exists and defines CloudConnectionOut with field_validator coerce_id_to_str
backend/api/cloud.py imports CloudConnectionOut from api.schemas (not api.admin)
All cloud endpoints continue to return the same JSON shape as before
CloudConnectionOut definition appears exactly once across the entire backend tree
path provides contains
backend/api/schemas.py Cross-package Pydantic response models (D-10 destination for shared schemas) class CloudConnectionOut
path provides contains
backend/api/cloud.py Cloud endpoint router updated to import from api.schemas from api.schemas import CloudConnectionOut
from to via pattern
backend/api/cloud.py backend/api/schemas.py import statement at module top from api.schemas import CloudConnectionOut
from to via pattern
backend/api/admin.py backend/api/schemas.py import statement to be added in plan 08-04 admin split from api.schemas import CloudConnectionOut
Create the new `backend/api/schemas.py` module and move `CloudConnectionOut` into it. Update `backend/api/cloud.py` to import from the new location. This MUST happen BEFORE plan 08-04 splits `api/admin.py` — otherwise the admin-split plan would break `cloud.py`'s `from api.admin import CloudConnectionOut` import.

Purpose: Eliminate the cross-package coupling between api/cloud.py and api/admin.py (RESEARCH.md §"Pitfall 3"). Establishes the api/schemas.py module that plan 08-04 will continue populating with any models discovered to be shared.

Output: New backend/api/schemas.py with CloudConnectionOut; one updated import in backend/api/cloud.py.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/08-stack-upgrade-backend-decomposition/08-CONTEXT.md @.planning/phases/08-stack-upgrade-backend-decomposition/08-RESEARCH.md @.planning/phases/08-stack-upgrade-backend-decomposition/08-PATTERNS.md @backend/api/admin.py @backend/api/cloud.py

class CloudConnectionOut(BaseModel): id: str provider: str display_name: str status: str connected_at: datetime server_url: Optional[str] = None connection_username: Optional[str] = None model_config = {"from_attributes": True}

@field_validator("id", mode="before")
@classmethod
def coerce_id_to_str(cls, v) -> str:
    return str(v)

from api.admin import CloudConnectionOut

from api.schemas import CloudConnectionOut

Task 1: Create backend/api/schemas.py with CloudConnectionOut backend/api/schemas.py - backend/api/admin.py lines 198-223 (current CloudConnectionOut definition — must be copied verbatim including the field_validator) - backend/api/__init__.py (confirm it exists as a package marker; do not modify) - .planning/phases/08-stack-upgrade-backend-decomposition/08-PATTERNS.md section "backend/api/schemas.py" (exact pattern template) Create `backend/api/schemas.py` as a new file. Add a `from __future__ import annotations` header. Add a module docstring: `"""Cross-package Pydantic response models. Models here are used by 2+ API packages and cannot live in a single package without creating circular imports (D-10, RESEARCH.md Pitfall 3)."""`. Add imports: `from datetime import datetime`, `from typing import Optional`, `from pydantic import BaseModel, field_validator`. Then define `class CloudConnectionOut(BaseModel)` with the exact field set from `backend/api/admin.py` lines ~198-223 (per D-10): `id: str`, `provider: str`, `display_name: str`, `status: str`, `connected_at: datetime`, `server_url: Optional[str] = None`, `connection_username: Optional[str] = None`, `model_config = {"from_attributes": True}`, and the `@field_validator("id", mode="before") coerce_id_to_str` classmethod that returns `str(v)`. Add a class-level docstring noting SEC-08: `credentials_enc` deliberately excluded, moved from `api/admin.py`, used by `api/cloud.py` and `api/admin/`. Do NOT remove the class from `api/admin.py` in this task — task 2 handles the import switch in cloud.py, and plan 08-04 will delete the original definition during the admin split. cd backend && python -c "from api.schemas import CloudConnectionOut; obj = CloudConnectionOut.model_validate({'id': 'abc-123', 'provider': 'google_drive', 'display_name': 'Test', 'status': 'ACTIVE', 'connected_at': '2026-06-07T00:00:00'}); assert obj.id == 'abc-123' and obj.provider == 'google_drive'" - File `backend/api/schemas.py` exists - `grep -c "^class CloudConnectionOut" backend/api/schemas.py` returns 1 - `grep -c "coerce_id_to_str" backend/api/schemas.py` returns 1 - `grep -c "from_attributes" backend/api/schemas.py` returns 1 - `python -c "from api.schemas import CloudConnectionOut"` from inside `backend/` exits 0 with no output - All seven fields (id, provider, display_name, status, connected_at, server_url, connection_username) are present per `grep -c " [a-z_]*: " backend/api/schemas.py` ≥ 7 schemas.py exists, importable, CloudConnectionOut validates a sample dict, original admin.py class is still in place (deletion deferred to plan 08-04). Task 2: Switch backend/api/cloud.py import to api.schemas backend/api/cloud.py - backend/api/cloud.py line 35 (current `from api.admin import CloudConnectionOut`) - backend/api/cloud.py top imports block (confirm no other re-exports from `api.admin` exist) In `backend/api/cloud.py`, replace the single line `from api.admin import CloudConnectionOut` with `from api.schemas import CloudConnectionOut`. Do not change any other imports or any code below. After this edit, run the full test suite to confirm cloud endpoints still respond with the identical JSON shape (existing `tests/test_cloud.py` covers admin response surface; if not, the broader `pytest -v` smoke covers the admin list-cloud-connections endpoint too). cd backend && grep -c "from api.admin import CloudConnectionOut" api/cloud.py; cd backend && grep -c "from api.schemas import CloudConnectionOut" api/cloud.py; cd backend && pytest tests/test_cloud.py -x -v 2>&1 | tail -20 - `grep -c "from api.admin import CloudConnectionOut" backend/api/cloud.py` returns 0 - `grep -c "from api.schemas import CloudConnectionOut" backend/api/cloud.py` returns 1 - `cd backend && pytest tests/test_cloud.py -x` exits 0 - `cd backend && pytest tests/test_admin.py -x -k "cloud"` exits 0 (admin endpoints that serialize CloudConnectionOut continue to work because the original definition in admin.py is still untouched at this point) cloud.py imports CloudConnectionOut from api.schemas; tests for cloud endpoints and any admin endpoints that surface cloud connections continue to pass.

<threat_model>

Trust Boundaries

Boundary Description
api/cloud.py → api/schemas.py Module-load-time import; no runtime data crosses this boundary other than a class reference
Admin list-cloud-connections endpoint → CloudConnectionOut serialization SEC-08 requires credentials_enc to be deliberately excluded from this model

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-08-02-01 Information Disclosure CloudConnectionOut schema mitigate Field list must NOT include credentials_enc; field set is restricted to the 7 fields documented in PATTERNS.md
T-08-02-02 Tampering id coercion mitigate Preserve @field_validator("id", mode="before") coerce_id_to_str so UUID→str conversion behavior is byte-identical to the old definition
T-08-02-03 Denial of Service Duplicate class definitions mitigate Plan 08-04 removes the old definition from api/admin.py during the admin split; until then both definitions coexist but only the schemas.py version is imported by cloud.py
T-08-02-SC Supply Chain No new packages accept This plan installs zero new packages
</threat_model>
- `cd backend && pytest tests/test_cloud.py tests/test_admin.py -x` — zero failures - `grep -rn "from api.admin import CloudConnectionOut" backend/` returns no matches (cloud.py was the only consumer) - `grep -rn "from api.schemas import CloudConnectionOut" backend/` returns exactly one match (cloud.py) - `backend/api/admin.py` still contains the original `class CloudConnectionOut` definition (deletion deferred to plan 08-04)

<success_criteria>

  • backend/api/schemas.py exists with CloudConnectionOut defined correctly
  • backend/api/cloud.py imports from api.schemas
  • Cloud and admin tests continue to pass
  • No other file is modified </success_criteria>
Create `.planning/phases/08-stack-upgrade-backend-decomposition/08-02-SUMMARY.md` when done. Include: confirmation that the original class in admin.py is left untouched, the exact `pytest tests/test_cloud.py tests/test_admin.py -v` summary line, and a note that plan 08-04 owns the deletion of the old admin.py definition.