Goal
Add first-class contracts for the Ankhorage nutrition/barcode product database so ankhorage/api-gateway and the upcoming scan app share one canonical DTO model.
This is the contract foundation for a field-scanning workflow where many people scan products in Swiss stores and submit structured nutrition data plus evidence images.
Scope
Create a new nutrition-facing contract surface, for example:
src/nutrition/index.ts
src/nutrition/products.ts
src/nutrition/capture.ts
src/nutrition/review.ts
- optional
src/nutrition/common.ts
Expose it from src/index.ts and package exports as @ankhorage/contracts/nutrition.
Required concepts
Model these as serializable TypeScript types/interfaces only. No runtime dependency unless absolutely necessary.
Product identity
NutritionBarcode
NutritionBarcodeType = ean_8 | ean_13 | upc_a | upc_e | gtin_14 | unknown
NutritionProductId
NutritionProductStatus = draft | pending_review | published | rejected | archived
NutritionDataSource = manual_scan | user_correction | open_food_facts | foodrepo_legacy | retailer_import | admin_import
Product content
NutritionProduct
NutritionProductSummary
NutritionProductDetail
NutritionFactsPer100g
NutritionServing
NutritionIngredientStatement
NutritionAllergenTag
NutritionStoreObservation
NutritionImageEvidence
Minimum nutrients per 100g/ml:
- energyKcal
- energyKj
- proteinG
- carbohydratesG
- sugarsG
- fatG
- saturatedFatG
- fiberG
- saltG
- sodiumG
Keep fields optional where label data may be missing, but make the product barcode, product name, source, status, and timestamps explicit.
Capture workflow
NutritionProductCaptureRequest
NutritionProductCaptureResponse
NutritionProductCaptureDraft
NutritionProductCorrectionRequest
NutritionCaptureSubmission
NutritionCaptureSubmissionStatus = queued | needs_more_data | accepted | rejected | merged
Capture metadata should support:
- scanner/user id when authenticated
- anonymous/device id when not authenticated
- country/store chain/store label
- image evidence references
- raw OCR/manual payload
- client timestamps
- app version/platform
Review workflow
NutritionReviewDecisionRequest
NutritionReviewDecisionResponse
NutritionReviewDecision = accept | reject | merge | request_changes | publish
- reviewer note and audit fields
API DTOs to support
Define request/response shapes for at least:
GET /v1/nutrition/products/by-barcode/{barcode}
POST /v1/nutrition/products/capture
GET /v1/nutrition/review/submissions
POST /v1/nutrition/review/submissions/{submissionId}/decision
Acceptance criteria
- Types are exported from
@ankhorage/contracts/nutrition.
- Root export remains backwards-compatible.
bun run build succeeds.
- Add minimal contract tests for representative objects and literal unions.
- DTO names are stable and app-facing; database row names can remain gateway-local.
- No Swiss retailer-specific hardcoding in contracts except generic store observation fields.
Goal
Add first-class contracts for the Ankhorage nutrition/barcode product database so
ankhorage/api-gatewayand the upcoming scan app share one canonical DTO model.This is the contract foundation for a field-scanning workflow where many people scan products in Swiss stores and submit structured nutrition data plus evidence images.
Scope
Create a new nutrition-facing contract surface, for example:
src/nutrition/index.tssrc/nutrition/products.tssrc/nutrition/capture.tssrc/nutrition/review.tssrc/nutrition/common.tsExpose it from
src/index.tsand package exports as@ankhorage/contracts/nutrition.Required concepts
Model these as serializable TypeScript types/interfaces only. No runtime dependency unless absolutely necessary.
Product identity
NutritionBarcodeNutritionBarcodeType=ean_8 | ean_13 | upc_a | upc_e | gtin_14 | unknownNutritionProductIdNutritionProductStatus=draft | pending_review | published | rejected | archivedNutritionDataSource=manual_scan | user_correction | open_food_facts | foodrepo_legacy | retailer_import | admin_importProduct content
NutritionProductNutritionProductSummaryNutritionProductDetailNutritionFactsPer100gNutritionServingNutritionIngredientStatementNutritionAllergenTagNutritionStoreObservationNutritionImageEvidenceMinimum nutrients per 100g/ml:
Keep fields optional where label data may be missing, but make the product barcode, product name, source, status, and timestamps explicit.
Capture workflow
NutritionProductCaptureRequestNutritionProductCaptureResponseNutritionProductCaptureDraftNutritionProductCorrectionRequestNutritionCaptureSubmissionNutritionCaptureSubmissionStatus=queued | needs_more_data | accepted | rejected | mergedCapture metadata should support:
Review workflow
NutritionReviewDecisionRequestNutritionReviewDecisionResponseNutritionReviewDecision=accept | reject | merge | request_changes | publishAPI DTOs to support
Define request/response shapes for at least:
GET /v1/nutrition/products/by-barcode/{barcode}POST /v1/nutrition/products/captureGET /v1/nutrition/review/submissionsPOST /v1/nutrition/review/submissions/{submissionId}/decisionAcceptance criteria
@ankhorage/contracts/nutrition.bun run buildsucceeds.