# Silo: Item Database and Part Management System **Version:** 0.2 **Date:** February 2026 **Author:** Kindred Systems LLC --- ## 1. Overview Silo is an item database with configurable part number generation, designed for R&D-oriented workflows. It provides revision tracking, BOM management, file versioning, and physical inventory location management through a REST API and web UI. CAD and workflow integration (FreeCAD workbench, LibreOffice Calc extension) is maintained in separate repositories ([silo-mod](https://git.kindred-systems.com/kindred/silo-mod), [silo-calc](https://git.kindred-systems.com/kindred/silo-calc)). ### 1.1 Core Philosophy Silo treats **part numbering schemas as configuration, not code**. Multiple numbering schemes can coexist, each defined in YAML. The system is schema-agnostic—it doesn't impose a particular part numbering philosophy (intelligent vs. non-intelligent numbers) but instead provides the machinery to implement whatever scheme the organization requires. ### 1.2 Key Principles - **Items are the atomic unit**: Everything is an item (parts, assemblies, drawings, documents) - **Schemas are mutable**: Part numbering schemas can evolve, though migration tooling is out of scope for MVP - **Append-only history**: All parameter changes are recorded; item state is reconstructable at any point in time - **Configuration over convention**: Hierarchies, relationships, and behaviors are YAML-defined --- ## 2. Architecture ### 2.1 Components ``` ┌─────────────────────────────────────────────────────────────┐ │ CAD Clients (silo-mod, silo-calc) │ │ FreeCAD Workbench · LibreOffice Calc Extension │ │ (maintained in separate repositories) │ └─────────────────────────────────────────────────────────────┘ │ REST API ▼ ┌─────────────────────────────────────────────────────────────┐ │ Silo Server (silod) │ │ - REST API (76 endpoints) │ │ - Authentication (local, LDAP, OIDC) │ │ - Schema parsing and validation │ │ - Part number generation engine │ │ - Revision management │ │ - Relationship graph / BOM │ │ - Web UI (htmx) │ └─────────────────────────────────────────────────────────────┘ │ ┌───────────────┴───────────────┐ ▼ ▼ ┌─────────────────────────┐ ┌─────────────────────────────┐ │ PostgreSQL │ │ MinIO │ │ (psql.kindred.internal)│ │ - File storage │ │ - Item metadata │ │ - Versioned objects │ │ - Relationships │ │ - Thumbnails │ │ - Revision history │ │ │ │ - Auth / Sessions │ │ │ │ - Audit log │ │ │ └─────────────────────────┘ └─────────────────────────────┘ ``` ### 2.2 Technology Stack | Component | Technology | Notes | |-----------|------------|-------| | Database | PostgreSQL 16 | Existing instance at psql.kindred.internal | | File Storage | MinIO | S3-compatible, versioning enabled | | CLI & API Server | Go (1.24) | chi/v5 router, pgx/v5 driver, zerolog | | Authentication | Multi-backend | Local (bcrypt), LDAP/FreeIPA, OIDC/Keycloak | | Sessions | PostgreSQL pgxstore | alexedwards/scs, 24h lifetime | | Web UI | Go html/template + htmx | Lightweight, minimal JS | --- ## 3. Data Model ### 3.1 Items An **item** is the fundamental entity. Items have: - A **part number** (generated according to a schema) - A **type** (part, assembly, drawing, document, etc.) - **Properties** (key-value pairs, schema-defined and custom) - **Relationships** to other items - **Revisions** (append-only history) - **Files** (optional, stored in MinIO) - **Location** (optional physical inventory location) ### 3.2 Database Schema (Conceptual) ```sql -- Part numbering schemas (YAML stored as text, parsed at runtime) CREATE TABLE schemas ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT UNIQUE NOT NULL, version INTEGER NOT NULL DEFAULT 1, definition JSONB NOT NULL, -- parsed YAML created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); -- Items (core entity) CREATE TABLE items ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), part_number TEXT UNIQUE NOT NULL, schema_id UUID REFERENCES schemas(id), item_type TEXT NOT NULL, -- 'part', 'assembly', 'drawing', etc. created_at TIMESTAMPTZ DEFAULT now(), current_revision_id UUID -- points to latest revision ); -- Append-only revision history CREATE TABLE revisions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), item_id UUID REFERENCES items(id) NOT NULL, revision_number INTEGER NOT NULL, properties JSONB NOT NULL, -- all properties at this revision file_version TEXT, -- MinIO version ID if applicable created_at TIMESTAMPTZ DEFAULT now(), created_by TEXT, -- user identifier (future: LDAP DN) comment TEXT, UNIQUE(item_id, revision_number) ); -- Item relationships (BOM structure) CREATE TABLE relationships ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), parent_item_id UUID REFERENCES items(id) NOT NULL, child_item_id UUID REFERENCES items(id) NOT NULL, relationship_type TEXT NOT NULL, -- 'component', 'alternate', 'reference' quantity DECIMAL, reference_designator TEXT, -- e.g., "R1", "C3" for electronics metadata JSONB, -- assembly-specific relationship config revision_id UUID REFERENCES revisions(id), -- which revision this applies to created_at TIMESTAMPTZ DEFAULT now() ); -- Location hierarchy (configurable via YAML) CREATE TABLE locations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), path TEXT UNIQUE NOT NULL, -- e.g., "lab/shelf-a/bin-3" name TEXT NOT NULL, parent_id UUID REFERENCES locations(id), location_type TEXT NOT NULL, -- defined in location schema metadata JSONB, created_at TIMESTAMPTZ DEFAULT now() ); -- Item inventory (quantity at location) CREATE TABLE inventory ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), item_id UUID REFERENCES items(id) NOT NULL, location_id UUID REFERENCES locations(id) NOT NULL, quantity DECIMAL NOT NULL DEFAULT 0, updated_at TIMESTAMPTZ DEFAULT now(), UNIQUE(item_id, location_id) ); -- Sequence counters for part number generation CREATE TABLE sequences ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), schema_id UUID REFERENCES schemas(id), scope TEXT NOT NULL, -- scope key (e.g., project code, type code) current_value INTEGER NOT NULL DEFAULT 0, UNIQUE(schema_id, scope) ); ``` --- ## 4. YAML Configuration System ### 4.1 Part Numbering Schema Schemas define how part numbers are generated. Each schema consists of **segments** that are concatenated with a **separator**. ```yaml # /etc/silo/schemas/kindred-rd.yaml schema: name: kindred-rd version: 3 description: "Kindred Systems R&D part numbering" # Separator between segments (default: "-") separator: "-" # Uniqueness enforcement uniqueness: scope: global case_sensitive: false segments: - name: category type: enum description: "Category code (2-3 characters)" required: true values: F01: "Hex Cap Screw" F02: "Socket Head Cap Screw" # ... 70+ categories across: # F01-F18: Fasteners # C01-C17: Fluid Fittings # R01-R44: Motion Components # S01-S17: Structural Materials # E01-E27: Electrical Components # M01-M18: Mechanical Components # T01-T08: Tooling and Fixtures # A01-A07: Assemblies # P01-P05: Purchased/Off-the-Shelf # X01-X08: Custom Fabricated Parts - name: sequence type: serial length: 4 padding: "0" start: 1 description: "Sequential number within category" scope: "{category}" format: "{category}-{sequence}" # Example outputs: # F01-0001 (first hex cap screw) # R27-0001 (first linear rail) # A01-0001 (first assembly) ``` > **Note:** The schema was migrated from a `{project}-{type}-{sequence}` format (v1) to `{category}-{sequence}` (v3). Projects are now managed as many-to-many tags on items rather than embedded in the part number. See `migrations/006_project_tags.sql`. ### 4.2 Segment Types | Type | Description | Options | |------|-------------|---------| | `string` | Fixed or variable length string | `length`, `min_length`, `max_length`, `pattern`, `case` | | `enum` | Predefined set of values | `values` (map of code → description) | | `serial` | Auto-incrementing integer | `length`, `padding`, `start`, `scope` | | `date` | Date-based segment | `format` (strftime-style) | | `constant` | Fixed value | `value` | ### 4.3 Serial Scope Templates The `scope` field in serial segments supports template variables referencing other segments: ```yaml # Sequence per category (current kindred-rd schema) scope: "{category}" # Global sequence (no scope) scope: null ``` ### 4.4 Alternative Schema Example (Simple Sequential) ```yaml # /etc/silo/schemas/simple.yaml schema: name: simple version: 1 description: "Simple non-intelligent numbering" segments: - name: prefix type: constant value: "P" - name: sequence type: serial length: 6 padding: "0" scope: null # global counter format: "{prefix}{sequence}" separator: "" # Output: P000001, P000002, ... ``` ### 4.5 Location Hierarchy Schema ```yaml # /etc/silo/schemas/locations.yaml location_schema: name: kindred-lab version: 1 hierarchy: - level: 0 type: facility name_pattern: "^[a-z-]+$" - level: 1 type: area name_pattern: "^[a-z-]+$" - level: 2 type: shelf name_pattern: "^shelf-[a-z]$" - level: 3 type: bin name_pattern: "^bin-[0-9]+$" # Path format path_separator: "/" # Example paths: # lab/main-area/shelf-a/bin-1 # lab/storage/shelf-b/bin-12 ``` ### 4.6 Assembly Metadata Schema Each assembly can define its own relationship tracking behavior: ```yaml # Stored in item properties or as a linked document assembly_config: # What relationship types this assembly uses relationship_types: - component # standard BOM entry - alternate # interchangeable substitute - reference # related but not part of BOM # Whether to track reference designators use_reference_designators: true designator_format: "^[A-Z]+[0-9]+$" # e.g., R1, C3, U12 # Revision linking behavior child_revision_tracking: specific # or "latest" # Custom properties for relationships relationship_properties: - name: mounting_orientation type: enum values: [top, bottom, left, right, front, back] - name: notes type: text ``` --- ## 5. Client Integration CAD workbench and spreadsheet extension implementations are maintained in separate repositories ([silo-mod](https://git.kindred-systems.com/kindred/silo-mod), [silo-calc](https://git.kindred-systems.com/kindred/silo-calc)). The Silo server provides the REST API endpoints consumed by those clients. ### 5.1 File Storage Strategy Files are stored as whole objects in MinIO with versioning enabled. Storage path convention: `items/{partNumber}/rev{N}.ext`. SHA-256 checksums are captured on upload for integrity verification. Future option: exploded storage (unpack ZIP-based CAD archives for better diffing). ### 5.2 Checkout Locking (Future) Future multi-user support will need a server-side locking strategy: - **Pessimistic locking**: Checkout acquires exclusive lock - **Optimistic locking**: Allow concurrent edits, handle conflicts on commit Recommendation: Pessimistic locking for CAD files (merge is impractical). --- ## 6. Web Interface ### 6.1 Features - **Browse**: Navigate item hierarchy (project → assembly → subassembly → part) - **Search**: Full-text search across part numbers, descriptions, properties - **View**: Item details, revision history, relationships, location - **BOM Viewer**: Expandable tree view of assembly structure - **"Open in FreeCAD"**: Launch FreeCAD with specific item via URI handler ### 6.2 URI Handler Register `silo://` protocol handler: ``` silo://open/PROTO-AS-0001 # Open latest revision silo://open/PROTO-AS-0001?rev=3 # Open specific revision ``` ### 6.3 Technology - **Backend**: Go with standard library HTTP - **Frontend**: htmx for interactivity, minimal JavaScript - **Templates**: Go html/template - **Search**: PostgreSQL full-text search (pg_trgm for fuzzy matching) --- ## 7. Revision Tracking ### 7.1 Append-Only Model Every property change creates a new revision record. The current state is always the latest revision, but any historical state can be reconstructed. ``` Item: PROTO-AS-0001 Revision 1 (2026-01-15): Initial creation - description: "Main chassis assembly" - material: null - weight: null Revision 2 (2026-01-20): Updated properties - description: "Main chassis assembly" - material: "6061-T6 Aluminum" - weight: 2.5 Revision 3 (2026-02-01): Design change - description: "Main chassis assembly v2" - material: "6061-T6 Aluminum" - weight: 2.3 ``` ### 7.2 Revision Creation Revisions are created explicitly by user action (not automatic): - `silo commit` from FreeCAD - "Save Revision" button in web UI - API call with explicit revision flag ### 7.3 Revision vs. File Version - **Revision**: Silo metadata revision (tracked in PostgreSQL) - **File Version**: MinIO object version (automatic on upload) A single Silo revision may span multiple file uploads during editing. Only committed revisions create formal revision records. --- ## 8. Relationships and BOM ### 8.1 Relationship Types | Type | Description | Use Case | |------|-------------|----------| | `component` | Part is used in assembly | Standard BOM entry | | `alternate` | Interchangeable substitute | Alternative sourcing | | `reference` | Related item, not in BOM | Drawings, specs, tools | ### 8.2 Reference Designators For assemblies that require them (electronics, complex mechanisms): ```yaml # Relationship record parent: PROTO-AS-0001 child: PROTO-PT-0042 type: component quantity: 4 reference_designators: ["R1", "R2", "R3", "R4"] ``` ### 8.3 Revision-Specific Relationships Relationships can link to specific child revisions or track latest: ```yaml # Locked to specific revision child: PROTO-PT-0042 child_revision: 3 # Always use latest (default for R&D) child: PROTO-PT-0042 child_revision: null # means "latest" ``` Assembly metadata YAML controls default behavior per assembly. ### 8.4 Flat BOM and Assembly Costing Two endpoints provide procurement- and manufacturing-oriented views of the BOM: **Flat BOM** (`GET /api/items/{partNumber}/bom/flat`) walks the full assembly tree and returns a consolidated list of **leaf parts only** (parts with no BOM children). Quantities are multiplied through each nesting level and duplicate parts are summed. ``` Assembly A (qty 1) ├── Sub-assembly B (qty 2) │ ├── Part X (qty 3) → total 6 │ └── Part Y (qty 1) → total 2 └── Part Z (qty 4) → total 4 ``` Response: ```json { "part_number": "A", "flat_bom": [ { "part_number": "X", "description": "...", "total_quantity": 6 }, { "part_number": "Y", "description": "...", "total_quantity": 2 }, { "part_number": "Z", "description": "...", "total_quantity": 4 } ] } ``` **Assembly Cost** (`GET /api/items/{partNumber}/bom/cost`) builds on the flat BOM and multiplies each leaf's `total_quantity` by its `standard_cost` to produce per-line extended costs and a total assembly cost. ```json { "part_number": "A", "total_cost": 124.50, "cost_breakdown": [ { "part_number": "X", "total_quantity": 6, "unit_cost": 10.00, "extended_cost": 60.00 }, { "part_number": "Y", "total_quantity": 2, "unit_cost": 7.25, "extended_cost": 14.50 }, { "part_number": "Z", "total_quantity": 4, "unit_cost": 12.50, "extended_cost": 50.00 } ] } ``` Both endpoints detect BOM cycles and return **HTTP 409** with the offending path: ```json { "error": "cycle_detected", "detail": "BOM cycle detected: A → B → A" } ``` --- ## 9. Physical Inventory ### 9.1 Location Management Locations are hierarchical, defined by YAML schema. Each item can exist at multiple locations with quantities. ``` Location: lab/main-area/shelf-a/bin-3 - PROTO-PT-0001: 15 units - PROTO-PT-0002: 8 units Location: lab/storage/shelf-b/bin-1 - PROTO-PT-0001: 50 units (spare stock) ``` ### 9.2 Inventory Operations - **Add**: Increase quantity at location - **Remove**: Decrease quantity at location - **Move**: Transfer between locations - **Adjust**: Set absolute quantity (for cycle counts) All operations logged for audit trail (future consideration). --- ## 10. Authentication Silo supports three authentication backends that can be enabled independently or combined. When authentication is disabled (`auth.enabled: false`), all routes are open and a synthetic dev user with the `admin` role is injected into every request. ### 10.1 Backends | Backend | Use Case | Config Key | |---------|----------|------------| | **Local** | Username/password stored in database (bcrypt cost 12) | `auth.local` | | **LDAP** | FreeIPA / Active Directory via LDAP bind | `auth.ldap` | | **OIDC** | Keycloak or any OpenID Connect provider (redirect flow) | `auth.oidc` | ### 10.2 Role Model Three roles with a strict hierarchy: `admin > editor > viewer` | Permission | viewer | editor | admin | |-----------|--------|--------|-------| | Read items, projects, schemas, BOMs | Yes | Yes | Yes | | Create/update items and revisions | No | Yes | Yes | | Upload files, manage BOMs | No | Yes | Yes | | Import CSV/ODS | No | Yes | Yes | | Manage own API tokens | Yes | Yes | Yes | | User management (future) | No | No | Yes | ### 10.3 API Tokens Raw token format: `silo_` + 64 hex characters (32 random bytes from `crypto/rand`). Only the SHA-256 hash is stored in the database. Tokens inherit the owning user's role. ### 10.4 Sessions PostgreSQL-backed sessions via `alexedwards/scs` pgxstore. Cookie: `silo_session`, HttpOnly, SameSite=Lax, 24h lifetime. `Secure` flag is set when `auth.enabled` is true. See [AUTH.md](AUTH.md) for full architecture details and [AUTH_USER_GUIDE.md](AUTH_USER_GUIDE.md) for setup instructions. --- ## 11. API Design ### 11.1 REST Endpoints (Implemented) ``` # Health (no auth) GET /health # Basic health check GET /ready # Readiness (DB + MinIO) # Auth (no auth required) GET /login # Login page POST /login # Login form handler POST /logout # Logout GET /auth/oidc # OIDC login redirect GET /auth/callback # OIDC callback # Web UI (auth + CSRF) GET / # Items page GET /projects # Projects page GET /schemas # Schemas page GET /audit # Audit/completeness page GET /settings # User settings / token management POST /settings/tokens # Create API token (web) POST /settings/tokens/{id}/revoke # Revoke API token (web) # Auth API GET /api/auth/me # Current authenticated user GET /api/auth/tokens # List user's API tokens POST /api/auth/tokens # Create API token DELETE /api/auth/tokens/{id} # Revoke API token # Schemas (read: viewer, write: editor) GET /api/schemas # List all schemas GET /api/schemas/{name} # Get schema details GET /api/schemas/{name}/properties # Get property schema for category POST /api/schemas/{name}/segments/{segment}/values # Add enum value [editor] PUT /api/schemas/{name}/segments/{segment}/values/{code} # Update enum value [editor] DELETE /api/schemas/{name}/segments/{segment}/values/{code} # Delete enum value [editor] # Projects (read: viewer, write: editor) GET /api/projects # List projects GET /api/projects/{code} # Get project GET /api/projects/{code}/items # Get project items GET /api/projects/{code}/sheet.ods # Export project sheet as ODS POST /api/projects # Create project [editor] PUT /api/projects/{code} # Update project [editor] DELETE /api/projects/{code} # Delete project [editor] # Items (read: viewer, write: editor) GET /api/items # List/filter items GET /api/items/search # Fuzzy search GET /api/items/export.csv # Export items to CSV GET /api/items/template.csv # CSV import template GET /api/items/export.ods # Export items to ODS GET /api/items/template.ods # ODS import template POST /api/items # Create item [editor] POST /api/items/import # Import items from CSV [editor] POST /api/items/import.ods # Import items from ODS [editor] # Item Detail GET /api/items/{partNumber} # Get item details PUT /api/items/{partNumber} # Update item [editor] DELETE /api/items/{partNumber} # Archive item [editor] # Item-Project Tags GET /api/items/{partNumber}/projects # Get item's projects POST /api/items/{partNumber}/projects # Add project tags [editor] DELETE /api/items/{partNumber}/projects/{code} # Remove project tag [editor] # Revisions GET /api/items/{partNumber}/revisions # List revisions GET /api/items/{partNumber}/revisions/compare # Compare two revisions GET /api/items/{partNumber}/revisions/{revision} # Get specific revision POST /api/items/{partNumber}/revisions # Create revision [editor] PATCH /api/items/{partNumber}/revisions/{revision} # Update status/labels [editor] POST /api/items/{partNumber}/revisions/{revision}/rollback # Rollback to revision [editor] # Files GET /api/items/{partNumber}/file # Download latest file GET /api/items/{partNumber}/file/{revision} # Download file at revision POST /api/items/{partNumber}/file # Upload file [editor] # BOM GET /api/items/{partNumber}/bom # List direct children GET /api/items/{partNumber}/bom/expanded # Multi-level BOM (recursive) GET /api/items/{partNumber}/bom/flat # Flattened BOM (leaf parts, rolled-up quantities) GET /api/items/{partNumber}/bom/cost # Assembly cost roll-up GET /api/items/{partNumber}/bom/where-used # Where-used (parent lookup) GET /api/items/{partNumber}/bom/export.csv # Export BOM as CSV GET /api/items/{partNumber}/bom/export.ods # Export BOM as ODS POST /api/items/{partNumber}/bom # Add BOM entry [editor] POST /api/items/{partNumber}/bom/import # Import BOM from CSV [editor] PUT /api/items/{partNumber}/bom/{childPartNumber} # Update BOM entry [editor] DELETE /api/items/{partNumber}/bom/{childPartNumber} # Remove BOM entry [editor] # Audit (viewer) GET /api/audit/completeness # Item completeness scores GET /api/audit/completeness/{partNumber} # Item detail breakdown # Integrations — Odoo (read: viewer, write: editor) GET /api/integrations/odoo/config # Get Odoo configuration GET /api/integrations/odoo/sync-log # Get sync history PUT /api/integrations/odoo/config # Update Odoo config [editor] POST /api/integrations/odoo/test-connection # Test connection [editor] (stub) POST /api/integrations/odoo/sync/push/{partNumber} # Push to Odoo [editor] (stub) POST /api/integrations/odoo/sync/pull/{odooId} # Pull from Odoo [editor] (stub) # Sheets (editor) POST /api/sheets/diff # Diff ODS sheet against DB [editor] # Part Number Generation (editor) POST /api/generate-part-number # Generate without creating item [editor] ``` ### 11.2 Not Yet Implemented The following endpoints from the original design are not yet implemented: ``` # Locations (tables exist, no API handlers) GET /api/locations POST /api/locations GET /api/locations/{path} DELETE /api/locations/{path} # Inventory (tables exist, no API handlers) GET /api/inventory/{partNumber} POST /api/inventory/{partNumber}/adjust POST /api/inventory/{partNumber}/move ``` --- ## 12. MVP Scope ### 12.1 Implemented - [x] PostgreSQL database schema (10 migrations) - [x] YAML schema parser for part numbering - [x] Part number generation engine - [x] CLI tool (`cmd/silo`) - [x] API server (`cmd/silod`) with 76 endpoints - [x] MinIO integration for file storage with versioning - [x] BOM relationships (component, alternate, reference) - [x] Multi-level BOM (recursive expansion with configurable depth) - [x] Where-used queries (reverse parent lookup) - [x] Flat BOM flattening with quantity roll-up and cycle detection - [x] Assembly cost roll-up using standard_cost - [x] BOM CSV and ODS export/import - [x] Reference designator tracking - [x] Revision history (append-only) with rollback and comparison - [x] Revision status and labels - [x] Project management with many-to-many item tagging - [x] CSV import/export with dry-run validation - [x] ODS spreadsheet import/export (items, BOMs, project sheets) - [x] Web UI for items, projects, schemas, audit (htmx) - [x] Authentication (local, LDAP, OIDC) with role-based access control - [x] API token management (SHA-256 hashed) - [x] Session management (PostgreSQL-backed) - [x] Audit logging and completeness scoring - [x] CSRF protection (nosurf) - [x] Fuzzy search - [x] Property schema versioning framework - [x] Docker Compose deployment (dev and prod) - [x] systemd service and deployment scripts ### 12.2 Partially Implemented - [ ] Location hierarchy (database tables exist, no API endpoints) - [ ] Inventory tracking (database tables exist, no API endpoints) - [ ] Date segment type (schema parser placeholder only) - [ ] Part number format validation on creation - [ ] Odoo ERP integration (config and sync-log functional; push/pull are stubs) ### 12.3 Not Started - [ ] Unit tests (Go server — minimal coverage exists) - [ ] Schema migration tooling - [ ] Checkout locking - [ ] Approval workflows - [ ] Exploded file storage with diffing - [ ] Notifications - [ ] Reporting/analytics --- ## 13. Open Questions 1. **Thumbnail generation**: Generate thumbnails from CAD files on commit? Useful for web UI browsing. 2. **Search indexing**: PostgreSQL full-text search sufficient, or add dedicated search (Meilisearch, etc.)? 3. **Checkout locking**: Pessimistic vs optimistic locking strategy for multi-user CAD file editing. --- ## 14. References ### 14.1 Design Influences - **CycloneDX BOM specification**: JSON/YAML schema patterns for component identification, relationships, and metadata (https://cyclonedx.org) - **OpenBOM data model**: Reference-instance separation, flexible property schemas - **Ansible inventory YAML**: Hierarchical configuration patterns with variable inheritance ### 14.2 Related Standards - **ISO 10303 (STEP)**: Product data representation - **IPC-2581**: Electronics assembly BOM format - **Package URL (PURL)**: Standardized component identification --- ## Appendix A: Example YAML Files ### A.1 Complete Part Numbering Schema See `schemas/kindred-rd.yaml` for the full schema (v3). Summary: ```yaml # kindred-rd-schema.yaml (abbreviated) schema: name: kindred-rd version: 3 description: "Kindred Systems R&D part numbering" separator: "-" uniqueness: scope: global case_sensitive: false segments: - name: category type: enum description: "Category code" required: true values: F01: "Hex Cap Screw" F02: "Socket Head Cap Screw" # ... 70+ categories (see full file) - name: sequence type: serial length: 4 padding: "0" start: 1 description: "Sequential number within category" scope: "{category}" format: "{category}-{sequence}" # Example outputs: F01-0001, R27-0001, A01-0001 ``` ### A.2 Complete Location Schema ```yaml # kindred-locations.yaml location_schema: name: kindred-lab version: 1 description: "Kindred Systems lab and storage locations" path_separator: "/" hierarchy: - level: 0 type: facility description: "Building or site" name_pattern: "^[a-z][a-z0-9-]*$" examples: ["lab", "warehouse", "office"] - level: 1 type: area description: "Room or zone within facility" name_pattern: "^[a-z][a-z0-9-]*$" examples: ["main-lab", "storage", "assembly"] - level: 2 type: shelf description: "Shelving unit" name_pattern: "^shelf-[a-z]$" examples: ["shelf-a", "shelf-b"] - level: 3 type: bin description: "Individual container or bin" name_pattern: "^bin-[0-9]{1,3}$" examples: ["bin-1", "bin-42", "bin-100"] # Properties tracked per location type properties: facility: - name: address type: text required: false area: - name: climate_controlled type: boolean default: false shelf: - name: max_weight_kg type: number required: false bin: - name: bin_size type: enum values: [small, medium, large] default: medium ``` ### A.3 Assembly Configuration ```yaml # Stored as item property or linked document # Example: assembly PROTO-AS-0001 assembly_config: name: "Main Chassis Assembly" relationship_types: - component - alternate - reference use_reference_designators: false child_revision_tracking: latest # Assembly-specific BOM properties relationship_properties: - name: installation_notes type: text - name: torque_spec type: text - name: adhesive_required type: boolean default: false # Validation rules validation: require_quantity: true min_components: 1 ```