Skip to content

Commit 4406faa

Browse files
committed
docs: update foundry module docs, fix migration numbering conflict
- foundry-module/.ai.md: Mark F-4.5/F-QoL/F-5 as DONE, add missing files (generic-adapter, sync-dashboard), update known limitations to reflect API-driven system matching and generic adapter - foundry-module/TESTING.md: Add generic adapter and sync dashboard test sections, update character sync prerequisites - .ai/status.md: Mark Phase 1 (Foundry Completion) as COMPLETE, update current phase and next session priorities - Renumber NPC addon migration from 000007 to 000009 to resolve conflict with campaign_invites (000007) after merge from main https://claude.ai/code/session_01WJEjfBqjZaGatHiXXXDupo
1 parent 13804a6 commit 4406faa

5 files changed

Lines changed: 80 additions & 31 deletions

File tree

.ai/status.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,15 @@ Branch: `claude/fix-journal-button-placement-UF4hD`.
237237

238238
## Phase & Sprint Plan
239239
See `.ai/phases.md` for the full roadmap. Phases organized by priority:
240-
1. **F**: Foundry Completion & QoL (F-4.5, F-QoL, F-5) ← CURRENT
240+
1. **F**: Foundry Completion & QoL (F-4.5, F-QoL, F-5) ← COMPLETE
241241
2. **X**: System Modularity & Owner Experience (X-1 through X-5)
242242
3. **W**: Maps & Spatial (W-2, W-2.5)
243243
4. **U**: Collaboration & Polish (U-1/2/3/4/5, W-1, W-4)
244244
5. **T**: Content & Integrations (T-3/4, W-3/5/6)
245245
6. **F**: Foundry Advanced (F-6, F-7)
246246

247247
## Current Phase
248-
**Phase 1: Foundry Completion — Sprint F-4.5 IN PROGRESS.**
248+
**Sprint 42: U-1 + W-1 + T-3.** Phase 1 (Foundry Completion: F-4.5, F-QoL, F-5) done. Next: Phase 2 (X-1: System Upload UX) or Phase 6 (F-6: Armory/Inventory).
249249

250250
### Sprint V-2: Backlinks Panel & Entity Aliases (COMPLETE)
251251
- **Fixed migration 060**: Removed incorrect first ALTER that tried to drop 'module' from ENUM directly, causing Error 1265. Kept correct 3-step approach.
@@ -686,9 +686,9 @@ Created `.ai/audit.md` — comprehensive feature parity and completeness audit c
686686
- Updated architecture.md directory structure to reflect systems/ path
687687

688688
## Next Session Should
689-
- **Sprint F-4.5: Generic System Adapter**Remove hardcoded SYSTEM_MAP, dynamic matching via API
690-
- **Sprint F-QoL: Foundry Sync Diagnostics**Validation report, health dashboard, error recovery
691-
- **Sprint F-5: NPC Viewer / Hall**Gallery of revealed NPCs
689+
- **W-1 Saved Filters**Persist command palette search filters per campaign
690+
- **Phase 2: X-1 System Upload UX**Guided wizard for system install
691+
- **Phase 6: F-6 Armory / Inventory System**Items as entities, character inventory, Foundry sync
692692
- See `.ai/phases.md` for full execution order
693693

694694
## Known Issues Right Now
File renamed without changes.
File renamed without changes.

foundry-module/.ai.md

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ v12/v13 module, connecting via REST API + WebSocket to the Chronicle backend.
1111
```
1212
module.mjs (entry point)
1313
└─ SyncManager (sync-manager.mjs)
14-
├─ ChronicleAPI (api-client.mjs) ← REST + WebSocket client
15-
├─ JournalSync (journal-sync.mjs) ← Entity ↔ JournalEntry
16-
├─ MapSync (map-sync.mjs) ← Map drawings/tokens ↔ Scene
17-
├─ CalendarSync (calendar-sync.mjs)← Calendar events/date ↔ Calendaria/SimpleCalendar
18-
├─ ShopWidget (shop-widget.mjs) ← Shop entity inventory in Foundry UI
19-
└─ ActorSync (actor-sync.mjs) ← Character entity ↔ Actor
20-
├─ dnd5e-adapter.mjs ← D&D 5e field mapping
21-
└─ pf2e-adapter.mjs ← Pathfinder 2e field mapping
14+
├─ ChronicleAPI (api-client.mjs) ← REST + WebSocket client
15+
├─ JournalSync (journal-sync.mjs) ← Entity ↔ JournalEntry
16+
├─ MapSync (map-sync.mjs) ← Map drawings/tokens ↔ Scene
17+
├─ CalendarSync (calendar-sync.mjs) ← Calendar events/date ↔ Calendaria/SimpleCalendar
18+
├─ ShopWidget (shop-widget.mjs) ← Shop entity inventory in Foundry UI
19+
├─ SyncDashboard (sync-dashboard.mjs) ← 6-tab ApplicationV2 status/management UI
20+
└─ ActorSync (actor-sync.mjs) ← Character entity ↔ Actor
21+
├─ dnd5e-adapter.mjs ← D&D 5e field mapping
22+
├─ pf2e-adapter.mjs ← Pathfinder 2e field mapping
23+
└─ generic-adapter.mjs ← Data-driven adapter (any system)
2224
```
2325

2426
### Data Flow
@@ -52,6 +54,9 @@ All sync modules use a `_syncing` boolean flag to prevent infinite loops:
5254
| `scripts/actor-sync.mjs` | Actor ↔ character entity bidirectional sync. System adapter loading, hook registration |
5355
| `scripts/adapters/dnd5e-adapter.mjs` | D&D 5e field mapping: 15 fields (ability scores, HP, AC, speed, level, class, race, alignment, proficiency_bonus) |
5456
| `scripts/adapters/pf2e-adapter.mjs` | PF2e field mapping: ability mods, HP, AC, perception, speed, level, class, ancestry, heritage. Only HP/name sync back |
57+
| `scripts/adapters/generic-adapter.mjs` | Data-driven adapter: fetches field defs from `/systems/:id/character-fields` API, auto-generates mappings from `foundry_path` annotations. Fallback for systems without a hand-written adapter |
58+
| `scripts/sync-dashboard.mjs` | 6-tab ApplicationV2 dashboard (Entities, Shops, Maps, Characters, Calendar, Status). Pull/push actions, health metrics, error log, search/filter |
59+
| `templates/sync-dashboard.hbs` | Handlebars template for the sync dashboard tabs and content |
5560
| `templates/shop-window.hbs` | Handlebars template for shop inventory display |
5661
| `styles/chronicle-sync.css` | Status indicator + shop window styles |
5762
| `lang/en.json` | English localization for all UI strings |
@@ -99,10 +104,10 @@ All sync modules use a `_syncing` boolean flag to prevent infinite loops:
99104
- **Single scene**: Only the active Foundry scene syncs (no multi-scene)
100105
- **GM only**: Full sync runs only for GM users; players get passive updates via Foundry
101106
- **Character sync: limited fields back from PF2e**: Only HP and name sync from Chronicle to PF2e actors (most values are derived from items/rules)
102-
- **Character sync: hardcoded adapters**: `_loadAdapter()` in actor-sync.mjs uses a switch statement that only loads dnd5e and pf2e adapters. Custom/uploaded game systems won't get character sync until F-4.5 (generic adapter) is implemented. The server infrastructure already supports it — custom systems can define `entity_presets` with a `-character` slug and field definitions. F-4.5 will replace the hardcoded switch with a generic adapter that reads field mappings from the Chronicle API.
103-
- **System ID mapping hardcoded**: `SYSTEM_MAP` in sync-manager.mjs only maps 3 Foundry system IDs. F-4.5 will query available systems from the API and match dynamically.
107+
- **Character sync: custom system requirements**: Custom game systems must include `foundry_path` annotations on their character preset fields for bidirectional sync. Systems without annotations get no character sync (the generic adapter returns null). dnd5e and pf2e have hand-written adapters that handle edge cases.
108+
- **System matching fallback**: `SYSTEM_MAP_FALLBACK` (3 entries: dnd5e, pf2e, drawsteel) in sync-manager.mjs is used only when the `/systems` API call fails or the system lacks a `foundry_system_id` in its manifest. Normal operation queries the API and matches dynamically.
104109

105-
## Planned Features (Phase F)
110+
## Features (Phase F)
106111

107112
See `.ai/todo.md` Phase F for full sprint breakdown.
108113

@@ -135,20 +140,31 @@ See `.ai/todo.md` Phase F for full sprint breakdown.
135140
- WS: `entity.created/updated/deleted` filtered by character type (via type_slug, type_name, or type_id)
136141
- Dashboard "Characters" tab: synced/unlinked actors, Push button, empty states
137142
- Delete from Chronicle unlinks Actor (preserves data); delete from Foundry deletes Chronicle entity
138-
- **Limitation**: Adapters are hardcoded per system. See F-4.5 for generic/dynamic adapter plan.
139-
140-
### F-4.5: Generic System Adapter & Dynamic System Matching (PLANNED)
141-
- **Goal**: Any game system (built-in or user-uploaded custom) works with character sync out of the box, with no Foundry module code changes required.
142-
- **Remove `SYSTEM_MAP` hardcoding**: Instead of mapping Foundry `game.system.id` → Chronicle system ID via a static JS object, query `GET /systems` and match by `foundry_system_id` field on the system manifest. Systems API already returns all registered systems. Add `foundry_system_id` to system manifest schema so custom uploads can declare their Foundry compatibility.
143-
- **Generic adapter**: New `adapters/generic-adapter.mjs` that reads character field definitions from the Chronicle API (`GET /systems/:id/character-fields` or from the character preset in the entity types response). For each field in the preset, it generates `toChronicleFields()` mappings (Foundry `system.*` → Chronicle `fields_data.*`) and `fromChronicleFields()` reverse mappings.
144-
- **Field mapping convention**: The generic adapter uses a convention-based approach: Chronicle field keys map to Foundry `system.<path>` using a `foundry_path` property on each field definition. Systems that declare `foundry_path` on their character preset fields get automatic bidirectional sync. Fields without `foundry_path` are pushed to Chronicle (read from Foundry's flat actor data) but not written back.
145-
- **Fallback to specific adapters**: dnd5e and pf2e adapters remain as overrides for known systems (they handle edge cases like PF2e's derived values). Generic adapter is the fallback for any system not in the override list.
146-
- **Server changes**: Add optional `foundry_system_id` and `foundry_path` fields to system manifest `entity_presets[].fields[]`. Expose character preset fields via API so the Foundry module can read them. Custom system upload already validates manifests, so these fields would be available on upload.
147-
- **Custom system workflow**: User uploads a custom game system ZIP to Chronicle with a manifest that includes `foundry_system_id: "my-system"` and character preset fields with `foundry_path` annotations. Foundry module auto-detects the system, reads field definitions from API, and syncs characters without any adapter code.
148-
149-
### F-5: NPC Viewer / Hall (website feature)
150-
- Campaign route `/campaigns/:id/npcs` — gallery of revealed NPCs
151-
- Foundry integration: ownership change on NPC journal → auto-reveal on Chronicle
143+
- dnd5e/pf2e adapters remain as overrides; generic adapter handles all other systems (see F-4.5).
144+
145+
### F-QoL: Foundry Sync Diagnostics & Error Handling (DONE)
146+
- `ValidationReport` type with `BuildValidationReport()` analyzing categories, fields, presets, Foundry compatibility
147+
- API client health metrics: success/error counts, uptime percentage, reconnect attempts, last timestamps
148+
- Structured error log (last 50 entries with timestamp, method, path, status, message)
149+
- Retry queue for failed write operations (processes on reconnect, max 3 retries, cap 50 items)
150+
- Dashboard Status tab: diagnostics grid, error log, field mapping debug info, activity log
151+
- Templ component shows capability badges + warnings after system upload
152+
153+
### F-4.5: Generic System Adapter & Dynamic System Matching (DONE)
154+
- `generic-adapter.mjs`: Fetches field definitions from `/systems/:id/character-fields` API. Auto-generates `toChronicleFields()`/`fromChronicleFields()` mappings from `foundry_path` annotations. Respects `foundry_writable` flag. Type casting for numbers.
155+
- `_detectSystem()` in sync-manager.mjs now API-driven: queries `/systems`, matches by `foundry_system_id`. Falls back to `SYSTEM_MAP_FALLBACK` for legacy support.
156+
- `_loadAdapter()` in actor-sync.mjs tries built-in adapters (dnd5e, pf2e) first, then falls back to generic adapter via `createGenericAdapter()`.
157+
- Server: `foundry_system_id` on `SystemManifest`, `foundry_path`/`foundry_writable` on `FieldDef`. `IsFoundryWritable()` helper. New `GET /systems/:id/character-fields` API. dnd5e (15 fields), pf2e (15 fields, most read-only), drawsteel annotated.
158+
- Custom system workflow: Upload ZIP with manifest including `foundry_system_id` and `foundry_path` annotations → Foundry module auto-detects, reads field defs from API, syncs characters without adapter code.
159+
- **Limitation**: Systems without `foundry_path` on their fields get no character sync.
160+
161+
### F-5: NPC Viewer / Hall (DONE)
162+
- NPC plugin at `internal/plugins/npcs/` with model/repo/service/handler/templates/routes
163+
- Campaign route `/campaigns/:id/npcs` — gallery/grid of revealed NPCs (non-private character entities)
164+
- Portrait, name, type label, tags. Search/sort/pagination. Reveal toggle via eye icon
165+
- `npc_gallery` layout block type for entity pages and dashboards
166+
- Foundry sync: NPC visibility changes sync bidirectionally — Chronicle `is_private` ↔ Foundry `prototypeToken.hidden`
167+
- REST API: `POST /entities/:id/reveal`. Sidebar navigation link. 7 tests
152168

153169
### F-6: Armory / Inventory System
154170
- Items with game-mechanic fields, character "Inventory" tab via relations

foundry-module/TESTING.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ Requires a running Chronicle instance and Foundry VTT with the chronicle-sync mo
151151
## Character Sync (Actor ↔ Entity)
152152

153153
### Prerequisites
154-
- [ ] Game system matches a Chronicle system (dnd5e or pf2e)
154+
- [ ] Game system matches a Chronicle system (built-in or custom with foundry_path annotations)
155155
- [ ] "Sync Characters" enabled in module settings
156156
- [ ] Character entity type exists in Chronicle campaign
157157

@@ -187,6 +187,16 @@ Requires a running Chronicle instance and Foundry VTT with the chronicle-sync mo
187187
- [ ] PF2e: Only HP and name sync back from Chronicle (derived values protected)
188188
- [ ] PF2e: ancestry, heritage, class, level, perception, speed push to Chronicle
189189

190+
### Generic Adapter (Custom Systems)
191+
- [ ] Custom system with foundry_path annotations → generic adapter loaded
192+
- [ ] Generic adapter maps annotated fields bidirectionally (Chronicle ↔ Foundry)
193+
- [ ] Fields with foundry_writable: false only push to Chronicle, not written back
194+
- [ ] System without foundry_path on any field → generic adapter returns null, character sync disabled
195+
- [ ] Type casting: number fields cast via Number(), string fields pass through
196+
- [ ] _detectSystem() matches by foundry_system_id from API (not SYSTEM_MAP)
197+
- [ ] _detectSystem() falls back to SYSTEM_MAP_FALLBACK when API fails
198+
- [ ] _loadAdapter() tries dnd5e/pf2e first, then generic adapter
199+
190200
### Edge Cases
191201
- [ ] Actor sync disabled when no system adapter available
192202
- [ ] Sync guard prevents infinite loops (change in A doesn't re-trigger back to A)
@@ -200,3 +210,26 @@ Requires a running Chronicle instance and Foundry VTT with the chronicle-sync mo
200210
- [ ] Network timeout during sync doesn't corrupt state
201211
- [ ] Partial sync failure (one entity fails) doesn't block others
202212
- [ ] Module gracefully handles Chronicle server restart
213+
214+
## Sync Dashboard
215+
216+
### Access
217+
- [ ] Click status indicator → dashboard opens (GM only)
218+
- [ ] Dashboard shows "Not configured" state when settings missing
219+
- [ ] Dashboard opens to last-active tab
220+
221+
### Tabs
222+
- [ ] Entities tab: entity list with sync status dots, pull/push actions, visibility toggle, search filter
223+
- [ ] Shops tab: shop entities with "Open Shop" button linking to ShopWidget
224+
- [ ] Maps tab: scene-to-map linking via dropdown, drawing/token counts
225+
- [ ] Characters tab: synced/unlinked actors, push button, system badge
226+
- [ ] Calendar tab: date comparison (Chronicle vs Foundry), pull/push buttons, module detection
227+
- [ ] Status tab: connection health, activity log, error log, diagnostics grid, system match info
228+
229+
### Diagnostics (F-QoL)
230+
- [ ] Health metrics: REST success/error counts, uptime percentage, reconnect attempts
231+
- [ ] Error log: last 50 errors with timestamp, method, path, status
232+
- [ ] Retry queue: failed writes queued and processed on reconnect (max 3 retries)
233+
- [ ] Activity log: last 100 sync actions with color-coded type icons
234+
- [ ] Clear log button resets activity log
235+
- [ ] Reconnect button triggers manual WebSocket reconnection

0 commit comments

Comments
 (0)