feat(shared): add domain types and zod schemas
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
export {};
|
export * from './types.js';
|
||||||
|
export * from './schemas.js';
|
||||||
|
|||||||
45
packages/shared/src/schemas.ts
Normal file
45
packages/shared/src/schemas.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const lessonCreateSchema = z.object({
|
||||||
|
parentId: z.number().int().nullable().optional(),
|
||||||
|
name: z.string().min(1).max(200),
|
||||||
|
description: z.string().max(2000).optional().nullable(),
|
||||||
|
bidirectional: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const lessonUpdateSchema = lessonCreateSchema.partial();
|
||||||
|
|
||||||
|
export const lessonMoveSchema = z.object({
|
||||||
|
parentId: z.number().int().nullable(),
|
||||||
|
position: z.number().int().min(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const cardCreateSchema = z.object({
|
||||||
|
question: z.string().min(1).max(2000),
|
||||||
|
answer: z.string().min(1).max(2000),
|
||||||
|
hint: z.string().max(2000).optional().nullable(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const cardUpdateSchema = cardCreateSchema.partial();
|
||||||
|
|
||||||
|
export const sessionStartSchema = z.object({
|
||||||
|
lessonId: z.number().int().positive(),
|
||||||
|
maxCards: z.number().int().min(1).max(500).nullable().optional(),
|
||||||
|
shuffle: z.boolean().optional(),
|
||||||
|
direction: z.enum(['forward', 'backward', 'both']).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const attemptCreateSchema = z.object({
|
||||||
|
cardId: z.number().int().positive(),
|
||||||
|
direction: z.enum(['forward', 'backward']),
|
||||||
|
result: z.enum(['correct', 'incorrect']),
|
||||||
|
timeToAnswerMs: z.number().int().min(0).nullable().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type LessonCreateInput = z.infer<typeof lessonCreateSchema>;
|
||||||
|
export type LessonUpdateInput = z.infer<typeof lessonUpdateSchema>;
|
||||||
|
export type LessonMoveInput = z.infer<typeof lessonMoveSchema>;
|
||||||
|
export type CardCreateInput = z.infer<typeof cardCreateSchema>;
|
||||||
|
export type CardUpdateInput = z.infer<typeof cardUpdateSchema>;
|
||||||
|
export type SessionStartInput = z.infer<typeof sessionStartSchema>;
|
||||||
|
export type AttemptCreateInput = z.infer<typeof attemptCreateSchema>;
|
||||||
73
packages/shared/src/types.ts
Normal file
73
packages/shared/src/types.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
export type Direction = 'forward' | 'backward';
|
||||||
|
export type AttemptResult = 'correct' | 'incorrect';
|
||||||
|
export type SessionStatus = 'active' | 'completed' | 'abandoned';
|
||||||
|
|
||||||
|
export interface Lesson {
|
||||||
|
id: number;
|
||||||
|
parentId: number | null;
|
||||||
|
name: string;
|
||||||
|
description: string | null;
|
||||||
|
position: number;
|
||||||
|
bidirectional: boolean;
|
||||||
|
createdAt: number;
|
||||||
|
updatedAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LessonTreeNode extends Lesson {
|
||||||
|
children: LessonTreeNode[];
|
||||||
|
cardCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Card {
|
||||||
|
id: number;
|
||||||
|
lessonId: number;
|
||||||
|
question: string;
|
||||||
|
answer: string;
|
||||||
|
hint: string | null;
|
||||||
|
position: number;
|
||||||
|
createdAt: number;
|
||||||
|
updatedAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CardProgress {
|
||||||
|
cardId: number;
|
||||||
|
direction: Direction;
|
||||||
|
box: number;
|
||||||
|
correctCount: number;
|
||||||
|
incorrectCount: number;
|
||||||
|
lastShownAt: number | null;
|
||||||
|
nextDueAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionRow {
|
||||||
|
id: number;
|
||||||
|
lessonId: number;
|
||||||
|
startedAt: number;
|
||||||
|
endedAt: number | null;
|
||||||
|
durationSeconds: number | null;
|
||||||
|
cardsShown: number;
|
||||||
|
cardsCorrect: number;
|
||||||
|
cardsIncorrect: number;
|
||||||
|
status: SessionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Attempt {
|
||||||
|
id: number;
|
||||||
|
sessionId: number;
|
||||||
|
cardId: number;
|
||||||
|
direction: Direction;
|
||||||
|
shownAt: number;
|
||||||
|
result: AttemptResult;
|
||||||
|
timeToAnswerMs: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QueueItem {
|
||||||
|
cardId: number;
|
||||||
|
direction: Direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SessionSettings {
|
||||||
|
maxCards: number | null;
|
||||||
|
shuffle: boolean;
|
||||||
|
direction: 'forward' | 'backward' | 'both';
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user