Step 10 - sharing and security
2 min read
Public share link with QR
Add board sharing. A Share dialog in the board toolbar shows: a QR code and a copyable link to {origin}/kanban/board/{projectId}/{code} (the board's 6-char code), and a toggle "Allow editing without an account" that writes publicEdit on the board doc.
Create the public route /kanban/board/:projectId/:code OUTSIDE the authenticated shell: it verifies the code matches the board doc, calls ensureSignedIn() (anonymous auth) before starting the streams, and renders the board in a publicView mode. Guests get read-only by default; when publicEdit is true they may create, edit, move and delete CARDS only - never columns, tags, sharing settings, or board rename. Guest-authored cards get authorName "Guest" and no authorId-based ownership. Unread tracking and the What's-new panel are disabled for guests. The task panel opens in the same restricted mode (no assignees, no share-dependent features).
Security rules and emulator tests
Write Firestore and Storage security rules for everything built so far, and test them against the emulator. Firestore: kanbanProjects - read for any signed-in user (anonymous included, since links contain the unguessable code); create requires workspace membership and ownerId == request.auth.uid; update/delete require membership of resource.data.workspaceId. tasks subcollection - read for signed-in; write allowed if the user is a workspace member OR (signed-in AND get() on the parent board shows publicEdit == true). workspaces - members read, owner writes. users/{uid} - only the owner reads/writes their profile. Comments - readable like their parent, author-only edit/delete.
Storage: uploads only under workspaces/{workspaceId}/kanban-{projectId}/... with a folder-shape guard on the segment (regex like kanban-[^-]+, so future prefixes such as kanban-form-* cannot be misread as a board id); writes require membership or a Firestore cross-check that the board has publicEdit == true; enforce a size limit and block HTML/SVG content types for non-members. Two gotchas to respect: (1) validate optional fields in rules via .get() with defaults, never direct access; (2) if you validate update payloads with hasOnly(), remember every future field addition must be added there too - leave a comment saying so. Write emulator test cases for: non-member write denied, member write allowed, anonymous card write allowed only when publicEdit, anonymous column change always denied.
Discussion
0 commentsNo comments yet. Start the discussion.