Skip to content

feat(boards): share boards by role and keep project settings per member - #9797

Open
joshistoast wants to merge 15 commits into
mainfrom
feat/sharing-foundations
Open

joshistoast wants to merge 15 commits into
mainfrom
feat/sharing-foundations

Conversation

@joshistoast

@joshistoast joshistoast commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Lays the foundations for sharing in 7.0, so that later collaboration work (members, share dialog, project grants, locks) does not need another data migration.

Board roles. Every board has an owner and a role per caller: Viewer, Contributor, Editor or Owner, with administrators overriding.

  • One board_access service decides every board and item action. Routers, graph execution, workflow calls and upload events all use it.
  • A board the caller cannot open answers 404; an action their role does not allow answers 403.
  • board_visibility and shared_boards become general_access (Restricted / Everyone can view / Everyone can contribute) plus a board_members table.
  • BoardDTO reports my_role, allowed_actions, admin_override and general_access.
  • Owners no longer permanently delete other people's media. Those items return to their own owner's Uncategorized.

Global project ids. Project ids are unique across accounts. Queue reads by origin are scoped to the caller.

Per-member project settings. A project's content (name, canvas, workflows) is saved apart from each member's workspace (layout, widgets, generation settings, prompt history, selection, staging):

  • project_workspaces table and PUT /projects/{id}/workspace
  • document schema 4, with a schema floor that refuses older clients
  • lazy client-side split of older documents
  • .invk v3: project.json is the content, with an optional workspace.json behind Include my settings for this project
  • new canvas and workflow items get UUID-based ids

Gallery board UI:

  • Shared with me and, for administrators, Other users' boards, with rows like "Ana · Can view".
  • Board menus offer only what the caller's role allows, with a header saying whose board it is. Moving a board, from its menu or by dragging it onto another project or the Library, is offered only on the caller's own boards.
  • Access lets owners and administrators set general access.
  • Results, uploads and moves never target a board the caller can only view: results go to the project's Inbox, which is marked Auto.
  • A refused or revoked action refreshes the list with a notice.

What's New: a "Share boards" headline (multi-user only) and notes on Public boards and per-member settings.

Builds on #9713.

Related Issues / Discussions

Fixes the board half of #9673. Workflow sharing is still listed under known bugs.

QA Instructions

Ran on this branch:

  • pnpm -C invokeai/frontend/webv2 check:release:

    • lint
    • 10203 unit tests and 2918 browser tests
    • architecture performance
    • project-file journeys
    • accessibility
    • all pass. One browser test, ToastContrast (untouched here), can time out on a hover under a heavy full run; it passes 3/3 on its own.
  • uv tool run ruff@0.11.2 check / format --check on the 85 changed Python files: clean.

  • uv run --no-sync python -m pytest -n 4: 13406 passed, 102 failed, 193 skipped. Each failure was traced to this machine, not this branch:

    • 91 in tests/model_identification: the Git LFS fixtures are not fetched here.
    • 3 in test_app_info.py (busy database): they fail only while webv2/dist is built, because the UI's catch-all mount answers first. With the build moved aside, the file passes 36/36.
    • 2 (test_16_channel_vae_loader, minimax_h3/test_text_encoder_checkpoint) fail the same way on feat(boards): boards belong to projects, with a Library tier and whole-project transfer #9713's branch.
    • 1 (test_directory_install_rollback_race_preserves_both_source_artifacts) depends on the checkout filesystem's directory order. It passes 2/2 from a worktree of this branch, as on feat(boards): boards belong to projects, with a Library tier and whole-project transfer #9713's.
    • 5 (test_ministral3_encoder_config, test_mistral_encoder_checkpoint_loader, test_ideogram4_diffusers_loader, test_migration_loader) ran out of /tmp quota here and pass when rerun.
    • The run also reported 4 collection errors in test_model_cache_ram_budget.py, caused by running with -p no:warnings; the file passes without it.

    No failing test is in a file this branch changes.

  • MySQL and MariaDB run the same suite in CI; the one query-plan check (SQLite's EXPLAIN QUERY PLAN) is marked SQLite-only.

  • Each migration has its own tests; board roles are migrated from 6.13- and alpha.1-shaped data (test_migration_2026_10_10_{board_roles,global_project_ids,project_workspaces}.py).

To try sharing in the browser against the mock backend:

  1. node --input-type=module -e "import { startMockBackend } from './scripts/mock-backend.mjs'; await startMockBackend(9191, { profile: 'representative' });" from invokeai/frontend/webv2
  2. INVOKEAI_DEV_BACKEND=http://127.0.0.1:9191 pnpm exec vite dev --port 5273
  3. curl -X POST -H 'content-type: application/json' -d '{"intermediatesCaller":"user","sharedBoards":true}' http://127.0.0.1:9191/__faults
    • "multiuser-admin" instead of "user" gives the administrator view.
    • POST /__board-access revokes access behind the page's back.
  4. Sign in with any email and password, then open the Gallery:
    • Shared with me lists a board you can edit, one you can add to, and one you can only view.
    • Selecting the view-only board moves Auto to the Inbox.
    • Your own boards' menus have Access.

Verified in the browser this way:

  • each role's menu and the admin's
  • the Access submenu and its change notice
  • a revocation (notice, board removed)
  • the Inbox redirect and its tooltip
  • the disabled upload control
  • the What's New dialog in multi-user mode
  • export with and without settings, and import of v2 and v3 files

Review

Material findings from review were fixed before merge. Among them:

  • Results could still go to a revoked or archived selected board, or, briefly, miss a just-created board; destination resolution now uses the newest relevant board listing.
  • Workflow board fields and field uploads now respect view-only boards.
  • An export with settings left out could still carry them for a project this build cannot read; it is now refused with a message.
  • A failed workspace save on import or duplicate is now reported.
  • Refusal ordering and document/canvas refusal reasons were corrected.
  • The release performance gate now passes; request counts are one lower on every route.

Remaining limits:

  • Media DTOs do not carry their owner, so the item menu cannot yet hide Delete or Remove on someone else's media. The server refuses them with its message.
  • In 7.0, exporting a closed project that is still stored whole includes the owner's settings. That is correct while projects have one member; 7.1 members will need the caller's own.

Compatibility / Rollout

  • Migrations: three linear migrations, after feat(boards): boards belong to projects, with a Library tier and whole-project transfer #9713's:

    • board roles (general_access, board_members; board_visibility/shared_boards dropped)
    • global project ids (re-keys duplicate ids with a logged warning; clears dangling boards.project_id)
    • project_workspaces plus minimum_document_schema_version

    Private boards become Restricted, shared boards Everyone can view, and public boards Everyone can contribute.

  • API:

    • board_visibility is kept as a deprecated alias derived from general_access until 8.0; sending both is a 422.
    • The upload socket event drops board_visibility, shared_user_ids and board_owner_id.
    • project_id on boards is returned only to owners and administrators.
    • openapi.json and schema.ts are regenerated.
  • Clients:

    • Earlier 7.0 alphas are refused projects saved in schema 4 (412 document_schema_unsupported) and refuse .invk v3 files.
    • This build still reads schema ≤3 projects and v2 files, and splits them on first save.
  • Docs: the multi-user user and admin guides ("Upgrading to 7.0"), the projects and gallery guides, the API guide, the database-layer guide and known bugs are updated.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Meaningful regression coverage added / updated where needed; obsolete tests/code removed
  • Persisted-state and API changes include required migrations / compatibility validation
  • Relevant performance/efficiency opportunities considered; material claims have evidence
  • Material review findings resolved and relevant checks rerun
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

Replace board visibility, is_public and shared_boards with board_members and general_access, read through the query layer.
Key projects by project_id across accounts, re-keying any shared id, and add per-member project_workspaces with a document schema floor.
Clear an account's board project memberships when the account is deleted.
Add a board access service that grants viewer, contributor, editor and owner actions from membership and general access; routers, graph execution, workflow calls and upload events all ask it.
Boards report general_access, my_role and allowed_actions, keep board_visibility as a deprecated alias, and answer 404 when unreadable and 403 when an action is not allowed.
Drop the unused general_access index, and document the roles and the API changes.
…o their owner

New draft projects mint project-<uuid> ids like every other client path; a create naming another account's id answers 409 and changes nothing.
Origin-scoped queue reads (item ids, current, next, status) return a non-admin only their own items, keeping their query plans.
Document global project ids and the queue scoping.
Projects read with the caller's workspace, which saves through its own revision-checked route and indexes its media separately.
A document schema floor refuses clients that predate the split; deleting a project or account drops every member's workspace references.
Document the content and workspace contract.
Layers, reference images, adjustments and workflow items take UUID-based ids from
createItemId instead of a timestamp with a short random suffix.
…'s workspace

Saves send the content (raising the document floor to 4) and then the caller's workspace,
each at its own revision, and loads join the two halves back into one document.
Drafts, recovery, conflicts, copies and duplicates track both halves, and the conflict banner names a settings-only conflict.
…settings

.invk v3 writes project.json as content beside an optional workspace.json, behind a remembered
"Include my settings for this project" option; v2 files still import, and newer schemas are refused from the manifest.
Imports and duplicates create the content, then save the creator's settings, warning when that save fails.
Groups the project halves module into the shared startup chunk, restoring the editor's request budget.
Boards shared with you list under Shared with me and admins' other-user boards under their own group; menus offer only what your role allows, with Access for owners.
Results, uploads and moves never target a board you can only view: they go to the project inbox, and refused or revoked access refreshes the list with a notice.
…ttings in What's New

Multi-user servers show a Share boards headline and the note that Public boards are now Everyone can contribute.
Every server notes that layout, generation settings and prompt history stay each member's own in a project.
@github-actions github-actions Bot added api python PRs that change python files services PRs that change app services frontend PRs that change frontend files python-tests PRs that change python tests docs PRs that change docs labels Oct 10, 2026
Board drag between projects is offered only on the caller's own boards their role lets them move.
A refused archive restores the auto-add board only if the user has not chosen another since.
The workspace reference query-plan check runs on SQLite only.
A board the caller can no longer open reads as gone when a project loads, as a deleted one does.
Board moves stay gated on the caller's role rather than board visibility: an owner can move a board whatever its general access.
Base automatically changed from feat/boards-library to main October 11, 2026 01:26
Observe borrow-release wakeups directly and allow session GC to finish on busy runners. Give nested-loop failure cleanup a consistent integration-test deadline.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api docs PRs that change docs frontend PRs that change frontend files python PRs that change python files python-tests PRs that change python tests services PRs that change app services

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants