Step 2 - Data model and security rules
2 min czytania
Define the whiteboard data model and Firestore layout. Do not build UI yet.
Firestore collections:
boards/{boardId} - board metadata boards/{boardId}/elements/{elementId} - ONE document per canvas element boards/{boardId}/presence/{uid} - live presence, doc id = auth uid boards/{boardId}/comments/{commentId} - comment threads boards/{boardId}/votes/{uid} - dot voting, doc id = auth uid boardTemplates/{templateId} - templates with elements EMBEDDED as an array
TypeScript interfaces in a core models file:
Board:
id, code (6-char join code), orgId, ownerId, title, createdAt, updatedAt, plus optional facilitation fields added later (focus, timer, voting, editLocked, privateMode, background, deletedAt for soft delete).
BoardElement:
one FLAT interface covering every element type (do NOT make a discriminated union with per-type interfaces; a flat optional-field interface keeps Firestore writes and rendering code simple): id, type: 'path'|'text'|'shape'|'note'|'connection'|'image'|'frame', color, width, points?: number[] (flat [x0,y0,x1,y1,...] for freehand), shape?: 'rect'|'ellipse'|'line'|'arrow'|'roundRect'|'triangle'|'diamond'|'hexagon'|'star'|'bubble', x?, y?, x2?, y2?, text?, fontSize?, bold?, italic?, align?: 'left'|'center'|'right', fill?, z?, fromId?, toId? (connection endpoints), src? (image URL), rotation?, locked?, groupId?, dashed?, authorId, authorName?, createdAt (number, used for stable sort).
BoardPresence:
id, uid, name, color, isTeacher?, cursorX/Y?, laserActive?, laserX/Y?, draft? (in-progress stroke), handRaised?, reaction?, viewCx/viewCy/viewScale?, updatedAt.
BoardComment:
id, authorId, authorName, authorColor, text, elementId? (absent = board-wide thread), createdAt, editedAt?. BoardVote: id, uid, counts: Record<elementId, number>. BoardTemplate: id, orgId, ownerId, title, description?, elements: BoardElement[], builtIn?, createdAt, updatedAt.
Create a BoardService (providedIn root) with typed CRUD for all of these: board$(id), elementsOf$(boardId), addElement, updateElement (full setDoc, last-write-wins), deleteElement, presence and comment and vote accessors, boardsOf$(orgId), createBoard (generates the join code). Sort elements by createdAt client-side; do not add composite indexes.
firestore.rules:
- boards: read for any signed-in user (including anonymous - guests join by link); create requires ownerId == request.auth.uid; update/delete for org members.
- elements: read signed-in; write signed-in AND (auth provider != 'anonymous' OR parent board's editLocked != true) - fetch the parent board with get() only for anonymous writers.
- presence + votes: doc id must equal request.auth.uid on create/update (no spoofing); delete by self or an org member.
- comments: create requires authorId == request.auth.uid; update only by author with authorId unchanged; delete by author or org member.
- boardTemplates: read/update/delete for org members, create requires ownerId == uid.
Acceptance: rules compile in the emulator; a seed script or spec can create a board with three elements and read them back sorted.
Dyskusja
Komentarze: 0Brak komentarzy. Rozpocznij dyskusję.