notes(#454): per-recipient view/edit folder sharing
- Schema: noteFolderShares.permission ('view'|'edit', default 'view').
- Server: resolveFolderEditAccess + emitFolderChanged helpers.
- POST/PATCH/DELETE/checklist now allow folder editors.
- Editors stamp notes with folder owner's userId; labels validated
against owner; PATCH editors blocked from unfile (folderId=null)
and cross-folder moves to non-matching owners.
- emitFolderChanged fires for owner AND editor mutations across
create / patch (old + new folder) / delete / checklist toggle.
- PUT /shares accepts both legacy recipientUserIds and new
recipients:[{userId,permission}]; diffs add/update/remove/perm-flip.
- GET /shares, /shared-with-me, /shared-notes return permission /
myPermission / readOnly.
- Client:
- notes-api types: FolderSharePermission, myPermission on
SharedFolder/SharedFolderView, permission on FolderShareRecipient,
readOnly:boolean on SharedFolderNote.
- useUpdateFolderShares takes recipients[].
- useCreate/Update/DeleteNote also invalidate ['note-folders'] so
actor's shared-folder rail badge stays fresh.
- FolderShareDialog: per-row checkbox + segmented View/Edit toggle.
- SharedFolderView: editor mode mounts Composer + NoteCard with
full edit/delete/archive affordances; Send hidden in editor
context (Composer + NoteCard hideSend prop) since /send is
owner-only.
- folders-rail: per-folder permission badge.
- socket: note-folder-shared also invalidates ['notes'] +
['note-folders'] for fanout to owner / other editors.
- Locales: shareDescriptionPerm, permissionView/Edit, canEdit
(en + ar).
- Pre-existing executive-meetings.ts type errors are out of scope.
This commit is contained in:
@@ -114,8 +114,10 @@ export type NoteReply = typeof noteRepliesTable.$inferSelect;
|
||||
* always see the owner's current notes via a join, so adds/edits/removes by the
|
||||
* owner are reflected live in the recipient's "Shared with me" view.
|
||||
*
|
||||
* Read-only by design: there is no role column. Recipients cannot edit, add,
|
||||
* move, or delete notes inside a shared folder; they can only read.
|
||||
* Permission per recipient (Task #454): "view" (default, read-only) or
|
||||
* "edit" (full create/update/delete on the owner's notes inside this folder).
|
||||
* Notes mutated by an editor still belong to the folder owner — the folder
|
||||
* stays a single namespace under `noteFoldersTable.userId`.
|
||||
*/
|
||||
export const noteFolderSharesTable = pgTable("note_folder_shares", {
|
||||
id: serial("id").primaryKey(),
|
||||
@@ -125,6 +127,7 @@ export const noteFolderSharesTable = pgTable("note_folder_shares", {
|
||||
recipientUserId: integer("recipient_user_id")
|
||||
.notNull()
|
||||
.references(() => usersTable.id, { onDelete: "cascade" }),
|
||||
permission: varchar("permission", { length: 8 }).notNull().default("view"),
|
||||
sharedAt: timestamp("shared_at", { withTimezone: true }).notNull().defaultNow(),
|
||||
}, (t) => ({
|
||||
folderRecipientUnique: uniqueIndex("note_folder_shares_folder_recipient_unique").on(
|
||||
|
||||
Reference in New Issue
Block a user