# Schema Reference — Base

Universal node types shared across all business verticals. Load this reference before any structured write to the graph. If a vertical reference is also loaded, it extends these types — it never replaces them.

When loading this reference, confirm which schema files were consulted by noting: "Using schema-base" (and the vertical file name, if loaded).

---

## Node Types

| Entity | Neo4j Label | Schema.org Type | Interchange Standard | Required Properties |
|--------|-------------|-----------------|----------------------|---------------------|
| Customer | `Person` | `schema:Person` | vCard (RFC 6350) | `accountId`, `givenName`, `familyName`, `email` or `telephone` |
| Supplier | `Organization` | `schema:Organization` | vCard (RFC 6350) | `accountId`, `name`, `telephone` or `email` |
| Staff | `Person` | `schema:Person` + `cdm:Contact` | vCard (RFC 6350) | `accountId`, `givenName`, `familyName`, `jobTitle`, `permissions` |
| Job | `Order` | `schema:Order` + `cdm:Opportunity` | — | `accountId`, `orderNumber`, `customer` (id), `orderStatus` |
| Event | `Event` | `schema:Event` | iCalendar (RFC 5545) | `accountId`, `name`, `startDate`, `endDate` |
| Invoice | `Invoice` | `schema:Invoice` | UBL 2.1 + PDF/A | `accountId`, `confirmationNumber`, `customer` (id), `totalPaymentDue`, `paymentStatus` |
| Service | `Service` | `schema:Service` | Schema.org JSON-LD | `accountId`, `name`, `description`, `offers` (price) |
| PriceRule | `PriceSpecification` | `schema:PriceSpecification` | — | `accountId`, `price`, `priceCurrency` |
| Communication | `Message` | `schema:Message` + `cdm:Activity` | — | `accountId`, `sender`, `recipient`, `dateSent`, `channel` |
| Document | `DigitalDocument` | `schema:DigitalDocument` | Original format preserved | `accountId`, `name`, `dateCreated`, `encodingFormat` |
| Address | `PostalAddress` | `schema:PostalAddress` | — | `streetAddress`, `addressLocality`, `postalCode` |
| Task | `Task` | `schema:Action` (semantics) | — | `accountId`, `taskId`, `name`, `status`, `priority` |
| Lead | `Lead` | `cdm:Lead` | CDM only | `accountId`, `subject`, `customer` (id), `status` |
| Case | `Case` | `cdm:Case` | CDM only | `accountId`, `title`, `customer` (id), `status`, `priority` |
| OpeningHours | `OpeningHoursSpecification` | `schema:OpeningHoursSpecification` | Schema.org JSON-LD | `accountId`, `dayOfWeek`, `opens`, `closes` |
| FAQ | `FAQPage` | `schema:FAQPage` | Schema.org JSON-LD | `accountId`, `name` |
| Question | `Question` | `schema:Question` | Schema.org JSON-LD | `accountId`, `name` (question text), `acceptedAnswer` |
| BrandAsset | `ImageObject` | `schema:ImageObject` | — | `accountId`, `name`, `contentUrl`, `encodingFormat`, `purpose` (logo/hero/icon) |
| CreativeWork | `CreativeWork` | `schema:CreativeWork` | — | `accountId`, `title`, `abstract` |
| DefinedTerm | `DefinedTerm` | `schema:DefinedTerm` | — | `accountId`, `name`, `description` |
| AccessGrant | `AccessGrant` | platform-native | — | `accountId`, `agentSlug`, `contactMethod`, `contactValue`, `status` (scope must be `admin`) |

**Branding properties on LocalBusiness:** `primaryColor`, `accentColor`, `backgroundColor`, `tagline` — optional, used to brand the public chat endpoint. Written via `memory-update` on the LocalBusiness node. Hex color values must match `#[0-9a-fA-F]{3,8}`. Logo and icon are linked via `HAS_BRAND_ASSET → ImageObject` with `purpose: "logo"` or `"icon"`.

**CreativeWork** covers long-form textual records written by the platform: session summaries (`session-compact`), workflow digests (e.g. public chat review), and skill definitions saved by `skill-builder`. The `title` is a short identifier; the `abstract` carries the full content that drives the embedding.

**DefinedTerm** covers reusable concepts, learnings, and glossary entries — e.g. project retrospective learnings (`name` is a short handle, `description` is the full learning). Additional properties like `category` are encouraged but not required.

---

## Property Naming Rules

Schema.org property names are camelCase. Use them exactly as defined — no synonyms, no abbreviations:

| Correct | Wrong |
|---------|-------|
| `givenName` | `firstName`, `first_name` |
| `familyName` | `lastName`, `last_name`, `surname` |
| `telephone` | `phone`, `phoneNumber`, `mobile` |
| `startDate` / `endDate` | `start`, `end`, `from`, `to` |
| `totalPaymentDue` | `amount`, `total`, `invoiceTotal` |
| `orderStatus` | `status` (on Order nodes — use the qualified name) |
| `dateSent` | `timestamp`, `date`, `sentAt` (on Message nodes) |
| `confirmationNumber` | `invoiceNumber`, `invoiceNo` |
| `addressLocality` | `city`, `town` |
| `postalCode` | `postcode`, `zipCode`, `zip` |

---

## accountId Scoping

Every node except `PostalAddress` must carry `accountId`. No write may omit it. No query result without `accountId` should be treated as valid. There is no default value and no fallback — if `accountId` is unknown, the write must not proceed.

`PostalAddress` nodes are exempt because addresses are shared across entities (a customer and their orders may share the same address node).

---

## Embedding

Every write that creates or updates a structured node produces a 768-dimension embedding via `nomic-embed-text` (Ollama). The `memory-write` tool handles embedding generation automatically. The agent's responsibility is to provide complete, meaningful property values so the embedding accurately represents the node's content.

Do not write placeholder values ("TBD", "unknown", empty strings) for properties that will be embedded — they degrade search quality.

---

## Relationship Patterns

```
(:Person)-[:WORKS_FOR]->(:Organization)
(:Order)-[:ORDERED_BY]->(:Person)
(:Invoice)-[:REFERENCES_ORDER]->(:Order)
(:Invoice)-[:BILLED_TO]->(:Person|Organization)
(:Event)-[:ATTENDED_BY]->(:Person)
(:Message)-[:SENT_TO]->(:Person|Organization)
(:DigitalDocument)-[:ABOUT]->(:*)
(:Task)-[:RAISED_BY]->(:Person)
(:Task)-[:ABOUT]->(:Person|Service|Order|*)
(:LocalBusiness)-[:HAS_HOURS]->(:OpeningHoursSpecification)
(:LocalBusiness)-[:HAS_FAQ]->(:FAQPage)
(:FAQPage)-[:CONTAINS]->(:Question)
(:LocalBusiness)-[:HAS_BRAND_ASSET]->(:ImageObject)
(:Person)-[:HAS_ACCESS]->(:AccessGrant)
```

---

## Order Node — Disambiguation

The base `Order` label is used for general jobs and orders. Several vertical schemas define specialised subtypes that also map to `schema:Order` but use different Neo4j labels:

- **Trades:** `Quote` (quote/estimate before acceptance)
- **Professional Services:** `Retainer` (recurring service agreement)
- **Food & Beverage:** `Order` with F&B-specific properties (table, servedBy)
- **Retail:** `PurchaseOrder` (supplier-facing order)

When a vertical is loaded, use its specific label for domain-specific orders. Use the base `Order` label only for general-purpose jobs or when no vertical-specific type applies.
