rspace-online/modules/rvote/schemas.ts

118 lines
2.3 KiB
TypeScript

/**
* rVote Automerge document schemas.
*
* Granularity: one Automerge document per proposal.
* DocId format: {space}:vote:proposals:{proposalId}
*
* Vote tallying uses the Intent/Claim pattern:
* clients submit vote intents, server validates and writes claims.
*/
import type { DocSchema } from '../../shared/local-first/document';
// ── Document types ──
export interface VoteItem {
id: string;
userId: string;
proposalId: string;
weight: number;
creditCost: number;
createdAt: number;
decaysAt: number;
}
export interface FinalVoteItem {
id: string;
userId: string;
proposalId: string;
vote: 'YES' | 'NO' | 'ABSTAIN';
createdAt: number;
}
export interface SpaceConfig {
slug: string;
name: string;
description: string;
ownerDid: string;
visibility: string;
promotionThreshold: number | null;
votingPeriodDays: number | null;
creditsPerDay: number | null;
maxCredits: number | null;
startingCredits: number | null;
createdAt: number;
updatedAt: number;
}
export interface ProposalMeta {
id: string;
spaceSlug: string;
authorId: string;
title: string;
description: string;
status: string;
score: number;
votingEndsAt: number;
finalYes: number;
finalNo: number;
finalAbstain: number;
createdAt: number;
updatedAt: number;
}
export interface ProposalDoc {
meta: {
module: string;
collection: string;
version: number;
spaceSlug: string;
createdAt: number;
};
spaceConfig: SpaceConfig | null;
proposal: ProposalMeta;
votes: Record<string, VoteItem>;
finalVotes: Record<string, FinalVoteItem>;
}
// ── Schema registration ──
export const proposalSchema: DocSchema<ProposalDoc> = {
module: 'vote',
collection: 'proposals',
version: 1,
init: (): ProposalDoc => ({
meta: {
module: 'vote',
collection: 'proposals',
version: 1,
spaceSlug: '',
createdAt: Date.now(),
},
spaceConfig: null,
proposal: {
id: '',
spaceSlug: '',
authorId: '',
title: '',
description: '',
status: 'RANKING',
score: 0,
votingEndsAt: 0,
finalYes: 0,
finalNo: 0,
finalAbstain: 0,
createdAt: Date.now(),
updatedAt: Date.now(),
},
votes: {},
finalVotes: {},
}),
};
// ── Helpers ──
export function proposalDocId(space: string, proposalId: string) {
return `${space}:vote:proposals:${proposalId}` as const;
}