docs: add architecture reference for Claude context

This commit is contained in:
jessikitty committed 2026-09-23 13:41:20 +10:00
1 parent 160d9077b3
commit f340fe4886
1 file changed
+130
+130
View File
@@ -0,0 +1,130 @@
# Architecture Reference
_Last updated: 2026-09-23 (v1.5.9)_
## Data Flow
```
Disco DB (open jobs)
│
├─► ServiceTrackerService.BuildDashboard()
│ │
Google Sheet CSV │ ├─► BuildDiscoTile() ─┐
│ │ └─► BuildSheetTile() ─┤
▼ │ ▼
GoogleSheetService List<DashboardTile>
(fetch → cache → parse) │
▼
Bucket sort into:
- ReadyForReturn
- OnHold
- AwaitingVendor
- AwaitingParts
- Tiles (main grid)
│
▼
DashboardViewModel
│
▼
WebHandler → HTML string
```
## Persistence (JSON files)
All under `App_Data/Plugins/Disco.Plugins.ServiceTracker/`:
| File | Contents |
|------|---------|
| `config.json` | `ServiceTrackerConfig` — priorities, locations, statuses, technicians, sheet config |
| `tickets/` | One JSON file per Disco job (`{jobId}.json`) — `ServiceTicket` overrides, notes, changelog |
| `external_tickets/` | One JSON file per NTT sheet row (`{internalId}.json`) — same shape as ServiceTicket |
| `sheet_cache.csv` | Last fetched CSV from Google; invalidated by `RefreshMinutes` |
## ID Generation for NTT Tickets
Stable integer ID from djb2 hash of `timestamp|email|task|issue` (lowercased, trimmed), modulo 800000 + 100000 offset. Collisions resolved by incrementing. IDs are stable across refreshes as long as those four fields don't change.
## Column Index Contract
All Google Sheet column indices live in `GoogleSheetConfig`. Current mapping (updated 2026-09-23):
```
0 ColTimestamp — Timestamp
1 ColEmail — Email address
2 ColTask — What is the task/request?
3 ColIssue — Detailed Description
4 ColLocation — Location / Classroom
5 ColRequestedBy — Requested By
6 ColPriority — Priority Level
7 ColPreferredDate — Preferred Completion Date
8 ColCampus — Campus (location fallback if ColLocation empty)
9 ColAssignedTo — Assigned to
10 ColStatus — Status
11 — — Column 1 (junk, ignored)
12 — — Campus duplicate (ignored)
13 ColNotes — Notes
14 — — Category (ignored)
15 — — Resolution Confirmed (ignored)
ColCompletionDate = -1 (no dedicated column; disabled)
```
Set any index to `-1` to disable it. `SafeGet()` returns null for index < 0.
## Sidebar Bucket Logic
Buckets are evaluated in priority order and are mutually exclusive:
```csharp
rfr = status contains "ready for return" OR "ready for pickup"
onHold = status contains "on hold" AND NOT in rfr
awaitingVendor= status contains "awaiting vendor" AND NOT in rfr, onHold
awaitingParts = status contains "awaiting parts" AND NOT in rfr, onHold, awaitingVendor
main = everything else
```
Status is checked against `StatusOverride ?? DiscoStatus`.
## NTT Closed Ticket Suppression
NTT tickets are skipped in `BuildDashboard` if their saved `StatusOverride` contains any of:
`resolved, dismissed, complete, closed, done, cancel, finished`
This is independent of the sheet's own status column — it prevents jobs dismissed in the tracker from reappearing on every sheet refresh.
## Location Resolution for NTT Tiles
```
ExternalTicket.Location (from ColLocation)
└─ empty? → try ColCampus
└─ still empty? → null
MatchSheetLocation(raw):
1. Exact ID match against cfg.Locations
2. Exact Name match (case-insensitive)
3. Substring match either direction
Match found → use matched location (id/name/icon/colour)
No match → use DefaultLocation + store raw in RawSheetLocation
(displayed as italic 📍 pill on tile)
Saved LocationId override (from external_tickets/) always wins over sheet text.
```
## HTML Generation Pattern
No Razor. Every page is a method returning `string` from a `StringBuilder`:
- `BuildDashboardPage(DashboardViewModel)` — main dashboard
- `BuildDetailPage(Job, ServiceTicket, ...)` — job detail + edit
- `BuildConfigPage(ServiceTrackerConfig, ...)` — settings
- `TileHtml(DashboardTile)` — single tile card
- `SidebarPanel(title, color, items, url, showCollected)` — reusable sidebar section
CSS is returned from `CSS()`, `DCSS()`, `CCSS()` string methods and inlined in `<style>` tags. No external stylesheets.
## Cache Invalidation
`DashboardCache` watches file modification times on `config.json`, `external_tickets.json`, and the tickets directory. Any file change invalidates the cache. Cache key includes sortBy + filter string.
## Priority SLA Logic
Each `PriorityLevel` has a `SlaHours` value. SLA deadline = `job.OpenedDate + SlaHours`. Warning fires at 75% elapsed. `SlaHours = 0` means no SLA (used for "Scheduled" priority).