@brite-future-schools-contracts/contracts 1.0.8 → 2.0.2

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 (40) hide show
  1. package/dist/chunk-AEZO7MJD.js +127 -0
  2. package/dist/chunk-AEZO7MJD.js.map +1 -0
  3. package/dist/chunk-IR6JUP6L.js +48 -0
  4. package/dist/chunk-IR6JUP6L.js.map +1 -0
  5. package/dist/chunk-PCHAGP5X.js +1 -0
  6. package/dist/contracts/index.cjs +179 -0
  7. package/dist/contracts/index.cjs.map +1 -0
  8. package/dist/contracts/index.d.cts +201 -0
  9. package/dist/contracts/index.d.ts +158 -9677
  10. package/dist/contracts/index.js +22 -1414
  11. package/dist/contracts/index.js.map +1 -1
  12. package/dist/index.cjs +222 -0
  13. package/dist/index.cjs.map +1 -0
  14. package/dist/index.d.cts +4 -0
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.js +62 -1538
  17. package/dist/index.js.map +1 -1
  18. package/dist/schemas/index.cjs +181 -0
  19. package/dist/schemas/index.cjs.map +1 -0
  20. package/dist/schemas/index.d.cts +145 -0
  21. package/dist/schemas/index.d.ts +130 -1024
  22. package/dist/schemas/index.js +42 -640
  23. package/dist/schemas/index.js.map +1 -1
  24. package/package.json +32 -59
  25. package/dist/chunk-M6LF6JUL.mjs +0 -557
  26. package/dist/chunk-M6LF6JUL.mjs.map +0 -1
  27. package/dist/chunk-VC6SCJVW.mjs +0 -935
  28. package/dist/chunk-VC6SCJVW.mjs.map +0 -1
  29. package/dist/contracts/index.d.mts +0 -9720
  30. package/dist/contracts/index.mjs +0 -36
  31. package/dist/index.d.mts +0 -4
  32. package/dist/index.mjs +0 -161
  33. package/dist/index.mjs.map +0 -1
  34. package/dist/schemas/index.d.mts +0 -1039
  35. package/dist/schemas/index.mjs +0 -129
  36. package/dist/schemas/index.mjs.map +0 -1
  37. package/src/contracts/index.ts +0 -1209
  38. package/src/index.ts +0 -2
  39. package/src/schemas/index.ts +0 -586
  40. /package/dist/{contracts/index.mjs.map → chunk-PCHAGP5X.js.map} +0 -0
@@ -1,1209 +0,0 @@
1
- import { oc } from "@orpc/contract";
2
- import { z } from "zod";
3
- import {
4
- loginInputSchema,
5
- loginOutputSchema,
6
- mfaVerifyInputSchema,
7
- changePasswordInputSchema,
8
- refreshTokenOutputSchema,
9
- refreshInputSchema,
10
- branchSchema,
11
- createBranchInputSchema,
12
- studentSchema,
13
- createStudentInputSchema,
14
- listStudentsInputSchema,
15
- guardianSchema,
16
- sponsorSchema,
17
- sponsorTypeEnum,
18
- subjectSchema,
19
- assessmentScoreInputSchema,
20
- reportCardStatusEnum,
21
- gradeLevelEnum,
22
- assessmentTypeEnum,
23
- feeItemSchema,
24
- recordPaymentInputSchema,
25
- invoiceStatusEnum,
26
- staffSchema,
27
- leaveRequestInputSchema,
28
- leaveStatusEnum,
29
- tripLogInputSchema,
30
- busRegisterEntrySchema,
31
- busRegisterStatusEnum,
32
- vehicleSchema,
33
- vehicleStatusEnum,
34
- vehicleOwnershipEnum,
35
- routeSchema,
36
- tripLogSchema,
37
- tripCategoryEnum,
38
- tripStatusEnum,
39
- maintenanceRequestSchema,
40
- transportApplicationSchema,
41
- transportAppStatusEnum,
42
- maintenanceRequestStatusEnum,
43
- assetCategoryEnum,
44
- assetConditionEnum,
45
- maintenanceTicketStatusEnum,
46
- borrowingStatusEnum,
47
- incidentSeverityEnum,
48
- incidentStatusEnum,
49
- disciplineRulingEnum,
50
- payrollRunStatusEnum,
51
- sendBulkSmsInputSchema,
52
- paginationSchema,
53
- uuidSchema,
54
- userSchema,
55
- } from "../schemas";
56
-
57
- // ─── Auth Router ──────────────────────────────────────────────────────────────
58
-
59
- export const authContract = {
60
- login: oc.input(loginInputSchema).output(loginOutputSchema),
61
-
62
- refresh: oc.input(refreshInputSchema).output(refreshTokenOutputSchema),
63
-
64
- logout: oc.output(z.object({ success: z.boolean() })),
65
-
66
- me: oc.output(
67
- userSchema.extend({
68
- roles: z.array(
69
- z.object({
70
- id: uuidSchema,
71
- name: z.string(),
72
- branchId: uuidSchema.nullable(),
73
- }),
74
- ),
75
- }),
76
- ),
77
-
78
- verifyMfa: oc
79
- .input(mfaVerifyInputSchema)
80
- .output(z.object({ verified: z.boolean() })),
81
-
82
- changePassword: oc
83
- .input(changePasswordInputSchema)
84
- .output(z.object({ success: z.boolean() })),
85
-
86
- switchBranch: oc
87
- .input(z.object({ branchId: uuidSchema }))
88
- .output(z.object({ accessToken: z.string() })),
89
- };
90
-
91
- // ─── Branches Router ──────────────────────────────────────────────────────────
92
-
93
- export const branchesContract = {
94
- list: oc.output(z.array(branchSchema)),
95
-
96
- get: oc.input(z.object({ id: uuidSchema })).output(branchSchema),
97
-
98
- create: oc.input(createBranchInputSchema).output(branchSchema),
99
-
100
- update: oc
101
- .input(createBranchInputSchema.partial().extend({ id: uuidSchema }))
102
- .output(branchSchema),
103
-
104
- updateFeatureFlags: oc
105
- .input(z.object({ branchId: uuidSchema, flags: z.record(z.boolean()) }))
106
- .output(branchSchema),
107
- };
108
-
109
- // ─── Students Router ──────────────────────────────────────────────────────────
110
-
111
- const studentWithGuardians = studentSchema.extend({
112
- guardians: z.array(guardianSchema),
113
- sponsors: z.array(sponsorSchema),
114
- currentClass: z
115
- .object({ id: uuidSchema, name: z.string(), grade: z.string() })
116
- .nullable(),
117
- });
118
-
119
- export const studentsContract = {
120
- list: oc.input(listStudentsInputSchema).output(
121
- z.object({
122
- data: z.array(studentSchema),
123
- total: z.number(),
124
- page: z.number(),
125
- limit: z.number(),
126
- }),
127
- ),
128
-
129
- get: oc.input(z.object({ id: uuidSchema })).output(studentWithGuardians),
130
-
131
- create: oc.input(createStudentInputSchema).output(studentSchema),
132
-
133
- update: oc
134
- .input(createStudentInputSchema.partial().extend({ id: uuidSchema }))
135
- .output(studentSchema),
136
-
137
- enroll: oc
138
- .input(
139
- z.object({
140
- studentId: uuidSchema,
141
- classId: uuidSchema,
142
- termId: uuidSchema,
143
- }),
144
- )
145
- .output(z.object({ success: z.boolean() })),
146
-
147
- transfer: oc
148
- .input(
149
- z.object({
150
- studentId: uuidSchema,
151
- toBranchId: uuidSchema,
152
- reason: z.string(),
153
- }),
154
- )
155
- .output(z.object({ success: z.boolean() })),
156
-
157
- linkGuardian: oc
158
- .input(
159
- z.object({
160
- studentId: uuidSchema,
161
- guardianId: uuidSchema,
162
- isPrimary: z.boolean(),
163
- }),
164
- )
165
- .output(z.object({ success: z.boolean() })),
166
-
167
- linkSponsor: oc
168
- .input(
169
- z.object({
170
- studentId: uuidSchema,
171
- sponsorId: uuidSchema,
172
- termId: uuidSchema,
173
- feeItemIds: z.array(uuidSchema),
174
- }),
175
- )
176
- .output(z.object({ success: z.boolean() })),
177
-
178
- listGuardians: oc
179
- .input(
180
- z.object({
181
- branchId: uuidSchema.optional(),
182
- search: z.string().optional(),
183
- }),
184
- )
185
- .output(
186
- z.array(
187
- guardianSchema.extend({
188
- email: z.string().nullable(),
189
- linkedStudents: z.array(
190
- z.object({
191
- id: uuidSchema,
192
- firstName: z.string(),
193
- lastName: z.string(),
194
- admissionNo: z.string(),
195
- status: z.string(),
196
- }),
197
- ),
198
- }),
199
- ),
200
- ),
201
-
202
- createGuardian: oc
203
- .input(
204
- z.object({
205
- firstName: z.string().min(1),
206
- middleName: z.string().optional(),
207
- lastName: z.string().min(1),
208
- relationship: z.string().min(1),
209
- phone: z.string().min(9),
210
- email: z.string().email().optional(),
211
- nationalId: z.string().optional(),
212
- occupation: z.string().optional(),
213
- address: z.string().optional(),
214
- }),
215
- )
216
- .output(guardianSchema),
217
-
218
- listClasses: oc
219
- .input(z.object({ branchId: uuidSchema.optional() }))
220
- .output(
221
- z.array(
222
- z.object({
223
- id: uuidSchema,
224
- name: z.string(),
225
- grade: z.string(),
226
- level: z.string(),
227
- }),
228
- ),
229
- ),
230
-
231
- listGrades: oc
232
- .input(z.object({ branchId: uuidSchema.optional() }))
233
- .output(
234
- z.array(
235
- z.object({
236
- id: uuidSchema,
237
- name: z.string(),
238
- level: z.string(),
239
- }),
240
- ),
241
- ),
242
-
243
- listTerms: oc
244
- .input(z.object({ branchId: uuidSchema.optional() }))
245
- .output(
246
- z.array(
247
- z.object({
248
- id: uuidSchema,
249
- name: z.string(),
250
- isCurrent: z.boolean(),
251
- startDate: z.string(),
252
- endDate: z.string(),
253
- }),
254
- ),
255
- ),
256
-
257
- listSponsors: oc
258
- .input(z.object({ branchId: uuidSchema.optional() }))
259
- .output(z.array(sponsorSchema)),
260
- };
261
-
262
- // ─── Academics Router ─────────────────────────────────────────────────────────
263
-
264
- export const academicsContract = {
265
- subjects: {
266
- list: oc
267
- .input(
268
- z.object({
269
- branchId: uuidSchema,
270
- gradeLevel: gradeLevelEnum.optional(),
271
- }),
272
- )
273
- .output(z.array(subjectSchema)),
274
- create: oc
275
- .input(
276
- z.object({
277
- name: z.string(),
278
- code: z.string(),
279
- gradeLevel: gradeLevelEnum,
280
- departmentId: uuidSchema.optional(),
281
- }),
282
- )
283
- .output(subjectSchema),
284
- },
285
-
286
- timetable: {
287
- get: oc.input(z.object({ classId: uuidSchema, termId: uuidSchema })).output(
288
- z.array(
289
- z.object({
290
- id: uuidSchema,
291
- dayOfWeek: z.number().min(1).max(5),
292
- periodNo: z.number(),
293
- subject: subjectSchema,
294
- teacherName: z.string(),
295
- room: z.string().nullable(),
296
- startTime: z.string(),
297
- endTime: z.string(),
298
- }),
299
- ),
300
- ),
301
- upsert: oc
302
- .input(
303
- z.object({
304
- classId: uuidSchema,
305
- termId: uuidSchema,
306
- slots: z.array(
307
- z.object({
308
- dayOfWeek: z.number().min(1).max(5),
309
- periodNo: z.number(),
310
- subjectId: uuidSchema,
311
- teacherId: uuidSchema,
312
- room: z.string().optional(),
313
- startTime: z.string(),
314
- endTime: z.string(),
315
- }),
316
- ),
317
- }),
318
- )
319
- .output(z.object({ success: z.boolean() })),
320
- },
321
-
322
- assessments: {
323
- list: oc
324
- .input(
325
- z.object({
326
- classId: uuidSchema,
327
- termId: uuidSchema,
328
- type: assessmentTypeEnum.optional(),
329
- }),
330
- )
331
- .output(
332
- z.array(
333
- z.object({
334
- id: uuidSchema,
335
- title: z.string(),
336
- type: assessmentTypeEnum,
337
- date: z.string(),
338
- maxScore: z.number(),
339
- subjectId: uuidSchema,
340
- }),
341
- ),
342
- ),
343
- create: oc
344
- .input(
345
- z.object({
346
- title: z.string(),
347
- type: assessmentTypeEnum,
348
- classId: uuidSchema,
349
- subjectId: uuidSchema,
350
- termId: uuidSchema,
351
- date: z.string(),
352
- maxScore: z.number(),
353
- }),
354
- )
355
- .output(z.object({ id: uuidSchema })),
356
- enterScores: oc
357
- .input(z.object({ scores: z.array(assessmentScoreInputSchema) }))
358
- .output(z.object({ saved: z.number() })),
359
- },
360
-
361
- reportCards: {
362
- list: oc
363
- .input(
364
- z.object({
365
- branchId: uuidSchema,
366
- termId: uuidSchema,
367
- classId: uuidSchema.optional(),
368
- status: reportCardStatusEnum.optional(),
369
- }),
370
- )
371
- .output(
372
- z.array(
373
- z.object({
374
- id: uuidSchema,
375
- studentId: uuidSchema,
376
- studentName: z.string(),
377
- status: reportCardStatusEnum,
378
- generatedAt: z.string().datetime().nullable(),
379
- }),
380
- ),
381
- ),
382
- get: oc
383
- .input(z.object({ studentId: uuidSchema, termId: uuidSchema }))
384
- .output(
385
- z.object({
386
- id: uuidSchema,
387
- studentId: uuidSchema,
388
- termId: uuidSchema,
389
- status: reportCardStatusEnum,
390
- scores: z.array(z.any()),
391
- teacherComments: z.string().nullable(),
392
- generatedAt: z.string().datetime().nullable(),
393
- }),
394
- ),
395
- updateStatus: oc
396
- .input(
397
- z.object({
398
- id: uuidSchema,
399
- status: reportCardStatusEnum,
400
- comments: z.string().optional(),
401
- }),
402
- )
403
- .output(z.object({ success: z.boolean() })),
404
- },
405
-
406
- attendance: {
407
- markClass: oc
408
- .input(
409
- z.object({
410
- classId: uuidSchema,
411
- date: z.string(),
412
- subjectId: uuidSchema,
413
- records: z.array(
414
- z.object({
415
- studentId: uuidSchema,
416
- present: z.boolean(),
417
- note: z.string().optional(),
418
- }),
419
- ),
420
- }),
421
- )
422
- .output(z.object({ saved: z.number() })),
423
- getClassAttendance: oc
424
- .input(
425
- z.object({ classId: uuidSchema, from: z.string(), to: z.string() }),
426
- )
427
- .output(
428
- z.array(
429
- z.object({
430
- studentId: uuidSchema,
431
- studentName: z.string(),
432
- presentDays: z.number(),
433
- absentDays: z.number(),
434
- percentage: z.number(),
435
- }),
436
- ),
437
- ),
438
- },
439
- };
440
-
441
- // ─── Finance Router ───────────────────────────────────────────────────────────
442
-
443
- export const financeContract = {
444
- feeItems: {
445
- list: oc
446
- .input(z.object({ branchId: uuidSchema }))
447
- .output(z.array(feeItemSchema)),
448
- create: oc
449
- .input(
450
- z.object({
451
- name: z.string(),
452
- category: z.any(),
453
- defaultAmount: z.number(),
454
- applicableGrades: z.array(gradeLevelEnum),
455
- }),
456
- )
457
- .output(feeItemSchema),
458
- },
459
-
460
- invoices: {
461
- listForStudent: oc
462
- .input(z.object({ studentId: uuidSchema, termId: uuidSchema.optional() }))
463
- .output(
464
- z.array(
465
- z.object({
466
- id: uuidSchema,
467
- termId: uuidSchema,
468
- payerType: z.string(),
469
- totalAmount: z.number(),
470
- paidAmount: z.number(),
471
- balance: z.number(),
472
- status: invoiceStatusEnum,
473
- dueDate: z.string().nullable(),
474
- }),
475
- ),
476
- ),
477
- generate: oc
478
- .input(
479
- z.object({
480
- branchId: uuidSchema,
481
- termId: uuidSchema,
482
- studentIds: z.array(uuidSchema).optional(),
483
- }),
484
- )
485
- .output(z.object({ generated: z.number() })),
486
- },
487
-
488
- payments: {
489
- record: oc
490
- .input(recordPaymentInputSchema)
491
- .output(z.object({ id: uuidSchema, receipt: z.string() })),
492
- listForStudent: oc.input(z.object({ studentId: uuidSchema })).output(
493
- z.array(
494
- z.object({
495
- id: uuidSchema,
496
- amount: z.number(),
497
- method: z.string(),
498
- reference: z.string().nullable(),
499
- paymentDate: z.string(),
500
- createdAt: z.string(),
501
- }),
502
- ),
503
- ),
504
- },
505
-
506
- blocks: {
507
- list: oc
508
- .input(
509
- z.object({
510
- branchId: uuidSchema,
511
- termId: uuidSchema,
512
- active: z.boolean().optional(),
513
- }),
514
- )
515
- .output(
516
- z.array(
517
- z.object({
518
- id: uuidSchema,
519
- studentId: uuidSchema,
520
- studentName: z.string(),
521
- blockType: z.string(),
522
- isActive: z.boolean(),
523
- balanceAtBlock: z.number(),
524
- }),
525
- ),
526
- ),
527
- lift: oc
528
- .input(z.object({ blockId: uuidSchema, reason: z.string() }))
529
- .output(z.object({ success: z.boolean() })),
530
- },
531
-
532
- reports: {
533
- termCollection: oc
534
- .input(z.object({ branchId: uuidSchema, termId: uuidSchema }))
535
- .output(
536
- z.object({
537
- totalExpected: z.number(),
538
- totalCollected: z.number(),
539
- totalOutstanding: z.number(),
540
- collectionRate: z.number(),
541
- byPaymentMethod: z.record(z.number()),
542
- }),
543
- ),
544
- },
545
- };
546
-
547
- // ─── HR Router ────────────────────────────────────────────────────────────────
548
-
549
- export const hrContract = {
550
- staff: {
551
- list: oc
552
- .input(
553
- paginationSchema.extend({
554
- branchId: uuidSchema,
555
- search: z.string().optional(),
556
- departmentId: uuidSchema.optional(),
557
- }),
558
- )
559
- .output(z.object({ data: z.array(staffSchema), total: z.number() })),
560
- get: oc.input(z.object({ id: uuidSchema })).output(staffSchema),
561
- create: oc
562
- .input(
563
- staffSchema
564
- .omit({ id: true })
565
- .partial({
566
- contractEnd: true,
567
- tscNumber: true,
568
- kraPin: true,
569
- nhifNo: true,
570
- nssfNo: true,
571
- bankName: true,
572
- bankAccount: true,
573
- departmentId: true,
574
- }),
575
- )
576
- .output(staffSchema),
577
- },
578
-
579
- leave: {
580
- request: oc
581
- .input(leaveRequestInputSchema)
582
- .output(z.object({ id: uuidSchema })),
583
- list: oc
584
- .input(
585
- z.object({
586
- branchId: uuidSchema,
587
- staffId: uuidSchema.optional(),
588
- status: leaveStatusEnum.optional(),
589
- }),
590
- )
591
- .output(z.array(z.any())),
592
- approve: oc
593
- .input(
594
- z.object({
595
- id: uuidSchema,
596
- approved: z.boolean(),
597
- comment: z.string().optional(),
598
- }),
599
- )
600
- .output(z.object({ success: z.boolean() })),
601
- },
602
-
603
- attendance: {
604
- mark: oc
605
- .input(
606
- z.object({
607
- staffId: uuidSchema,
608
- date: z.string(),
609
- checkIn: z.string().optional(),
610
- checkOut: z.string().optional(),
611
- status: z.enum(["present", "absent", "late", "half_day"]),
612
- }),
613
- )
614
- .output(z.object({ success: z.boolean() })),
615
- getSummary: oc
616
- .input(
617
- z.object({ staffId: uuidSchema, month: z.number(), year: z.number() }),
618
- )
619
- .output(
620
- z.object({
621
- presentDays: z.number(),
622
- absentDays: z.number(),
623
- lateDays: z.number(),
624
- }),
625
- ),
626
- },
627
- };
628
-
629
- // ─── Payroll Router ───────────────────────────────────────────────────────────
630
-
631
- export const payrollContract = {
632
- runs: {
633
- list: oc
634
- .input(z.object({ branchId: uuidSchema, year: z.number().optional() }))
635
- .output(
636
- z.array(
637
- z.object({
638
- id: uuidSchema,
639
- month: z.number(),
640
- year: z.number(),
641
- status: payrollRunStatusEnum,
642
- netTotal: z.number(),
643
- }),
644
- ),
645
- ),
646
- initiate: oc
647
- .input(
648
- z.object({ branchId: uuidSchema, month: z.number(), year: z.number() }),
649
- )
650
- .output(z.object({ id: uuidSchema, preview: z.array(z.any()) })),
651
- approve: oc
652
- .input(z.object({ id: uuidSchema }))
653
- .output(z.object({ success: z.boolean() })),
654
- getPayslip: oc
655
- .input(z.object({ payrollRunId: uuidSchema, staffId: uuidSchema }))
656
- .output(z.object({ url: z.string() })),
657
- },
658
- };
659
-
660
- // ─── Transport Router ─────────────────────────────────────────────────────────
661
-
662
- export const transportContract = {
663
- vehicles: {
664
- list: oc
665
- .input(z.object({ branchId: uuidSchema }))
666
- .output(z.array(vehicleSchema)),
667
- create: oc
668
- .input(z.object({
669
- branchId: uuidSchema,
670
- plateNo: z.string().min(1),
671
- type: z.string().min(1),
672
- ownershipType: vehicleOwnershipEnum,
673
- make: z.string().optional(),
674
- model: z.string().optional(),
675
- capacity: z.number().int().positive().optional(),
676
- insuranceExpiry: z.string().optional(),
677
- inspectionDate: z.string().optional(),
678
- driverUserId: uuidSchema.optional(),
679
- notes: z.string().optional(),
680
- }))
681
- .output(vehicleSchema),
682
- update: oc
683
- .input(z.object({
684
- id: uuidSchema,
685
- plateNo: z.string().optional(),
686
- type: z.string().optional(),
687
- ownershipType: vehicleOwnershipEnum.optional(),
688
- make: z.string().optional(),
689
- model: z.string().optional(),
690
- capacity: z.number().int().positive().optional(),
691
- insuranceExpiry: z.string().optional(),
692
- inspectionDate: z.string().optional(),
693
- driverUserId: uuidSchema.optional(),
694
- notes: z.string().optional(),
695
- }))
696
- .output(vehicleSchema),
697
- updateStatus: oc
698
- .input(z.object({ id: uuidSchema, status: vehicleStatusEnum }))
699
- .output(vehicleSchema),
700
- },
701
-
702
- routes: {
703
- list: oc
704
- .input(z.object({ branchId: uuidSchema }))
705
- .output(z.array(routeSchema)),
706
- get: oc
707
- .input(z.object({ routeId: uuidSchema }))
708
- .output(routeSchema),
709
- create: oc
710
- .input(z.object({
711
- branchId: uuidSchema,
712
- name: z.string().min(1),
713
- description: z.string().optional(),
714
- vehicleId: uuidSchema.optional(),
715
- routeCategory: z.string().optional(),
716
- departureTime: z.string().optional(),
717
- returnTime: z.string().optional(),
718
- fare: z.number().optional(),
719
- stops: z.array(z.object({
720
- stopName: z.string().min(1),
721
- stopOrder: z.number().int(),
722
- estimatedTime: z.string().optional(),
723
- })).optional(),
724
- }))
725
- .output(routeSchema),
726
- update: oc
727
- .input(z.object({
728
- id: uuidSchema,
729
- name: z.string().optional(),
730
- description: z.string().optional(),
731
- vehicleId: uuidSchema.optional(),
732
- routeCategory: z.string().optional(),
733
- departureTime: z.string().optional(),
734
- returnTime: z.string().optional(),
735
- fare: z.number().optional(),
736
- }))
737
- .output(routeSchema),
738
- toggle: oc
739
- .input(z.object({ id: uuidSchema, isActive: z.boolean() }))
740
- .output(z.object({ success: z.boolean() })),
741
- roster: oc
742
- .input(z.object({ routeId: uuidSchema, termId: uuidSchema }))
743
- .output(z.array(z.object({
744
- studentId: uuidSchema,
745
- studentName: z.string(),
746
- admissionNo: z.string(),
747
- pickupStop: z.string().nullable(),
748
- dropoffStop: z.string().nullable(),
749
- }))),
750
- enroll: oc
751
- .input(z.object({
752
- studentId: uuidSchema,
753
- routeId: uuidSchema,
754
- termId: uuidSchema,
755
- pickupStopId: uuidSchema.optional(),
756
- dropoffStopId: uuidSchema.optional(),
757
- }))
758
- .output(z.object({ success: z.boolean() })),
759
- unenroll: oc
760
- .input(z.object({ studentId: uuidSchema, routeId: uuidSchema, termId: uuidSchema }))
761
- .output(z.object({ success: z.boolean() })),
762
- },
763
-
764
- trips: {
765
- list: oc
766
- .input(z.object({
767
- branchId: uuidSchema,
768
- date: z.string().optional(),
769
- vehicleId: uuidSchema.optional(),
770
- tripCategory: tripCategoryEnum.optional(),
771
- status: tripStatusEnum.optional(),
772
- }))
773
- .output(z.array(tripLogSchema)),
774
- get: oc
775
- .input(z.object({ tripId: uuidSchema }))
776
- .output(tripLogSchema.extend({
777
- boardings: z.array(z.object({
778
- studentId: uuidSchema,
779
- studentName: z.string(),
780
- status: busRegisterStatusEnum,
781
- recordedAt: z.string().datetime(),
782
- })),
783
- })),
784
- create: oc
785
- .input(z.object({
786
- branchId: uuidSchema,
787
- vehicleId: uuidSchema,
788
- routeId: uuidSchema.optional(),
789
- tripType: z.string(),
790
- tripCategory: tripCategoryEnum,
791
- departureTime: z.string().datetime(),
792
- returnTime: z.string().datetime().optional(),
793
- title: z.string().optional(),
794
- description: z.string().optional(),
795
- destination: z.string().optional(),
796
- expectedStudents: z.number().optional(),
797
- notes: z.string().optional(),
798
- }))
799
- .output(z.object({ id: uuidSchema })),
800
- updateStatus: oc
801
- .input(z.object({ tripId: uuidSchema, status: tripStatusEnum }))
802
- .output(z.object({ success: z.boolean() })),
803
- complete: oc
804
- .input(z.object({ tripId: uuidSchema, arrivalTime: z.string().datetime() }))
805
- .output(z.object({ success: z.boolean() })),
806
- recordBoardings: oc
807
- .input(z.object({
808
- tripId: uuidSchema,
809
- entries: z.array(busRegisterEntrySchema),
810
- }))
811
- .output(z.object({ saved: z.number() })),
812
- reportIncident: oc
813
- .input(z.object({
814
- tripId: uuidSchema,
815
- description: z.string(),
816
- severity: incidentSeverityEnum,
817
- location: z.string().optional(),
818
- }))
819
- .output(z.object({ id: uuidSchema })),
820
- enrollStudent: oc
821
- .input(z.object({ tripId: uuidSchema, studentId: uuidSchema }))
822
- .output(z.object({ success: z.boolean() })),
823
- unenrollStudent: oc
824
- .input(z.object({ tripId: uuidSchema, studentId: uuidSchema }))
825
- .output(z.object({ success: z.boolean() })),
826
- listEnrolled: oc
827
- .input(z.object({ tripId: uuidSchema }))
828
- .output(z.array(z.object({
829
- studentId: uuidSchema,
830
- studentName: z.string(),
831
- admissionNo: z.string(),
832
- status: busRegisterStatusEnum.nullable(),
833
- }))),
834
- },
835
-
836
- maintenance: {
837
- submit: oc
838
- .input(z.object({
839
- vehicleId: uuidSchema,
840
- issue: z.string().min(5),
841
- severity: z.enum(["routine", "urgent", "critical"]),
842
- }))
843
- .output(z.object({ id: uuidSchema })),
844
- list: oc
845
- .input(z.object({
846
- branchId: uuidSchema,
847
- vehicleId: uuidSchema.optional(),
848
- status: maintenanceRequestStatusEnum.optional(),
849
- }))
850
- .output(z.array(maintenanceRequestSchema)),
851
- review: oc
852
- .input(z.object({
853
- id: uuidSchema,
854
- approved: z.boolean(),
855
- reviewNotes: z.string().optional(),
856
- }))
857
- .output(z.object({ success: z.boolean() })),
858
- resolve: oc
859
- .input(z.object({
860
- id: uuidSchema,
861
- notes: z.string().optional(),
862
- cost: z.number().optional(),
863
- }))
864
- .output(z.object({ success: z.boolean() })),
865
- },
866
-
867
- applications: {
868
- list: oc
869
- .input(z.object({
870
- branchId: uuidSchema,
871
- status: transportAppStatusEnum.optional(),
872
- applicationType: z.enum(["route", "trip"]).optional(),
873
- }))
874
- .output(z.array(transportApplicationSchema)),
875
- apply: oc
876
- .input(z.object({
877
- branchId: uuidSchema,
878
- studentId: uuidSchema,
879
- applicationType: z.enum(["route", "trip"]),
880
- routeId: uuidSchema.optional(),
881
- tripLogId: uuidSchema.optional(),
882
- feeItemId: uuidSchema.optional(),
883
- }))
884
- .output(z.object({ id: uuidSchema })),
885
- review: oc
886
- .input(z.object({
887
- id: uuidSchema,
888
- approved: z.boolean(),
889
- reviewNotes: z.string().optional(),
890
- updateInvoice: z.boolean().optional(),
891
- }))
892
- .output(z.object({ success: z.boolean() })),
893
- },
894
- };
895
-
896
- // ─── Assets Router ────────────────────────────────────────────────────────────
897
-
898
- export const assetsContract = {
899
- list: oc
900
- .input(
901
- paginationSchema.extend({
902
- branchId: uuidSchema,
903
- category: assetCategoryEnum.optional(),
904
- search: z.string().optional(),
905
- }),
906
- )
907
- .output(z.object({ data: z.array(z.any()), total: z.number() })),
908
- create: oc
909
- .input(
910
- z.object({
911
- name: z.string(),
912
- category: assetCategoryEnum,
913
- serialNo: z.string().optional(),
914
- purchaseDate: z.string(),
915
- purchaseCost: z.number(),
916
- supplier: z.string().optional(),
917
- warrantyExpiry: z.string().optional(),
918
- condition: assetConditionEnum,
919
- depreciationRate: z.number().min(0).max(100),
920
- }),
921
- )
922
- .output(z.object({ id: uuidSchema })),
923
- assign: oc
924
- .input(
925
- z.object({
926
- assetId: uuidSchema,
927
- staffId: uuidSchema.optional(),
928
- room: z.string().optional(),
929
- }),
930
- )
931
- .output(z.object({ success: z.boolean() })),
932
- ticket: {
933
- create: oc
934
- .input(
935
- z.object({
936
- assetId: uuidSchema,
937
- description: z.string(),
938
- severity: z.string(),
939
- }),
940
- )
941
- .output(z.object({ id: uuidSchema })),
942
- update: oc
943
- .input(
944
- z.object({
945
- ticketId: uuidSchema,
946
- status: maintenanceTicketStatusEnum,
947
- notes: z.string().optional(),
948
- cost: z.number().optional(),
949
- }),
950
- )
951
- .output(z.object({ success: z.boolean() })),
952
- },
953
- };
954
-
955
- // ─── Library Router ───────────────────────────────────────────────────────────
956
-
957
- export const libraryContract = {
958
- books: {
959
- list: oc
960
- .input(
961
- paginationSchema.extend({
962
- branchId: uuidSchema,
963
- search: z.string().optional(),
964
- available: z.boolean().optional(),
965
- }),
966
- )
967
- .output(z.object({ data: z.array(z.any()), total: z.number() })),
968
- create: oc
969
- .input(
970
- z.object({
971
- isbn: z.string(),
972
- title: z.string(),
973
- author: z.string(),
974
- publisher: z.string().optional(),
975
- year: z.number().optional(),
976
- subjectArea: z.string().optional(),
977
- copiesTotal: z.number().min(1),
978
- shelfLocation: z.string().optional(),
979
- }),
980
- )
981
- .output(z.object({ id: uuidSchema })),
982
- },
983
- borrowings: {
984
- checkout: oc
985
- .input(
986
- z.object({
987
- bookId: uuidSchema,
988
- borrowerType: z.enum(["student", "staff"]),
989
- borrowerId: uuidSchema,
990
- dueDate: z.string(),
991
- }),
992
- )
993
- .output(z.object({ id: uuidSchema })),
994
- return: oc
995
- .input(
996
- z.object({ borrowingId: uuidSchema, condition: z.string().optional() }),
997
- )
998
- .output(z.object({ fine: z.number() })),
999
- listOverdue: oc
1000
- .input(z.object({ branchId: uuidSchema }))
1001
- .output(z.array(z.any())),
1002
- },
1003
- };
1004
-
1005
- // ─── Discipline Router ────────────────────────────────────────────────────────
1006
-
1007
- export const disciplineContract = {
1008
- incidents: {
1009
- log: oc
1010
- .input(
1011
- z.object({
1012
- studentId: uuidSchema,
1013
- incidentType: z.string(),
1014
- description: z.string(),
1015
- severity: incidentSeverityEnum,
1016
- incidentDate: z.string(),
1017
- requiresCounsellor: z.boolean().default(false),
1018
- }),
1019
- )
1020
- .output(z.object({ id: uuidSchema })),
1021
- list: oc
1022
- .input(
1023
- paginationSchema.extend({
1024
- branchId: uuidSchema,
1025
- studentId: uuidSchema.optional(),
1026
- status: incidentStatusEnum.optional(),
1027
- }),
1028
- )
1029
- .output(z.object({ data: z.array(z.any()), total: z.number() })),
1030
- rule: oc
1031
- .input(
1032
- z.object({
1033
- incidentId: uuidSchema,
1034
- ruling: disciplineRulingEnum,
1035
- suspensionDays: z.number().optional(),
1036
- notes: z.string(),
1037
- }),
1038
- )
1039
- .output(z.object({ success: z.boolean() })),
1040
- },
1041
- };
1042
-
1043
- // ─── Communications Router ────────────────────────────────────────────────────
1044
-
1045
- export const commsContract = {
1046
- notifications: {
1047
- list: oc
1048
- .input(paginationSchema.extend({ unreadOnly: z.boolean().optional() }))
1049
- .output(z.object({ data: z.array(z.any()), unreadCount: z.number() })),
1050
- markRead: oc
1051
- .input(z.object({ ids: z.array(uuidSchema) }))
1052
- .output(z.object({ updated: z.number() })),
1053
- },
1054
- messages: {
1055
- list: oc.input(paginationSchema).output(z.array(z.any())),
1056
- send: oc
1057
- .input(
1058
- z.object({
1059
- recipientId: uuidSchema,
1060
- subject: z.string(),
1061
- body: z.string(),
1062
- parentId: uuidSchema.optional(),
1063
- }),
1064
- )
1065
- .output(z.object({ id: uuidSchema })),
1066
- },
1067
- sms: {
1068
- send: oc
1069
- .input(sendBulkSmsInputSchema)
1070
- .output(z.object({ queued: z.number() })),
1071
- },
1072
- notices: {
1073
- list: oc
1074
- .input(z.object({ branchId: uuidSchema, active: z.boolean().optional() }))
1075
- .output(z.array(z.any())),
1076
- create: oc
1077
- .input(
1078
- z.object({
1079
- title: z.string(),
1080
- body: z.string(),
1081
- audienceType: z.string(),
1082
- audienceIds: z.array(uuidSchema).optional(),
1083
- publishAt: z.string().optional(),
1084
- expiresAt: z.string().optional(),
1085
- }),
1086
- )
1087
- .output(z.object({ id: uuidSchema })),
1088
- },
1089
- };
1090
-
1091
- // ─── Admin Router ─────────────────────────────────────────────────────────────
1092
-
1093
- export const adminContract = {
1094
- auditLogs: {
1095
- list: oc
1096
- .input(
1097
- paginationSchema.extend({
1098
- branchId: uuidSchema.optional(),
1099
- userId: uuidSchema.optional(),
1100
- action: z.string().optional(),
1101
- from: z.string().optional(),
1102
- to: z.string().optional(),
1103
- }),
1104
- )
1105
- .output(z.object({ data: z.array(z.any()), total: z.number() })),
1106
- },
1107
- users: {
1108
- create: oc
1109
- .input(
1110
- z.object({
1111
- firstName: z.string(),
1112
- middleName: z.string().optional(),
1113
- lastName: z.string(),
1114
- email: z.string().email(),
1115
- phone: z.string().optional(),
1116
- roleId: uuidSchema,
1117
- branchId: uuidSchema,
1118
- temporaryPassword: z.string().min(8),
1119
- }),
1120
- )
1121
- .output(z.object({ id: uuidSchema })),
1122
- suspend: oc
1123
- .input(z.object({ userId: uuidSchema, reason: z.string() }))
1124
- .output(z.object({ success: z.boolean() })),
1125
- },
1126
- roles: {
1127
- list: oc
1128
- .input(z.object({ branchId: uuidSchema }))
1129
- .output(
1130
- z.array(
1131
- z.object({
1132
- id: uuidSchema,
1133
- name: z.string(),
1134
- isSystem: z.boolean(),
1135
- permissionCount: z.number(),
1136
- }),
1137
- ),
1138
- ),
1139
- create: oc
1140
- .input(
1141
- z.object({
1142
- name: z.string(),
1143
- description: z.string().optional(),
1144
- permissionIds: z.array(uuidSchema),
1145
- }),
1146
- )
1147
- .output(z.object({ id: uuidSchema })),
1148
- },
1149
- };
1150
-
1151
- // ─── Storage Router ───────────────────────────────────────────────────────────
1152
-
1153
- export const storageContract = {
1154
- presignUpload: oc
1155
- .input(
1156
- z.object({
1157
- fileName: z.string(),
1158
- mimeType: z.string(),
1159
- category: z.enum([
1160
- "student_photo",
1161
- "staff_photo",
1162
- "document",
1163
- "payslip",
1164
- "report_card",
1165
- "asset_photo",
1166
- "notice_attachment",
1167
- ]),
1168
- resourceId: uuidSchema.optional(),
1169
- }),
1170
- )
1171
- .output(
1172
- z.object({
1173
- uploadUrl: z.string(),
1174
- fileKey: z.string(),
1175
- expiresIn: z.number(),
1176
- }),
1177
- ),
1178
-
1179
- confirmUpload: oc
1180
- .input(
1181
- z.object({
1182
- fileKey: z.string(),
1183
- resourceId: uuidSchema,
1184
- resourceType: z.string(),
1185
- }),
1186
- )
1187
- .output(z.object({ publicUrl: z.string() })),
1188
- };
1189
-
1190
- // ─── Root Contract (flat router type for client inference) ───────────────────
1191
-
1192
- export const appContract = {
1193
- auth: authContract,
1194
- branches: branchesContract,
1195
- students: studentsContract,
1196
- academics: academicsContract,
1197
- finance: financeContract,
1198
- hr: hrContract,
1199
- payroll: payrollContract,
1200
- transport: transportContract,
1201
- assets: assetsContract,
1202
- library: libraryContract,
1203
- discipline: disciplineContract,
1204
- comms: commsContract,
1205
- admin: adminContract,
1206
- storage: storageContract,
1207
- };
1208
-
1209
- export type AppContract = typeof appContract;