@x12i/static-memorix-explorer-api 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +150 -16
  2. package/dist/config.js +1 -1
  3. package/dist/engine/identity.js +11 -9
  4. package/dist/engine/write.js +48 -4
  5. package/dist/routes/index.js +57 -7
  6. package/dist/server.js +42 -20
  7. package/guides/demo-app.md +524 -0
  8. package/guides/managing-json-files.md +310 -0
  9. package/guides/running-the-service.md +171 -0
  10. package/guides/using-the-api.md +265 -0
  11. package/mocks/data/admin/snapshots.json +52 -0
  12. package/mocks/data/assets/analysis.json +14 -0
  13. package/mocks/data/assets/decisions.json +14 -0
  14. package/mocks/data/assets/events.json +4 -0
  15. package/mocks/data/assets/snapshots.json +49 -0
  16. package/mocks/data/findings/analysis.json +4 -0
  17. package/mocks/data/findings/decisions.json +4 -0
  18. package/mocks/data/findings/events.json +3 -0
  19. package/mocks/data/findings/snapshots.json +21 -0
  20. package/mocks/data/marketing/snapshots.json +75 -0
  21. package/mocks/data/memory/memory.json +31 -0
  22. package/mocks/data/product/snapshots.json +84 -0
  23. package/mocks/data/system/inventory.json +8 -0
  24. package/mocks/data/users/snapshots.json +5 -0
  25. package/mocks/demo.html +828 -0
  26. package/mocks/metadata/agents.json +7 -0
  27. package/mocks/metadata/lists/assets-default.json +22 -0
  28. package/mocks/metadata/lists/backlog.json +10 -0
  29. package/mocks/metadata/lists/findings-default.json +9 -0
  30. package/mocks/metadata/lists/my-plate.json +10 -0
  31. package/mocks/metadata/lists/this-week.json +10 -0
  32. package/mocks/metadata/narratives/admin.json +7 -0
  33. package/mocks/metadata/narratives/assets.json +17 -0
  34. package/mocks/metadata/narratives/findings.json +7 -0
  35. package/mocks/metadata/narratives/marketing.json +17 -0
  36. package/mocks/metadata/narratives/product.json +12 -0
  37. package/mocks/metadata/object-types/admin.json +6 -0
  38. package/mocks/metadata/object-types/assets.json +9 -0
  39. package/mocks/metadata/object-types/findings.json +8 -0
  40. package/mocks/metadata/object-types/marketing.json +6 -0
  41. package/mocks/metadata/object-types/memory.json +6 -0
  42. package/mocks/metadata/object-types/product.json +6 -0
  43. package/mocks/metadata/object-types/users.json +13 -0
  44. package/mocks/metadata/write-descriptors/admin-task-write.json +20 -0
  45. package/mocks/metadata/write-descriptors/assets-analysis-write.json +14 -0
  46. package/mocks/metadata/write-descriptors/marketing-task-write.json +20 -0
  47. package/mocks/metadata/write-descriptors/memory-write.json +14 -0
  48. package/mocks/metadata/write-descriptors/product-task-write.json +20 -0
  49. package/package.json +5 -2
@@ -0,0 +1,265 @@
1
+ # Using the API
2
+
3
+ The mock server exposes the full Memorix Explorer API under `/api/explorer/`.
4
+ All responses are JSON. Errors follow the shape `{ ok: false, error: "..." }`.
5
+
6
+ Base URL defaults to `http://localhost:5030`.
7
+
8
+ ## Endpoints
9
+
10
+ ### Health
11
+
12
+ | Method | Path | Description |
13
+ | ------ | ------------------------------------- | ------------------------------------- |
14
+ | `GET` | `/health` | Simple `{"ok":true}` |
15
+ | `GET` | `/api/explorer/health?includeInventory=1` | Full health with optional inventory |
16
+
17
+ ### Inventory
18
+
19
+ | Method | Path | Description |
20
+ | ------ | ---------------------------------------- | ----------------------------------- |
21
+ | `GET` | `/api/explorer/inventory/collections` | Inventory rows for all object types |
22
+ | `GET` | `/api/explorer/inventory/summary` | Aggregated counts |
23
+ | `GET` | `/api/explorer/inventory/issues` | Orphan/missing-collection rows |
24
+ | `GET` | `/api/explorer/inventory/graph` | `{ nodes, edges }` from catalogRelations |
25
+
26
+ Query param: `sourceLens=db-first|catalox-first` (default: `catalox-first`).
27
+
28
+ ### Snapshots
29
+
30
+ | Method | Path | Description |
31
+ | ------ | ----------------------------------------------------------------- | ---------------------------------- |
32
+ | `GET` | `/api/explorer/snapshots/:objectType/:recordId` | Normalized snapshot with associated bucket |
33
+ | `GET` | `/api/explorer/snapshots/:objectType/:recordId/associated` | Just the associated bucket |
34
+ | `GET` | `/api/explorer/snapshots/:objectType/:recordId/associated/:prop` | Single associated property |
35
+ | `GET` | `/api/explorer/snapshots/:objectType/associated-properties` | All `associated*` properties |
36
+ | `POST` | `/api/explorer/associations/plan` | Generate association plan |
37
+ | `POST` | `/api/explorer/associations/apply` | Apply association plan |
38
+ | `POST` | `/api/explorer/associations/verify` | Verify association fingerprint |
39
+
40
+ ### Records
41
+
42
+ | Method | Path | Description |
43
+ | ------ | --------------------------------------- | ---------------------------------------- |
44
+ | `GET` | `/api/explorer/records/collection` | Query with filters, search, sort, pagination |
45
+ | `GET` | `/api/explorer/records/full` | All content types for a recordId |
46
+ | `GET` | `/api/explorer/records/item` | Single item with optional descriptor hydration |
47
+ | `GET` | `/api/explorer/records/content` | Single content record by contentType + identity key |
48
+ | `GET` | `/api/explorer/records/raw-collection` | Raw collection array |
49
+ | `GET` | `/api/explorer/records/raw-item` | Single raw item by collectionName + recordId |
50
+ | `GET` | `/api/explorer/records/workspace` | Cross-entity workspace query |
51
+ | `POST` | `/api/explorer/records/write` | Write records (validate/dryRun/add/upsert/patch/replace/delete) |
52
+ | `DELETE`| `/api/explorer/records/item` | Delete a record by entityName + recordId |
53
+
54
+ ### Lists
55
+
56
+ | Method | Path | Description |
57
+ | ------ | ----------------------------------------- | ----------------------------- |
58
+ | `GET` | `/api/explorer/lists` | List all descriptors |
59
+ | `GET` | `/api/explorer/lists/:listId` | Single descriptor |
60
+ | `GET` | `/api/explorer/lists/:listId/records` | Execute list query |
61
+ | `GET` | `/api/explorer/lists/:listId/records-ws` | Execute list query (WS variant)|
62
+ | `GET` | `/api/explorer/lists/suggest` | Suggest extensions |
63
+ | `POST` | `/api/explorer/lists` | Create descriptor (requires flag) |
64
+ | `PATCH`| `/api/explorer/lists/:listId` | Update descriptor (requires flag) |
65
+ | `PUT` | `/api/explorer/lists/:listId/sort` | Update sort (requires flag) |
66
+ | `DELETE`| `/api/explorer/lists/:listId` | Delete descriptor (requires flag) |
67
+
68
+ ### Narratives
69
+
70
+ | Method | Path | Description |
71
+ | ------ | ----------------------------------------------- | ------------------------- |
72
+ | `GET` | `/api/explorer/narratives` | All narratives |
73
+ | `GET` | `/api/explorer/narratives/:entity` | Merged narratives for entity |
74
+ | `GET` | `/api/explorer/narratives/:entity/raw` | Raw authored narratives |
75
+ | `GET` | `/api/explorer/narratives/:entity/:key` | Single narrative |
76
+ | `GET` | `/api/explorer/narratives/:entity/:key/records` | Records tagged with narrative |
77
+ | `POST` | `/api/explorer/narratives` | Create (requires flag) |
78
+ | `PATCH`| `/api/explorer/narratives/:entity/:key` | Update (requires flag) |
79
+ | `DELETE`| `/api/explorer/narratives/:entity/:key` | Delete (requires flag) |
80
+
81
+ ### Object Types
82
+
83
+ | Method | Path | Description |
84
+ | ------ | ---------------------------------------------------------- | ------------------------ |
85
+ | `GET` | `/api/explorer/object-types` | List all object types |
86
+ | `GET` | `/api/explorer/object-types/:name` | Single object type |
87
+ | `GET` | `/api/explorer/object-types/:name/root-property-catalog` | Get root property catalog|
88
+ | `POST` | `/api/explorer/object-types/:name/root-property-catalog/compute` | Compute + persist catalog |
89
+
90
+ ### Agents & Auth
91
+
92
+ | Method | Path | Description |
93
+ | ------ | -------------------------------- | ------------------------------ |
94
+ | `GET` | `/api/explorer/agents` | Agent registry |
95
+ | `POST` | `/api/explorer/auth/token` | Mock M2M token |
96
+
97
+ ## Query conventions
98
+
99
+ ### Filtering
100
+
101
+ ```
102
+ filter=field:operator:value
103
+ ```
104
+
105
+ Operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `exists`, `regex`.
106
+
107
+ Repeatable with `&` or `;`-separated:
108
+
109
+ ```
110
+ filter=severity:eq:critical&filter=status:eq:open
111
+ filter=severity:eq:critical;status:eq:open
112
+ ```
113
+
114
+ For `in`/`nin`, use `|` as the value separator:
115
+
116
+ ```
117
+ filter=severity:in:critical|high
118
+ ```
119
+
120
+ ### Virtual narrative filters
121
+
122
+ Narrative filters rewrite the query to check the `narratives` map on each
123
+ document:
124
+
125
+ ```
126
+ filter=narrativeId:eq:has-vulns
127
+ ```
128
+
129
+ This evaluates `doc.narratives["has-vulns"]` being truthy.
130
+
131
+ ### Sorting
132
+
133
+ ```
134
+ sort=severity:desc&sort=entityId:asc
135
+ ```
136
+
137
+ ### Full-text search
138
+
139
+ ```
140
+ searchText=web-prod
141
+ q=web-prod
142
+ ```
143
+
144
+ Substring match across string fields.
145
+
146
+ ### Pagination
147
+
148
+ ```
149
+ limit=50&offset=0&includeTotal=1
150
+ ```
151
+
152
+ - `limit`: max 500, defaults to 100.
153
+ - `offset` or `skip`: number of records to skip.
154
+ - `includeTotal`: when `1`, includes `total` in the response.
155
+
156
+ ### Target tier
157
+
158
+ ```
159
+ target=memory
160
+ ```
161
+
162
+ Queries the memory tier instead of the default entity tier.
163
+
164
+ ## Identity keys
165
+
166
+ Each record must carry exactly one identity key:
167
+
168
+ | Key | Tier | Used by |
169
+ | ------------- | -------- | ------------------------------ |
170
+ | `recordId` | entities | snapshots, analysis, decisions |
171
+ | `entityId` | entities | snapshots (secondary) |
172
+ | `eventId` | events | events |
173
+ | `knowledgeId` | knowledge| analysis |
174
+ | `memoryId` | memory | memory |
175
+
176
+ Endpoints like `/records/full` and `/records/content` require exactly one
177
+ identity key per request.
178
+
179
+ ## Snapshot alias translation
180
+
181
+ The API translates associated data between storage format and client format:
182
+
183
+ ```
184
+ Storage: associatedData, associatedDiscovery, associatedInferred, associatedAnalysis
185
+ Client: associated.data, associated.discovery, associated.analysis
186
+ ```
187
+
188
+ `associatedInferred` is merged into `associated.discovery` alongside
189
+ `associatedDiscovery`. Custom buckets (e.g. `associatedCustom`) are mapped to
190
+ `associated.custom`.
191
+
192
+ ## Write operations
193
+
194
+ `POST /api/explorer/records/write` accepts:
195
+
196
+ ```json
197
+ {
198
+ "writeDescriptorId": "assets-analysis-write",
199
+ "operation": "upsert",
200
+ "input": [
201
+ { "recordId": "asset-1", "analysisType": "risk", "score": 8.5 }
202
+ ],
203
+ "dryRun": false,
204
+ "validateOnly": false
205
+ }
206
+ ```
207
+
208
+ ### Operations
209
+
210
+ | Operation | Behavior |
211
+ | ---------- | ------------------------------------------------ |
212
+ | `add` | Appends records (auto-generates ID if missing) |
213
+ | `upsert` | Updates existing by identity key, or appends |
214
+ | `patch` | Updates existing by identity key, no-op if missing |
215
+ | `replace` | Replaces the entire collection (use with caution)|
216
+ | `delete` | Removes all records matching the supplied identity keys; returns the removed records |
217
+
218
+ ### Required-field semantics
219
+
220
+ The `schema.required` array is enforced **fully** only for `add` and `replace`
221
+ operations. For `upsert`, `patch`, and `delete`, only the collection's identity
222
+ field (`recordId`, or `memoryId` on the memory tier) is required — every other
223
+ field is optional and treated as a partial update. This lets you send
224
+ `{recordId, status}` on a status-only edit without re-supplying the title.
225
+
226
+ ### Flags
227
+
228
+ - `validateOnly: true` validates input against the write descriptor schema
229
+ without modifying state.
230
+ - `dryRun: true` validates and simulates the operation without changing live
231
+ in-memory state or disk.
232
+
233
+ ### Delete via REST endpoint
234
+
235
+ For ergonomics, deletes can also be issued with a dedicated REST endpoint.
236
+ It still requires and verifies a write descriptor, so it cannot bypass the
237
+ same collection contract used by `POST /records/write`:
238
+
239
+ ```
240
+ DELETE /api/explorer/records/item?entityName=product&recordId=t1&writeDescriptorId=product-task-write
241
+ ```
242
+
243
+ Returns `{ ok: true, count: <n>, removed: [<record>…] }`. Flushes immediately.
244
+
245
+ ### Delete via `op: "delete"`
246
+
247
+ The equivalent call via the write endpoint:
248
+
249
+ ```json
250
+ {
251
+ "writeDescriptorId": "product-task-write",
252
+ "operation": "delete",
253
+ "input": { "recordId": "t1" }
254
+ }
255
+ ```
256
+
257
+ ## Feature flag gates
258
+
259
+ Mutation endpoints return `{ ok: false, error: "Metadata writes are disabled" }`
260
+ when the corresponding feature flag is not enabled. Set the environment
261
+ variable to `true` or `1` to allow writes:
262
+
263
+ ```bash
264
+ MEMORIX_EXPLORER_ENABLE_METADATA_WRITES=true mock-memorix-explorer-api
265
+ ```
@@ -0,0 +1,52 @@
1
+ [
2
+ {
3
+ "recordId": "t10",
4
+ "title": "Reconcile initial expenses for Q1 server setup",
5
+ "status": "todo",
6
+ "priority": "normal",
7
+ "owner": "Sam",
8
+ "area": "admin",
9
+ "assigneeId": "usr-1",
10
+ "dueDate": "2026-07-22",
11
+ "notes": "Compile all receipts for the dedicated server hardware and confirm the ledger matches.",
12
+ "chat": [],
13
+ "narratives": {
14
+ "q1-review": true
15
+ }
16
+ },
17
+ {
18
+ "recordId": "t11",
19
+ "title": "File the LLC formation paperwork",
20
+ "status": "doing",
21
+ "priority": "urgent",
22
+ "owner": "Alex",
23
+ "area": "admin",
24
+ "assigneeId": "usr-1",
25
+ "dueDate": "2026-07-20",
26
+ "notes": "Articles of organization, operating agreement, and EIN application.",
27
+ "chat": [
28
+ {
29
+ "id": "cmt-4",
30
+ "authorId": "usr-2",
31
+ "timestamp": "2026-07-19T09:00:00Z",
32
+ "text": "I have the forms ready. Need your digital signatures."
33
+ }
34
+ ],
35
+ "narratives": {}
36
+ },
37
+ {
38
+ "recordId": "t12",
39
+ "title": "Review and sign the hosting contract",
40
+ "status": "done",
41
+ "priority": "normal",
42
+ "owner": "Alex",
43
+ "area": "admin",
44
+ "assigneeId": "usr-1",
45
+ "dueDate": "2026-07-15",
46
+ "notes": "12-month term, 99.9% SLA, 24/7 support included.",
47
+ "chat": [],
48
+ "narratives": {
49
+ "q1-review": true
50
+ }
51
+ }
52
+ ]
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "recordId": "asset-1",
4
+ "analysisType": "vulnerability-scan",
5
+ "score": 9.1,
6
+ "notes": ["Outdated TLS", "Public exposure"]
7
+ },
8
+ {
9
+ "recordId": "asset-2",
10
+ "analysisType": "vulnerability-scan",
11
+ "score": 7.4,
12
+ "notes": ["Unpatched engine"]
13
+ }
14
+ ]
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "recordId": "asset-1",
4
+ "decision": "remediate-now",
5
+ "owner": "sec-team",
6
+ "sla": "24h"
7
+ },
8
+ {
9
+ "recordId": "asset-2",
10
+ "decision": "monitor",
11
+ "owner": "db-team",
12
+ "sla": "7d"
13
+ }
14
+ ]
@@ -0,0 +1,4 @@
1
+ [
2
+ { "recordId": "asset-1", "event": "scan-started", "at": "2026-07-01T10:00:00Z" },
3
+ { "recordId": "asset-1", "event": "scan-completed", "at": "2026-07-01T10:05:00Z" }
4
+ ]
@@ -0,0 +1,49 @@
1
+ [
2
+ {
3
+ "recordId": "asset-1",
4
+ "entityId": "web-prod-01",
5
+ "severity": "critical",
6
+ "status": "open",
7
+ "region": "us-east-1",
8
+ "ownerId": "agent-1",
9
+ "narratives": { "has-vulns": true, "exposed-public": true },
10
+ "associatedData": [
11
+ { "kind": "tag", "value": "prod" },
12
+ { "kind": "tag", "value": "web" }
13
+ ],
14
+ "associatedInferred": [
15
+ { "kind": "discovery", "value": "public-ip" }
16
+ ],
17
+ "associatedAnalysis": [
18
+ { "kind": "analysis", "value": "cve-score-9" }
19
+ ]
20
+ },
21
+ {
22
+ "recordId": "asset-2",
23
+ "entityId": "db-prod-01",
24
+ "severity": "high",
25
+ "status": "open",
26
+ "region": "us-east-1",
27
+ "ownerId": "agent-2",
28
+ "narratives": { "has-vulns": true, "critical-owner": true },
29
+ "associatedData": [
30
+ { "kind": "tag", "value": "prod" },
31
+ { "kind": "tag", "value": "database" }
32
+ ],
33
+ "associatedDiscovery": [
34
+ { "kind": "discovery", "value": "internal-rds" }
35
+ ]
36
+ },
37
+ {
38
+ "recordId": "asset-3",
39
+ "entityId": "cache-dev-01",
40
+ "severity": "low",
41
+ "status": "closed",
42
+ "region": "eu-west-1",
43
+ "ownerId": "agent-1",
44
+ "narratives": { "exposed-public": true },
45
+ "associatedData": [
46
+ { "kind": "tag", "value": "dev" }
47
+ ]
48
+ }
49
+ ]
@@ -0,0 +1,4 @@
1
+ [
2
+ { "recordId": "finding-1", "analysisType": "cvss", "score": 9.1 },
3
+ { "recordId": "finding-2", "analysisType": "cvss", "score": 7.4 }
4
+ ]
@@ -0,0 +1,4 @@
1
+ [
2
+ { "recordId": "finding-1", "decision": "patch", "owner": "sec-team" },
3
+ { "recordId": "finding-2", "decision": "patch", "owner": "db-team" }
4
+ ]
@@ -0,0 +1,3 @@
1
+ [
2
+ { "recordId": "finding-1", "event": "detected", "at": "2026-07-01T10:05:00Z" }
3
+ ]
@@ -0,0 +1,21 @@
1
+ [
2
+ {
3
+ "recordId": "finding-1",
4
+ "entityId": "web-prod-01",
5
+ "assetId": "asset-1",
6
+ "severity": "critical",
7
+ "status": "open",
8
+ "cve": "CVE-2026-1234",
9
+ "narratives": { "high-severity": true },
10
+ "associatedData": [{ "kind": "reference", "value": "CVE-2026-1234" }]
11
+ },
12
+ {
13
+ "recordId": "finding-2",
14
+ "entityId": "db-prod-01",
15
+ "assetId": "asset-2",
16
+ "severity": "high",
17
+ "status": "open",
18
+ "cve": "CVE-2026-5678",
19
+ "narratives": { "high-severity": true }
20
+ }
21
+ ]
@@ -0,0 +1,75 @@
1
+ [
2
+ {
3
+ "recordId": "t6",
4
+ "title": "Draft the open-source monetization blog post",
5
+ "status": "doing",
6
+ "priority": "urgent",
7
+ "owner": "Jordan",
8
+ "area": "marketing",
9
+ "assigneeId": "usr-3",
10
+ "dueDate": "2026-07-22",
11
+ "notes": "Focus the narrative on programmatic SEO strategies and the managed service provider angle.",
12
+ "chat": [
13
+ {
14
+ "id": "cmt-2",
15
+ "authorId": "usr-1",
16
+ "timestamp": "2026-07-20T10:15:00Z",
17
+ "text": "Let me know when the first draft is ready for review."
18
+ },
19
+ {
20
+ "id": "cmt-3",
21
+ "authorId": "usr-3",
22
+ "timestamp": "2026-07-20T11:30:00Z",
23
+ "text": "Will have it by end of day."
24
+ }
25
+ ],
26
+ "narratives": {
27
+ "blog-content": true
28
+ }
29
+ },
30
+ {
31
+ "recordId": "t7",
32
+ "title": "Record product demo video for the landing page",
33
+ "status": "todo",
34
+ "priority": "normal",
35
+ "owner": "Jordan",
36
+ "area": "marketing",
37
+ "assigneeId": "usr-3",
38
+ "dueDate": "2026-07-28",
39
+ "notes": "Keep it under 60 seconds. Highlight the drag-and-drop workflow and real-time collaboration.",
40
+ "chat": [],
41
+ "narratives": {
42
+ "website-refresh": true
43
+ }
44
+ },
45
+ {
46
+ "recordId": "t8",
47
+ "title": "Set up the email newsletter welcome sequence",
48
+ "status": "todo",
49
+ "priority": "normal",
50
+ "owner": "Casey",
51
+ "area": "marketing",
52
+ "assigneeId": "usr-3",
53
+ "dueDate": "2026-07-24",
54
+ "notes": "Three emails over 5 days. First email delivers value, third has CTA for trial signup.",
55
+ "chat": [],
56
+ "narratives": {
57
+ "launch-prep": true
58
+ }
59
+ },
60
+ {
61
+ "recordId": "t9",
62
+ "title": "Schedule 3 posts for the launch week",
63
+ "status": "someday",
64
+ "priority": "low",
65
+ "owner": "",
66
+ "area": "marketing",
67
+ "assigneeId": null,
68
+ "dueDate": "",
69
+ "notes": "Topics: technical deep dive, customer story, and product announcement.",
70
+ "chat": [],
71
+ "narratives": {
72
+ "launch-prep": true
73
+ }
74
+ }
75
+ ]
@@ -0,0 +1,31 @@
1
+ [
2
+ {
3
+ "memoryId": "mem-1",
4
+ "entityId": "web-prod-01",
5
+ "kind": "conversation-summary",
6
+ "summary": "Discussed upgrade path for web-prod-01 from v2 to v3.",
7
+ "createdAt": "2026-07-10T08:00:00Z"
8
+ },
9
+ {
10
+ "memoryId": "mem-2",
11
+ "entityId": "db-prod-01",
12
+ "kind": "decision-rationale",
13
+ "summary": "Chose AWS RDS over self-hosted for db-prod-01 due to maintenance costs.",
14
+ "createdAt": "2026-07-10T09:00:00Z"
15
+ },
16
+ {
17
+ "memoryId": "mem-3",
18
+ "eventId": "evt-1",
19
+ "kind": "post-mortem",
20
+ "summary": "Investigated event-1 (disk pressure) and added alerts.",
21
+ "createdAt": "2026-07-10T10:00:00Z"
22
+ },
23
+ {
24
+ "memoryId": "mem-99",
25
+ "kind": "test"
26
+ },
27
+ {
28
+ "memoryId": "mem-99",
29
+ "kind": "test"
30
+ }
31
+ ]
@@ -0,0 +1,84 @@
1
+ [
2
+ {
3
+ "recordId": "t1",
4
+ "title": "Review new frontend styling for the landing page",
5
+ "status": "doing",
6
+ "priority": "urgent",
7
+ "owner": "Sam",
8
+ "area": "product",
9
+ "assigneeId": "usr-2",
10
+ "dueDate": "2026-07-21",
11
+ "notes": "Ensure the dark-mode contrast ratios meet the updated accessibility guidelines we discussed.",
12
+ "chat": [],
13
+ "narratives": {
14
+ "website-refresh": true
15
+ }
16
+ },
17
+ {
18
+ "recordId": "t2",
19
+ "title": "Finalize the API rate-limiting strategy",
20
+ "status": "todo",
21
+ "priority": "normal",
22
+ "owner": "Alex",
23
+ "area": "product",
24
+ "assigneeId": "usr-2",
25
+ "dueDate": "2026-07-23",
26
+ "notes": "Document the rate limits per endpoint and implement exponential backoff for exceeded clients.",
27
+ "chat": [],
28
+ "narratives": {
29
+ "launch-prep": true
30
+ }
31
+ },
32
+ {
33
+ "recordId": "t3",
34
+ "title": "Write unit tests for the auth module",
35
+ "status": "todo",
36
+ "priority": "normal",
37
+ "owner": "Sam",
38
+ "area": "product",
39
+ "assigneeId": "usr-2",
40
+ "dueDate": "2026-07-25",
41
+ "notes": "Focus on edge cases: expired tokens, malformed payloads, and concurrent login attempts.",
42
+ "chat": [
43
+ {
44
+ "id": "cmt-1",
45
+ "authorId": "usr-1",
46
+ "timestamp": "2026-07-19T14:22:00Z",
47
+ "text": "Can you add tests for the refresh token flow as well?"
48
+ }
49
+ ],
50
+ "narratives": {
51
+ "launch-prep": true
52
+ }
53
+ },
54
+ {
55
+ "recordId": "t4",
56
+ "title": "Set up error tracking in production",
57
+ "status": "done",
58
+ "priority": "urgent",
59
+ "owner": "Alex",
60
+ "area": "product",
61
+ "assigneeId": "usr-1",
62
+ "dueDate": "2026-07-18",
63
+ "notes": "Configure Sentry to capture unhandled exceptions and track error rates by endpoint.",
64
+ "chat": [],
65
+ "narratives": {
66
+ "launch-prep": true
67
+ }
68
+ },
69
+ {
70
+ "recordId": "t5",
71
+ "title": "Add dark mode toggle to settings",
72
+ "status": "someday",
73
+ "priority": "low",
74
+ "owner": "",
75
+ "area": "product",
76
+ "assigneeId": null,
77
+ "dueDate": "",
78
+ "notes": "Save preference to localStorage and persist to user profile on next sync.",
79
+ "chat": [],
80
+ "narratives": {
81
+ "website-refresh": true
82
+ }
83
+ }
84
+ ]
@@ -0,0 +1,8 @@
1
+ {
2
+ "policy": {
3
+ "seedInventoryEnabled": true,
4
+ "defaultLens": "catalox-first",
5
+ "collectionOverrides": {}
6
+ },
7
+ "collectionOverrides": []
8
+ }
@@ -0,0 +1,5 @@
1
+ [
2
+ { "recordId": "usr-1", "name": "Ami", "role": "owner" },
3
+ { "recordId": "usr-2", "name": "Devran", "role": "engineer" },
4
+ { "recordId": "usr-3", "name": "Ilan", "role": "growth" }
5
+ ]