@apart-tech/intelligence-core 1.15.1 → 1.16.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota-service.test.js","sourceRoot":"","sources":["../../src/services/quota-service.test.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,13 @@ export interface PlanLimits {
3
3
  maxNodes: number;
4
4
  maxApiCallsPerMonth: number;
5
5
  maxMembers: number;
6
+ maxOcrPagesPerMonth: number;
7
+ maxStorageBytes: number;
8
+ maxAgentRunsPerMonth: number;
9
+ maxFileSizeBytes: number;
10
+ maxPagesPerDocument: number;
6
11
  }
12
+ export type UsageMetric = "nodes" | "apiCalls" | "members" | "ocrPages" | "storageBytes" | "agentRuns";
7
13
  export interface UsageSnapshot {
8
14
  plan: string;
9
15
  limits: PlanLimits;
@@ -11,6 +17,9 @@ export interface UsageSnapshot {
11
17
  nodes: number;
12
18
  apiCalls: number;
13
19
  members: number;
20
+ ocrPages: number;
21
+ storageBytes: number;
22
+ agentRuns: number;
14
23
  };
15
24
  stripeCustomerId: string | null;
16
25
  stripeSubscriptionId: string | null;
@@ -26,6 +35,10 @@ export interface UsageSnapshot {
26
35
  export declare class UsageService {
27
36
  private db;
28
37
  constructor(db: PrismaClient);
38
+ /**
39
+ * Get the base plan limits for a given plan name.
40
+ */
41
+ static getPlanLimits(plan: string): PlanLimits;
29
42
  /**
30
43
  * Get the full usage snapshot for an organization.
31
44
  */
@@ -35,11 +48,45 @@ export declare class UsageService {
35
48
  * Uses upsert to create or increment atomically.
36
49
  */
37
50
  incrementApiCalls(organizationId: string, count?: number): Promise<void>;
51
+ /**
52
+ * Increment the OCR pages counter for the current month.
53
+ */
54
+ incrementOcrPages(organizationId: string, count?: number): Promise<void>;
55
+ /**
56
+ * Increment the agent runs counter for the current month.
57
+ */
58
+ incrementAgentRuns(organizationId: string, count?: number): Promise<void>;
59
+ /**
60
+ * Get OCR pages used in the current period.
61
+ */
62
+ getOcrPagesUsed(organizationId: string): Promise<number>;
63
+ /**
64
+ * Get agent runs used in the current period.
65
+ */
66
+ getAgentRunsUsed(organizationId: string): Promise<number>;
67
+ /**
68
+ * Get total storage used by an org, computed as SUM(fileSizeBytes) from documents.
69
+ */
70
+ getStorageUsed(organizationId: string): Promise<number>;
71
+ /**
72
+ * Get usage history for a metric over the last N months.
73
+ */
74
+ getUsageHistory(organizationId: string, metric: string, months?: number): Promise<{
75
+ periodStart: Date;
76
+ count: number;
77
+ }[]>;
38
78
  /**
39
79
  * Check whether an organization has exceeded a specific limit.
40
80
  */
41
- isOverLimit(organizationId: string, metric: "nodes" | "apiCalls" | "members"): Promise<boolean>;
42
- private getApiCallCount;
81
+ isOverLimit(organizationId: string, metric: UsageMetric): Promise<boolean>;
82
+ /**
83
+ * Generic metric increment — upsert a usage_records row for the current period.
84
+ */
85
+ private incrementMetric;
86
+ /**
87
+ * Get the count for a metric in the current period.
88
+ */
89
+ private getMetricCount;
43
90
  /**
44
91
  * First day of the current month at midnight UTC.
45
92
  */
@@ -1 +1 @@
1
- {"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/services/usage-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,IAAI,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAEpC;;OAEG;IACG,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA4B9D;;;OAGG;IACG,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBjF;;OAEG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;YAcvF,eAAe;IAiB7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAI3B"}
1
+ {"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/services/usage-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAyBD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,cAAc,GAAG,WAAW,CAAC;AAEvG,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,IAAI,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACX,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAEpC;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAI9C;;OAEG;IACG,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAkC9D;;;OAGG;IACG,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjF;;OAEG;IACG,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjF;;OAEG;IACG,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlF;;OAEG;IACG,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI9D;;OAEG;IACG,gBAAgB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/D;;OAEG;IACG,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ7D;;OAEG;IACG,eAAe,CACnB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAU,GACjB,OAAO,CAAC;QAAE,WAAW,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAmBlD;;OAEG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBhF;;OAEG;YACW,eAAe;IAwB7B;;OAEG;YACW,cAAc;IAiB5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAI3B"}
@@ -3,11 +3,21 @@ const PLAN_LIMITS = {
3
3
  maxNodes: 500,
4
4
  maxApiCallsPerMonth: 1_000,
5
5
  maxMembers: 3,
6
+ maxOcrPagesPerMonth: 25,
7
+ maxStorageBytes: 1_073_741_824, // 1 GB
8
+ maxAgentRunsPerMonth: 0,
9
+ maxFileSizeBytes: 10_485_760, // 10 MB
10
+ maxPagesPerDocument: 20,
6
11
  },
7
12
  pro: {
8
13
  maxNodes: Infinity,
9
14
  maxApiCallsPerMonth: 50_000,
10
15
  maxMembers: Infinity,
16
+ maxOcrPagesPerMonth: 500, // per seat — multiplied at runtime
17
+ maxStorageBytes: 10_737_418_240, // 10 GB per seat — multiplied at runtime
18
+ maxAgentRunsPerMonth: 50, // per seat — multiplied at runtime
19
+ maxFileSizeBytes: 52_428_800, // 50 MB
20
+ maxPagesPerDocument: Infinity,
11
21
  },
12
22
  };
13
23
  /**
@@ -22,18 +32,27 @@ export class UsageService {
22
32
  constructor(db) {
23
33
  this.db = db;
24
34
  }
35
+ /**
36
+ * Get the base plan limits for a given plan name.
37
+ */
38
+ static getPlanLimits(plan) {
39
+ return PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
40
+ }
25
41
  /**
26
42
  * Get the full usage snapshot for an organization.
27
43
  */
28
44
  async getUsage(organizationId) {
29
- const [org, nodeCount, memberCount, apiCalls] = await Promise.all([
45
+ const [org, nodeCount, memberCount, apiCalls, ocrPages, storageBytes, agentRuns] = await Promise.all([
30
46
  this.db.organization.findUnique({
31
47
  where: { id: organizationId },
32
48
  select: { plan: true, stripeCustomerId: true, stripeSubscriptionId: true, currentPeriodEnd: true },
33
49
  }),
34
50
  this.db.node.count({ where: { organizationId } }),
35
51
  this.db.membership.count({ where: { organizationId } }),
36
- this.getApiCallCount(organizationId),
52
+ this.getMetricCount(organizationId, "api_calls"),
53
+ this.getMetricCount(organizationId, "ocr_pages"),
54
+ this.getStorageUsed(organizationId),
55
+ this.getMetricCount(organizationId, "agent_runs"),
37
56
  ]);
38
57
  const plan = org?.plan ?? "free";
39
58
  const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
@@ -44,6 +63,9 @@ export class UsageService {
44
63
  nodes: nodeCount,
45
64
  apiCalls,
46
65
  members: memberCount,
66
+ ocrPages,
67
+ storageBytes,
68
+ agentRuns,
47
69
  },
48
70
  stripeCustomerId: org?.stripeCustomerId ?? null,
49
71
  stripeSubscriptionId: org?.stripeSubscriptionId ?? null,
@@ -55,18 +77,98 @@ export class UsageService {
55
77
  * Uses upsert to create or increment atomically.
56
78
  */
57
79
  async incrementApiCalls(organizationId, count = 1) {
80
+ await this.incrementMetric(organizationId, "api_calls", count);
81
+ }
82
+ /**
83
+ * Increment the OCR pages counter for the current month.
84
+ */
85
+ async incrementOcrPages(organizationId, count = 1) {
86
+ await this.incrementMetric(organizationId, "ocr_pages", count);
87
+ }
88
+ /**
89
+ * Increment the agent runs counter for the current month.
90
+ */
91
+ async incrementAgentRuns(organizationId, count = 1) {
92
+ await this.incrementMetric(organizationId, "agent_runs", count);
93
+ }
94
+ /**
95
+ * Get OCR pages used in the current period.
96
+ */
97
+ async getOcrPagesUsed(organizationId) {
98
+ return this.getMetricCount(organizationId, "ocr_pages");
99
+ }
100
+ /**
101
+ * Get agent runs used in the current period.
102
+ */
103
+ async getAgentRunsUsed(organizationId) {
104
+ return this.getMetricCount(organizationId, "agent_runs");
105
+ }
106
+ /**
107
+ * Get total storage used by an org, computed as SUM(fileSizeBytes) from documents.
108
+ */
109
+ async getStorageUsed(organizationId) {
110
+ const result = await this.db.document.aggregate({
111
+ where: { organizationId },
112
+ _sum: { fileSizeBytes: true },
113
+ });
114
+ return result._sum.fileSizeBytes ?? 0;
115
+ }
116
+ /**
117
+ * Get usage history for a metric over the last N months.
118
+ */
119
+ async getUsageHistory(organizationId, metric, months = 6) {
120
+ const cutoff = new Date();
121
+ cutoff.setUTCMonth(cutoff.getUTCMonth() - months);
122
+ cutoff.setUTCDate(1);
123
+ cutoff.setUTCHours(0, 0, 0, 0);
124
+ const records = await this.db.usageRecord.findMany({
125
+ where: {
126
+ organizationId,
127
+ metric,
128
+ periodStart: { gte: cutoff },
129
+ },
130
+ orderBy: { periodStart: "asc" },
131
+ select: { periodStart: true, count: true },
132
+ });
133
+ return records;
134
+ }
135
+ /**
136
+ * Check whether an organization has exceeded a specific limit.
137
+ */
138
+ async isOverLimit(organizationId, metric) {
139
+ const snapshot = await this.getUsage(organizationId);
140
+ const limits = snapshot.limits;
141
+ switch (metric) {
142
+ case "nodes":
143
+ return snapshot.usage.nodes >= limits.maxNodes;
144
+ case "apiCalls":
145
+ return snapshot.usage.apiCalls >= limits.maxApiCallsPerMonth;
146
+ case "members":
147
+ return snapshot.usage.members >= limits.maxMembers;
148
+ case "ocrPages":
149
+ return snapshot.usage.ocrPages >= limits.maxOcrPagesPerMonth;
150
+ case "storageBytes":
151
+ return snapshot.usage.storageBytes >= limits.maxStorageBytes;
152
+ case "agentRuns":
153
+ return snapshot.usage.agentRuns >= limits.maxAgentRunsPerMonth;
154
+ }
155
+ }
156
+ /**
157
+ * Generic metric increment — upsert a usage_records row for the current period.
158
+ */
159
+ async incrementMetric(organizationId, metric, count) {
58
160
  const periodStart = this.currentPeriodStart();
59
161
  await this.db.usageRecord.upsert({
60
162
  where: {
61
163
  organizationId_metric_periodStart: {
62
164
  organizationId,
63
- metric: "api_calls",
165
+ metric,
64
166
  periodStart,
65
167
  },
66
168
  },
67
169
  create: {
68
170
  organizationId,
69
- metric: "api_calls",
171
+ metric,
70
172
  periodStart,
71
173
  count,
72
174
  },
@@ -77,27 +179,15 @@ export class UsageService {
77
179
  });
78
180
  }
79
181
  /**
80
- * Check whether an organization has exceeded a specific limit.
182
+ * Get the count for a metric in the current period.
81
183
  */
82
- async isOverLimit(organizationId, metric) {
83
- const snapshot = await this.getUsage(organizationId);
84
- const limits = snapshot.limits;
85
- switch (metric) {
86
- case "nodes":
87
- return snapshot.usage.nodes >= limits.maxNodes;
88
- case "apiCalls":
89
- return snapshot.usage.apiCalls >= limits.maxApiCallsPerMonth;
90
- case "members":
91
- return snapshot.usage.members >= limits.maxMembers;
92
- }
93
- }
94
- async getApiCallCount(organizationId) {
184
+ async getMetricCount(organizationId, metric) {
95
185
  const periodStart = this.currentPeriodStart();
96
186
  const record = await this.db.usageRecord.findUnique({
97
187
  where: {
98
188
  organizationId_metric_periodStart: {
99
189
  organizationId,
100
- metric: "api_calls",
190
+ metric,
101
191
  periodStart,
102
192
  },
103
193
  },
@@ -1 +1 @@
1
- {"version":3,"file":"usage-service.js","sourceRoot":"","sources":["../../src/services/usage-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"usage-service.js","sourceRoot":"","sources":["../../src/services/usage-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=usage-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-service.test.d.ts","sourceRoot":"","sources":["../../src/services/usage-service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,191 @@
1
+ import { describe, expect, it, vi, beforeEach } from "vitest";
2
+ import { UsageService } from "./usage-service.js";
3
+ const ORG_ID = "org-1";
4
+ function makeMockDb() {
5
+ const usageStore = {};
6
+ const nodeCount = 42;
7
+ const memberCount = 2;
8
+ const orgData = {
9
+ plan: "free",
10
+ stripeCustomerId: null,
11
+ stripeSubscriptionId: null,
12
+ currentPeriodEnd: null,
13
+ };
14
+ return {
15
+ organization: {
16
+ findUnique: vi.fn(async () => orgData),
17
+ },
18
+ node: {
19
+ count: vi.fn(async () => nodeCount),
20
+ },
21
+ membership: {
22
+ count: vi.fn(async () => memberCount),
23
+ },
24
+ document: {
25
+ aggregate: vi.fn(async () => ({
26
+ _sum: { fileSizeBytes: 512_000 },
27
+ })),
28
+ },
29
+ usageRecord: {
30
+ findUnique: vi.fn(async ({ where }) => {
31
+ const key = where.organizationId_metric_periodStart.metric;
32
+ return usageStore[key] ?? null;
33
+ }),
34
+ findMany: vi.fn(async () => []),
35
+ upsert: vi.fn(async ({ where, create, update }) => {
36
+ const key = where.organizationId_metric_periodStart.metric;
37
+ if (usageStore[key]) {
38
+ usageStore[key].count += update.count.increment;
39
+ }
40
+ else {
41
+ usageStore[key] = { count: create.count };
42
+ }
43
+ return usageStore[key];
44
+ }),
45
+ },
46
+ _usageStore: usageStore,
47
+ _orgData: orgData,
48
+ };
49
+ }
50
+ describe("UsageService", () => {
51
+ let db;
52
+ let svc;
53
+ beforeEach(() => {
54
+ db = makeMockDb();
55
+ svc = new UsageService(db);
56
+ });
57
+ describe("getUsage", () => {
58
+ it("returns full snapshot with all metrics", async () => {
59
+ const snapshot = await svc.getUsage(ORG_ID);
60
+ expect(snapshot.plan).toBe("free");
61
+ expect(snapshot.usage.nodes).toBe(42);
62
+ expect(snapshot.usage.members).toBe(2);
63
+ expect(snapshot.usage.apiCalls).toBe(0);
64
+ expect(snapshot.usage.ocrPages).toBe(0);
65
+ expect(snapshot.usage.storageBytes).toBe(512_000);
66
+ expect(snapshot.usage.agentRuns).toBe(0);
67
+ expect(snapshot.limits.maxNodes).toBe(500);
68
+ expect(snapshot.limits.maxOcrPagesPerMonth).toBe(25);
69
+ expect(snapshot.limits.maxStorageBytes).toBe(1_073_741_824);
70
+ expect(snapshot.limits.maxAgentRunsPerMonth).toBe(0);
71
+ });
72
+ it("returns pro limits for pro plan", async () => {
73
+ db._orgData.plan = "pro";
74
+ const snapshot = await svc.getUsage(ORG_ID);
75
+ expect(snapshot.plan).toBe("pro");
76
+ expect(snapshot.limits.maxNodes).toBe(Infinity);
77
+ expect(snapshot.limits.maxOcrPagesPerMonth).toBe(500);
78
+ expect(snapshot.limits.maxAgentRunsPerMonth).toBe(50);
79
+ });
80
+ it("falls back to free limits for unknown plan", async () => {
81
+ db._orgData.plan = "enterprise";
82
+ const snapshot = await svc.getUsage(ORG_ID);
83
+ expect(snapshot.limits.maxNodes).toBe(500);
84
+ });
85
+ });
86
+ describe("incrementApiCalls", () => {
87
+ it("creates a new record on first call", async () => {
88
+ await svc.incrementApiCalls(ORG_ID, 5);
89
+ expect(db.usageRecord.upsert).toHaveBeenCalledTimes(1);
90
+ expect(db._usageStore["api_calls"]?.count).toBe(5);
91
+ });
92
+ it("increments existing record", async () => {
93
+ await svc.incrementApiCalls(ORG_ID, 3);
94
+ await svc.incrementApiCalls(ORG_ID, 7);
95
+ expect(db._usageStore["api_calls"]?.count).toBe(10);
96
+ });
97
+ });
98
+ describe("incrementOcrPages", () => {
99
+ it("tracks OCR page usage", async () => {
100
+ await svc.incrementOcrPages(ORG_ID, 10);
101
+ expect(db._usageStore["ocr_pages"]?.count).toBe(10);
102
+ await svc.incrementOcrPages(ORG_ID, 5);
103
+ expect(db._usageStore["ocr_pages"]?.count).toBe(15);
104
+ });
105
+ });
106
+ describe("incrementAgentRuns", () => {
107
+ it("tracks agent run usage", async () => {
108
+ await svc.incrementAgentRuns(ORG_ID);
109
+ expect(db._usageStore["agent_runs"]?.count).toBe(1);
110
+ await svc.incrementAgentRuns(ORG_ID);
111
+ expect(db._usageStore["agent_runs"]?.count).toBe(2);
112
+ });
113
+ });
114
+ describe("getStorageUsed", () => {
115
+ it("returns sum of fileSizeBytes from documents", async () => {
116
+ const result = await svc.getStorageUsed(ORG_ID);
117
+ expect(result).toBe(512_000);
118
+ expect(db.document.aggregate).toHaveBeenCalledWith({
119
+ where: { organizationId: ORG_ID },
120
+ _sum: { fileSizeBytes: true },
121
+ });
122
+ });
123
+ it("returns 0 when no documents", async () => {
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ db.document.aggregate.mockResolvedValueOnce({ _sum: { fileSizeBytes: null } });
126
+ const result = await svc.getStorageUsed(ORG_ID);
127
+ expect(result).toBe(0);
128
+ });
129
+ });
130
+ describe("isOverLimit", () => {
131
+ it("returns true when nodes at limit", async () => {
132
+ // Free limit is 500 nodes; mock returns 42
133
+ const result = await svc.isOverLimit(ORG_ID, "nodes");
134
+ expect(result).toBe(false);
135
+ });
136
+ it("detects OCR over limit", async () => {
137
+ // Free limit is 25 OCR pages
138
+ db._usageStore["ocr_pages"] = { count: 30 };
139
+ const result = await svc.isOverLimit(ORG_ID, "ocrPages");
140
+ expect(result).toBe(true);
141
+ });
142
+ it("detects storage over limit", async () => {
143
+ // Free limit is 1 GB
144
+ db.document.aggregate.mockResolvedValueOnce({
145
+ _sum: { fileSizeBytes: 2_000_000_000 },
146
+ });
147
+ const result = await svc.isOverLimit(ORG_ID, "storageBytes");
148
+ expect(result).toBe(true);
149
+ });
150
+ it("detects agent runs at zero limit for free tier", async () => {
151
+ // Free tier has 0 agent runs
152
+ db._usageStore["agent_runs"] = { count: 1 };
153
+ const result = await svc.isOverLimit(ORG_ID, "agentRuns");
154
+ expect(result).toBe(true);
155
+ });
156
+ it("free tier blocks agent runs even at 0", async () => {
157
+ const result = await svc.isOverLimit(ORG_ID, "agentRuns");
158
+ // 0 >= 0 is true
159
+ expect(result).toBe(true);
160
+ });
161
+ });
162
+ describe("getUsageHistory", () => {
163
+ it("queries usage records for the metric", async () => {
164
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
165
+ db.usageRecord.findMany.mockResolvedValueOnce([
166
+ { periodStart: new Date("2026-01-01"), count: 100 },
167
+ { periodStart: new Date("2026-02-01"), count: 150 },
168
+ ]);
169
+ const history = await svc.getUsageHistory(ORG_ID, "api_calls", 3);
170
+ expect(history).toHaveLength(2);
171
+ expect(db.usageRecord.findMany).toHaveBeenCalledTimes(1);
172
+ });
173
+ });
174
+ describe("getPlanLimits (static)", () => {
175
+ it("returns correct free limits", () => {
176
+ const limits = UsageService.getPlanLimits("free");
177
+ expect(limits.maxNodes).toBe(500);
178
+ expect(limits.maxOcrPagesPerMonth).toBe(25);
179
+ });
180
+ it("returns correct pro limits", () => {
181
+ const limits = UsageService.getPlanLimits("pro");
182
+ expect(limits.maxNodes).toBe(Infinity);
183
+ expect(limits.maxOcrPagesPerMonth).toBe(500);
184
+ });
185
+ it("falls back to free for unknown plan", () => {
186
+ const limits = UsageService.getPlanLimits("unknown");
187
+ expect(limits.maxNodes).toBe(500);
188
+ });
189
+ });
190
+ });
191
+ //# sourceMappingURL=usage-service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-service.test.js","sourceRoot":"","sources":["../../src/services/usage-service.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,MAAM,MAAM,GAAG,OAAO,CAAC;AAEvB,SAAS,UAAU;IACjB,MAAM,UAAU,GAAsC,EAAE,CAAC;IACzD,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,WAAW,GAAG,CAAC,CAAC;IACtB,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,MAAM;QACZ,gBAAgB,EAAE,IAAI;QACtB,oBAAoB,EAAE,IAAI;QAC1B,gBAAgB,EAAE,IAAI;KACvB,CAAC;IAEF,OAAO;QACL,YAAY,EAAE;YACZ,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC;SACvC;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC;SACpC;QACD,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC;SACtC;QACD,QAAQ,EAAE;YACR,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAC5B,IAAI,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE;aACjC,CAAC,CAAC;SACJ;QACD,WAAW,EAAE;YACX,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAwE,EAAE,EAAE;gBAC1G,MAAM,GAAG,GAAG,KAAK,CAAC,iCAAiC,CAAC,MAAM,CAAC;gBAC3D,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;YACjC,CAAC,CAAC;YACF,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;YAC/B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAI3C,EAAE,EAAE;gBACH,MAAM,GAAG,GAAG,KAAK,CAAC,iCAAiC,CAAC,MAAM,CAAC;gBAC3D,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpB,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC;gBAClD,CAAC;qBAAM,CAAC;oBACN,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;gBAC5C,CAAC;gBACD,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC,CAAC;SACH;QACD,WAAW,EAAE,UAAU;QACvB,QAAQ,EAAE,OAAO;KAClB,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,EAAiC,CAAC;IACtC,IAAI,GAAiB,CAAC;IAEtB,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,GAAG,UAAU,EAAE,CAAC;QAClB,GAAG,GAAG,IAAI,YAAY,CAAC,EAAW,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAE5C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC;YACzB,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAE5C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,YAAY,CAAC;YAChC,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAE5C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,GAAG,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAEvC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,GAAG,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvC,MAAM,GAAG,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAEvC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,GAAG,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YACxC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEpD,MAAM,GAAG,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACtC,MAAM,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAEpD,MAAM,GAAG,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7B,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,oBAAoB,CAAC;gBACjD,KAAK,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE;gBACjC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE;aAC9B,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YAC3C,8DAA8D;YAC9D,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,EAAS,CAAC,CAAC;YACtF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,2CAA2C;YAC3C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACtC,6BAA6B;YAC7B,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YACzD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,qBAAqB;YACrB,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,qBAAqB,CAAC;gBAC1C,IAAI,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE;aACvC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;YAC7D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;YAC9D,6BAA6B;YAC7B,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAC1D,iBAAiB;YACjB,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,8DAA8D;YAC9D,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC;gBAC5C,EAAE,WAAW,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;gBACnD,EAAE,WAAW,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;aAC7C,CAAC,CAAC;YAEV,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;YAElE,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAClD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACjD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;YACrD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apart-tech/intelligence-core",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "Core library: database, services, and providers for Apart Intelligence",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,11 +35,14 @@ model Organization {
35
35
  orgAgentTypes OrgAgentType[]
36
36
  orgMcpServers OrgMcpServer[]
37
37
  usageRecords UsageRecord[]
38
- tagDefinitions TagDefinition[]
39
- nodeTags NodeTag[]
40
- nodeChunks NodeChunk[]
41
- piiQueryLogs PiiQueryLog[]
42
- documents Document[]
38
+ quotaOverrides QuotaOverride[]
39
+ onboardingPackages OnboardingPackage[]
40
+ billingEvents BillingEvent[]
41
+ tagDefinitions TagDefinition[]
42
+ nodeTags NodeTag[]
43
+ nodeChunks NodeChunk[]
44
+ piiQueryLogs PiiQueryLog[]
45
+ documents Document[]
43
46
 
44
47
  @@map("organizations")
45
48
  }
@@ -55,6 +58,7 @@ model User {
55
58
  claudeOauthTokenEncrypted String? @map("claude_oauth_token_encrypted") @db.Text
56
59
  apartRefreshTokenEncrypted String? @map("apart_refresh_token_encrypted") @db.Text
57
60
  agentSecretsEncrypted String? @map("agent_secrets_encrypted") @db.Text
61
+ isSuperAdmin Boolean @default(false) @map("is_super_admin")
58
62
 
59
63
  memberships Membership[]
60
64
  createdAgentTypes OrgAgentType[] @relation("OrgAgentTypeCreatedBy")
@@ -616,6 +620,24 @@ model NodeTagAudit {
616
620
  @@map("node_tag_audit")
617
621
  }
618
622
 
623
+ // ── Quota Overrides ─────────────────────────────────────────────────────────
624
+
625
+ model QuotaOverride {
626
+ id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
627
+ organizationId String @map("organization_id") @db.Uuid
628
+ resource String @db.VarChar(50)
629
+ overrideLimit Int @map("override_limit")
630
+ reason String @default("") @db.Text
631
+ grantedBy String @map("granted_by") @db.VarChar(255)
632
+ expiresAt DateTime? @map("expires_at") @db.Timestamptz
633
+ createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
634
+
635
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
636
+
637
+ @@index([organizationId], map: "idx_quota_overrides_org")
638
+ @@map("quota_overrides")
639
+ }
640
+
619
641
  // ── Document Archive ────────────────────────────────────────────────────────
620
642
 
621
643
  model Document {
@@ -643,3 +665,42 @@ model Document {
643
665
  @@index([organizationId, status], map: "idx_documents_org_status")
644
666
  @@map("documents")
645
667
  }
668
+
669
+ // ── Onboarding Packages ──────────────────────────────────────────────────────
670
+
671
+ model OnboardingPackage {
672
+ id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
673
+ organizationId String @map("organization_id") @db.Uuid
674
+ status String @default("pending") @db.VarChar(20)
675
+ ocrPagesAllotment Int @default(10000) @map("ocr_pages_allotment")
676
+ ocrPagesUsed Int @default(0) @map("ocr_pages_used")
677
+ storageBytesAllotment BigInt @default(26843545600) @map("storage_bytes_allotment")
678
+ proSeats Int @default(3) @map("pro_seats")
679
+ proExpiresAt DateTime? @map("pro_expires_at") @db.Timestamptz
680
+ stripePaymentIntentId String? @map("stripe_payment_intent_id") @db.VarChar(255)
681
+ purchasedAt DateTime? @map("purchased_at") @db.Timestamptz
682
+ completedAt DateTime? @map("completed_at") @db.Timestamptz
683
+ createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
684
+
685
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
686
+
687
+ @@index([organizationId], map: "idx_onboarding_packages_org")
688
+ @@map("onboarding_packages")
689
+ }
690
+
691
+ // ── Billing Events (Audit Trail) ────────────────────────────────────────────
692
+
693
+ model BillingEvent {
694
+ id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
695
+ organizationId String @map("organization_id") @db.Uuid
696
+ eventType String @map("event_type") @db.VarChar(50)
697
+ detail Json @default("{}") @db.JsonB
698
+ actor String @default("system") @db.VarChar(255)
699
+ createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
700
+
701
+ organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
702
+
703
+ @@index([organizationId], map: "idx_billing_events_org")
704
+ @@index([eventType], map: "idx_billing_events_type")
705
+ @@map("billing_events")
706
+ }