Files
company-celebration/packages/shared/src/utils/validation.ts
empty e7397d22a9 feat: initialize Annual Gala Interactive System monorepo
- Set up pnpm workspace with 4 packages: shared, server, client-mobile, client-screen
- Implement Redis atomic voting with Lua scripts (HINCRBY + distributed lock)
- Add optimistic UI with IndexedDB queue for offline resilience
- Configure Socket.io with auto-reconnection (infinite retries)
- Separate mobile (Vant) and big screen (Pixi.js) dependencies

Tech stack:
- Frontend Mobile: Vue 3 + Vant + Socket.io-client
- Frontend Screen: Vue 3 + Pixi.js + GSAP
- Backend: Express + Socket.io + Redis + Prisma/MySQL

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 01:19:36 +08:00

65 lines
2.3 KiB
TypeScript

import { z } from 'zod';
import { VOTE_CATEGORIES, PRIZE_LEVELS } from '../types/socket.types';
// ============================================================================
// Vote Validation Schemas
// ============================================================================
export const voteSubmitSchema = z.object({
candidateId: z.string().min(1).max(64),
category: z.enum(VOTE_CATEGORIES as unknown as [string, ...string[]]),
clientTimestamp: z.number().positive(),
localId: z.string().uuid(),
});
export const voteBatchSchema = z.object({
votes: z.array(voteSubmitSchema).min(1).max(7),
});
// ============================================================================
// Draw Validation Schemas
// ============================================================================
export const drawFiltersSchema = z.object({
excludeWinners: z.boolean().optional(),
zodiacFilter: z.string().optional(),
ageRange: z
.object({
min: z.number().min(18).max(100).optional(),
max: z.number().min(18).max(100).optional(),
})
.optional(),
departments: z.array(z.string()).optional(),
});
export const drawStartSchema = z.object({
prizeLevel: z.enum(PRIZE_LEVELS as unknown as [string, ...string[]]),
filters: drawFiltersSchema.optional(),
});
// ============================================================================
// Connection Validation Schemas
// ============================================================================
export const joinPayloadSchema = z.object({
userId: z.string().min(1).max(64),
userName: z.string().min(1).max(100),
role: z.enum(['user', 'admin', 'screen']),
sessionToken: z.string().optional(),
});
export const syncRequestSchema = z.object({
lastEventId: z.string().optional(),
lastTimestamp: z.number().optional(),
});
// ============================================================================
// Type Exports
// ============================================================================
export type VoteSubmitInput = z.infer<typeof voteSubmitSchema>;
export type VoteBatchInput = z.infer<typeof voteBatchSchema>;
export type DrawStartInput = z.infer<typeof drawStartSchema>;
export type JoinPayloadInput = z.infer<typeof joinPayloadSchema>;
export type SyncRequestInput = z.infer<typeof syncRequestSchema>;