rspace-online/modules/rdesign/schemas.ts

88 lines
2.0 KiB
TypeScript

/**
* rDesign Automerge document schemas.
*
* Syncs full design state (pages, frames) per space via CRDT.
* Source of truth for collaborative editing — Scribus state is
* periodically reconciled via sla-bridge.ts.
*
* DocId format: {space}:design:doc
*/
import type { DocSchema } from '../../shared/local-first/document';
export interface DesignFrame {
id: string;
type: 'text' | 'image' | 'rect' | 'ellipse';
page: number;
x: number;
y: number;
width: number;
height: number;
text?: string;
fontSize?: number;
fontName?: string;
imageUrl?: string;
imagePath?: string;
shapeType?: string;
fill?: string;
stroke?: string;
strokeWidth?: number;
createdBy?: string;
createdAt?: number;
updatedAt?: number;
}
export interface DesignPage {
id: string;
number: number;
width: number;
height: number;
margins: number;
background?: string;
}
export interface DesignDoc {
meta: {
module: string;
collection: string;
version: number;
spaceSlug: string;
createdAt: number;
};
document: {
title: string;
unit: string;
pages: Record<string, DesignPage>;
frames: Record<string, DesignFrame>;
};
}
export const designSchema: DocSchema<DesignDoc> = {
module: 'design',
collection: 'doc',
version: 2,
init: (): DesignDoc => ({
meta: { module: 'design', collection: 'doc', version: 2, spaceSlug: '', createdAt: Date.now() },
document: {
title: 'Untitled Design',
unit: 'mm',
pages: {},
frames: {},
},
}),
migrate: (doc: any) => {
// v1 → v2: migrate from LinkedProject schema to full design state
if (doc.linkedProjects && !doc.document) {
doc.document = { title: 'Untitled Design', unit: 'mm', pages: {}, frames: {} };
delete doc.linkedProjects;
}
if (!doc.document) doc.document = { title: 'Untitled Design', unit: 'mm', pages: {}, frames: {} };
if (!doc.document.pages) doc.document.pages = {};
if (!doc.document.frames) doc.document.frames = {};
doc.meta.version = 2;
return doc;
},
};
export function designDocId(space: string) { return `${space}:design:doc` as const; }