feat: Wired source_videos and body_sections_format into technique detai…
- "backend/routers/techniques.py" GSD-Task: S03/T02
This commit is contained in:
parent
bd0dbb4df9
commit
dc18d0a543
4 changed files with 112 additions and 2 deletions
|
|
@ -45,7 +45,7 @@ This is the data layer foundation — migration file, model changes, and schema
|
|||
- Estimate: 30m
|
||||
- Files: alembic/versions/012_multi_source_format.py, backend/models.py, backend/schemas.py
|
||||
- Verify: cd backend && python -c "from models import TechniquePageVideo, TechniquePage; assert hasattr(TechniquePage, 'body_sections_format'); print('models OK')" && python -c "from schemas import SourceVideoSummary, TechniquePageDetail; print('schemas OK')"
|
||||
- [ ] **T02: Wire source_videos into technique detail endpoint** — Update the technique detail endpoint to eagerly load source_video_links and build the source_videos list on the response. Verify end-to-end with an API call.
|
||||
- [x] **T02: Wired source_videos and body_sections_format into technique detail API response with eager-loaded association table** — Update the technique detail endpoint to eagerly load source_video_links and build the source_videos list on the response. Verify end-to-end with an API call.
|
||||
|
||||
## Steps
|
||||
|
||||
|
|
|
|||
16
.gsd/milestones/M014/slices/S03/tasks/T01-VERIFY.json
Normal file
16
.gsd/milestones/M014/slices/S03/tasks/T01-VERIFY.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"taskId": "T01",
|
||||
"unitId": "M014/S03/T01",
|
||||
"timestamp": 1775178991056,
|
||||
"passed": true,
|
||||
"discoverySource": "task-plan",
|
||||
"checks": [
|
||||
{
|
||||
"command": "cd backend",
|
||||
"exitCode": 0,
|
||||
"durationMs": 5,
|
||||
"verdict": "pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
77
.gsd/milestones/M014/slices/S03/tasks/T02-SUMMARY.md
Normal file
77
.gsd/milestones/M014/slices/S03/tasks/T02-SUMMARY.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
---
|
||||
id: T02
|
||||
parent: S03
|
||||
milestone: M014
|
||||
provides: []
|
||||
requires: []
|
||||
affects: []
|
||||
key_files: ["backend/routers/techniques.py"]
|
||||
key_decisions: []
|
||||
patterns_established: []
|
||||
drill_down_paths: []
|
||||
observability_surfaces: []
|
||||
duration: ""
|
||||
verification_result: "Alembic migration 012 ran clean. API response for existing technique shows body_sections_format: "v1" and source_videos: []. Tested via both Docker internal curl and external ub01:8096 URL."
|
||||
completed_at: 2026-04-03T01:19:28.974Z
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T02: Wired source_videos and body_sections_format into technique detail API response with eager-loaded association table
|
||||
|
||||
> Wired source_videos and body_sections_format into technique detail API response with eager-loaded association table
|
||||
|
||||
## What Happened
|
||||
---
|
||||
id: T02
|
||||
parent: S03
|
||||
milestone: M014
|
||||
key_files:
|
||||
- backend/routers/techniques.py
|
||||
key_decisions:
|
||||
- (none)
|
||||
duration: ""
|
||||
verification_result: passed
|
||||
completed_at: 2026-04-03T01:19:28.974Z
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T02: Wired source_videos and body_sections_format into technique detail API response with eager-loaded association table
|
||||
|
||||
**Wired source_videos and body_sections_format into technique detail API response with eager-loaded association table**
|
||||
|
||||
## What Happened
|
||||
|
||||
Updated get_technique() in backend/routers/techniques.py to eagerly load source_video_links relationship chained to source_video via selectinload. Built source_videos list from association table rows with content_type enum handling. Added imports for TechniquePageVideo and SourceVideoSummary. Deployed to ub01, ran Alembic migration 012, and verified API response includes both new fields with correct defaults.
|
||||
|
||||
## Verification
|
||||
|
||||
Alembic migration 012 ran clean. API response for existing technique shows body_sections_format: "v1" and source_videos: []. Tested via both Docker internal curl and external ub01:8096 URL.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
| # | Command | Exit Code | Verdict | Duration |
|
||||
|---|---------|-----------|---------|----------|
|
||||
| 1 | `cd backend && python -c "from models import TechniquePageVideo, TechniquePage; assert hasattr(TechniquePage, 'body_sections_format'); print('models OK')"` | 0 | ✅ pass | 500ms |
|
||||
| 2 | `cd backend && python -c "from schemas import SourceVideoSummary, TechniquePageDetail; print('schemas OK')"` | 0 | ✅ pass | 400ms |
|
||||
| 3 | `ssh ub01 'docker exec chrysopedia-api alembic upgrade head'` | 0 | ✅ pass | 2000ms |
|
||||
| 4 | `ssh ub01 'curl -s http://ub01:8096/api/v1/techniques/parallel-stereo-processing-keota | python3 -m json.tool | grep -E body_sections_format|source_videos'` | 0 | ✅ pass | 1000ms |
|
||||
|
||||
|
||||
## Deviations
|
||||
|
||||
None.
|
||||
|
||||
## Known Issues
|
||||
|
||||
None.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `backend/routers/techniques.py`
|
||||
|
||||
|
||||
## Deviations
|
||||
None.
|
||||
|
||||
## Known Issues
|
||||
None.
|
||||
|
|
@ -11,12 +11,13 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from database import get_session
|
||||
from models import Creator, KeyMoment, RelatedTechniqueLink, SourceVideo, TechniquePage, TechniquePageVersion
|
||||
from models import Creator, KeyMoment, RelatedTechniqueLink, SourceVideo, TechniquePage, TechniquePageVersion, TechniquePageVideo
|
||||
from schemas import (
|
||||
CreatorInfo,
|
||||
KeyMomentSummary,
|
||||
PaginatedResponse,
|
||||
RelatedLinkItem,
|
||||
SourceVideoSummary,
|
||||
TechniquePageDetail,
|
||||
TechniquePageRead,
|
||||
TechniquePageVersionDetail,
|
||||
|
|
@ -223,6 +224,9 @@ async def get_technique(
|
|||
selectinload(TechniquePage.incoming_links).selectinload(
|
||||
RelatedTechniqueLink.source_page
|
||||
),
|
||||
selectinload(TechniquePage.source_video_links).selectinload(
|
||||
TechniquePageVideo.source_video
|
||||
),
|
||||
)
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
|
|
@ -295,12 +299,25 @@ async def get_technique(
|
|||
version_count_result = await db.execute(version_count_stmt)
|
||||
version_count = version_count_result.scalar() or 0
|
||||
|
||||
# Build source video list from association table
|
||||
source_videos = [
|
||||
SourceVideoSummary(
|
||||
id=link.source_video.id,
|
||||
filename=link.source_video.filename,
|
||||
content_type=link.source_video.content_type.value if hasattr(link.source_video.content_type, 'value') else str(link.source_video.content_type),
|
||||
added_at=link.added_at,
|
||||
)
|
||||
for link in page.source_video_links
|
||||
if link.source_video is not None
|
||||
]
|
||||
|
||||
return TechniquePageDetail(
|
||||
**base.model_dump(),
|
||||
key_moments=key_moment_items,
|
||||
creator_info=creator_info,
|
||||
related_links=related_links,
|
||||
version_count=version_count,
|
||||
source_videos=source_videos,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue