[t-016] Create attach.py route — POST /v1/ios/chat/{id}/attach (mult #16

Open
opened 2026-07-05 08:31:01 +00:00 by david · 0 comments
Owner

Goal

Implement the multipart file upload endpoint that stages files for chat attachments.

References

Reference

  • DESIGN.md §5 API Contract (attach endpoint)
  • AGENT.md §10 Security Constraints

Implementation Steps

Implementation Steps

1. Create src/routes/attach.py

Create the attach route:

# src/routes/attach.py
from fastapi import APIRouter, Depends, UploadFile
from src.core.auth import authenticate
from src.services.staging import validate_upload, stage_file

def init_routes(app):
    router = APIRouter(prefix="/v1/ios", dependencies=[Depends(authenticate)])

    @router.post("/chat/{session_id}/attach")
    async def attach_file(session_id: str, file: UploadFile):
        file_data = await file.read()
        mime_type = file.content_type or "application/octet-stream"
        if not validate_upload(file_data, mime_type):
            from fastapi import HTTPException
            if len(file_data) > 50 * 1024 * 1024:
                raise HTTPException(status_code=413, detail="file_too_large")
            raise HTTPException(status_code=415, detail="unsupported_file_type")
        result = stage_file(file_data, file.filename or "unknown", mime_type)
        return result

Verification Gate

Verification Gate

Run:

cd /home/david/Projects/keryx-bff && uv run python -c "from src.routes.attach import init_routes; print('attach route module loaded')"
# Expected output: attach route module loaded

And verify the route is registered:

cd /home/david/Projects/keryx-bff && uv run python -c "
from src.server import app
routes = [r for r in app.routes if hasattr(r, 'path') and 'attach' in r.path]
assert len(routes) > 0
print('OK')"
# Expected output: OK

STOP Conditions

STOP Conditions

  • If the route is not registered after init_routes call, stop and fix server.py integration.

Depends on: t-015

## Goal Implement the multipart file upload endpoint that stages files for chat attachments. ## References ## Reference - DESIGN.md §5 API Contract (attach endpoint) - AGENT.md §10 Security Constraints ## Implementation Steps ## Implementation Steps ### 1. Create `src/routes/attach.py` Create the attach route: ```python # src/routes/attach.py from fastapi import APIRouter, Depends, UploadFile from src.core.auth import authenticate from src.services.staging import validate_upload, stage_file def init_routes(app): router = APIRouter(prefix="/v1/ios", dependencies=[Depends(authenticate)]) @router.post("/chat/{session_id}/attach") async def attach_file(session_id: str, file: UploadFile): file_data = await file.read() mime_type = file.content_type or "application/octet-stream" if not validate_upload(file_data, mime_type): from fastapi import HTTPException if len(file_data) > 50 * 1024 * 1024: raise HTTPException(status_code=413, detail="file_too_large") raise HTTPException(status_code=415, detail="unsupported_file_type") result = stage_file(file_data, file.filename or "unknown", mime_type) return result ``` ## Verification Gate ## Verification Gate Run: ```bash cd /home/david/Projects/keryx-bff && uv run python -c "from src.routes.attach import init_routes; print('attach route module loaded')" # Expected output: attach route module loaded ``` And verify the route is registered: ```bash cd /home/david/Projects/keryx-bff && uv run python -c " from src.server import app routes = [r for r in app.routes if hasattr(r, 'path') and 'attach' in r.path] assert len(routes) > 0 print('OK')" # Expected output: OK ``` ## STOP Conditions ## STOP Conditions - If the route is not registered after init_routes call, stop and fix server.py integration. Depends on: t-015
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: david/keryx-bff#16
No description provided.