Skip to content

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 _id under the component sweep's single-flight guard (a sweep_marker on the project_figma_file doc); no surrogate unique key.
  • Reads are scoped by project_id, with organization_id added wherever the caller carries one.

Type Codes

kind:

  • published: a published Figma component; carries a component_key, and _id is built from it.
  • local: a local (unpublished) component; component_key is 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_id is 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 variants entry โ€” 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 _id hands 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_path VALUES 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_key nor component_node_id is 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.