[P1] Add internal-key catalog endpoint for static builds #3

Closed
opened 2026-07-16 22:44:46 +00:00 by yuris · 1 comment
Owner

Goal

Expose a small, public-safe, read-only catalog endpoint that garage-store calls during its build to generate static product and service pages. The public site must not connect directly to PostgreSQL.

Endpoint

GET /api/public/catalog (or the equivalent existing API route convention).

Authentication

Protect the endpoint with a dedicated internal API key.

  • Garage stores the expected key as a server-only environment secret.
  • garage-store receives the same key as a Vercel build-time secret.
  • The build request sends it through a header such as x-api-key.
  • Never put the key in client-side JavaScript, rendered HTML, logs, or the catalog response.
  • Reject missing or incorrect keys with 401 or 403.
  • Use constant-time comparison where practical and avoid exposing whether the key was almost correct.

Response requirements

  • Published records only.
  • Stable product slug and fields from issue #2: public name, description, images list, publish state as needed, and existing type only if useful.
  • Explicit schemaVersion and generatedAt.
  • No brand, new category, optional fitment/viscosity/part number, buy price, average cost, suppliers, stock movements, customer data, auth data, or private IDs in this first version.
  • Deterministic ordering.
  • Exact stock quantity is not required; the storefront asks users to confirm availability through WhatsApp.

Operations

  • Read-only; no mutation method.
  • Safe error responses without database details.
  • Rate limiting or caching may be added at the existing API boundary if needed.
  • Document local and Vercel build environment variables.

Acceptance criteria

  • A clean garage-store build fetches the endpoint with the internal key and generates static pages.
  • Missing and invalid keys are rejected.
  • Endpoint output contains only the documented public schema.
  • Unpublished records are absent.
  • Contract tests fail if a private field is added to the response or the key is accepted from a client-side path.
  • Existing dashboard authentication and APIs remain unchanged.

Depends on issue #2. This replaces the earlier export-command concept.

PRD: https://git.nokopia.com/yuris/garage/src/branch/main/docs/store-prd.md

## Goal Expose a small, public-safe, read-only catalog endpoint that `garage-store` calls during its build to generate static product and service pages. The public site must not connect directly to PostgreSQL. ## Endpoint `GET /api/public/catalog` (or the equivalent existing API route convention). ## Authentication Protect the endpoint with a dedicated internal API key. - Garage stores the expected key as a server-only environment secret. - `garage-store` receives the same key as a Vercel build-time secret. - The build request sends it through a header such as `x-api-key`. - Never put the key in client-side JavaScript, rendered HTML, logs, or the catalog response. - Reject missing or incorrect keys with `401` or `403`. - Use constant-time comparison where practical and avoid exposing whether the key was almost correct. ## Response requirements - Published records only. - Stable product `slug` and fields from issue #2: public name, description, images list, publish state as needed, and existing `type` only if useful. - Explicit `schemaVersion` and `generatedAt`. - No brand, new category, optional fitment/viscosity/part number, buy price, average cost, suppliers, stock movements, customer data, auth data, or private IDs in this first version. - Deterministic ordering. - Exact stock quantity is not required; the storefront asks users to confirm availability through WhatsApp. ## Operations - Read-only; no mutation method. - Safe error responses without database details. - Rate limiting or caching may be added at the existing API boundary if needed. - Document local and Vercel build environment variables. ## Acceptance criteria - A clean `garage-store` build fetches the endpoint with the internal key and generates static pages. - Missing and invalid keys are rejected. - Endpoint output contains only the documented public schema. - Unpublished records are absent. - Contract tests fail if a private field is added to the response or the key is accepted from a client-side path. - Existing dashboard authentication and APIs remain unchanged. Depends on issue #2. This replaces the earlier export-command concept. PRD: https://git.nokopia.com/yuris/garage/src/branch/main/docs/store-prd.md
yuris changed title from [P1] Generate validated garage-store catalog export to [P1] Add read-only public catalog endpoint for static builds 2026-07-16 22:53:30 +00:00
yuris changed title from [P1] Add read-only public catalog endpoint for static builds to [P1] Add internal-key catalog endpoint for static builds 2026-07-16 22:58:44 +00:00
Author
Owner

Implemented in the local working tree. Added GET /api/public/catalog, protected by server-only CATALOG_API_KEY via x-api-key with SHA-256 digest + constant-time comparison. The query selects only published public fields, orders by slug, and returns schemaVersion, generatedAt, and safe items. Added .env.example and Docker wiring for the shared Garage/garage-store build secret.

Verification: missing and invalid keys returned 401; a valid key returned 200; seeded published/unpublished smoke records returned only the published safe projection; smoke records were removed. pnpm test — 28 passed; pnpm build — passed.

Leaving open until the working-tree changes are committed/pushed.

Implemented in the local working tree. Added `GET /api/public/catalog`, protected by server-only `CATALOG_API_KEY` via `x-api-key` with SHA-256 digest + constant-time comparison. The query selects only published public fields, orders by slug, and returns `schemaVersion`, `generatedAt`, and safe items. Added `.env.example` and Docker wiring for the shared Garage/garage-store build secret. Verification: missing and invalid keys returned 401; a valid key returned 200; seeded published/unpublished smoke records returned only the published safe projection; smoke records were removed. `pnpm test` — 28 passed; `pnpm build` — passed. Leaving open until the working-tree changes are committed/pushed.
yuris closed this issue 2026-07-16 23:16:23 +00:00
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
yuris/garage#3
No description provided.