# VL Metadata Spec 3.1 > Status: canonical metadata schema for VLCode-Lite and DocCenter Path `4` > > Scope: > - Defines the canonical `ProjectMeta` JSON consumed by metadata diff, workflow regeneration, project context, and DocCenter-backed tooling > - Normalizes legacy extractor output into one stable shape > - Aligns Theme metadata with VL 3.7 / THEME 6.6 > - Clarifies that DocCenter / workflow document bindings live in project config as `Doc ID`, not inside `ProjectMeta` ## 1. Purpose `ProjectMeta` is the machine-readable project model for a VL workspace. It exists to support: - deterministic workflow regeneration - project-wide diff and impact analysis - DocCenter-backed prompt context - IDE visualization and debug tooling - stable references across `Apps/`, `Sections/`, `ExtComponents/`, `Services/`, `Database/`, and `Theme/` This spec defines the canonical schema. Legacy field names may still be accepted by importers, but they are not canonical output. ## 2. Canonical Rules ### 2.1 Root schema Canonical root object: ```json { "$schema": "VL-ProjectMeta/3.0", "projectName": "SmartCampus", "projectDescription": "optional", "vlVersion": "3.7", "config": { "deviceTarget": "web", "screenResolution": "1440x900" }, "fileManifest": [], "valueDomains": {}, "apps": [], "sections": [], "components": [], "services": [], "dataSchema": { "tables": [], "relations": [] }, "theme": null, "dependencyGraph": null } ``` ### 2.2 Identifier policy - `apps[*].id` is the canonical app identifier - `sections[*].id` is the canonical section identifier - `components[*].id` is the canonical component identifier - `services[*].domainId` is the canonical service-domain identifier - `services[*].methods[*].id` is the canonical method identifier - `services[*].methods[*].serviceId` is the canonical fully-qualified service identifier, normally `domainId.methodId` - `dataSchema.tables[*].id` is the canonical table identifier - `theme.id` is the canonical theme identifier Legacy aliases such as `appId`, `sectionId`, `componentId`, `tableName`, `serviceDomains`, `servicesUsed`, and `componentRefs` are compatibility inputs only. ### 2.3 File path policy Canonical default file locations: - app: `Apps/.vx` - section: `Sections/.sc` - component: `ExtComponents/.cp` - service: `Services/.vs` - database: `Database/.vdb` or explicit per-table/file-level mapping when available - theme: `Theme/Theme.vth` If `filePath` is omitted during normalization, tooling may synthesize the conventional path above. ### 2.4 Doc binding exclusion `ProjectMeta` must not inline DocCenter binding configuration for core specs or workflow prompts. The following values belong to IDE / project profile configuration, not metadata schema: - `coreDocIds` - `docIdOverrides` - any UI-level `Doc Ref` or viewer URL such as `vl://doc/16` or `/doc-center.html?docId=16` Reason: - `ProjectMeta` models the project itself - doc bindings model external tooling configuration - keeping them separate prevents schema drift when official docs are republished or remapped ## 3. Entity Schemas ### 3.1 App ```json { "id": "AdminApp", "filePath": "Apps/AdminApp.vx", "vlVersion": "3.7", "device": "web", "resolution": "1440x900", "description": "", "globalVars": [], "pages": [ { "id": "Dashboard", "route": "/dashboard", "sections": ["DashboardMain"], "sectionRefs": [ { "sectionId": "DashboardMain", "instanceId": "mainSection", "layoutProps": {} } ], "componentRefs": [], "layout": [] } ], "routeMap": { "/dashboard": "DashboardMain" }, "homeRoute": "/dashboard", "wiring": [], "navSectionInstanceId": null, "navEventName": null } ``` Rules: - `pages[*].id` must be stable inside the app - `pages[*].sections` contains section IDs only - `pages[*].sectionRefs[*].sectionId` must resolve to an existing section - `routeMap` is a convenience index, not a second source of truth ### 3.2 Section ```json { "id": "DashboardMain", "filePath": "Sections/DashboardMain.sc", "vlVersion": "3.7", "previewSize": null, "publicProps": [], "publicEvents": [], "publicMethods": [], "globalVars": [], "derivedVars": [], "consumesServices": [ "CampusService.getOverview", "CampusService.listAlerts" ], "usesComponents": [ "StatCard", "AlertTable" ], "interactiveElements": [], "internalMethods": [], "pipeFuncs": [], "isNavSection": false, "navMenuItems": [], "navItemInstanceId": null, "keyStates": {}, "description": "" } ``` Rules: - `consumesServices` is an array of service ID strings, not nested service objects - `usesComponents` is an array of component ID strings, not component ref objects - `consumesServices[*]` must resolve to an existing `services[*].methods[*].serviceId` - `usesComponents[*]` must resolve to an existing `components[*].id` ### 3.3 Component ```json { "id": "StatCard", "filePath": "ExtComponents/StatCard.cp", "vlVersion": "3.7", "previewSize": null, "publicProps": [], "publicEvents": [], "derivedVars": [], "interactiveElements": [], "internalMethods": [], "pipeFuncs": [], "description": "" } ``` ### 3.4 Service domain ```json { "domainId": "CampusService", "filePath": "Services/CampusService.vs", "vlVersion": "3.7", "envVars": [], "methods": [ { "id": "getOverview", "serviceId": "CampusService.getOverview", "type": null, "params": [], "returns": {}, "expose": null, "sig": null } ], "virtualTables": [ { "id": "OverviewView", "source": "campus_overview", "fields": ["id", "title"], "extraSpecs": {} } ], "transactions": [], "backendComponents": [] } ``` Rules: - `domainId` is canonical; `id`/`name` are compatibility inputs only - `methods[*].id` is canonical; `methods[*].name` is compatibility input only - `methods[*].serviceId` should be emitted even when it can be derived - `virtualTables[*].source` must reference an existing table ID when it points to a physical table ### 3.5 Database schema ```json { "dataSchema": { "tables": [ { "id": "campus_overview", "name": "campus_overview", "filePath": "", "fields": [ { "name": "id", "type": "STRING", "notNull": true, "default": null, "enumRef": null, "sourceField": null } ], "indexes": [], "seedData": null } ], "relations": [ { "id": "overview_to_building", "from": "campus_overview", "to": "building", "cardinality": "N:1" } ] } } ``` Rules: - canonical table key is `id`, not `tableName` - canonical column collection is `fields`; `columns` is compatibility input only - `enumRef` must resolve into `valueDomains.enums[*].name` when used ### 3.6 Theme ```json { "theme": { "id": "Theme", "name": "Theme", "filePath": "Theme/Theme.vth", "vlVersion": "3.7", "rootTag": "Theme-Enterprise-6.6", "meta": { "mode": "light", "version": "6.6.0", "styleSpaceVersion": "1.6", "base_theme": "Platform/Theme-Default-Light@1", "profile": "enterprise" }, "slots": { "intent.primary.intentBg": "#2563EB", "size.md.sizeMinHeight": "40px", "state.focus.stateShadow": "@intent.intentFocusRing" }, "designTokens": [], "componentVariants": [], "bindingRules": [], "overrides": [] } } ``` Rules: - for VL 3.7 / THEME 6.6, the canonical theme model is `# Meta` plus `# Point Slot Values` - `theme.slots` is the canonical compiled metadata view of `.vth` point-slot assignments - `designTokens`, `componentVariants`, `bindingRules`, and `overrides` are compatibility carry-through fields only; new tooling should not require them ## 4. Consistency Constraints Validation must reject or flag at least the following: - section consumes a non-existent service ID - section uses a non-existent component ID - service virtual table points at a non-existent table - app wiring references an instance ID not present in layout refs - field `enumRef` points at a non-existent enum ## 5. Legacy Compatibility Mapping Normalizers may accept the following legacy inputs: | Legacy input | Canonical output | | --- | --- | | `project.name` / `project.projectName` | `projectName` | | `database` | `dataSchema` | | `serviceDomains` | `services` | | `appId` | `apps[*].id` | | `sectionId` | `sections[*].id` | | `componentId` | `components[*].id` | | `servicesUsed` / `services` / `serviceDomains` on section | `consumesServices` | | `componentRefs` / `components` on section | `usesComponents` | | `tableName` / `entityId` | `dataSchema.tables[*].id` | | `columns` | `fields` | | `methods[*].name` | `methods[*].id` | | `theme.pointSlotValues` / `theme.pointSlots` | `theme.slots` | Compatibility input does not change canonical output names. ## 6. Producer Requirements Any producer that claims compliance with Metadata Spec 3.1 must emit: - `$schema: "VL-ProjectMeta/3.0"` - canonical IDs and field names - `sections[*].consumesServices` as string IDs - `sections[*].usesComponents` as string IDs - `services[*].methods[*].id` - `dataSchema.tables[*].id` - `theme.slots` when theme slot data is available ## 7. Consumer Requirements Consumers should: - read canonical fields first - optionally normalize known legacy aliases on import - never write new metadata using legacy key names - treat DocCenter path references and workflow prompts as external configuration, not as metadata schema fields ## 8. Canonical Schema String Use exactly: ```text VL-ProjectMeta/3.0 ```