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>
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 |
|
true |
|
|
|
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.pyclass 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> |
<success_criteria>
backend/api/schemas.pyexists withCloudConnectionOutdefined correctlybackend/api/cloud.pyimports fromapi.schemas- Cloud and admin tests continue to pass
- No other file is modified </success_criteria>