Gate B [09/10]: Draft store stub D-1 — POST /api/v1/slabs (#29)

POST /api/v1/slabs accepts multipart/form-data with:
- data: JSON-encoded SlabCreate payload
- files[]: original image files (1-5 photos)
- meta[]: JSON-encoded photo metadata objects

Returns 201 with status: calibrated and server_rev: 1.

Server stores client-sent numbers only (sqft, bdft, widths) without
server-side recompute. Client is authoritative for deterministic math.

Includes:
- SlabCreateData Pydantic model mirroring OPENAPI.md SlabCreate schema
- PhotoMeta model for photo metadata validation
- SlabRead/PhotoRead response models
- File storage with configurable images directory (temp fallback for tests)
- Duplicate SKU detection (409)
- python-multipart added to requirements.txt

D-1 test coverage (8 tests, all green):
- 201 response on valid multipart upload
- status: calibrated in response
- server_rev: 1 in response
- Full response shape assertion
- Multiple photos handling
- Missing data field returns 400
- Duplicate SKU returns 409
- TestClient lifespan management (FUND-9)

Evidence: pytest tests/ -v → 31 passed, 0 failed
This commit is contained in:
grokbot_ty
2026-09-07 08:08:39 +00:00
parent 82219fe5ad
commit 5019b10584
4 changed files with 955 additions and 0 deletions
+2
View File
@@ -7,6 +7,7 @@ from fastapi import FastAPI
from app.api import health as health_router
from app.api import settings as settings_router
from app.api import slabs as slabs_router
from app.config import Settings
from app.db.engine import close_db_connection, init_db
from app.logging_config import configure_logging
@@ -50,5 +51,6 @@ def create_app(app_settings: Settings | None = None) -> FastAPI:
app.include_router(health_router.router)
app.include_router(settings_router.router)
app.include_router(slabs_router.router)
return app