The Workspace feature allows users to save, organize, and access their drawings from any device using OIDC authentication (e.g., Authentik) or local email/password authentication.
- User Authentication: Sign in with SSO (OIDC) or local email/password
- Multi-Workspace Support: Create and switch between multiple workspaces
- Dashboard View: Central hub showing recently modified and visited scenes
- Collection Views: Browse scenes organized by collection in the main content area
- Scene Management: Save, open, rename, duplicate, and delete scenes
- Collections: Organize scenes into folders with team-based access control
- Emoji picker for collection icons (category tabs, search, frequently used)
- Edit collection name and icon from context menu
- Teams & Roles: Collaborate with team members using ADMIN/MEMBER/VIEWER roles
- Navigation Sidebar: Quick access to dashboard, settings, and collections
- Auto-save: Scene data is automatically saved with change detection
- Localization: Full Russian translation support including time formats
See also: Roles, Teams & Collections for detailed access control documentation.
AstraDraw has two main UI modes:
When you open a scene or create a new one, you're in canvas mode:
- Full drawing canvas with Excalidraw tools
- Minimal sidebar navigation (BoardModeNav) showing scenes from active collection
- "Dashboard" link to return to dashboard
- Scene list with the current scene highlighted
The central hub for managing your scenes and settings. The dashboard has multiple views accessible from the sidebar:
Dashboard Home (dashboardView: "home"):
- Recently Modified by You: Grid of scenes you've recently edited
- Recently Visited by You: Grid of scenes you've recently viewed
- Team Members: Shows active collaborators (placeholder)
Collection View (dashboardView: "collection"):
- Collection header with icon and name
- Sort options (Last created / Last modified)
- Import scenes and Create scene buttons
- Scene grid showing all scenes in that collection
- Empty state with call-to-action when no scenes exist
Settings Views (integrated into dashboard):
- Profile (
dashboardView: "profile"): User profile, avatar, display name - Workspace Settings (
dashboardView: "workspace"): Workspace name, icon, danger zone - Team Members (
dashboardView: "members"): Invite members, manage roles - Teams & Collections (
dashboardView: "teams-collections"): Manage teams and collections
All views share the full navigation sidebar (FullModeNav) with:
- Workspace selector
- Quick search
- Dashboard, Profile, Workspace settings, Team members, Teams & Collections links
- Collections list with context menu (Create Scene, Edit, Delete)
- User profile footer
When a user creates a new scene from a collection's context menu:
- Scene Creation: Backend creates the scene in the specified collection
- For shared workspace non-private collections: Backend auto-generates
roomIdandroomKeyfor collaboration
- For shared workspace non-private collections: Backend auto-generates
- Canvas Preparation: Canvas is reset for the new scene
- State Updates:
currentSceneIdandcurrentSceneTitleare setactiveCollectionIdis set to the collection where scene was created
- Collaboration Initialization (for shared workspaces):
- If workspace type is
SHAREDand scene hasroomId:- Call
startCollaboration(sceneId)API to getroomKey - Call
collabAPI.startCollaboration({ roomId, roomKey, isAutoCollab: true }) - Set
isAutoCollabScenetotrue
- Call
- This ensures the scene is immediately ready for real-time collaboration
- If workspace type is
- Sidebar Behavior: Sidebar stays open and switches to "board" mode
- Mode Switch: App switches from dashboard to canvas mode
- Result: User sees the canvas with sidebar showing the collection's scenes, new scene highlighted
This ensures continuity - the user can immediately start drawing while seeing their new scene in the collection's scene list.
See also: Auto-Collaboration for full details on automatic collaboration for shared collections.
When a user clicks on a scene card:
- Data Loading: Scene data is fetched from backend via
loadWorkspaceScene()- Response includes
access,roomId, androomKey(if user hascanCollaboratepermission)
- Response includes
- Canvas Update: Canvas is populated with scene elements and app state
- State Updates:
currentSceneIdandcurrentSceneTitleare set - Collaboration Auto-Join (for shared workspaces):
- If
access.canCollaborate && roomId && roomKey:- Call
collabAPI.startCollaboration({ roomId, roomKey, isAutoCollab: true }) - Data is loaded from room storage (source of truth for collaboration)
- Set
isAutoCollabScenetotrue
- Call
- If not eligible for collaboration:
- Data is loaded from workspace storage (backend API)
- Set
isAutoCollabScenetofalse
- If
- Mode Switch: App switches to canvas mode
- Sidebar: Switches to "board" mode showing scenes from the active collection
Important: For collaboration scenes, room storage (
/rooms/{roomId}) is the source of truth, not workspace storage (/scenes/{storageKey}). See Auto-Collaboration for storage architecture details.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend (Vite) β
β ββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ β
β β AuthProvider β β WorkspaceSidebar β β ExcalidrawWrapperβ β
β ββββββββββββββββ β ββ BoardModeNav β ββββββββββββββββββββ β
β β ββ FullModeNav β β
β ββββββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β WorkspaceMainContent (Router) β β
β β βββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β β β DashboardView β β CollectionView β β β
β β β - Recently β β - Collection header β β β
β β β modified β β - Sort options β β β
β β β - Recently β β - Scene grid β β β
β β β visited β β - Empty state β β β
β β βββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β β βββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β β β ProfilePage β β WorkspaceSettingsPage β β β
β β β MembersPage β β TeamsCollectionsPage β β β
β β βββββββββββββββββββ ββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SceneCardGrid β β
β β (Reusable scene display) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Storage Backend (NestJS) β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββββ β
β β AuthControllerβ βWorkspaceCtrl β β Storage Service β β
β β (OIDC/JWT) β β (Scenes API) β β (S3/MinIO) β β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββββ β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββββ β
β βWorkspacesCtrlβ β TeamsCtrl β β CollectionsCtrl β β
β β(Members/Roles)β β(Team CRUD) β β (Collection CRUD) β β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Prisma ORM β β
β β Users, Workspaces, Members, Teams, Collections, Scenes β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββ΄ββββββββββββββββββββ
βΌ βΌ
βββββββββββββββββββββββ βββββββββββββββββββββββ
β PostgreSQL β β MinIO/S3 β
β (User metadata, β β (Scene data, β
β Scene metadata, β β Files) β
β Workspaces/Teams) β βββββββββββββββββββββββ
βββββββββββββββββββββββ
- Create a new OAuth2/OIDC Provider in Authentik
- Set the Redirect URI to:
https://your-domain.com/api/v2/auth/callback - Note the Client ID and Client Secret
Add to your .env file:
# OIDC Configuration (Authentik)
OIDC_ISSUER_URL=https://auth.yourdomain.com/application/o/astradraw/
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret
# JWT Secret (generate with: openssl rand -base64 32)
JWT_SECRET=your-secure-jwt-secret
# PostgreSQL is already configured for workspace metadata
# Uses existing POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DBcd deploy
docker compose down
docker compose up -d --buildThe storage backend will automatically run Prisma migrations on startup.
When a new user registers (via OIDC or local auth):
-
Personal Workspace is automatically created:
- Name:
"{Username}'s Workspace"(e.g., "John's Workspace") - User is added as ADMIN
- Slug derived from email (e.g.,
john-doe)
- Name:
-
Private Collection is created in the workspace:
- Name: "Private" with π icon
isPrivate: true- only the owner can see it- All new scenes go here by default
-
Scene Saving Logic:
- When user creates a scene without selecting a collection β Private collection
- When user selects a specific collection β That collection
- Dashboard view shows all scenes from all accessible collections
Later, the user can:
- Create additional workspaces (for work, projects, etc.)
- Be invited to other users' workspaces
- Create shared collections within workspaces
- Sign In: Click the hamburger menu β "Sign in" β Authenticate with your OIDC provider
- Open Workspace: Click the hamburger menu β "Workspace" to open the left sidebar
- Save Scene: Click "Save to Workspace" in the menu or use the sidebar's "New Scene" button
- Open Scene: Click any scene in the workspace sidebar to load it
- Sign Out: Click your user menu in the sidebar β "Sign out"
GET /api/v2/auth/status- Check if OIDC is configuredGET /api/v2/auth/login?redirect=/path- Start OIDC login flowGET /api/v2/auth/callback- OIDC callback (internal)GET /api/v2/auth/me- Get current user infoGET /api/v2/auth/logout- Sign out
GET /api/v2/workspace/scenes- List user's scenesGET /api/v2/workspace/scenes/:id- Get scene metadataGET /api/v2/workspace/scenes/:id/data- Get scene data (binary)POST /api/v2/workspace/scenes- Create new scenePUT /api/v2/workspace/scenes/:id- Update scene metadataPUT /api/v2/workspace/scenes/:id/data- Update scene dataDELETE /api/v2/workspace/scenes/:id- Delete scene
model User {
id String @id
email String @unique
name String?
avatarUrl String?
oidcId String? @unique // For SSO users
passwordHash String? // For local auth users
scenes Scene[]
workspaceMembers WorkspaceMember[]
teamMembers TeamMember[]
ownedCollections Collection[]
}
model Workspace {
id String @id
name String
slug String @unique
avatarUrl String?
members WorkspaceMember[]
teams Team[]
collections Collection[]
inviteLinks InviteLink[]
}
model WorkspaceMember {
id String @id
role WorkspaceRole @default(MEMBER) // ADMIN, MEMBER, VIEWER
workspaceId String
userId String
@@unique([workspaceId, userId])
}
model Collection {
id String @id
name String
icon String?
isPrivate Boolean @default(false)
userId String // Owner
workspaceId String
scenes Scene[]
}
model Scene {
id String @id
title String
thumbnailUrl String?
storageKey String @unique // S3 key
roomId String? // Collaboration room
userId String
collectionId String?
isPublic Boolean
createdAt DateTime
updatedAt DateTime
}See also: Roles, Teams & Collections for the complete schema including Teams and InviteLinks.
- JWT Tokens: Session tokens are stored as HTTP-only cookies (not accessible via JavaScript)
- PKCE: Authorization flow uses PKCE for enhanced security
- Ownership: Users can only access their own scenes unless marked public
- API Keys: OIDC secrets are server-side only
- Verify OIDC_ISSUER_URL, OIDC_CLIENT_ID, and OIDC_CLIENT_SECRET are set in
deploy/.env - Check API logs:
cd deploy && docker compose logs api
- Verify OIDC_CALLBACK_URL matches your Authentik redirect URI
- Ensure APP_PROTOCOL and APP_DOMAIN are correct in
deploy/.env
- Check PostgreSQL is running:
cd deploy && docker compose ps - Verify DATABASE_URL format:
postgresql://user:password@host:5432/db
- Run migrations manually:
cd deploy && docker compose exec api npx prisma migrate deploy