@okrlinkhub/okrhub 0.1.0

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 (148) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +579 -0
  3. package/dist/client/_generated/_ignore.d.ts +1 -0
  4. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  5. package/dist/client/_generated/_ignore.js +3 -0
  6. package/dist/client/_generated/_ignore.js.map +1 -0
  7. package/dist/client/index.d.ts +593 -0
  8. package/dist/client/index.d.ts.map +1 -0
  9. package/dist/client/index.js +704 -0
  10. package/dist/client/index.js.map +1 -0
  11. package/dist/component/_generated/api.d.ts +72 -0
  12. package/dist/component/_generated/api.d.ts.map +1 -0
  13. package/dist/component/_generated/api.js +31 -0
  14. package/dist/component/_generated/api.js.map +1 -0
  15. package/dist/component/_generated/component.d.ts +1986 -0
  16. package/dist/component/_generated/component.d.ts.map +1 -0
  17. package/dist/component/_generated/component.js +11 -0
  18. package/dist/component/_generated/component.js.map +1 -0
  19. package/dist/component/_generated/dataModel.d.ts +46 -0
  20. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  21. package/dist/component/_generated/dataModel.js +11 -0
  22. package/dist/component/_generated/dataModel.js.map +1 -0
  23. package/dist/component/_generated/server.d.ts +121 -0
  24. package/dist/component/_generated/server.d.ts.map +1 -0
  25. package/dist/component/_generated/server.js +78 -0
  26. package/dist/component/_generated/server.js.map +1 -0
  27. package/dist/component/convex.config.d.ts +3 -0
  28. package/dist/component/convex.config.d.ts.map +1 -0
  29. package/dist/component/convex.config.js +3 -0
  30. package/dist/component/convex.config.js.map +1 -0
  31. package/dist/component/entities/batch.d.ts +121 -0
  32. package/dist/component/entities/batch.d.ts.map +1 -0
  33. package/dist/component/entities/batch.js +81 -0
  34. package/dist/component/entities/batch.js.map +1 -0
  35. package/dist/component/entities/index.d.ts +13 -0
  36. package/dist/component/entities/index.d.ts.map +1 -0
  37. package/dist/component/entities/index.js +22 -0
  38. package/dist/component/entities/index.js.map +1 -0
  39. package/dist/component/entities/indicatorForecasts.d.ts +61 -0
  40. package/dist/component/entities/indicatorForecasts.d.ts.map +1 -0
  41. package/dist/component/entities/indicatorForecasts.js +180 -0
  42. package/dist/component/entities/indicatorForecasts.js.map +1 -0
  43. package/dist/component/entities/indicatorValues.d.ts +77 -0
  44. package/dist/component/entities/indicatorValues.d.ts.map +1 -0
  45. package/dist/component/entities/indicatorValues.js +218 -0
  46. package/dist/component/entities/indicatorValues.js.map +1 -0
  47. package/dist/component/entities/indicators.d.ts +90 -0
  48. package/dist/component/entities/indicators.d.ts.map +1 -0
  49. package/dist/component/entities/indicators.js +239 -0
  50. package/dist/component/entities/indicators.js.map +1 -0
  51. package/dist/component/entities/initiatives.d.ts +103 -0
  52. package/dist/component/entities/initiatives.d.ts.map +1 -0
  53. package/dist/component/entities/initiatives.js +275 -0
  54. package/dist/component/entities/initiatives.js.map +1 -0
  55. package/dist/component/entities/keyResults.d.ts +111 -0
  56. package/dist/component/entities/keyResults.d.ts.map +1 -0
  57. package/dist/component/entities/keyResults.js +284 -0
  58. package/dist/component/entities/keyResults.js.map +1 -0
  59. package/dist/component/entities/milestones.d.ts +93 -0
  60. package/dist/component/entities/milestones.d.ts.map +1 -0
  61. package/dist/component/entities/milestones.js +249 -0
  62. package/dist/component/entities/milestones.js.map +1 -0
  63. package/dist/component/entities/objectives.d.ts +99 -0
  64. package/dist/component/entities/objectives.d.ts.map +1 -0
  65. package/dist/component/entities/objectives.js +261 -0
  66. package/dist/component/entities/objectives.js.map +1 -0
  67. package/dist/component/entities/risks.d.ts +126 -0
  68. package/dist/component/entities/risks.d.ts.map +1 -0
  69. package/dist/component/entities/risks.js +315 -0
  70. package/dist/component/entities/risks.js.map +1 -0
  71. package/dist/component/externalId.d.ts +79 -0
  72. package/dist/component/externalId.d.ts.map +1 -0
  73. package/dist/component/externalId.js +124 -0
  74. package/dist/component/externalId.js.map +1 -0
  75. package/dist/component/lib/hmac.d.ts +18 -0
  76. package/dist/component/lib/hmac.d.ts.map +1 -0
  77. package/dist/component/lib/hmac.js +35 -0
  78. package/dist/component/lib/hmac.js.map +1 -0
  79. package/dist/component/lib/index.d.ts +7 -0
  80. package/dist/component/lib/index.d.ts.map +1 -0
  81. package/dist/component/lib/index.js +6 -0
  82. package/dist/component/lib/index.js.map +1 -0
  83. package/dist/component/lib/types.d.ts +30 -0
  84. package/dist/component/lib/types.d.ts.map +1 -0
  85. package/dist/component/lib/types.js +7 -0
  86. package/dist/component/lib/types.js.map +1 -0
  87. package/dist/component/lib/validation.d.ts +15 -0
  88. package/dist/component/lib/validation.d.ts.map +1 -0
  89. package/dist/component/lib/validation.js +29 -0
  90. package/dist/component/lib/validation.js.map +1 -0
  91. package/dist/component/okrhub.d.ts +31 -0
  92. package/dist/component/okrhub.d.ts.map +1 -0
  93. package/dist/component/okrhub.js +45 -0
  94. package/dist/component/okrhub.js.map +1 -0
  95. package/dist/component/schema.d.ts +943 -0
  96. package/dist/component/schema.d.ts.map +1 -0
  97. package/dist/component/schema.js +437 -0
  98. package/dist/component/schema.js.map +1 -0
  99. package/dist/component/sync/http.d.ts +30 -0
  100. package/dist/component/sync/http.d.ts.map +1 -0
  101. package/dist/component/sync/http.js +114 -0
  102. package/dist/component/sync/http.js.map +1 -0
  103. package/dist/component/sync/index.d.ts +7 -0
  104. package/dist/component/sync/index.d.ts.map +1 -0
  105. package/dist/component/sync/index.js +7 -0
  106. package/dist/component/sync/index.js.map +1 -0
  107. package/dist/component/sync/processor.d.ts +20 -0
  108. package/dist/component/sync/processor.d.ts.map +1 -0
  109. package/dist/component/sync/processor.js +67 -0
  110. package/dist/component/sync/processor.js.map +1 -0
  111. package/dist/component/sync/queue.d.ts +40 -0
  112. package/dist/component/sync/queue.d.ts.map +1 -0
  113. package/dist/component/sync/queue.js +176 -0
  114. package/dist/component/sync/queue.js.map +1 -0
  115. package/dist/react/index.d.ts +2 -0
  116. package/dist/react/index.d.ts.map +1 -0
  117. package/dist/react/index.js +6 -0
  118. package/dist/react/index.js.map +1 -0
  119. package/package.json +117 -0
  120. package/src/client/_generated/_ignore.ts +1 -0
  121. package/src/client/index.ts +1004 -0
  122. package/src/component/_generated/api.ts +88 -0
  123. package/src/component/_generated/component.ts +2685 -0
  124. package/src/component/_generated/dataModel.ts +60 -0
  125. package/src/component/_generated/server.ts +156 -0
  126. package/src/component/convex.config.ts +3 -0
  127. package/src/component/entities/batch.ts +90 -0
  128. package/src/component/entities/index.ts +64 -0
  129. package/src/component/entities/indicatorForecasts.ts +205 -0
  130. package/src/component/entities/indicatorValues.ts +254 -0
  131. package/src/component/entities/indicators.ts +290 -0
  132. package/src/component/entities/initiatives.ts +342 -0
  133. package/src/component/entities/keyResults.ts +334 -0
  134. package/src/component/entities/milestones.ts +296 -0
  135. package/src/component/entities/objectives.ts +294 -0
  136. package/src/component/entities/risks.ts +383 -0
  137. package/src/component/externalId.ts +172 -0
  138. package/src/component/lib/hmac.ts +53 -0
  139. package/src/component/lib/index.ts +7 -0
  140. package/src/component/lib/types.ts +31 -0
  141. package/src/component/lib/validation.ts +41 -0
  142. package/src/component/okrhub.ts +110 -0
  143. package/src/component/schema.ts +574 -0
  144. package/src/component/sync/http.ts +138 -0
  145. package/src/component/sync/index.ts +11 -0
  146. package/src/component/sync/processor.ts +77 -0
  147. package/src/component/sync/queue.ts +201 -0
  148. package/src/react/index.ts +7 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * OKRHub Component - Main Entry Point
3
+ *
4
+ * This file serves as the main barrel export for backward compatibility.
5
+ * All functionality has been refactored into modular files under:
6
+ * - entities/ - Entity-specific CRUD operations and queries
7
+ * - sync/ - Sync queue management and HTTP actions
8
+ * - lib/ - Shared utilities (HMAC, validation, types)
9
+ *
10
+ * Import patterns:
11
+ * - For specific entities: import { createObjective } from "./entities/objectives.js"
12
+ * - For sync operations: import { processSyncQueue } from "./sync/processor.js"
13
+ * - For utilities: import { createHmacSignature } from "./lib/hmac.js"
14
+ *
15
+ * Or use this file for backward-compatible imports:
16
+ * - import { createObjective, processSyncQueue } from "./okrhub.js"
17
+ */
18
+
19
+ // ============================================================================
20
+ // ENTITY EXPORTS
21
+ // ============================================================================
22
+
23
+ // Objectives
24
+ export {
25
+ createObjective,
26
+ updateObjective,
27
+ getObjectivesByTeam,
28
+ getAllObjectives,
29
+ insertObjective,
30
+ } from "./entities/objectives.js";
31
+
32
+ // Key Results
33
+ export {
34
+ createKeyResult,
35
+ updateKeyResult,
36
+ getKeyResultsByObjective,
37
+ getAllKeyResults,
38
+ insertKeyResult,
39
+ } from "./entities/keyResults.js";
40
+
41
+ // Risks
42
+ export {
43
+ createRisk,
44
+ updateRisk,
45
+ getRisksByKeyResult,
46
+ getAllRisks,
47
+ insertRisk,
48
+ } from "./entities/risks.js";
49
+
50
+ // Initiatives
51
+ export {
52
+ createInitiative,
53
+ updateInitiative,
54
+ getAllInitiatives,
55
+ insertInitiative,
56
+ } from "./entities/initiatives.js";
57
+
58
+ // Indicators
59
+ export {
60
+ createIndicator,
61
+ updateIndicator,
62
+ getAllIndicators,
63
+ insertIndicator,
64
+ } from "./entities/indicators.js";
65
+
66
+ // Indicator Values
67
+ export {
68
+ createIndicatorValue,
69
+ updateIndicatorValue,
70
+ getAllIndicatorValues,
71
+ insertIndicatorValue,
72
+ } from "./entities/indicatorValues.js";
73
+
74
+ // Indicator Forecasts
75
+ export {
76
+ createIndicatorForecast,
77
+ updateIndicatorForecast,
78
+ getAllIndicatorForecasts,
79
+ } from "./entities/indicatorForecasts.js";
80
+
81
+ // Milestones
82
+ export {
83
+ createMilestone,
84
+ updateMilestone,
85
+ getAllMilestones,
86
+ insertMilestone,
87
+ } from "./entities/milestones.js";
88
+
89
+ // Batch
90
+ export { insertBatch } from "./entities/batch.js";
91
+
92
+ // ============================================================================
93
+ // SYNC EXPORTS
94
+ // ============================================================================
95
+
96
+ export {
97
+ addToSyncQueue,
98
+ updateSyncQueueItem,
99
+ getPendingSyncItems,
100
+ } from "./sync/queue.js";
101
+
102
+ export { sendToLinkHub, sendBatchToLinkHub } from "./sync/http.js";
103
+
104
+ export { processSyncQueue } from "./sync/processor.js";
105
+
106
+ // ============================================================================
107
+ // TYPE EXPORTS
108
+ // ============================================================================
109
+
110
+ export type { IngestResponse, BatchIngestResponse } from "./lib/types.js";
@@ -0,0 +1,574 @@
1
+ /**
2
+ * OKRHub Component Schema
3
+ *
4
+ * This file defines payload validators for the OKRHub component.
5
+ * These are simplified versions of LinkHub's schema that use externalId
6
+ * instead of Convex internal IDs.
7
+ *
8
+ * IMPORTANT: All references use externalId strings, not v.id() types,
9
+ * because the component runs in a different Convex deployment.
10
+ */
11
+
12
+ import { defineSchema, defineTable } from "convex/server";
13
+ import { v } from "convex/values";
14
+
15
+ // ============================================================================
16
+ // ENUMS - Matching LinkHub's schema
17
+ // ============================================================================
18
+
19
+ export const PrioritySchema = v.union(
20
+ v.literal("lowest"),
21
+ v.literal("low"),
22
+ v.literal("medium"),
23
+ v.literal("high"),
24
+ v.literal("highest")
25
+ );
26
+
27
+ export const PeriodicitySchema = v.union(
28
+ v.literal("weekly"),
29
+ v.literal("monthly"),
30
+ v.literal("quarterly"),
31
+ v.literal("semesterly"),
32
+ v.literal("yearly")
33
+ );
34
+
35
+ export const InitiativeStatusSchema = v.union(
36
+ v.literal("ON_TIME"),
37
+ v.literal("OVERDUE"),
38
+ v.literal("FINISHED")
39
+ );
40
+
41
+ export const MilestoneStatusSchema = v.union(
42
+ v.literal("ON_TIME"),
43
+ v.literal("OVERDUE"),
44
+ v.literal("ACHIEVED_ON_TIME"),
45
+ v.literal("ACHIEVED_LATE")
46
+ );
47
+
48
+ export const IndicatorTypeSchema = v.union(
49
+ v.literal("OUTPUT"),
50
+ v.literal("OUTCOME")
51
+ );
52
+
53
+ // ============================================================================
54
+ // PAYLOAD VALIDATORS - For ingestion into LinkHub
55
+ // ============================================================================
56
+
57
+ /**
58
+ * Objective payload for insertion/update
59
+ * Maps to LinkHub's objectives table
60
+ */
61
+ export const objectivePayloadValidator = v.object({
62
+ // Required: External ID for mapping
63
+ externalId: v.string(),
64
+
65
+ // Required fields
66
+ title: v.string(),
67
+ description: v.string(),
68
+ teamExternalId: v.string(), // Reference to team via externalId
69
+
70
+ // Optional metadata
71
+ createdAt: v.optional(v.number()),
72
+ updatedAt: v.optional(v.number()),
73
+ });
74
+
75
+ /**
76
+ * Key Result payload for insertion/update
77
+ * Maps to LinkHub's keyResults table
78
+ */
79
+ export const keyResultPayloadValidator = v.object({
80
+ // Required: External ID for mapping
81
+ externalId: v.string(),
82
+
83
+ // Required: Reference to parent objective
84
+ objectiveExternalId: v.string(),
85
+
86
+ // Required: Reference to indicator
87
+ indicatorExternalId: v.string(),
88
+
89
+ // Required: Reference to team
90
+ teamExternalId: v.string(),
91
+
92
+ // Required: Weight (percentage 0-100)
93
+ weight: v.number(),
94
+
95
+ // Optional values
96
+ impact: v.optional(v.number()),
97
+ forecastValue: v.optional(v.number()),
98
+ targetValue: v.optional(v.number()),
99
+
100
+ // Optional metadata
101
+ createdAt: v.optional(v.number()),
102
+ updatedAt: v.optional(v.number()),
103
+ });
104
+
105
+ /**
106
+ * Risk (KPI) payload for insertion/update
107
+ * Maps to LinkHub's risks table
108
+ */
109
+ export const riskPayloadValidator = v.object({
110
+ // Required: External ID for mapping
111
+ externalId: v.string(),
112
+
113
+ // Required fields
114
+ description: v.string(),
115
+ teamExternalId: v.string(),
116
+ priority: PrioritySchema,
117
+
118
+ // Required: Reference to parent key result
119
+ keyResultExternalId: v.string(),
120
+
121
+ // Optional: Reference to indicator for KPI trigger
122
+ indicatorExternalId: v.optional(v.string()),
123
+
124
+ // KPI trigger configuration
125
+ triggerValue: v.optional(v.number()),
126
+ triggeredIfLower: v.optional(v.boolean()),
127
+ useForecastAsTrigger: v.optional(v.boolean()),
128
+
129
+ // Optional status
130
+ isRed: v.optional(v.boolean()),
131
+
132
+ // Optional metadata
133
+ createdAt: v.optional(v.number()),
134
+ });
135
+
136
+ /**
137
+ * Initiative payload for insertion/update
138
+ * Maps to LinkHub's initiatives table
139
+ */
140
+ export const initiativePayloadValidator = v.object({
141
+ // Required: External ID for mapping
142
+ externalId: v.string(),
143
+
144
+ // Required fields
145
+ description: v.string(),
146
+ teamExternalId: v.string(),
147
+ assigneeExternalId: v.string(), // User external ID
148
+ createdByExternalId: v.string(), // User external ID
149
+ priority: PrioritySchema,
150
+
151
+ // Required: Reference to parent risk
152
+ riskExternalId: v.string(),
153
+
154
+ // Status (required, default ON_TIME)
155
+ status: InitiativeStatusSchema,
156
+ isNew: v.optional(v.boolean()),
157
+ finishedAt: v.optional(v.number()),
158
+
159
+ // Optional fields
160
+ externalUrl: v.optional(v.string()),
161
+
162
+ // Optional metadata
163
+ createdAt: v.optional(v.number()),
164
+ updatedAt: v.optional(v.number()),
165
+ });
166
+
167
+ /**
168
+ * Indicator payload for insertion/update
169
+ * Maps to LinkHub's indicators table
170
+ */
171
+ export const indicatorPayloadValidator = v.object({
172
+ // Required: External ID for mapping
173
+ externalId: v.string(),
174
+
175
+ // Required: Reference to company
176
+ companyExternalId: v.string(),
177
+
178
+ // Required fields
179
+ description: v.string(),
180
+ symbol: v.string(),
181
+ periodicity: PeriodicitySchema,
182
+
183
+ // Optional fields
184
+ isReverse: v.optional(v.boolean()),
185
+ automationUrl: v.optional(v.string()),
186
+ automationDescription: v.optional(v.string()),
187
+ forecastDate: v.optional(v.number()),
188
+
189
+ // Optional metadata
190
+ createdAt: v.optional(v.number()),
191
+ });
192
+
193
+ /**
194
+ * Indicator Value payload for tracking
195
+ * Maps to LinkHub's values table
196
+ */
197
+ export const indicatorValuePayloadValidator = v.object({
198
+ // Required: External ID for mapping
199
+ externalId: v.string(),
200
+
201
+ // Required: Reference to indicator
202
+ indicatorExternalId: v.string(),
203
+
204
+ // Required: Value data
205
+ value: v.number(),
206
+ date: v.number(), // Timestamp
207
+
208
+ // Optional metadata
209
+ createdAt: v.optional(v.number()),
210
+ });
211
+
212
+ /**
213
+ * Indicator Forecast payload
214
+ * Maps to LinkHub's forecasts table
215
+ */
216
+ export const indicatorForecastPayloadValidator = v.object({
217
+ // Required: External ID for mapping
218
+ externalId: v.string(),
219
+
220
+ // Required: Reference to indicator
221
+ indicatorExternalId: v.string(),
222
+
223
+ // Required: Forecast data
224
+ value: v.number(),
225
+ date: v.number(), // Timestamp
226
+
227
+ // Optional metadata
228
+ createdAt: v.optional(v.number()),
229
+ });
230
+
231
+ /**
232
+ * Milestone payload for insertion/update
233
+ * Maps to LinkHub's milestones table
234
+ */
235
+ export const milestonePayloadValidator = v.object({
236
+ // Required: External ID for mapping
237
+ externalId: v.string(),
238
+
239
+ // Required: Reference to indicator
240
+ indicatorExternalId: v.string(),
241
+
242
+ // Required fields
243
+ description: v.string(),
244
+ value: v.number(),
245
+ status: MilestoneStatusSchema, // Required, default ON_TIME
246
+
247
+ // Optional: Achievement tracking
248
+ achievedAt: v.optional(v.number()),
249
+ forecastDate: v.optional(v.number()),
250
+
251
+ // Optional metadata
252
+ createdAt: v.optional(v.number()),
253
+ updatedAt: v.optional(v.number()),
254
+ });
255
+
256
+ /**
257
+ * Team payload for reference mapping
258
+ * Used to map external team IDs to LinkHub teams
259
+ */
260
+ export const teamPayloadValidator = v.object({
261
+ // Required: External ID for mapping
262
+ externalId: v.string(),
263
+
264
+ // Required: Reference to company
265
+ companyExternalId: v.string(),
266
+
267
+ // Required fields
268
+ name: v.string(),
269
+
270
+ // Optional metadata
271
+ createdAt: v.optional(v.number()),
272
+ });
273
+
274
+ /**
275
+ * User payload for reference mapping
276
+ * Used to map external user IDs to LinkHub users
277
+ */
278
+ export const userPayloadValidator = v.object({
279
+ // Required: External ID for mapping
280
+ externalId: v.string(),
281
+
282
+ // Required fields
283
+ email: v.string(),
284
+ name: v.optional(v.string()),
285
+ surname: v.optional(v.string()),
286
+
287
+ // Optional metadata
288
+ createdAt: v.optional(v.number()),
289
+ });
290
+
291
+ /**
292
+ * Company payload for reference mapping
293
+ * Used to map external company IDs to LinkHub companies
294
+ */
295
+ export const companyPayloadValidator = v.object({
296
+ // Required: External ID for mapping
297
+ externalId: v.string(),
298
+
299
+ // Required fields
300
+ name: v.string(),
301
+
302
+ // Optional metadata
303
+ createdAt: v.optional(v.number()),
304
+ });
305
+
306
+ // ============================================================================
307
+ // BATCH PAYLOAD VALIDATORS
308
+ // ============================================================================
309
+
310
+ /**
311
+ * Batch payload for inserting multiple entities at once
312
+ */
313
+ export const batchPayloadValidator = v.object({
314
+ // Optional: Companies to create/update
315
+ companies: v.optional(v.array(companyPayloadValidator)),
316
+
317
+ // Optional: Teams to create/update
318
+ teams: v.optional(v.array(teamPayloadValidator)),
319
+
320
+ // Optional: Users to create/update
321
+ users: v.optional(v.array(userPayloadValidator)),
322
+
323
+ // Optional: Indicators to create/update
324
+ indicators: v.optional(v.array(indicatorPayloadValidator)),
325
+
326
+ // Optional: Objectives to create/update
327
+ objectives: v.optional(v.array(objectivePayloadValidator)),
328
+
329
+ // Optional: Key Results to create/update
330
+ keyResults: v.optional(v.array(keyResultPayloadValidator)),
331
+
332
+ // Optional: Risks to create/update
333
+ risks: v.optional(v.array(riskPayloadValidator)),
334
+
335
+ // Optional: Initiatives to create/update
336
+ initiatives: v.optional(v.array(initiativePayloadValidator)),
337
+
338
+ // Optional: Milestones to create/update
339
+ milestones: v.optional(v.array(milestonePayloadValidator)),
340
+
341
+ // Optional: Indicator values to create
342
+ indicatorValues: v.optional(v.array(indicatorValuePayloadValidator)),
343
+
344
+ // Optional: Indicator forecasts to create
345
+ indicatorForecasts: v.optional(v.array(indicatorForecastPayloadValidator)),
346
+ });
347
+
348
+ // ============================================================================
349
+ // SYNC STATUS ENUM
350
+ // ============================================================================
351
+
352
+ export const SyncStatusSchema = v.union(
353
+ v.literal("pending"),
354
+ v.literal("synced"),
355
+ v.literal("failed")
356
+ );
357
+
358
+ // ============================================================================
359
+ // COMPONENT INTERNAL SCHEMA
360
+ // ============================================================================
361
+
362
+ /**
363
+ * Component schema with local tables for OKR entities.
364
+ * These tables store data locally before syncing to LinkHub.
365
+ */
366
+ export default defineSchema({
367
+ // =========================================================================
368
+ // SYNC INFRASTRUCTURE
369
+ // =========================================================================
370
+
371
+ // Sync queue for pending items
372
+ syncQueue: defineTable({
373
+ entityType: v.string(), // objective, keyResult, risk, etc.
374
+ externalId: v.string(),
375
+ payload: v.string(), // JSON stringified payload
376
+ status: v.union(
377
+ v.literal("pending"),
378
+ v.literal("processing"),
379
+ v.literal("success"),
380
+ v.literal("failed")
381
+ ),
382
+ attempts: v.number(),
383
+ lastAttemptAt: v.optional(v.number()),
384
+ errorMessage: v.optional(v.string()),
385
+ createdAt: v.number(),
386
+ })
387
+ .index("by_status", ["status"])
388
+ .index("by_external_id", ["externalId"])
389
+ .index("by_entity_type_status", ["entityType", "status"]),
390
+
391
+ // Sync log for tracking successful syncs
392
+ syncLog: defineTable({
393
+ entityType: v.string(),
394
+ externalId: v.string(),
395
+ linkHubId: v.optional(v.string()), // The ID returned from LinkHub
396
+ syncedAt: v.number(),
397
+ action: v.union(v.literal("create"), v.literal("update")),
398
+ })
399
+ .index("by_external_id", ["externalId"])
400
+ .index("by_entity_type", ["entityType"])
401
+ .index("by_synced_at", ["syncedAt"]),
402
+
403
+ // =========================================================================
404
+ // LOCAL OKR TABLES
405
+ // =========================================================================
406
+
407
+ // Objectives - local storage before sync
408
+ objectives: defineTable({
409
+ externalId: v.string(),
410
+ title: v.string(),
411
+ description: v.string(),
412
+ teamExternalId: v.string(),
413
+ slug: v.string(),
414
+ syncStatus: SyncStatusSchema,
415
+ createdAt: v.number(),
416
+ updatedAt: v.optional(v.number()),
417
+ deletedAt: v.optional(v.number()),
418
+ })
419
+ .index("by_external_id", ["externalId"])
420
+ .index("by_team", ["teamExternalId"])
421
+ .index("by_slug", ["slug"])
422
+ .index("by_sync_status", ["syncStatus"]),
423
+
424
+ // Key Results - local storage before sync
425
+ keyResults: defineTable({
426
+ externalId: v.string(),
427
+ objectiveExternalId: v.string(), // Required: Reference to objective
428
+ indicatorExternalId: v.string(),
429
+ teamExternalId: v.string(),
430
+ forecastValue: v.optional(v.number()),
431
+ targetValue: v.optional(v.number()),
432
+ slug: v.string(),
433
+ syncStatus: SyncStatusSchema,
434
+ createdAt: v.number(),
435
+ updatedAt: v.optional(v.number()),
436
+ deletedAt: v.optional(v.number()),
437
+ })
438
+ .index("by_external_id", ["externalId"])
439
+ .index("by_objective", ["objectiveExternalId"])
440
+ .index("by_team", ["teamExternalId"])
441
+ .index("by_indicator", ["indicatorExternalId"])
442
+ .index("by_slug", ["slug"])
443
+ .index("by_sync_status", ["syncStatus"]),
444
+
445
+ // Risks - local storage before sync
446
+ risks: defineTable({
447
+ externalId: v.string(),
448
+ description: v.string(),
449
+ teamExternalId: v.string(),
450
+ keyResultExternalId: v.string(), // Required: Reference to key result
451
+ priority: PrioritySchema,
452
+ indicatorExternalId: v.optional(v.string()),
453
+ triggerValue: v.optional(v.number()),
454
+ triggeredIfLower: v.optional(v.boolean()),
455
+ useForecastAsTrigger: v.optional(v.boolean()),
456
+ isRed: v.optional(v.boolean()),
457
+ slug: v.string(),
458
+ syncStatus: SyncStatusSchema,
459
+ createdAt: v.number(),
460
+ deletedAt: v.optional(v.number()),
461
+ })
462
+ .index("by_external_id", ["externalId"])
463
+ .index("by_key_result", ["keyResultExternalId"])
464
+ .index("by_team", ["teamExternalId"])
465
+ .index("by_slug", ["slug"])
466
+ .index("by_sync_status", ["syncStatus"]),
467
+
468
+ // Initiatives - local storage before sync
469
+ initiatives: defineTable({
470
+ externalId: v.string(),
471
+ description: v.string(),
472
+ teamExternalId: v.string(),
473
+ riskExternalId: v.string(), // Required: Reference to risk
474
+ assigneeExternalId: v.string(),
475
+ createdByExternalId: v.string(),
476
+ status: InitiativeStatusSchema, // Required, default ON_TIME
477
+ priority: PrioritySchema,
478
+ finishedAt: v.optional(v.number()),
479
+ slug: v.string(),
480
+ syncStatus: SyncStatusSchema,
481
+ createdAt: v.number(),
482
+ updatedAt: v.optional(v.number()),
483
+ deletedAt: v.optional(v.number()),
484
+ })
485
+ .index("by_external_id", ["externalId"])
486
+ .index("by_risk", ["riskExternalId"])
487
+ .index("by_team", ["teamExternalId"])
488
+ .index("by_assignee", ["assigneeExternalId"])
489
+ .index("by_slug", ["slug"])
490
+ .index("by_sync_status", ["syncStatus"]),
491
+
492
+ // Indicators - local storage before sync
493
+ indicators: defineTable({
494
+ externalId: v.string(),
495
+ companyExternalId: v.string(),
496
+ description: v.string(),
497
+ symbol: v.string(),
498
+ periodicity: PeriodicitySchema,
499
+ isReverse: v.optional(v.boolean()),
500
+ slug: v.string(),
501
+ syncStatus: SyncStatusSchema,
502
+ createdAt: v.number(),
503
+ deletedAt: v.optional(v.number()),
504
+ })
505
+ .index("by_external_id", ["externalId"])
506
+ .index("by_company", ["companyExternalId"])
507
+ .index("by_slug", ["slug"])
508
+ .index("by_sync_status", ["syncStatus"]),
509
+
510
+ // Indicator Values - local storage before sync
511
+ indicatorValues: defineTable({
512
+ externalId: v.string(),
513
+ indicatorExternalId: v.string(),
514
+ value: v.number(),
515
+ date: v.number(),
516
+ syncStatus: SyncStatusSchema,
517
+ createdAt: v.number(),
518
+ })
519
+ .index("by_external_id", ["externalId"])
520
+ .index("by_indicator", ["indicatorExternalId"])
521
+ .index("by_sync_status", ["syncStatus"]),
522
+
523
+ // Indicator Forecasts - local storage before sync
524
+ indicatorForecasts: defineTable({
525
+ externalId: v.string(),
526
+ indicatorExternalId: v.string(),
527
+ value: v.number(),
528
+ date: v.number(),
529
+ syncStatus: SyncStatusSchema,
530
+ createdAt: v.number(),
531
+ })
532
+ .index("by_external_id", ["externalId"])
533
+ .index("by_indicator", ["indicatorExternalId"])
534
+ .index("by_sync_status", ["syncStatus"]),
535
+
536
+ // Milestones - local storage before sync
537
+ milestones: defineTable({
538
+ externalId: v.string(),
539
+ indicatorExternalId: v.string(),
540
+ description: v.string(),
541
+ value: v.number(),
542
+ forecastDate: v.optional(v.number()),
543
+ status: MilestoneStatusSchema, // Required, default ON_TIME
544
+ achievedAt: v.optional(v.number()),
545
+ slug: v.string(),
546
+ syncStatus: SyncStatusSchema,
547
+ createdAt: v.number(),
548
+ updatedAt: v.optional(v.number()),
549
+ deletedAt: v.optional(v.number()),
550
+ })
551
+ .index("by_external_id", ["externalId"])
552
+ .index("by_indicator", ["indicatorExternalId"])
553
+ .index("by_slug", ["slug"])
554
+ .index("by_sync_status", ["syncStatus"]),
555
+ });
556
+
557
+ // ============================================================================
558
+ // TYPE EXPORTS
559
+ // ============================================================================
560
+
561
+ export type ObjectivePayload = typeof objectivePayloadValidator.type;
562
+ export type KeyResultPayload = typeof keyResultPayloadValidator.type;
563
+ export type RiskPayload = typeof riskPayloadValidator.type;
564
+ export type InitiativePayload = typeof initiativePayloadValidator.type;
565
+ export type IndicatorPayload = typeof indicatorPayloadValidator.type;
566
+ export type IndicatorValuePayload = typeof indicatorValuePayloadValidator.type;
567
+ export type IndicatorForecastPayload =
568
+ typeof indicatorForecastPayloadValidator.type;
569
+ export type MilestonePayload = typeof milestonePayloadValidator.type;
570
+ export type TeamPayload = typeof teamPayloadValidator.type;
571
+ export type UserPayload = typeof userPayloadValidator.type;
572
+ export type CompanyPayload = typeof companyPayloadValidator.type;
573
+ export type BatchPayload = typeof batchPayloadValidator.type;
574
+ export type SyncStatus = typeof SyncStatusSchema.type;