Storage
The marketing worker writes to three stores. D1 holds the canonical row per run plus the QA notes. R2 holds the component index and the slide PNGs. Vectorize holds the brief embedding so retrieval finds similar past runs. Each store has a specific job and a specific access pattern; together they make the pipeline self-improving over time.
Overview
- D1 database
carousel-engine- R2 buckets
- carousel-engine-index, carousel-engine-exemplars
- Vectorize index
carousel-briefs(768 dim, cosine)- Schema source
cf-workers/marketing-swarm/carousel-engine/schema.sql- Write paths
- Promote stage (carousels + briefs + exemplars), every run (render_runs), QA stage (slide_qa)
- Read paths
- Retrieve stage (briefs + exemplars), star endpoint (carousels), analytics (all three)
D1 database
Cloudflare D1 is a serverless SQLite that lives at the edge. The marketing worker reads and writes it directly through the DB binding.
D1 fits this pipeline well because reads are infrequent (only retrieval queries) and writes are small (one row per run, plus N rows for slide QA). No background process needs to crawl the database, which means SQLite's write lock never becomes a contention point.
Schema
Three tables. One row per run, one per slide, one per render attempt.
render_runs exists for analytics. It captures every attempt, including failures, so you can plot the failure rate per stage and the latency breakdown across releases. carousels is the public catalogue of promoted runs that the retrieval stage reads.R2 buckets
Two buckets. One for the component index, one for the slide assets.
| Bucket | Holds | Read path | Write path |
|---|---|---|---|
carousel-engine-index | component-index.json with metadata for every registered component | Read by the planner at the start of every run | Written by the index build script after a library change |
carousel-engine-exemplars | Slide PNGs plus spec JSON for promoted runs at <InlineCode>carousels/<id>/<file></InlineCode> | Read by retrieval to hydrate exemplars; signed URL returned in the response | Written by promote |
Vectorize index
A 768-dimensional cosine index keyed by run id, with status as a filter dimension.
The Vectorize index is also used for a smaller secondary corpus: design-system documents the planner pulls in when the brief asks for an on-brand carousel. Those entries are differentiated by the type metadata field so the retrieval step can scope its query.
Storage lifecycle
A run touches the stores in a fixed order.
| Stage | Reads | Writes |
|---|---|---|
| Retrieve | Vectorize (briefs), R2 (exemplars) | - |
| Plan | R2 (component index) | - |
| Validate | - | - |
| Render | R2 (fonts) | - |
| QA | - | - |
| Promote (if score >= 0.85) | - | D1 (carousels), Vectorize (briefs), R2 (exemplars), D1 (slide_qa) |
| Promote (every run) | - | D1 (render_runs) |