Wireframe Component Collection
Overview
Collection holding the WIREFRAME KIT registry โ the vocabulary a des2wf run draws
from when its mode is kit. It is the design system's design_component in the
same document shape, for a DIFFERENT library: the kit is not a subset of the design
system, so it does not live in the design registry. The shared component sweep
writes it under its wireframe registry target (deterministic Figma REST full-file
walk, upsert on _id, single-flight guarded, no LLM). Des2WF selection reads it at
run time, expanding each document into one row per variant; a primitives run
never reads it.
Table Definition
| Logical Name | Physical Name | Column Name | Data Type | Primary Key | Relation | Unique | Nullable | Default Value | Remarks |
|---|---|---|---|---|---|---|---|---|---|
| Wireframe Component | wireframe_component | _id | string | โฏ | {project_id}_{component_key} โ composite on the componentSet PUBLISH KEY, never a node id. Node ids are per-file-copy: the kit's pages are COPIED into the working file, so the same kit duplicated onto two boards yields different ids for one master, and a kit keyed on node id registers that master twice and matches neither. A master with no publish key falls back to the node composite {project_id}_{figma_file_key}_{node_id} rather than going unregistered. SHARED by every variant of the set โ so it is not what selection votes for |
||||
| organization_id | number | Tenant owner | |||||||
| project_id | number | project:id | Project scope | ||||||
| component_key | string | โฏ | Figma publish key โ the identity _id is built from it. NULLABLE: null for a master whose key has not been read yet, which is why the node-composite fallback exists |
||||||
| component_node_id | string | โฏ | WHERE the master lives โ the node id of the COMPONENT_SET (or standalone COMPONENT). STORED, not derived: the design registry recovers a node id from its composite _id, a kit entry cannot, because it is keyed on the publish key instead. The kit's masters are LOCAL copies, so importComponentByKeyAsync has nothing to import and this is the only way the plugin can instance them |
||||||
| name | string | Display name; explicitly not identity | |||||||
| family | object | โฏ | { name, node_id, node_type } โ the board the entry was swept from, the kit's OWN grouping. Used to collapse interchangeable stand-ins, never matched against a design layer name. node_type separates taxonomy (a SECTION) from mere provenance (a FRAME the component happened to sit in) |
||||||
| kind | string | published / local โ see Type Codes | |||||||
| default_size | object | { w: number, h: number }, e.g. {"w": 375, "h": 56} โ the SET's own size, which is the default variant's. Read directly only for a document that declares no variants; a variant stating no size of its own falls back to it |
|||||||
| text_slots | object[] | Text replacement slots [{ layer_path: string, default_text: string, ambiguous: boolean }] (ambiguity flagged at sweep time) โ the SET's own, which is the default variant's. Read directly only when variants is empty; otherwise the variant's own list is what capacity is measured on |
|||||||
| image_slots | object[] | Image layers the sweep discovers in a component (parallel to text_slots) [{ layer_path: string, ambiguous: boolean }] โ structural placeholders recorded for instancing context; not auto-filled |
|||||||
| text_props | string[] | Non-variant text property names the component exposes | |||||||
| variant_properties | object | The whole set's axes { <property>: [string] }, e.g. {"type": ["default", "logged-in"]}. A variant value the set does not enumerate is never accepted โ Figma refuses it at materialize time |
|||||||
| variant_defaults | object | Axis โ default value, as the component set declares it | |||||||
| variants | object[] | Per-variant profile [{ variant_props, size, text_slots[], nested_components[], layout_shape, appearance[], semantics[] }] โ THE SELECTABLE ROWS. A component set cannot be instanced; one of its variants can, and siblings differ in size, in their text-layer set, and in what they absorb, so a variant is described in its own right rather than by its axis label |
|||||||
| semantics | object | โฏ | { kind, also_kinds[], is_placeholder, function[], appearance[], model_id, prompt_version, tagged_at, facts_hash }. Semantic enrichment is a DESIGN-system pass โ it labels components against a design-UI vocabulary โ and does not apply to the kit target, whose atoms are already named by their own shape; NULL here |
||||||
| lineage | object | Shared lineage block on every doc { source_url, source_hash, processor_version, index_schema_version, processed_at, job_id }. source_hash โก the component-subtree content hash; job_id = the producing sweep run. It identifies WHICH kit, and which version of it, an entry came from โ the kit is designer-chosen and a swap is a re-registration, so stale entries must be tellable from current ones |
Relations
_idโ{project_id}_{component_key}, by value; the componentSet publish key IS the identity (no surrogate).- project_id โ project.id
- No direct relation is enforced inside DocumentDB; relations are logical and validated by application code.
Indexes
- PRIMARY KEY (_id)
- Upsert on
_idunder the component sweep's single-flight guard (asweep_markeron theproject_figma_filedoc); no surrogate unique key. - Reads are scoped by
project_id, withorganization_idadded wherever the caller carries one.
Type Codes
kind:
- published: a published Figma component; carries a
component_key, and_idis built from it. - local: a local (unpublished) component;
component_keyis null and the entry is filed under the node composite instead.
Notes
- ONE sweep serves both libraries. It is parameterised by a registry target carrying the three facts that differ: the collection, the identity rule (
{project_id}_{component_key}for the kit, the node composite for the design system), and whether the semantic enrichment pass applies. Everything between reading a Figma node and writing a document is identical. - IDENTITY IS THE PUBLISH KEY, NOT THE NODE ID. A design component is addressed by where it lives โ a node in a file the project owns. A kit component is addressed by what it IS, because the kit's pages are copied into the working file and node ids are per-file-copy. Keying a kit on node id registers the same master once per copy and matches neither.
component_node_idis therefore stored as its own field rather than split out of_id. - THE SELECTABLE UNIT IS A VARIANT, NOT THE DOCUMENT. A component set cannot be instanced; one of its variants can. Selection expands each document into one row per
variantsentry โ falling back to the top level only for a document that declares none โ and votes for, and resolves by, a key unique to that row. Every variant shares the document's_id, so keying by_idhands the guards an arbitrary sibling of the variant that was shortlisted, and measures the wrong object: the top level states the default variant's slots and size. A live registry for one kit holds 415 documents expanding to 927 variant rows. - SLOT CAPACITY IS THE NUMBER OF DISTINCT
text_slots[].layer_pathVALUES a variant declares. The materializer addresses a slot by path and writes it, so two declarations of one path are ONE destination โ the second write overwrites the first, and that design string is gone. Capacity counts paths, never declarations. - An entry carrying neither
component_keynorcomponent_node_idis unreachable and dropped at load: emitted as an instance it becomes a build-error placeholder on canvas, which is strictly worse than the primitive box the fallback draws. - The kit is a different library from the design system, not a subset of it. Registry READS stay bound to the design accessor, so a read cannot drift onto the kit and quietly make its atoms design candidates.
- Selection reads this collection at RUN time rather than through a precomputed table, so a swapped kit takes effect on the next run: an entry absent from the currently registered kit is simply not among the atoms a run loads. Nothing kit-specific is encoded in code or in a schema default โ a kit swap is expressible entirely as a data change here.
- For how selection, the guards and the kit-mode fallback use these fields, see Des2WF stores.