Guide7 min read5 sections

Named workspace access

docs/WORKSPACE_ACCESS.mdSource updated 2026-10-26
Markdown
On this page 5 sections

The atelier supports individual owner, editor and viewer keys for a private workspace. Start the editor normally (npm run dev:editor or npm run dev:art) and open its private owner link. Choose People & access, enter a name and role, and create a key. Copy the private link and give it to that collaborator. The generated key is shown once; closing the panel clears it. This does not send an invitation or contact anyone automatically.

Role Capabilities
Viewer Read the world, inspect schemas/tasks/history for their identity, validate proposals and try local previews. Cannot save, apply, publish or change access.
Editor Viewer capabilities plus saved edits, their own undo/redo, creator tasks and shared development-room Apply. Cannot publish, archive invitations or manage keys.
Owner Editor capabilities plus publication, invitation retention and workspace access management.

The editor displays the connected name and role. Viewer Save, Undo/Redo and Apply controls are disabled; publishing and invitation retention require owner access. Local preview controls remain usable by viewers so they can inspect a possible change without altering the shared draft. Permission checks run on the server for every authoring write, including direct HTTP/CLI calls, task acceptance and history operations. UI controls are convenience, not the security boundary.

Each named member has a stable UUID. The server binds history requests and task acceptance to that member, ignoring a supplied browser actor ID. Reopening with the same key restores that identity's undo history even after the browser's local undo identifier is removed. Existing deployment-owner browser histories remain compatible. Named presence uses the saved member name; viewers do not announce editable transform previews.

#Manage access

An owner can change a role, replace a key, or revoke a member from People & access. A replacement preserves identity/undo and invalidates the old key. Revocation immediately rejects subsequent requests. Already downloaded content cannot be recalled, and an edit already admitted before revocation can finish. Reload the editor after a role change to refresh its controls; stale clients still face the current server permissions. The deployment key always retains recovery-owner access and is managed through the existing server configuration.

Membership is persisted in authoring/access.json beside the saved world. Only SHA-256 hashes of random 256-bit member keys are retained. File replacement and directory synchronization finish before the response. Back up this file with the authoring workspace; preserve its restrictive permissions. Do not expose it as a static client asset. The server checks its format and fails startup if membership is malformed instead of silently granting access.

The current limit is 64 named members, with the last 256 membership changes kept as a bounded audit trail. Revoking an unused key frees a slot. Version checks reject stale owner changes; refresh after a conflict or uncertain response. If key creation succeeded but its response was lost, find the new member in the refreshed list and use Replace key. Old plaintext keys cannot be recovered. Membership changes do not modify world revisions or player rooms.

#HTTP interface

Authenticate using the ordinary Authorization: Bearer <key> header. The existing origin and cross-site protections continue to apply. Responses are Cache-Control: no-store.

  • GET /api/authoring/access returns the caller's identity and membership revision. Owners additionally receive member metadata and membership events; hashes and other members' keys are never returned.
  • Owner-only POST /api/authoring/access accepts revision and one action: create with name and role; role with id and role; rotate or revoke with id. Creation/rotation returns issued: {id, key} once.
  • Invalid or revoked keys return 401, denied roles return 403, and stale membership revisions return 409. Unknown fields and roles are rejected.

This is a private, operator-provisioned workspace identity system. It is not a public signup service, email verification system, global player account or cross-world login. Expiring invites, federated login, multitenant authorization, complete mutation-audit attribution, multiple authoring processes sharing one directory, and crash/backup qualification remain open. Public untrusted creator hosting stays disabled. Those limits do not reduce the full engine objective; they identify the remaining integration work.

#Focused acceptance

Two native/service checks pass: hashed membership restoration/rotation/revocation, then real HTTP role enforcement, owner-only operations, cross-origin rejection, role downgrade and identity-bound undo. The real software-WebGPU editor journey passes: owner creates editor/viewer access, the editor saves a reviewed proposal, reload recovers undo after deleting its local actor ID, the viewer loads the saved world with write controls disabled, and owner revocation prevents the editor from reconnecting. The final journey completed in 32.9 seconds. Type/import checks and the browser harness's client/engine builds pass.

The access panel, invitation state and viewer scene were visually reviewed. Access panel retains no issued key. Tests: tests/author-access.test.ts and tests/browser/editor-access.spec.ts. Run the latter with the standard isolated editor browser environment (DW_PLAYTEST=garden-ferry, VITE_DW_PLAYTEST=garden-ferry, a temporary DW_EDITOR_TOKEN and the configured Playwright browser). Broader mobile, keyboard/screen-reader, crash/fsync and hosted backup checks remain unqualified.

Separate operator-mediated traveler recovery is now available for lost room credentials. Workspace keys do not grant that database operation. Account-linked collaborators use account key replacement instead.

Private player accounts now support cross-browser room return and explicit account-backed workspace roles, as described below.

#Account-backed authoring roles

An existing player account can be invited to a workspace as an owner, editor or viewer. The same role checks used by workspace keys apply to every server write. Player-room membership alone grants no authoring privileges; each workspace requires its own invitation. Roles bind to the stable account ID, not its key, so account key replacement preserves role and account-owned undo history.

Use the same PostgreSQL database as your player accounts and choose a stable, unique workspace ID for this authoring directory. For local use, set your normal PostgreSQL connection variables (or DW_DATABASE_URL), then start:

Terminal
DW_PLAYER_ACCOUNTS=1 DW_AUTHORING_WORKSPACE=lantern-atelier npm run dev:editor

Restart an already running editor first: the launcher reuses a healthy process and cannot apply changed environment variables to it. Open the printed deployment owner link. In People & access → Invite a player account, enter the account ID printed by npm run player:account -- list, select a role, and invite. The collaborator opens /editor.html, chooses Use a player account, and enters their private account key. A valid invited account cookie can reconnect without re-entering the key. The key is cleared after submission and is not put in browser storage; requests use the HttpOnly session cookie.

The connected name and role appear in the atelier. Account editors can save and Apply, viewers can inspect and preview, and owners can publish and manage both account invitations and workspace keys. History/accepted creator tasks bind to the authenticated account ID; a client cannot choose another account's undo history. Existing workspace-key history remains associated with its original member ID; this does not merge those histories into accounts automatically.

Account members can use Sign out in the top bar. Role downgrade/revocation, account disablement and account key replacement are checked on subsequent server requests, including another check after reading a mutation's body. Already completed saves and downloaded content remain. A request already past its permission check may finish; this is not distributed cancellation of in-flight work. Signing out revokes that browser account session, including its player-room credentials on services sharing it.

Memberships, role revisions and the last 256 role events are stored in the dw_author_accounts PostgreSQL namespace. A workspace admits at most 64 account members. Account owner changes are serialized with revision checks; stale forms must refresh. The deployment owner key remains recovery access even if all account roles are revoked. Existing individual workspace keys remain supported. Use a different DW_AUTHORING_WORKSPACE for an unrelated authoring directory; reuse the same ID when restoring that workspace.

compose.yaml, compose.coolify.yaml and compose.ferry.yaml expose DW_PLAYER_ACCOUNTS, DW_AUTHORING_WORKSPACE and DW_DATABASE_URL. Set the latter to your private account database connection; these templates do not create an additional database or expose it publicly. The standard image now includes node accounts-dist/player-account.js for private account provisioning. Rebuild and restart the application to enable it. Keep the existing draft-data volume.

The updated database backup includes account workspace membership and role events. Also preserve the authoring directory: draft worlds, assets, legacy workspace keys and undo history still live there, and are not copied by the PostgreSQL/ retained-engine backup command. A full atelier restore requires both stores.

#Focused acceptance and remaining review

The native account-role check passes for editor/viewer restrictions, account-owner publication and invitations, cross-workspace denial, identity-bound undo, key replacement, role downgrade/revocation and persistent membership reopening. Both existing workspace-key checks still pass. The database archive/restore check preserves account roles. The real browser journey passes in 8.2 seconds: deployment owner invites editor/viewer accounts; the editor saves a proposal and recovers undo after reload; the viewer has disabled write controls; revocation denies reconnect. The account role panel was visually reviewed. Type/import, client and relay-service builds pass.

Tests: tests/account-authoring.test.ts, tests/author-access.test.ts, and the account-inclusive check in tests/backup.test.ts. Run through node tools/cli/test-control.mjs. To include the browser journey, set DW_AUTHOR_ACCOUNT_CLIENT_DIR to a freshly built client and configure the Playwright browser executable.

Return to these during qualification: multi-tab changes and in-flight operations, coordinated database/draft-volume backup and crash recovery, hosted cookie/TLS configuration, account/session expiry under load, keyboard/screen-reader/narrow screen use, complete mutation auditing and multi-process workspace ownership. Public signup/federation and untrusted multitenant hosting are not provided. The required character/environment/arrival art approval remains open.

End of Workspace access