chore: merge executor worktree (worktree-agent-ad0b098c151ab9e3f)

This commit is contained in:
curo1305
2026-06-08 16:24:51 +02:00
3 changed files with 146 additions and 1 deletions
@@ -0,0 +1,103 @@
---
phase: 08-stack-upgrade-backend-decomposition
plan: "02"
subsystem: api
tags: [pydantic, schemas, refactor, cross-package, backend]
# Dependency graph
requires:
- phase: none
provides: "Wave 0 prerequisite — no prior plan dependency"
provides:
- "backend/api/schemas.py: new cross-package Pydantic schemas module with CloudConnectionOut"
- "backend/api/cloud.py: no longer imports from api/admin (coupling eliminated)"
affects:
- "08-04-admin-split: plan 08-04 will delete original CloudConnectionOut from admin.py and import from api.schemas"
# Tech tracking
tech-stack:
added: []
patterns:
- "api/schemas.py as top-level home for Pydantic models shared across 2+ API packages (D-10)"
key-files:
created:
- backend/api/schemas.py
modified:
- backend/api/cloud.py
key-decisions:
- "CloudConnectionOut stays duplicated in admin.py until plan 08-04 admin split (intentional transient state)"
- "credentials_enc excluded from CloudConnectionOut field set — SEC-08 whitelist preserved verbatim"
- "coerce_id_to_str field_validator preserved byte-identically to prevent any UUID serialization regression"
patterns-established:
- "backend/api/schemas.py: shared Pydantic models for 2+ packages live here, not in any single package"
requirements-completed: [CODE-08]
# Metrics
duration: 5min
completed: 2026-06-08
---
# Phase 8 Plan 02: Shared Schemas Module Summary
**New `backend/api/schemas.py` cross-package module with `CloudConnectionOut` extracted from `api/admin.py`; `api/cloud.py` import switched from `api.admin` to `api.schemas`, eliminating cross-package coupling (Pitfall 3)**
## Performance
- **Duration:** ~5 min
- **Started:** 2026-06-08
- **Completed:** 2026-06-08
- **Tasks:** 2 / 2
- **Files modified:** 2 (1 created, 1 modified)
## Accomplishments
- Created `backend/api/schemas.py` as the canonical home for Pydantic response models shared across 2+ API packages (D-10)
- `CloudConnectionOut` copied verbatim from `api/admin.py` including SEC-08 docstring, 7-field whitelist, `from_attributes` config, and `coerce_id_to_str` field_validator
- Switched `backend/api/cloud.py` line 35 from `from api.admin import CloudConnectionOut` to `from api.schemas import CloudConnectionOut`
- All 51 cloud and admin tests continue to pass after the import switch
- Original `CloudConnectionOut` definition in `api/admin.py` left untouched — plan 08-04 owns the deletion during the admin split
## Task Commits
Each task was committed atomically:
1. **Task 1: Create backend/api/schemas.py with CloudConnectionOut** - `10e0900` (feat)
2. **Task 2: Switch backend/api/cloud.py import to api.schemas** - `61fa6e2` (refactor)
**Plan metadata:** (SUMMARY committed separately)
## Files Created/Modified
- `backend/api/schemas.py` — New cross-package Pydantic schemas module; contains `CloudConnectionOut` with SEC-08 whitelist, 7 fields, `coerce_id_to_str` validator
- `backend/api/cloud.py` — Single-line import change: `from api.admin``from api.schemas`
## Decisions Made
- Original `CloudConnectionOut` in `api/admin.py` is intentionally left in place until plan 08-04. Both definitions coexist temporarily; only `api/cloud.py` imports from `api/schemas`. This avoids a two-plan cascading dependency and is explicitly documented in T-08-02-03 as accepted transient duplication.
- No changes to any other file — plan scope held exactly.
## Deviations from Plan
None — plan executed exactly as written.
## Issues Encountered
- `tests/test_admin.py` does not exist; the correct file is `tests/test_admin_api.py`. Plan's verify command referenced the wrong filename, but the test run with the correct filename confirmed all 51 tests pass. No code change needed.
## User Setup Required
None — no external service configuration required.
## Next Phase Readiness
- `backend/api/schemas.py` is ready for plan 08-04 (admin split) to import from it and delete the original `CloudConnectionOut` from `api/admin.py`
- No blockers. Verification output: `51 passed, 5 warnings` from `pytest tests/test_cloud.py tests/test_admin_api.py -x -v`
- Final check: `grep -rn "from api.admin import CloudConnectionOut" backend/` returns no matches
---
*Phase: 08-stack-upgrade-backend-decomposition*
*Completed: 2026-06-08*
+1 -1
View File
@@ -32,7 +32,7 @@ from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from api.admin import CloudConnectionOut
from api.schemas import CloudConnectionOut
from config import settings
from db.models import CloudConnection, User
from deps.auth import get_regular_user
+42
View File
@@ -0,0 +1,42 @@
"""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).
"""
from __future__ import annotations
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, field_validator
class CloudConnectionOut(BaseModel):
"""SEC-08: credentials_enc deliberately excluded from this response model.
Any admin or user endpoint returning CloudConnection ORM objects MUST use
this model to prevent accidental exposure of encrypted credentials.
Safe-by-default: whitelist of allowed fields (not blacklist).
Moved from api/admin.py to eliminate cross-package coupling between
api/cloud.py and api/admin.py (D-10, RESEARCH.md Pitfall 3).
Used by api/cloud.py and api/admin/ (after plan 08-04 admin split).
Note: id is declared as str and coerced via validator so UUID ORM values
serialize correctly without json_encoders.
"""
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:
"""Coerce UUID objects to str so the model validates from ORM instances."""
return str(v)