Plings Core Schema (Neo4j)
Plings Core Schema (Neo4j)
This document defines the core data schema for the Universal Object Graph System, designed for use with Neo4j. The schema is built around a property graph model of nodes and relationships.
Graph Model Overview
The system models the physical world using a graph containing several key node labels and relationship types.
- Nodes: Represent entities like object blueprints (
ObjectClass), physical items (ObjectInstance), and identifiers (PlingsIdentifier). - Relationships: Represent how these entities are connected, such as an instance being an
INSTANCE_OFa class, a component beingPART_OFanother, or an object beingINa container.
Node Reference
1. :ObjectClass Node
Represents a template or definition of an object.
| Property | Type | Description | Example |
|---|---|---|---|
name |
String |
Required. The unique name of the class. | "Mountain Bike" |
description |
String |
A detailed description of the object class. | "A bicycle designed for off-road cycling." |
version |
Integer |
The version number for the class definition. | 2 |
owner |
String |
The entity that defined or owns this class. | "ACME Inc." |
visibility |
String |
Access control for the class (“public”, “private”). | "public" |
capabilities |
List<String> |
A list of potential uses for this object type. | ["off-road", "sport"] |
anchor_key |
String |
The public cryptographic anchor key from the HD Wallet. | "xpub..." |
path_template |
String |
The schema for interpreting the HD Wallet derivation path. | "model/factory/instance" |
2. :ObjectInstance Node
Represents a specific, physical object in the real world.
| Property | Type | Description | Example |
|---|---|---|---|
statuses |
List<String> |
The current state(s) of the physical object. | ["for_sale", "broken"] |
owner |
String |
The user or organization that owns this instance. | "user:12345" |
3. :PlingsIdentifier Node
Represents a physical or digital identifier (e.g., QR code, NFC tag).
| Property | Type | Description | Example |
|---|---|---|---|
key |
String |
Required. The unique identifier value. | "plg:44-..." |
identifier_type |
String |
The medium of the identifier. | "QR" |
status |
String |
The state of the identifier itself. | "active" |
is_one_time_use |
Boolean |
Flag for OTP-style verification identifiers. | true |
4. :ScanEvent Node
Represents a single scan event of a PlingsIdentifier, creating a historical audit trail.
| Property | Type | Description | Example |
|---|---|---|---|
timestamp |
DateTime |
Required. The exact time of the scan. | 2024-07-30T10:00:00Z |
latitude |
Float |
The GPS latitude of the scan location. | 34.0522 |
longitude |
Float |
The GPS longitude of the scan location. | -118.2437 |
scanning_user |
String |
The user who performed the scan. | "user:54321" |
owner_at_time_of_scan |
String |
The recorded owner at the moment of the scan. | "user:12345" |
Relationship Reference
Core Relationships
| Start Node | Type | End Node | Description |
|---|---|---|---|
:ObjectInstance |
INSTANCE_OF |
:ObjectClass |
Links a physical item to its blueprint. |
:ObjectClass |
SUBCLASS_OF |
:ObjectClass |
Creates the class hierarchy (e.g., Mountain Bike is a subclass of Bicycle). |
:ObjectInstance |
PART_OF |
:ObjectInstance |
Defines the physical composition of complex objects (a wheel is part of a bike). |
:PlingsIdentifier |
IDENTIFIES |
:ObjectInstance |
Links an identifier to the specific object it represents. |
:ScanEvent |
SCANNED |
:PlingsIdentifier |
Records that a specific identifier was scanned in an event. |
Spatial Relationships
These relationship types model the physical world.
| Start Node | Type | End Node | Description |
|---|---|---|---|
:ObjectInstance |
IN |
:ObjectInstance |
The subject is inside the object (e.g., keys in a box). |
:ObjectInstance |
ON |
:ObjectInstance |
The subject is on the surface of the object (e.g., laptop on a desk). |
:ObjectInstance |
UNDER |
:ObjectInstance |
The subject is under the object. |
:ObjectInstance |
NEXT_TO |
:ObjectInstance |
The subject is adjacent to the object. |
:ObjectInstance |
ATTACHED_TO |
:ObjectInstance |
The subject is physically attached to the object. |
:ObjectInstance |
LEFT_OF |
:ObjectInstance |
The subject is to the left of the object. |
:ObjectInstance |
RIGHT_OF |
:ObjectInstance |
The subject is to the right of the object. |
| … | etc. | … | Other predicates from the spatial system are also relationship types. |
Functional Relationships
These relationship types describe how objects interact rather than where they are located. They come from the authoritative catalogue in functional_relationships_system.md and are stored as uppercase relationship types in Neo4j (directional pairs are stored both ways; symmetric predicates are stored once in canonical order).
| Category | Type (Predicate) | Inverse | Symmetric? | Description | Example |
|---|---|---|---|---|---|
| Compatibility | IS_FOR |
ACCEPTS |
No | Subject is designed for target | (:Remote)-[:IS_FOR]->(:TV) |
ACCEPTS |
IS_FOR |
No | Target accepts subject | (:TV)-[:ACCEPTS]->(:Remote) |
|
WORKS_WITH |
— | Yes | Designed to function together | (:Scanner)-[:WORKS_WITH]-(:Computer) |
|
| Control | CONTROLS |
CONTROLLED_BY |
No | Subject operates target | (:Remote)-[:CONTROLS]->(:TV) |
OPERATES |
OPERATED_BY |
No | Activates / runs target | (:Switch)-[:OPERATES]->(:Light) |
|
| Power | POWERS |
POWERED_BY |
No | Subject provides electrical power | (:Battery)-[:POWERS]->(:Flashlight) |
CHARGES |
CHARGED_BY |
No | Replenishes energy of target | (:Charger)-[:CHARGES]->(:Phone) |
|
| Access | UNLOCKS |
UNLOCKED_BY |
No | Grants access to target | (:Key)-[:UNLOCKS]->(:Door) |
| Pairing | PAIRS_WITH |
— | Yes | Two items form an intended pair | (:LeftGlove)-[:PAIRS_WITH]-(:RightGlove) |
| Replacement | REPLACES |
REPLACED_BY |
No | Subject serves as substitute | (:BackupBattery)-[:REPLACES]->(:MainBattery) |
Note: Functional predicates can also be created between ObjectClass nodes to act as templates. The API resolver automatically merges explicit instance-level edges with class-level edges (marked inherited = true) so that every object gains the functional context of its class hierarchy without data duplication.
Example Cypher
// Find everything that powers a given laptop (instance-level + class templates)
MATCH (l:ObjectInstance {id:$laptop})<-[:POWERS|POWERED_BY|CHARGES|CHARGED_BY]-(src)
RETURN DISTINCT src.id, type(relationships(src,l)) AS predicate;
Supabase (Postgres) Schema
Tables
- profiles
id: uuid, not nullablefull_name: text, nullableavatar_url: text, nullableupdated_at: timestamp with time zone, nullable, defaultnow()
- organizations
id: uuid, not nullable, defaultgen_random_uuid()name: text, not nullablecreated_at: timestamp with time zone, nullable, defaultnow()created_by: uuid, nullabletype: text, not nullable, default'Individual'::textdescription: text, nullable
- organization_members
organization_id: uuid, not nullableuser_id: uuid, not nullablerole: text, not nullablejoined_at: timestamp with time zone, nullable, defaultnow()
- object_instances
id: uuid, not nullableneo4j_id: text, nullablename: text, not nullabledescription: text, nullableowner_organization_id: uuid, not nullablecreated_by: uuid, not nullablecreated_at: timestamp with time zone, nullable, defaultnow()updated_at: timestamp with time zone, nullable, defaultnow()status: text, nullablemain_image_url: text, nullablelast_scanned_at: timestamp with time zone, nullablelast_scanned_by: uuid, nullable
- object_images
id: uuid, not nullableobject_instance_id: uuid, not nullablestorage_path: text, not nullablepublic_url: text, not nullableis_main: boolean, not nullable, defaultfalseuploaded_by: uuid, not nullableuploaded_at: timestamp with time zone, nullable, defaultnow()file_size: integer, nullablecontent_type: text, nullable
- functional_predicates
key: text, not nullablecategory: text, nullabledescription: text, nullableinverse_key: text, nullableis_symmetric: boolean, not nullable, defaultfalseicon_name: text, nullabledeprecated: boolean, not nullable, defaultfalsecreated_at: timestamp with time zone, nullable, defaultnow()
- spatial_predicates
key: text, not nullableaxis: text, nullabledescription: text, nullableinverse_key: text, nullableis_symmetric: boolean, not nullable, defaultfalseicon_name: text, nullabledeprecated: boolean, not nullable, defaultfalsecreated_at: timestamp with time zone, nullable, defaultnow()
RLS policies enforce per-organisation isolation.