diff --git a/.hidden/.gitignore b/.hidden/.gitignore
deleted file mode 100644
index 8afdcb6..0000000
--- a/.hidden/.gitignore
+++ /dev/null
@@ -1,454 +0,0 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-##
-## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
-
-# User-specific files
-*.rsuser
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Mono auto generated files
-mono_crash.*
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-[Ww][Ii][Nn]32/
-[Aa][Rr][Mm]/
-[Aa][Rr][Mm]64/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-[Ll]ogs/
-
-# Visual Studio 2015/2017 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# Visual Studio 2017 auto generated files
-Generated\ Files/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUnit
-*.VisualState.xml
-TestResult.xml
-nunit-*.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# Benchmark Results
-BenchmarkDotNet.Artifacts/
-
-# .NET Core
-project.lock.json
-project.fragment.lock.json
-artifacts/
-
-# Tye
-.tye/
-
-# ASP.NET Scaffolding
-ScaffoldingReadMe.txt
-
-# StyleCop
-StyleCopReport.xml
-
-# Files built by Visual Studio
-*_i.c
-*_p.c
-*_h.h
-*.ilk
-*.meta
-*.obj
-*.iobj
-*.pch
-*.pdb
-*.ipdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*_wpftmp.csproj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# Visual Studio Trace Files
-*.e2e
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# AxoCover is a Code Coverage Tool
-.axoCover/*
-!.axoCover/settings.json
-
-# Coverlet is a free, cross platform Code Coverage Tool
-coverage*.json
-coverage*.xml
-coverage*.info
-
-# Visual Studio code coverage results
-*.coverage
-*.coveragexml
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# Note: Comment the next line if you want to checkin your web deploy settings,
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# NuGet Symbol Packages
-*.snupkg
-# The packages folder can be ignored because of Package Restore
-**/[Pp]ackages/*
-# except build/, which is used as an MSBuild target.
-!**/[Pp]ackages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/[Pp]ackages/repositories.config
-# NuGet v3's project.json files produces more ignorable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-*.appx
-*.appxbundle
-*.appxupload
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!?*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.jfm
-*.pfx
-*.publishsettings
-orleans.codegen.cs
-
-# Including strong name files can present a security risk
-# (https://github.com/github/gitignore/pull/2483#issue-259490424)
-#*.snk
-
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-ServiceFabricBackup/
-*.rptproj.bak
-
-# SQL Server files
-*.mdf
-*.ldf
-*.ndf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-*.rptproj.rsuser
-*- [Bb]ackup.rdl
-*- [Bb]ackup ([0-9]).rdl
-*- [Bb]ackup ([0-9][0-9]).rdl
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-node_modules/
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
-*.vbw
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# CodeRush personal settings
-.cr/personal
-
-# Python Tools for Visual Studio (PTVS)
-__pycache__/
-*.pyc
-
-# Cake - Uncomment if you are using it
-# tools/**
-# !tools/packages.config
-
-# Tabs Studio
-*.tss
-
-# Telerik's JustMock configuration file
-*.jmconfig
-
-# BizTalk build output
-*.btp.cs
-*.btm.cs
-*.odx.cs
-*.xsd.cs
-
-# OpenCover UI analysis results
-OpenCover/
-
-# Azure Stream Analytics local run output
-ASALocalRun/
-
-# MSBuild Binary and Structured Log
-*.binlog
-
-# NVidia Nsight GPU debugger configuration file
-*.nvuser
-
-# MFractors (Xamarin productivity tool) working folder
-.mfractor/
-
-# Local History for Visual Studio
-.localhistory/
-
-# BeatPulse healthcheck temp database
-healthchecksdb
-
-# Backup folder for Package Reference Convert tool in Visual Studio 2017
-MigrationBackup/
-
-# Ionide (cross platform F# VS Code tools) working folder
-.ionide/
-
-# Fody - auto-generated XML schema
-FodyWeavers.xsd
-
-##
-## Visual studio for Mac
-##
-
-
-# globs
-Makefile.in
-*.userprefs
-*.usertasks
-config.make
-config.status
-aclocal.m4
-install-sh
-autom4te.cache/
-*.tar.gz
-tarballs/
-test-results/
-
-# Mac bundle stuff
-*.dmg
-*.app
-
-# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
-# General
-.DS_Store
-.AppleDouble
-.LSOverride
-
-# Icon must end with two \r
-Icon
-
-
-# Thumbnails
-._*
-
-# Files that might appear in the root of a volume
-.DocumentRevisions-V100
-.fseventsd
-.Spotlight-V100
-.TemporaryItems
-.Trashes
-.VolumeIcon.icns
-.com.apple.timemachine.donotpresent
-
-# Directories potentially created on remote AFP share
-.AppleDB
-.AppleDesktop
-Network Trash Folder
-Temporary Items
-.apdisk
-
-# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
-# Windows thumbnail cache files
-Thumbs.db
-ehthumbs.db
-ehthumbs_vista.db
-
-# Dump file
-*.stackdump
-
-# Folder config file
-[Dd]esktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-
-# Windows Installer files
-*.cab
-*.msi
-*.msix
-*.msm
-*.msp
-
-# Windows shortcuts
-*.lnk
-
-# JetBrains Rider
-.idea/
-*.sln.iml
-
-##
-## Visual Studio Code
-##
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
diff --git a/.hidden/SessionZero.sln b/.hidden/SessionZero.sln
deleted file mode 100644
index d56de21..0000000
--- a/.hidden/SessionZero.sln
+++ /dev/null
@@ -1,34 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionZero.Shared", "src\SessionZero.Shared\SessionZero.Shared.csproj", "{86CD0D66-D47D-41DA-B857-F8371AC6E6A9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionZero.Client", "src\SessionZero.Client\SessionZero.Client.csproj", "{A6455219-BBF2-4A67-B13C-449249083703}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SessionZero.Server", "src\SessionZero.Server\SessionZero.Server.csproj", "{54824F5A-0499-4BC9-AC8E-88E943C66256}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "szpack", "tools\szpack\szpack.csproj", "{70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {86CD0D66-D47D-41DA-B857-F8371AC6E6A9}.Release|Any CPU.Build.0 = Release|Any CPU
- {A6455219-BBF2-4A67-B13C-449249083703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A6455219-BBF2-4A67-B13C-449249083703}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A6455219-BBF2-4A67-B13C-449249083703}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A6455219-BBF2-4A67-B13C-449249083703}.Release|Any CPU.Build.0 = Release|Any CPU
- {54824F5A-0499-4BC9-AC8E-88E943C66256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {54824F5A-0499-4BC9-AC8E-88E943C66256}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {54824F5A-0499-4BC9-AC8E-88E943C66256}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {54824F5A-0499-4BC9-AC8E-88E943C66256}.Release|Any CPU.Build.0 = Release|Any CPU
- {70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {70FDB950-CAE6-4C38-A476-3FC10BFCF6E6}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/.hidden/docs/design-doc.md b/.hidden/docs/design-doc.md
deleted file mode 100644
index 4f5ef71..0000000
--- a/.hidden/docs/design-doc.md
+++ /dev/null
@@ -1,354 +0,0 @@
-# **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.
diff --git a/.hidden/docs/rambling.md b/.hidden/docs/rambling.md
deleted file mode 100644
index e69de29..0000000
diff --git a/.hidden/samples/samples.txt b/.hidden/samples/samples.txt
deleted file mode 100644
index bf4847c..0000000
--- a/.hidden/samples/samples.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Samples:
-- This folder will include sample datapacks
diff --git a/.hidden/src/SessionZero.Client/App.axaml b/.hidden/src/SessionZero.Client/App.axaml
deleted file mode 100644
index 99d86a9..0000000
--- a/.hidden/src/SessionZero.Client/App.axaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/App.axaml.cs b/.hidden/src/SessionZero.Client/App.axaml.cs
deleted file mode 100644
index 415fbb3..0000000
--- a/.hidden/src/SessionZero.Client/App.axaml.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using Avalonia;
-using Avalonia.Controls.ApplicationLifetimes;
-using Avalonia.Data.Core;
-using Avalonia.Data.Core.Plugins;
-using System.Linq;
-using Avalonia.Markup.Xaml;
-using SessionZero.Client.ViewModels;
-using SessionZero.Client.Views;
-
-namespace SessionZero.Client;
-
-public partial class App : Application
-{
- public override void Initialize()
- {
- AvaloniaXamlLoader.Load(this);
- }
-
- public override void OnFrameworkInitializationCompleted()
- {
- if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- {
- // Avoid duplicate validations from both Avalonia and the CommunityToolkit.
- // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
- DisableAvaloniaDataAnnotationValidation();
- desktop.MainWindow = new MainWindow
- {
- DataContext = new MainWindowViewModel(),
- };
- }
-
- base.OnFrameworkInitializationCompleted();
- }
-
- private void DisableAvaloniaDataAnnotationValidation()
- {
- // Get an array of plugins to remove
- var dataValidationPluginsToRemove =
- BindingPlugins.DataValidators.OfType().ToArray();
-
- // remove each entry found
- foreach (var plugin in dataValidationPluginsToRemove)
- {
- BindingPlugins.DataValidators.Remove(plugin);
- }
- }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/Assets/avalonia-logo.ico b/.hidden/src/SessionZero.Client/Assets/avalonia-logo.ico
deleted file mode 100644
index f7da8bb..0000000
Binary files a/.hidden/src/SessionZero.Client/Assets/avalonia-logo.ico and /dev/null differ
diff --git a/.hidden/src/SessionZero.Client/Program.cs b/.hidden/src/SessionZero.Client/Program.cs
deleted file mode 100644
index 0addfe3..0000000
--- a/.hidden/src/SessionZero.Client/Program.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Avalonia;
-using System;
-
-namespace SessionZero.Client;
-
-sealed class Program
-{
- // Initialization code. Don't use any Avalonia, third-party APIs or any
- // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
- // yet and stuff might break.
- [STAThread]
- public static void Main(string[] args) => BuildAvaloniaApp()
- .StartWithClassicDesktopLifetime(args);
-
- // Avalonia configuration, don't remove; also used by visual designer.
- public static AppBuilder BuildAvaloniaApp()
- => AppBuilder.Configure()
- .UsePlatformDetect()
- .WithInterFont()
- .LogToTrace();
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/SessionZero.Client.csproj b/.hidden/src/SessionZero.Client/SessionZero.Client.csproj
deleted file mode 100644
index 939b4e4..0000000
--- a/.hidden/src/SessionZero.Client/SessionZero.Client.csproj
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
- WinExe
- net9.0
- enable
- true
- app.manifest
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- None
- All
-
-
-
-
-
-
-
-
diff --git a/.hidden/src/SessionZero.Client/ViewLocator.cs b/.hidden/src/SessionZero.Client/ViewLocator.cs
deleted file mode 100644
index d59f1cb..0000000
--- a/.hidden/src/SessionZero.Client/ViewLocator.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using Avalonia.Controls;
-using Avalonia.Controls.Templates;
-using SessionZero.Client.ViewModels;
-
-namespace SessionZero.Client;
-
-public class ViewLocator : IDataTemplate
-{
- public Control? Build(object? param)
- {
- if (param is null)
- return null;
-
- var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
- var type = Type.GetType(name);
-
- if (type != null)
- {
- return (Control)Activator.CreateInstance(type)!;
- }
-
- return new TextBlock { Text = "Not Found: " + name };
- }
-
- public bool Match(object? data)
- {
- return data is ViewModelBase;
- }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/ViewModels/MainWindowViewModel.cs b/.hidden/src/SessionZero.Client/ViewModels/MainWindowViewModel.cs
deleted file mode 100644
index 799c449..0000000
--- a/.hidden/src/SessionZero.Client/ViewModels/MainWindowViewModel.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace SessionZero.Client.ViewModels;
-
-public partial class MainWindowViewModel : ViewModelBase
-{
- public string Greeting { get; } = "Welcome to Avalonia!";
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/ViewModels/ViewModelBase.cs b/.hidden/src/SessionZero.Client/ViewModels/ViewModelBase.cs
deleted file mode 100644
index 3873adc..0000000
--- a/.hidden/src/SessionZero.Client/ViewModels/ViewModelBase.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using CommunityToolkit.Mvvm.ComponentModel;
-
-namespace SessionZero.Client.ViewModels;
-
-public class ViewModelBase : ObservableObject
-{
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/Views/MainWindow.axaml b/.hidden/src/SessionZero.Client/Views/MainWindow.axaml
deleted file mode 100644
index 81ce6f2..0000000
--- a/.hidden/src/SessionZero.Client/Views/MainWindow.axaml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/.hidden/src/SessionZero.Client/Views/MainWindow.axaml.cs b/.hidden/src/SessionZero.Client/Views/MainWindow.axaml.cs
deleted file mode 100644
index 44ac4e8..0000000
--- a/.hidden/src/SessionZero.Client/Views/MainWindow.axaml.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Avalonia.Controls;
-
-namespace SessionZero.Client.Views;
-
-public partial class MainWindow : Window
-{
- public MainWindow()
- {
- InitializeComponent();
- }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Client/app.manifest b/.hidden/src/SessionZero.Client/app.manifest
deleted file mode 100644
index eb09286..0000000
--- a/.hidden/src/SessionZero.Client/app.manifest
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.hidden/src/SessionZero.Server/Program.cs b/.hidden/src/SessionZero.Server/Program.cs
deleted file mode 100644
index d5e0ef3..0000000
--- a/.hidden/src/SessionZero.Server/Program.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-var builder = WebApplication.CreateBuilder(args);
-
-// Add services to the container.
-// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
-builder.Services.AddOpenApi();
-
-var app = builder.Build();
-
-// Configure the HTTP request pipeline.
-if (app.Environment.IsDevelopment())
-{
- app.MapOpenApi();
-}
-
-app.UseHttpsRedirection();
-
-var summaries = new[]
-{
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
-};
-
-app.MapGet("/weatherforecast", () =>
- {
- var forecast = Enumerable.Range(1, 5).Select(index =>
- new WeatherForecast
- (
- DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
- Random.Shared.Next(-20, 55),
- summaries[Random.Shared.Next(summaries.Length)]
- ))
- .ToArray();
- return forecast;
- })
- .WithName("GetWeatherForecast");
-
-app.Run();
-
-record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
-{
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Server/Properties/launchSettings.json b/.hidden/src/SessionZero.Server/Properties/launchSettings.json
deleted file mode 100644
index def5fae..0000000
--- a/.hidden/src/SessionZero.Server/Properties/launchSettings.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/launchsettings.json",
- "profiles": {
- "http": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": false,
- "applicationUrl": "http://localhost:5227",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "https": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": false,
- "applicationUrl": "https://localhost:7090;http://localhost:5227",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- }
- }
-}
diff --git a/.hidden/src/SessionZero.Server/SessionZero.Server.csproj b/.hidden/src/SessionZero.Server/SessionZero.Server.csproj
deleted file mode 100644
index 63257cb..0000000
--- a/.hidden/src/SessionZero.Server/SessionZero.Server.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- net9.0
- enable
- enable
-
-
-
-
-
-
-
diff --git a/.hidden/src/SessionZero.Server/SessionZero.Server.http b/.hidden/src/SessionZero.Server/SessionZero.Server.http
deleted file mode 100644
index 57ddf6a..0000000
--- a/.hidden/src/SessionZero.Server/SessionZero.Server.http
+++ /dev/null
@@ -1,6 +0,0 @@
-@SessionZero.Server_HostAddress = http://localhost:5227
-
-GET {{SessionZero.Server_HostAddress}}/weatherforecast/
-Accept: application/json
-
-###
diff --git a/.hidden/src/SessionZero.Server/appsettings.Development.json b/.hidden/src/SessionZero.Server/appsettings.Development.json
deleted file mode 100644
index 0c208ae..0000000
--- a/.hidden/src/SessionZero.Server/appsettings.Development.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- }
-}
diff --git a/.hidden/src/SessionZero.Server/appsettings.json b/.hidden/src/SessionZero.Server/appsettings.json
deleted file mode 100644
index 10f68b8..0000000
--- a/.hidden/src/SessionZero.Server/appsettings.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- },
- "AllowedHosts": "*"
-}
diff --git a/.hidden/src/SessionZero.Shared/Models/CharacterTemplate.cs b/.hidden/src/SessionZero.Shared/Models/CharacterTemplate.cs
deleted file mode 100644
index 33dcd12..0000000
--- a/.hidden/src/SessionZero.Shared/Models/CharacterTemplate.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace SessionZero.Shared.Models;
-
-public class CharacterTemplate : TemplateBase
-{
-
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/Models/Datapack.cs b/.hidden/src/SessionZero.Shared/Models/Datapack.cs
deleted file mode 100644
index d7f98d8..0000000
--- a/.hidden/src/SessionZero.Shared/Models/Datapack.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace SessionZero.Shared.Models;
-
-///
-/// The model for a datapack (used for the szpack.json file).
-///
-public class Datapack
-{
- public required Guid Id { get; set; }
- public required string Name { get; set; }
- public required string Version { get; set; }
- public required string Author { get; set; }
- public required string License { get; set; }
- public string Description { get; set; } = string.Empty;
- public required DateTime CreatedAt { get; set; }
- public required string SessionZeroVersion { get; set; }
-
- public List Dependencies { get; set; } = new();
-}
-
-///
-/// Represents a dependency of a datapack.
-///
-public class DatapackDependency
-{
- public required Guid Id { get; set; }
- public required string Name { get; set; }
- public required string Version { get; set; }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/Models/Dataset.cs b/.hidden/src/SessionZero.Shared/Models/Dataset.cs
deleted file mode 100644
index c9e6d87..0000000
--- a/.hidden/src/SessionZero.Shared/Models/Dataset.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using SessionZero.Shared.Schema;
-
-namespace SessionZero.Shared.Models;
-
-public class Dataset : SzObject
-{
- ///
- /// Arbitrary string used to identify the dataset type (e.g. "items", "quests", "npcs", etc.).
- ///
- public required string DatasetType { get; set; }
-
- ///
- /// The entries in the dataset.
- ///
- public required Dictionary Entries { get; set; } = new();
-
- ///
- /// Retrieves a FieldValue from the dataset using a dot-separated path.
- /// Format: [EntryName].[FieldName] or [EntryName].[GroupName].[FieldName]
- ///
- /// The dot-separated path to the field.
- /// The FieldValue if found, otherwise null.
- public FieldValue? GetField(string fieldName)
- {
- var split = fieldName.Split('.');
-
- // Path must contain at least EntryName.FieldName (length 2)
- if (split.Length < 2 || split.Length > 3)
- {
- return null;
- }
-
- var entryName = split[0];
- if (!Entries.TryGetValue(entryName, out var entry))
- {
- return null;
- }
-
- if (split.Length == 2)
- {
- // Format: EntryName.FieldName (Top-level field)
- var fName = split[1];
-
- if (entry.TopLevelFields is null) return null;
-
- return entry.TopLevelFields.TryGetValue(fName, out var value) ? value : null;
- }
- else
- {
- // Format: EntryName.GroupName.FieldName
- var groupName = split[1];
- var fName = split[2];
-
- if (entry.Groups is null) return null;
-
- var dataGroup = entry.Groups.FirstOrDefault(g => g.Name == groupName);
-
- if (dataGroup is null || dataGroup.Fields is null)
- {
- return null;
- }
-
- return dataGroup.Fields.TryGetValue(fName, out var value) ? value : null;
- }
- }
-
- ///
- /// Sets a FieldValue in the dataset using a dot-separated path.
- /// Format: [EntryName].[FieldName] or [EntryName].[GroupName].[FieldName]
- ///
- /// The dot-separated path to the field.
- /// The value to set.
- /// True if the value was set, false otherwise
- public static bool SetField(string fieldName, FieldValue value)
- {
- // TODO: Implementation for SetField
- return false;
- }
-}
-
diff --git a/.hidden/src/SessionZero.Shared/Models/SessionTemplate.cs b/.hidden/src/SessionZero.Shared/Models/SessionTemplate.cs
deleted file mode 100644
index 4ab3277..0000000
--- a/.hidden/src/SessionZero.Shared/Models/SessionTemplate.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using SessionZero.Shared.Schema;
-
-namespace SessionZero.Shared.Models;
-
-public class SessionTemplate : TemplateBase
-{
- ///
- /// Reference to the required Character Template for character creation in this session.
- ///
- public required CharacterTemplateLink CharacterTemplateLink { get; set; }
-
- ///
- /// List of required Datasets that this session template depends on
- /// (datapack ids must be present in the DatapackDependency list in the datapack object)
- ///
- public required List RequiredDatasets { get; set; } = new();
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/Models/SzObject.cs b/.hidden/src/SessionZero.Shared/Models/SzObject.cs
deleted file mode 100644
index 6002bbb..0000000
--- a/.hidden/src/SessionZero.Shared/Models/SzObject.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace SessionZero.Shared.Models;
-
-public class SzObject
-{
- public required string Id { get; set; }
- public required string Name { get; set; }
- public required string SzType { get; set; }
- public string Description { get; set; } = string.Empty;
- public string Icon { get; set; } = string.Empty;
- public required string Version { get; set; }
- public required string SchemaVersion { get; set; }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/Models/TemplateBase.cs b/.hidden/src/SessionZero.Shared/Models/TemplateBase.cs
deleted file mode 100644
index fa32fb5..0000000
--- a/.hidden/src/SessionZero.Shared/Models/TemplateBase.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using SessionZero.Shared.Schema;
-
-namespace SessionZero.Shared.Models;
-
-///
-/// Base class for templates.
-///
-public class TemplateBase : SzObject
-{
- public required List Sections { get; set; } = new();
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/Schema/Schema.cs b/.hidden/src/SessionZero.Shared/Schema/Schema.cs
deleted file mode 100644
index 24921d2..0000000
--- a/.hidden/src/SessionZero.Shared/Schema/Schema.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-namespace SessionZero.Shared.Schema;
-
-///
-/// Valid types for fields.
-///
-public enum FieldType
-{
- Text,
- MultiText,
- Number,
- Boolean,
- Formula,
- List
-}
-
-///
-/// Represents a list of allowed values for a field with type List.
-///
-public class SzListType
-{
- // NOTE: Only one of these lists should be allowed
- public List? AllowedDatasetTypes { get; set; }
- public List? AllowedDatasetIds { get; set; }
- public string? CustomValues { get; set; }
-}
-
-///
-/// Represents a formula field.
-///
-public class SzFormulaType
-{
- // TODO: Implement a way to parse formulas
- public string? Formula { get; set; }
-}
-
-///
-/// Used to link a dataset in other data or template objects.
-///
-public class DatasetLink
-{
- public required Guid DatapackId { get; set; }
- public required string DatasetId { get; set; }
- public required string Version { get; set; }
-}
-
-///
-/// Used to link a character template in other template objects.
-///
-public class CharacterTemplateLink
-{
- public required Guid DatapackId { get; set; }
- public required string TemplateId { get; set; }
- public required string Version { get; set; }
-}
-
-///
-/// Represents a field value.
-///
-public class FieldValue
-{
- public required FieldType Type { get; set; }
- public required object Value { get; set; }
-}
-
-///
-/// Represents a group of fields in a dataset.
-///
-public class DataGroup
-{
- public required string Id { get; set; }
- public required string Name { get; set; }
- public required Dictionary Fields { get; set; } = new();
-}
-
-///
-/// Represents a dataset entry used in datasets.
-///
-public class DatasetEntry
-{
- public required string Id { get; set; }
- public required string Name { get; set; }
- public string Description { get; set; } = string.Empty;
- public string Icon { get; set; } = string.Empty;
-
- public Dictionary? TopLevelFields { get; set; } = new();
- public List? Groups { get; set; } = new();
-}
-
-///
-/// Represents a section in a template that houses multiple groups.
-///
-public class TemplateSection
-{
- public required string Id { get; set; }
- public required string Name { get; set; }
- public required List Groups { get; set; } = new();
-}
-
-///
-/// Represents a group of fields in a template.
-///
-public class TemplateGroup
-{
- public required string Id { get; set; }
- public required string Name { get; set; }
- public required List? Fields { get; set; } = new();
-}
-
-///
-/// Represents a field definition in a template
-/// (Does not hold actual field values as templates are meant to be filled in upon instance creation).
-///
-public class TemplateFieldDefinition
-{
- public required string Id { get; set; }
- public required string Name { get; set; }
- public required FieldType Type { get; set; }
- public object? DefaultValue { get; set; }
- public DatasetLink? DatasetLink { get; set; }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/Services/DatapackService.cs b/.hidden/src/SessionZero.Shared/Services/DatapackService.cs
deleted file mode 100644
index b657d63..0000000
--- a/.hidden/src/SessionZero.Shared/Services/DatapackService.cs
+++ /dev/null
@@ -1,172 +0,0 @@
-using System.Text.Json;
-using SessionZero.Shared.Models;
-using System.IO;
-using System.Threading.Tasks;
-using System;
-using System.Collections.Generic;
-using System.IO.Compression;
-
-namespace SessionZero.Shared.Services;
-
-public static class DatapackService
-{
- private static readonly JsonSerializerOptions JsonOptions = new()
- {
- WriteIndented = true,
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase
- };
-
- ///
- /// Creates a new Datapack model with required metadata.
- ///
- /// The display name of the datapack.
- /// The initial version string (e.g., "1.0.0").
- /// The pack creator's name.
- /// The license (e.g., "CC-BY-SA-4.0").
- /// A fully initialized Datapack model.
- public static Datapack CreateEmptyDatapack(string name, string version, string author, string license)
- {
- return new Datapack
- {
- Id = Guid.NewGuid(),
- Name = name,
- Version = version,
- Author = author,
- License = license,
- Description = String.Empty,
- CreatedAt = DateTime.UtcNow,
- SessionZeroVersion = "0.0.1",
- Dependencies = new()
- };
- }
-
- ///
- /// Serializes a Datapack model and saves it to a file named 'szpack.json'
- /// inside a new subdirectory named after the datapack's slug.
- ///
- /// The Datapack object to save.
- /// The directory where the new datapack folder will be created.
- /// The full path to the created szpack.json file.
- public static async Task SaveDatapackMetadataAsync(Datapack datapack, string parentDirectoryPath)
- {
- var packDirectoryName = datapack.Name.ToLower().Replace(' ', '-').Trim();
- var packRootDirectory = Path.Combine(parentDirectoryPath, packDirectoryName);
-
- Directory.CreateDirectory(packRootDirectory);
-
- var filePath = Path.Combine(packRootDirectory, "szpack.json");
-
- var jsonString = JsonSerializer.Serialize(datapack, JsonOptions);
- await File.WriteAllTextAsync(filePath, jsonString);
-
- return filePath;
- }
-
- ///
- /// Serializes an SzObject (Dataset, Template, etc.) and saves it to a file.
- ///
- /// The type of the object, must inherit from SzObject.
- /// The object to save.
- /// The specific subdirectory (e.g., 'datasets') within the datapack root.
- /// The full path to the created JSON file.
- public static async Task SaveSzObjectAsync(T szObject, string directoryPath) where T : SzObject
- {
- Directory.CreateDirectory(directoryPath);
-
- var fileName = $"{szObject.Id}.json";
- var filePath = Path.Combine(directoryPath, fileName);
- var jsonString = JsonSerializer.Serialize(szObject, JsonOptions);
- await File.WriteAllTextAsync(filePath, jsonString);
-
- return filePath;
- }
-
- ///
- /// Defines and creates the standard directory structure for a SessionZero datapack.
- ///
- /// The root directory path of the new datapack.
- /// A dictionary containing the standard folder names and their absolute paths.
- public static Dictionary CreateDatapackDirectoryStructure(string rootPath)
- {
- var structure = new Dictionary
- {
- { "datasets", Path.Combine(rootPath, "datasets") },
- { "character_templates", Path.Combine(rootPath, "characters") },
- { "session_templates", Path.Combine(rootPath, "sessions") },
- { "media", Path.Combine(rootPath, "media") },
- { "images", Path.Combine(rootPath, "media", "images") }
- };
-
- foreach (var path in structure.Values)
- {
- Directory.CreateDirectory(path);
- }
-
- return structure;
- }
-
- ///
- /// Compresses a datapack directory into a .szpack zip archive.
- ///
- /// The path to the datapack's root directory.
- /// The full path and filename for the output .szpack file.
- public static void PackDatapack(string sourceDirectoryPath, string outputFilePath)
- {
- if (!Directory.Exists(sourceDirectoryPath))
- {
- throw new DirectoryNotFoundException($"Source directory not found: {sourceDirectoryPath}");
- }
-
- if (File.Exists(outputFilePath))
- {
- File.Delete(outputFilePath);
- }
-
- ZipFile.CreateFromDirectory(sourceDirectoryPath, outputFilePath);
- }
-
- ///
- /// Extracts a .szpack zip archive into a target directory.
- ///
- /// The path to the .szpack file.
- /// The directory where the contents will be extracted.
- public static void UnpackDatapack(string sourceFilePath, string destinationDirectoryPath)
- {
- if (!File.Exists(sourceFilePath))
- {
- throw new FileNotFoundException($"Datapack file not found: {sourceFilePath}");
- }
-
- Directory.CreateDirectory(destinationDirectoryPath);
-
- ZipFile.ExtractToDirectory(sourceFilePath, destinationDirectoryPath, overwriteFiles: true);
- }
-
- ///
- /// Deserializes and loads the core Datapack metadata (szpack.json) from a directory.
- ///
- /// The path to the datapack's root directory.
- /// A Datapack model containing the metadata.
- /// Thrown if szpack.json is not found.
- /// Thrown if deserialization fails.
- public static async Task LoadDatapackMetadataAsync(string datapackRootPath)
- {
- var filePath = Path.Combine(datapackRootPath, "szpack.json");
-
- if (!File.Exists(filePath))
- {
- throw new FileNotFoundException($"The required metadata file 'szpack.json' was not found in: {datapackRootPath}", filePath);
- }
-
- var jsonString = await File.ReadAllTextAsync(filePath);
-
- var datapack = JsonSerializer.Deserialize(jsonString, JsonOptions);
-
- if (datapack is null)
- {
- throw new JsonException($"Failed to deserialize szpack.json from {filePath}. The file may be corrupt or invalid.");
- }
-
- return datapack;
- }
-}
\ No newline at end of file
diff --git a/.hidden/src/SessionZero.Shared/SessionZero.Shared.csproj b/.hidden/src/SessionZero.Shared/SessionZero.Shared.csproj
deleted file mode 100644
index 17b910f..0000000
--- a/.hidden/src/SessionZero.Shared/SessionZero.Shared.csproj
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- net9.0
- enable
- enable
-
-
-
diff --git a/.hidden/src/SessionZero.Shared/Validation/DatapackValidator.cs b/.hidden/src/SessionZero.Shared/Validation/DatapackValidator.cs
deleted file mode 100644
index 828e9b2..0000000
--- a/.hidden/src/SessionZero.Shared/Validation/DatapackValidator.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-using SessionZero.Shared.Models;
-
-namespace SessionZero.Shared.Validation;
-
-public static class DatapackValidator
-{
- public static List ValidateDatapack(Datapack datapack)
- {
- var errors = new List();
-
- if (datapack.Id == Guid.Empty) errors.Add("Datapack 'Id' is required and must not be an empty GUID.");
-
- ValidateRequiredString(errors, datapack.Name, nameof(datapack.Name));
- ValidateRequiredString(errors, datapack.Version, nameof(datapack.Version));
- ValidateRequiredString(errors, datapack.Author, nameof(datapack.Author));
- ValidateRequiredString(errors, datapack.License, nameof(datapack.License));
- ValidateRequiredString(errors, datapack.SessionZeroVersion, nameof(datapack.SessionZeroVersion));
-
- if (datapack.CreatedAt == DateTime.MinValue) errors.Add("Datapack 'CreatedAt' is required and must not be an empty DateTime.");
-
- return errors;
- }
-
- public static List ValidateSzObject(SzObject szObject)
- {
- var errors = new List();
- var objectName = szObject.Id;
-
- ValidateRequiredString(errors, szObject.Id, $"{objectName}'s Id");
- ValidateRequiredString(errors, szObject.Name, $"{objectName}'s Name");
- ValidateRequiredString(errors, szObject.SzType, $"{objectName}'s SzType");
- ValidateRequiredString(errors, szObject.Version, $"{objectName}'s Version");
- ValidateRequiredString(errors, szObject.SchemaVersion, $"{objectName}'s SchemaVersion");
-
- // 2. Validate Icon path format (optional/future: e.g., only allows alphanumeric + slashes + extension)
- // For now, we'll only check if it's not null, which is done by the property definition in SzObject.
-
- return errors;
- }
-
- private static void ValidateRequiredString(List errors, string? value, string fieldName)
- {
- if (string.IsNullOrWhiteSpace(value)) errors.Add($"'{fieldName}' is required and must not be empty.");
- }
-}
\ No newline at end of file
diff --git a/.hidden/tools/szpack/CreateCommand.cs b/.hidden/tools/szpack/CreateCommand.cs
deleted file mode 100644
index 6a1fd25..0000000
--- a/.hidden/tools/szpack/CreateCommand.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * WARNING:
- * This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
- * It was created to be used as a quick and dirty validation tool for the szpack format.
-*/
-
-using SessionZero.Shared.Models;
-using SessionZero.Shared.Services;
-using Spectre.Console;
-using Spectre.Console.Cli;
-using System.ComponentModel;
-using System.Diagnostics.CodeAnalysis;
-
-namespace SessionZero.Tools.Packer;
-
-// Settings class defines the command-line arguments
-public class CreateSettings : CommandSettings
-{
- [CommandArgument(0, "")]
- [Description("The display name of the datapack (e.g., 'My Fantasy Spells').")]
- public required string Name { get; init; }
-
- [CommandArgument(1, "[author]")]
- [Description("The author's name.")]
- [DefaultValue("Test Author")]
- public string Author { get; init; } = "Test Author";
-
- [CommandOption("-o|--output")]
- [Description("The parent directory where the new pack folder will be created.")]
- [DefaultValue(".")]
- public string Output { get; init; } = Environment.CurrentDirectory;
-}
-
-public class CreateCommand : AsyncCommand
-{
- public override async Task ExecuteAsync([NotNull] CommandContext context, [NotNull] CreateSettings settings, CancellationToken cancellationToken)
- {
- AnsiConsole.MarkupLine($"\n[bold white on blue] --- Creating Datapack: '{settings.Name}' --- [/]");
-
- try
- {
- // 1. Create the top-level model and save szpack.json
- var newPack = DatapackService.CreateEmptyDatapack(settings.Name, "1.0.0", settings.Author, "MIT");
- var szpackPath = await DatapackService.SaveDatapackMetadataAsync(newPack, settings.Output);
- var packRootDirectory = Path.GetDirectoryName(szpackPath)!;
-
- AnsiConsole.MarkupLine($"[green]✅ Created metadata file at: {szpackPath}[/]");
-
- // 2. Create the standard directory structure
- var structure = DatapackService.CreateDatapackDirectoryStructure(packRootDirectory);
- AnsiConsole.MarkupLine($"[green]✅ Created standard directories at: {packRootDirectory}[/]");
-
- // 3. Create and save test objects
- await CreateTestObjects(packRootDirectory, structure);
-
- AnsiConsole.MarkupLine("\n[bold]Creation Complete![/] Use 'szpack pack' to compress it.");
- return 0;
- }
- catch (Exception ex)
- {
- AnsiConsole.MarkupLine($"\n[bold white on red]❌ ERROR:[/] Failed to create datapack. Details: {ex.Message}");
- return 1;
- }
- }
-
- // Helper method for creating test objects (copied from previous Program.cs)
- private static async Task CreateTestObjects(string rootPath, Dictionary structure)
- {
- // ... (Test object creation logic remains the same, ensure you have the necessary usings in this file)
-
- // --- Test object creation logic (omitted for brevity, assume the previous logic is here) ---
- var testDataset = new Dataset { /* ... test data ... */ Id = "basic-attributes", Name = "Basic Character Attributes", SzType = "Dataset", Version = "1.0.0", SchemaVersion = "1.0.0", DatasetType = "Attribute", Entries = new() };
- var dsPath = await DatapackService.SaveSzObjectAsync(testDataset, structure["datasets"]);
- AnsiConsole.MarkupLine($" -> Saved Test Dataset: [yellow]{Path.GetFileName(dsPath)}[/]");
-
- var testCharTemplate = new CharacterTemplate { /* ... test data ... */ Id = "default-char-sheet", Name = "Default Character Template", SzType = "Template", Version = "1.0.0", SchemaVersion = "1.0.0", Sections = new() };
- var charPath = await DatapackService.SaveSzObjectAsync(testCharTemplate, structure["character_templates"]);
- AnsiConsole.MarkupLine($" -> Saved Test Character Template: [yellow]{Path.GetFileName(charPath)}[/]");
-
- var testSessionTemplate = new SessionTemplate
- {
- /* ... test data ... */ Id = "basic-encounter",
- Name = "Basic Encounter Template",
- SzType = "Template",
- Version = "1.0.0",
- SchemaVersion = "1.0.0",
- CharacterTemplateLink = new()
- {
- DatapackId = Guid.Empty,
- TemplateId = testCharTemplate.Id,
- Version = testCharTemplate.Version
- },
- RequiredDatasets = new()
- {
- new()
- {
- DatapackId = Guid.Empty,
- DatasetId = testDataset.Id,
- Version = testDataset.Version
- }
- },
- Sections = new()
- };
- var sessionPath = await DatapackService.SaveSzObjectAsync(testSessionTemplate, structure["session_templates"]);
- AnsiConsole.MarkupLine($" -> Saved Test Session Template: [yellow]{Path.GetFileName(sessionPath)}[/]");
- }
-}
\ No newline at end of file
diff --git a/.hidden/tools/szpack/PackCommand.cs b/.hidden/tools/szpack/PackCommand.cs
deleted file mode 100644
index 7e6c411..0000000
--- a/.hidden/tools/szpack/PackCommand.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * WARNING:
- * This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
- * It was created to be used as a quick and dirty validation tool for the szpack format.
-*/
-
-using SessionZero.Shared.Services;
-using Spectre.Console;
-using Spectre.Console.Cli;
-using System.ComponentModel;
-using System.Diagnostics.CodeAnalysis;
-
-namespace SessionZero.Tools.Packer;
-
-public class PackSettings : CommandSettings
-{
- [CommandArgument(0, "")]
- [Description("The root directory of the datapack to pack.")]
- public required string Input { get; init; }
-}
-
-public class PackCommand : Command
-{
- public override int Execute([NotNull] CommandContext context, [NotNull] PackSettings settings, CancellationToken cancellationToken)
- {
- AnsiConsole.MarkupLine($"\n[bold white on blue] --- Packing Datapack: {settings.Input} --- [/]");
- try
- {
- var packDirectoryName = new DirectoryInfo(settings.Input).Name;
- var outputFilePath = Path.Combine(Path.GetDirectoryName(settings.Input) ?? Environment.CurrentDirectory, $"{packDirectoryName}.szpack");
-
- DatapackService.PackDatapack(settings.Input, outputFilePath);
-
- AnsiConsole.MarkupLine($"[green]✅ Successfully created archive: {outputFilePath}[/]");
- return 0;
- }
- catch (Exception ex)
- {
- AnsiConsole.MarkupLine($"\n[bold white on red]❌ ERROR:[/] Failed to pack datapack. Details: {ex.Message}");
- return 1;
- }
- }
-}
\ No newline at end of file
diff --git a/.hidden/tools/szpack/Program.cs b/.hidden/tools/szpack/Program.cs
deleted file mode 100644
index eb8b3ee..0000000
--- a/.hidden/tools/szpack/Program.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * WARNING:
- * This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
- * It was created to be used as a quick and dirty validation tool for the szpack format.
-*/
-
-using Spectre.Console.Cli;
-
-namespace SessionZero.Tools.Packer;
-
-internal class Program
-{
- static int Main(string[] args)
- {
- var app = new CommandApp();
-
- app.Configure(config =>
- {
- config.SetApplicationName("szpack");
-
- config.AddCommand("create")
- .WithDescription("Creates a new datapack directory with test objects.");
-
- config.AddCommand("pack")
- .WithDescription("Compresses a datapack directory into a .szpack file.");
-
- config.AddCommand("unpack")
- .WithDescription("Extracts a .szpack file and displays its metadata.");
-
- // Optional: Set a default command if no command is specified
- // config.SetDefaultCommand();
- });
-
- return app.Run(args);
- }
-}
\ No newline at end of file
diff --git a/.hidden/tools/szpack/UnpackCommand.cs b/.hidden/tools/szpack/UnpackCommand.cs
deleted file mode 100644
index 6509b2d..0000000
--- a/.hidden/tools/szpack/UnpackCommand.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * WARNING:
- * This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
- * It was created to be used as a quick and dirty validation tool for the szpack format.
-*/
-
-using SessionZero.Shared.Services;
-using Spectre.Console;
-using Spectre.Console.Cli;
-using System.ComponentModel;
-using System.Diagnostics.CodeAnalysis;
-
-namespace SessionZero.Tools.Packer;
-
-public class UnpackSettings : CommandSettings
-{
- [CommandArgument(0, "")]
- [Description("The path to the .szpack file.")]
- public required string Input { get; init; }
-
- [CommandOption("-o|--output")]
- [Description("The directory where the pack will be extracted.")]
- [DefaultValue("unpacked")]
- public string Output { get; init; } = "unpacked";
-}
-
-public class UnpackCommand : AsyncCommand
-{
- public override async Task ExecuteAsync([NotNull] CommandContext context, [NotNull] UnpackSettings settings, CancellationToken cancellationToken)
- {
- AnsiConsole.MarkupLine($"\n[bold white on blue] --- Unpacking Datapack: {settings.Input} --- [/]");
- try
- {
- // Unpack the archive
- DatapackService.UnpackDatapack(settings.Input, settings.Output);
- AnsiConsole.MarkupLine($"[green]✅ Successfully unpacked archive to: {settings.Output}[/]");
-
- // Load and display the core data
- var datapack = await DatapackService.LoadDatapackMetadataAsync(settings.Output);
-
- AnsiConsole.MarkupLine("\n[bold]--- Datapack Info (szpack.json) ---[/]");
- AnsiConsole.MarkupLine($"[yellow]ID:[/]\t\t{datapack.Id}");
- AnsiConsole.MarkupLine($"[yellow]Name:[/]\t{datapack.Name}");
- AnsiConsole.MarkupLine($"[yellow]Version:[/]\t{datapack.Version}");
- AnsiConsole.MarkupLine($"[yellow]Author:[/]\t{datapack.Author}");
-
- return 0;
- }
- catch (Exception ex)
- {
- AnsiConsole.MarkupLine($"\n[bold white on red]❌ ERROR:[/] Failed to unpack or load datapack. Details: {ex.Message}");
- return 1;
- }
- }
-}
\ No newline at end of file
diff --git a/.hidden/tools/szpack/readme.md b/.hidden/tools/szpack/readme.md
deleted file mode 100644
index 4575808..0000000
--- a/.hidden/tools/szpack/readme.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# SZPACK CLI Tool
-
-## ***WARNING:***
-This tool was created by an LLM based on the SessionZero shared lib project, therefore it is subject to errors and does not reflect the architecture of the SessionZero project.
-It was created to be used as a quick and dirty validation tool for the szpack format.
-
-## Usage
-* `szpack create `: Creates a sample datapack directory with a given name
-* `szpack pack `: Packs a datapack directory into a szpack file (must be a valid datapack)
-* `szpack unpack `: Unpacks a .szpack file into a datapack directory and displays some metadata
\ No newline at end of file
diff --git a/.hidden/tools/szpack/szpack.csproj b/.hidden/tools/szpack/szpack.csproj
deleted file mode 100644
index 2437a23..0000000
--- a/.hidden/tools/szpack/szpack.csproj
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- Exe
- net9.0
- enable
- enable
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.hidden/tools/tools.txt b/.hidden/tools/tools.txt
deleted file mode 100644
index 94beeaa..0000000
--- a/.hidden/tools/tools.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Planned tools:
-- szpack: a cli tool for validating and packing szpack archives