118 lines
2.3 KiB
TypeScript
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;
|
|
}
|