diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index cb0ff5c..e903b98 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1 +1,2 @@ -export {}; +export * from './types.js'; +export * from './schemas.js'; diff --git a/packages/shared/src/schemas.ts b/packages/shared/src/schemas.ts new file mode 100644 index 0000000..ab250dd --- /dev/null +++ b/packages/shared/src/schemas.ts @@ -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; +export type LessonUpdateInput = z.infer; +export type LessonMoveInput = z.infer; +export type CardCreateInput = z.infer; +export type CardUpdateInput = z.infer; +export type SessionStartInput = z.infer; +export type AttemptCreateInput = z.infer; diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts new file mode 100644 index 0000000..1cc1220 --- /dev/null +++ b/packages/shared/src/types.ts @@ -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'; +}