# **SessionZero Design Document** ## **1. Introduction** ### **1.1 Purpose** SessionZero is a free and open-source TTRPG companion app designed to streamline tabletop role-playing game management. It emphasizes flexibility, modularity, and federation through a **system-agnostic datapack format**, supporting both offline and self-hostable online play. The goal is to empower players and GMs with full control over their data, rulesets, and session management. ### **1.2 Scope** The project will begin as a cross-platform desktop application (Windows and Linux), offering tools for creating and managing TTRPG data such as characters, datasets, templates, and sessions. The backend supports user accounts, a database for shared content (SessionZeroDB), and prepares for future federation capabilities. Phase 2 introduces federation, while Phase 3 focuses on mobile support and plugin extensibility. ### **1.3 Objectives** * Provide a modular, open-source companion app for any TTRPG system. * Implement a JSON-based datapack format for extensible content storage. * Support both local use and self-hostable online instances. * Create a foundation for future federation and mobile support. ## **2. System Overview** SessionZero consists of three main layers: 1. **Frontend (Client):** Cross-platform desktop application (.NET Avalonia). 2. **Backend (Server):** ASP.NET backend managing user accounts, SessionZeroDB, and P2P connections. 3. **Datapack System:** A structured archive format for storing and sharing game data. ## **3. Technology Stack** * **Core:** C# / .NET 9.0 (minimal API) * **Client:** Avalonia UI (cross-platform desktop) * **Database:** PostgreSQL (primary data store for shared/online content) * **Offline/Local:** Local file storage, perhaps SQLite for local instances. * **Networking:** WebSockets for real-time session updates; SignalR/gRPC considered for P2P/federation. ## **4. Core Data Concepts** ### **4.1 Datapack** The top-level container (.szp file), bundling all system-specific data (templates, datasets, assets). ### **4.2 Template** A reusable definition of a data structure (e.g., a **Character Template** defining character sheet fields, or a **Session Template** defining campaign structure). ### **4.3 Dataset** A structured collection of external data records (e.g., a bestiary, a list of items, or spells). ### **4.4 Instance** The runtime data created from a Template (e.g., "Aelric's Character Sheet" based on the "Fantasy Character" Template). ### **4.5 Schema** Formal JSON Schemas used to validate the structure of Datapacks and their contents. ## **5. Datapack Specification** A datapack is a self-contained archive (.szp) that holds all data and assets for a specific TTRPG system, module, or expansion. It serves as the foundation for SessionZero's extensible content model. Each pack can define **datasets**, **templates**, and optionally contain instance data (though instances are usually stored separately as save files). The structure emphasizes modularity, portability, and reliable dependency management between packs. ### **5.1 Directory Structure** ```text pack-name/ ├── szpack.json # Pack metadata and manifest ├── media/ │ └── images/ # Image assets (referenced by objects) └── objects/ ├── datasets/ # User-defined structured data (e.g. items, NPCs) ├── character-templates/ # Templates defining character structures └── session-templates/ # Templates defining session/campaign structures ``` ### **5.2 Pack Metadata (szpack.json)** Each datapack contains a root metadata file that defines its identity, authorship, dependencies, and compatibility information. This structure aligns with the C# Datapack and DatapackDependency models. ```json { "id": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62", "name": "Example Pack", "version": "1.0.0", "author": "UserName", "license": "CC-BY-SA-4.0", "description": "A fantasy setting datapack containing items and NPCs.", "createdAt": "2025-10-15T00:00:00Z", "sessionZeroVersion": "1.0.0", "dependencies": [ { "id": "c2e6d0a4-2a8f-4a51-b36e-9f8f2c7b1d11", "name": "Core-Ruleset", "version": "1.2.0" } ] } ``` ### **5.3 Common Object Metadata** Objects within the datapack (datasets, templates) inherit from **SzObject**. The **szType** field is required to identify the object type. **Image paths are relative to the media/images folder.** ```json { "id": "core-items", "name": "Core Items", "szType": "dataset", "description": "A collection of basic weapons and armor.", "icon": "core-items.png", "version": "1.0.0", "schemaVersion": "1.0.0" } ``` *Note: The system resolves the icon field path (e.g., "core-items.png") to datapack/media/images/core-items.png.* ### **5.4 Dataset Objects** Datasets are structured collections of data entries. The entry structure includes TopLevelFields and optional Groups of fields, aligning with the DatasetEntry C# model. ```json { "id": "core-items", "szType": "dataset", "datasetType": "items", "name": "Core Items", "description": "Weapons, armor, and consumables for the base ruleset.", "version": "1.0.0", "schemaVersion": "1.0.0", "entries": { "sword": { "id": "sword", "name": "Sword", "description": "A basic weapon.", "icon": "weapons/sword.png", "topLevelFields": { "damage": { "type": "Number", "value": 10 }, "weight": { "type": "Number", "value": 3 } }, "groups": [ { "id": "stats", "name": "Stats", "fields": { "rarity": { "type": "Text", "value": "Common" } } } ] }, "potion": { "id": "potion", "name": "Healing Potion", "description": "Restores a small amount of HP.", "icon": "consumables/potion.png", "topLevelFields": { "healAmount": { "type": "Number", "value": 20 }, "consumable": { "type": "Boolean", "value": true } } } } } ``` *Note: The field retrieval path is expected to be EntryName.FieldName or EntryName.GroupName.FieldName, matching the logic in Dataset.cs.* ### **5.5 Character Templates** Character templates define the fields and structure for characters. Note the use of the specific **DatasetLink** object for list fields, requiring a Datapack ID, Dataset ID, and Version. ```json { "id": "default-character", "szType": "character-template", "name": "Generic Character", "description": "A base character layout usable across multiple systems.", "icon": "character.png", "version": "1.0.0", "schemaVersion": "1.0.0", "sections": [ { "id": "core", "name": "Core Stats", "groups": [ { "id": "attributes", "name": "Attributes", "fields": [ { "id": "strength", "name": "Strength", "type": "Number", "defaultValue": 10 }, { "id": "dexterity", "name": "Dexterity", "type": "Number", "defaultValue": 10 }, { "id": "intelligence", "name": "Intelligence", "type": "Number", "defaultValue": 10 } ] }, { "id": "inventory", "name": "Inventory", "fields": [ { "id": "equipment", "name": "Equipment", "type": "List", "datasetLink": { "datapackId": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62", "datasetId": "core-items", "version": "1.0.0" } } ] } ] } ] } ``` ### **5.6 Session Templates** Session templates are blueprints for setting up a campaign. This example uses **CharacterTemplateLink** and a list of **DatasetLink** objects for **RequiredDatasets** as defined in SessionTemplate.cs. ```json { "id": "basic-session", "szType": "session-template", "name": "Basic Fantasy Campaign", "description": "A classic campaign setup with standard fantasy rules.", "icon": "session.png", "version": "1.0.0", "schemaVersion": "1.0.0", "characterTemplateLink": { "datapackId": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62", "templateId": "default-character", "version": "1.0.0" }, "requiredDatasets": [ { "datapackId": "c9a3f9c8-8b8a-4f1f-9f3b-2d8c7f2c6c62", "datasetId": "core-items", "version": "1.0.0" } ], "sections": [ { "id": "session-info", "name": "Session Info", "groups": [ { "id": "details", "name": "Details", "fields": [ { "id": "setting", "name": "Setting", "type": "Text", "defaultValue": "Thalindra" }, { "id": "gmNotes", "name": "GM Notes", "type": "MultiText" } ] } ] } ] } ``` ### **5.7 Instances (Stored Separately)** Instances, such as a specific character or a running campaign's state, are typically stored outside of the core, reusable datapacks but follow a similar structure, referencing a template. ```json { "szType": "character-instance", "templateId": "default-character", "name": "Aelric Stormhand", "fields": { "strength": 14, "dexterity": 11, "inventory": ["sword", "potion"] } } ``` ### **5.8 Validation and Schema Versioning** Formal, versioned JSON Schemas define the structure of szpack.json and core object types. * Each object declares a **schemaVersion** (global versioning per SessionZero release). * Validation tools confirm compliance before import/export. * Internal references (DatasetLink, CharacterTemplateLink, etc.) are resolved within the pack automatically. * External references are verified via dependencies in szpack.json. **Session Datapack vs Templates:** * **Session Template:** A reusable blueprint for campaign/session setup. Lives under objects/session-templates/. * **Session Datapack:** The persisted, evolving state of an ongoing campaign. It is stored as a special pack and does not appear alongside normal content packs in the UI. Snapshots are versioned with timestamps. Export/import uses the same .szp format with a distinct type flag in szpack.json. ## **6. Networking & Synchronization** ### **6.1 Session Model** A "Session" is a single game instance, hosted by a GM. It uses a centralized, shared document model (SessionZeroDB/PostgreSQL) with real-time updates pushed via WebSockets. ### **6.2 Data Flow** 1. **GM Action:** GM updates an NPC in their local client. 2. **Client:** Pushes the update to the server via API/WebSockets. 3. **Server:** Validates, commits to DB, and broadcasts the change to all connected players (including the GM). 4. **Players:** Receive the update and apply it to their local model. ### **6.3 Offline Mode** The application supports full offline functionality, using local storage. When connectivity is restored, the system uses conflict-resolution logic (timestamp-based or operational transformation) to reconcile changes with the SessionZeroDB. ## **7. Federation** ### **7.1 Concept** Federation allows different SessionZero instances (e.g., self-hosted servers) to share and discover content (Datapacks, public Datasets, Templates). This requires standardized APIs for content retrieval and identity verification. ### **7.2 Identity** * Users have a unique global identifier (UID). * Datapacks are identified by their UUID (id). ### **7.3 Data Sharing** Publicly shared Datapacks are discoverable through a federation layer, allowing users to import content from other trusted servers. ## **8. Licensing** ### **8.1 Source Code License** * **AGPL-3.0 (Affero General Public License):** Ensures open-source continuity and attribution, prevents uncredited commercial rebranding. ### **8.2 User Content License** * **Creative Commons BY-SA 4.0:** Allows sharing and adaptation with attribution. ## **9. Development Phases** ### **Phase 1: Core Platform (MVP)** * Client (UI, datapack editing, session management) * Backend (accounts, SessionZeroDB, P2P prep) * JSON datapack format implementation ### **Phase 2: Federation** * Cross-server communication * Access controls and search indexing ### **Phase 3: Mobile and Plugins** * Cross-platform mobile apps * Plugin and API extensibility ## **10. Testing & Quality** * **Unit Tests:** Core services (DataPackService, StorageService, NetworkingService) with fixtures for characters/datasets/templates. * **Schema Validation:** CI job validates sample packs against JSON Schemas (see section 5.8) and rejects PRs with invalid packs. * **Integration Tests:** Import/export round-trips, dependency resolution, and session snapshot/recovery. * **Compatibility Matrix:** Validate on Windows and Linux for net9.0; browser target smoke tests where applicable. ## **11. Accessibility & Internationalization** * **Accessibility:** Keyboard navigation across all primary views, sufficient color contrast, focus indicators, and screen-reader-friendly labels. * **Internationalization:** Resource-based localization for UI strings; UTF-8 throughout; prepare for RTL support; date/number formatting via invariant + locale-aware overlays.