@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.
- package/LICENSE +201 -0
- package/README.md +579 -0
- package/dist/client/_generated/_ignore.d.ts +1 -0
- package/dist/client/_generated/_ignore.d.ts.map +1 -0
- package/dist/client/_generated/_ignore.js +3 -0
- package/dist/client/_generated/_ignore.js.map +1 -0
- package/dist/client/index.d.ts +593 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +704 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +72 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +1986 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +3 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/entities/batch.d.ts +121 -0
- package/dist/component/entities/batch.d.ts.map +1 -0
- package/dist/component/entities/batch.js +81 -0
- package/dist/component/entities/batch.js.map +1 -0
- package/dist/component/entities/index.d.ts +13 -0
- package/dist/component/entities/index.d.ts.map +1 -0
- package/dist/component/entities/index.js +22 -0
- package/dist/component/entities/index.js.map +1 -0
- package/dist/component/entities/indicatorForecasts.d.ts +61 -0
- package/dist/component/entities/indicatorForecasts.d.ts.map +1 -0
- package/dist/component/entities/indicatorForecasts.js +180 -0
- package/dist/component/entities/indicatorForecasts.js.map +1 -0
- package/dist/component/entities/indicatorValues.d.ts +77 -0
- package/dist/component/entities/indicatorValues.d.ts.map +1 -0
- package/dist/component/entities/indicatorValues.js +218 -0
- package/dist/component/entities/indicatorValues.js.map +1 -0
- package/dist/component/entities/indicators.d.ts +90 -0
- package/dist/component/entities/indicators.d.ts.map +1 -0
- package/dist/component/entities/indicators.js +239 -0
- package/dist/component/entities/indicators.js.map +1 -0
- package/dist/component/entities/initiatives.d.ts +103 -0
- package/dist/component/entities/initiatives.d.ts.map +1 -0
- package/dist/component/entities/initiatives.js +275 -0
- package/dist/component/entities/initiatives.js.map +1 -0
- package/dist/component/entities/keyResults.d.ts +111 -0
- package/dist/component/entities/keyResults.d.ts.map +1 -0
- package/dist/component/entities/keyResults.js +284 -0
- package/dist/component/entities/keyResults.js.map +1 -0
- package/dist/component/entities/milestones.d.ts +93 -0
- package/dist/component/entities/milestones.d.ts.map +1 -0
- package/dist/component/entities/milestones.js +249 -0
- package/dist/component/entities/milestones.js.map +1 -0
- package/dist/component/entities/objectives.d.ts +99 -0
- package/dist/component/entities/objectives.d.ts.map +1 -0
- package/dist/component/entities/objectives.js +261 -0
- package/dist/component/entities/objectives.js.map +1 -0
- package/dist/component/entities/risks.d.ts +126 -0
- package/dist/component/entities/risks.d.ts.map +1 -0
- package/dist/component/entities/risks.js +315 -0
- package/dist/component/entities/risks.js.map +1 -0
- package/dist/component/externalId.d.ts +79 -0
- package/dist/component/externalId.d.ts.map +1 -0
- package/dist/component/externalId.js +124 -0
- package/dist/component/externalId.js.map +1 -0
- package/dist/component/lib/hmac.d.ts +18 -0
- package/dist/component/lib/hmac.d.ts.map +1 -0
- package/dist/component/lib/hmac.js +35 -0
- package/dist/component/lib/hmac.js.map +1 -0
- package/dist/component/lib/index.d.ts +7 -0
- package/dist/component/lib/index.d.ts.map +1 -0
- package/dist/component/lib/index.js +6 -0
- package/dist/component/lib/index.js.map +1 -0
- package/dist/component/lib/types.d.ts +30 -0
- package/dist/component/lib/types.d.ts.map +1 -0
- package/dist/component/lib/types.js +7 -0
- package/dist/component/lib/types.js.map +1 -0
- package/dist/component/lib/validation.d.ts +15 -0
- package/dist/component/lib/validation.d.ts.map +1 -0
- package/dist/component/lib/validation.js +29 -0
- package/dist/component/lib/validation.js.map +1 -0
- package/dist/component/okrhub.d.ts +31 -0
- package/dist/component/okrhub.d.ts.map +1 -0
- package/dist/component/okrhub.js +45 -0
- package/dist/component/okrhub.js.map +1 -0
- package/dist/component/schema.d.ts +943 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +437 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/sync/http.d.ts +30 -0
- package/dist/component/sync/http.d.ts.map +1 -0
- package/dist/component/sync/http.js +114 -0
- package/dist/component/sync/http.js.map +1 -0
- package/dist/component/sync/index.d.ts +7 -0
- package/dist/component/sync/index.d.ts.map +1 -0
- package/dist/component/sync/index.js +7 -0
- package/dist/component/sync/index.js.map +1 -0
- package/dist/component/sync/processor.d.ts +20 -0
- package/dist/component/sync/processor.d.ts.map +1 -0
- package/dist/component/sync/processor.js +67 -0
- package/dist/component/sync/processor.js.map +1 -0
- package/dist/component/sync/queue.d.ts +40 -0
- package/dist/component/sync/queue.d.ts.map +1 -0
- package/dist/component/sync/queue.js +176 -0
- package/dist/component/sync/queue.js.map +1 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +117 -0
- package/src/client/_generated/_ignore.ts +1 -0
- package/src/client/index.ts +1004 -0
- package/src/component/_generated/api.ts +88 -0
- package/src/component/_generated/component.ts +2685 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/entities/batch.ts +90 -0
- package/src/component/entities/index.ts +64 -0
- package/src/component/entities/indicatorForecasts.ts +205 -0
- package/src/component/entities/indicatorValues.ts +254 -0
- package/src/component/entities/indicators.ts +290 -0
- package/src/component/entities/initiatives.ts +342 -0
- package/src/component/entities/keyResults.ts +334 -0
- package/src/component/entities/milestones.ts +296 -0
- package/src/component/entities/objectives.ts +294 -0
- package/src/component/entities/risks.ts +383 -0
- package/src/component/externalId.ts +172 -0
- package/src/component/lib/hmac.ts +53 -0
- package/src/component/lib/index.ts +7 -0
- package/src/component/lib/types.ts +31 -0
- package/src/component/lib/validation.ts +41 -0
- package/src/component/okrhub.ts +110 -0
- package/src/component/schema.ts +574 -0
- package/src/component/sync/http.ts +138 -0
- package/src/component/sync/index.ts +11 -0
- package/src/component/sync/processor.ts +77 -0
- package/src/component/sync/queue.ts +201 -0
- 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;
|