rspace-online/modules/rwork/schemas.ts

111 lines
2.0 KiB
TypeScript

/**
* rWork Automerge document schemas.
*
* Granularity: one Automerge document per board/workspace.
* DocId format: {space}:work:boards:{boardId}
*/
import type { DocSchema } from '../../shared/local-first/document';
// ── Document types ──
export interface TaskItem {
id: string;
spaceId: string;
title: string;
description: string;
status: string;
priority: string | null;
labels: string[];
assigneeId: string | null;
createdBy: string | null;
sortOrder: number;
createdAt: number;
updatedAt: number;
}
export interface BoardMeta {
id: string;
name: string;
slug: string;
description: string;
icon: string | null;
ownerDid: string | null;
statuses: string[];
labels: string[];
createdAt: number;
updatedAt: number;
}
export interface BoardDoc {
meta: {
module: string;
collection: string;
version: number;
spaceSlug: string;
createdAt: number;
};
board: BoardMeta;
tasks: Record<string, TaskItem>;
}
// ── Schema registration ──
export const boardSchema: DocSchema<BoardDoc> = {
module: 'work',
collection: 'boards',
version: 1,
init: (): BoardDoc => ({
meta: {
module: 'work',
collection: 'boards',
version: 1,
spaceSlug: '',
createdAt: Date.now(),
},
board: {
id: '',
name: 'Untitled Board',
slug: '',
description: '',
icon: null,
ownerDid: null,
statuses: ['TODO', 'IN_PROGRESS', 'DONE'],
labels: [],
createdAt: Date.now(),
updatedAt: Date.now(),
},
tasks: {},
}),
};
// ── Helpers ──
export function boardDocId(space: string, boardId: string) {
return `${space}:work:boards:${boardId}` as const;
}
export function createTaskItem(
id: string,
spaceId: string,
title: string,
opts: Partial<TaskItem> = {},
): TaskItem {
const now = Date.now();
return {
id,
spaceId,
title,
description: '',
status: 'TODO',
priority: null,
labels: [],
assigneeId: null,
createdBy: null,
sortOrder: 0,
createdAt: now,
updatedAt: now,
...opts,
};
}