Rulesets and Assignments
Storage Layout
src/lib/s3-rulesets.ts stores JSON under configured prefix (RULESETS_S3_PREFIX, default rulesets) in RULESETS_S3_BUCKET (fallback PRODUCTS_S3_BUCKET):
<prefix>/<rulesetId>/meta.json<prefix>/<rulesetId>/latest.json<prefix>/<rulesetId>/versions/vNNNN.json<prefix>/assignments/products.json
Ruleset Behavior
- Ruleset IDs are required on create and strictly validated as
[a-z0-9-]{2,64}. POST /api/rulesetsusessaveRulesetInS3:- if ruleset does not exist, create
v0001 - if ruleset exists, publish next
vNNNNversion
- if ruleset does not exist, create
- Rulesets are listed by scanning
meta.jsonobjects and sorted byupdatedAtdesc. - Each ruleset version document includes:
rulesetIdversioncreatedAtstepstierPolicy
Step Parsing and Validation
parseRuleStepsInput (API write path):
- Requires an array of explicit widget steps:
{ id?, widgetId, config }. - Rejects unknown widget IDs.
- Rejects unsupported config keys for the referenced widget.
- Enforces field type/range constraints using current widget manifest definitions.
parseRuleStepsFromStorage (S3 read path):
- Still requires explicit
widgetIdstep shape. - Uses lenient config normalization:
- known widgets get field-default/type/range normalization
- unknown widgets are preserved with best-effort config pass-through
No legacy { type, op/value } conversion exists in current parser.
Tier Policy Integration
- API input requires
tierPolicyand validates it throughparseTierPolicyInput. - Stored version JSON is parsed through
parseTierPolicyFromStorage(fallback-tolerant read behavior). listRulesetsFromS3andgetRulesetFromS3return versions with resolvedtierPolicy.- Detailed tier model and validation rules are documented in
_docs/tier-pricing-policy.md.
Assignment Behavior
- Assignment payload is an object keyed by SKU with
{ rulesetId, version }. - Input parser strictly validates
rulesetIdas[a-z0-9-]{2,64}and requires a non-emptyversionstring. - API validation ensures assigned ruleset IDs exist before saving.
GET /api/rule-assignmentsreturns{ assignments, source }; if the S3 object is missing it returnsassignments: {}withsource.exists: falseinstead of failing.- UI currently writes
version: "latest"when saving assignments.