Skip to content

feat(nutrition): define barcode product and food capture contracts #69

Description

@artiphishle

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions