rspace-online/modules/rchoices/schemas.ts

83 lines
1.8 KiB
TypeScript

/**
* rChoices Automerge document schemas.
*
* Stores collaborative voting sessions with real-time vote sync.
* Canvas-based choice shapes remain in community-store; this doc
* handles standalone multiplayer sessions via the dashboard.
*
* DocId format: {space}:choices:sessions
*/
import type { DocSchema } from '../../shared/local-first/document';
// ── Document types ──
export interface ChoiceOption {
id: string;
label: string;
color: string;
}
export interface ChoiceSession {
id: string;
title: string;
type: 'vote' | 'rank' | 'score';
/** 'vote' mode: plurality, approval, or single */
mode?: 'plurality' | 'approval' | 'single';
options: ChoiceOption[];
createdBy: string | null;
createdAt: number;
closed: boolean;
}
export interface ChoiceVote {
participantDid: string;
/** For 'vote': optionId → 1 (selected). For 'rank': optionId → rank position. For 'score': optionId → 0-100. */
choices: Record<string, number>;
updatedAt: number;
}
export interface ChoicesDoc {
meta: {
module: string;
collection: string;
version: number;
spaceSlug: string;
createdAt: number;
};
sessions: Record<string, ChoiceSession>;
/** Keyed by `${sessionId}:${participantDid}` */
votes: Record<string, ChoiceVote>;
}
// ── Schema registration ──
export const choicesSchema: DocSchema<ChoicesDoc> = {
module: 'choices',
collection: 'sessions',
version: 1,
init: (): ChoicesDoc => ({
meta: {
module: 'choices',
collection: 'sessions',
version: 1,
spaceSlug: '',
createdAt: Date.now(),
},
sessions: {},
votes: {},
}),
migrate: (doc: any, _fromVersion: number) => {
if (!doc.sessions) doc.sessions = {};
if (!doc.votes) doc.votes = {};
doc.meta.version = 1;
return doc;
},
};
// ── Helpers ──
export function choicesDocId(space: string) {
return `${space}:choices:sessions` as const;
}