The Entities domain manages the actual content pages of MinMaxHub (e.g., "Dwarf", "Bard", "Peter (Civ 6)"). While Nodes provide the folder structure and routing, entities hold the concrete data and layout configuration that drives each page.
Core Concepts
Layout Snapshotting
When an entity is created under a parent node, it copies the node's layout templates into its own layout field. This means each entity is self-contained -- editing the parent node's templates does not retroactively change existing entities.
A configVersion field tracks which version of the parent's templates the entity was created from, allowing the system to detect when an entity is out of sync.
Refreshing Layouts
When a parent node's templates change, an admin can explicitly refresh an entity's layout to pick up the new templates. This is an intentional action, not automatic -- preventing accidental changes to existing content.
Scoped Slug Uniqueness
Entity slugs are scoped per parent node. This means "Fireball" can exist under both "Wizard Spells" and "Sorcerer Spells" without conflict, as long as they belong to different parent nodes.
The full URL path is constructed as {parentNode.slugPath}/{slug}.
Entity Fields
| Field | Type | Description |
|---|---|---|
entityId | UUID | Unique identifier |
nodeId | UUID | Parent node reference |
slug | string | URL-safe identifier (kebab-case) |
slugPath | string | Full URL path (e.g., dnd/classes/bard) |
title | string | Display name |
status | draft, published, or archived | Lifecycle state |
heroImage | object or null | Optional cover image (url, alt) |
heroDescription | string or null | Optional summary text for entity cards |
layout | array | Layout templates defining the page's sections |
configVersion | number | Template generation tracker |
createdAt / updatedAt | ISO date | Timestamps |
createdBy / updatedBy | object | { userId, username, photoUrl } |
Layout Templates
Each template in the layout array defines a topic (section) on the entity page:
| Field | Description |
|---|---|
kind | 'single' (one value), 'collections' (list of items), or 'wrapper' (groups child topics) |
topicKey | Unique identifier within the layout |
rule | JSON Schema rule name used for validation |
order | Display order |
defaultValue | Fallback content when no consensus exists |
description | Description of this section |
collectionMode | Collections only: 'expandable' (users can add items) or 'closed' (predefined items only) |
children | Wrappers only: nested child topics |
Status Lifecycle
- Draft -- not visible to the public, editable by authenticated users.
- Published -- visible on the public site, included in static generation.
- Archived -- removed from public view. The slug becomes available for reuse.
API Endpoints
| Method | Endpoint | Purpose | Auth |
|---|---|---|---|
GET | /entities?nodeId={nodeId} | List entities under a node | Required |
GET | /entities/{entityId} | Get entity by ID | Required |
GET | /entities/slugs | Get all published entity slug paths | Public |
POST | /entities | Create an entity under a node | Required |
PATCH | /entities/{entityId} | Update entity (title, status, hero image) | Required |
PATCH | /entities/{entityId}/refresh | Refresh layout from parent node | Required |
DELETE | /entities/{entityId} | Delete an entity | Required |