API Routes
All routes are in src/app/api/*, run in Node (runtime = "nodejs"), and disable caching (Cache-Control: no-store).
Products
GET /api/products- Loads products from S3 CSV via
loadProductsFromS3. - Returns
{ products, source }. sourceincludes{ bucket, key, exists, lastModified }.
- Loads products from S3 CSV via
POST /api/products/upload- Accepts multipart CSV file (
file) or raw CSV request body. - Parses and normalizes CSV before writing to S3.
- Returns
{ products, source }on success.
- Accepts multipart CSV file (
GET /api/products/download- Returns
text/csvas downloadable response. - Falls back to generated CSV from defaults if source object is missing.
- Returns
Rulesets
GET /api/rulesets- No query params: list all rulesets with latest snapshot.
- Query
id(+ optionalversion, defaultlatest): fetch specific ruleset/version. - Single ruleset response shape is
{ meta, version }.
POST /api/rulesets- Expects body
{ id, steps, tierPolicy }. idis validated as[a-z0-9-]{2,64}.stepsare strictly validated against the live widget catalog.tierPolicyis strictly validated.- Uses
saveRulesetInS3, which auto-createsv0001for new IDs or publishes the next version for existing IDs. - Returns
{ meta, version }.
- Expects body
DELETE /api/rulesets?id=<rulesetId>- Deletes every S3 object under
<prefix>/<rulesetId>/. - Returns
{ deleted: true }on success.
- Deletes every S3 object under
Assignments
GET /api/rule-assignments- Loads product-to-ruleset mapping from
<prefix>/assignments/products.json. - Returns
{ assignments, source }wheresourceincludes bucket/key/exists/lastModified metadata. - If the S3 object is absent, returns
assignments: {}withsource.exists: false.
- Loads product-to-ruleset mapping from
PUT /api/rule-assignments- Expects body
{ assignments }where each SKU entry is{ rulesetId, version }. - Validates assignment payload shape (
rulesetIdmust match[a-z0-9-]{2,64},versionrequired/non-empty). - Rejects unknown
rulesetIdvalues by checking current rulesets list. - Persists mapping JSON and returns
{ assignments, source }.
- Expects body
Widgets
GET /api/widgets- Loads widget catalog from S3 (with default seeding behavior).
Removed Route
POST /api/rulesets/publishhas been removed. Create and publish now sharePOST /api/rulesets.