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/accessreturns 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/accessacceptsrevisionand one action:createwithnameandrole;rolewithidandrole;rotateorrevokewithid. Creation/rotation returnsissued: {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:
DW_PLAYER_ACCOUNTS=1 DW_AUTHORING_WORKSPACE=lantern-atelier npm run dev:editorRestart 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.