# Multitenancy OSW Studio server mode supports workspaces and multiple users on a single instance. Workspaces are the primary unit of organization and isolation. Users are granted access to workspaces with roles. ## Concepts ### Workspaces A workspace is a self-contained environment with its own projects, deployments, templates, skills, and quotas. Each workspace maps to its own SQLite database at `data/workspaces/{id}/osws.sqlite`. Data in one workspace is completely isolated from other workspaces. Workspaces are what you manage. Users are just accounts that get access to workspaces. ### Access Model There are two levels of access: - **Instance admin** -- can create and manage workspaces, users, and instance settings via `/admin/users` and `/admin/workspaces` - **Workspace member** -- can use the AI, edit projects, publish sites, and manage deployments within workspaces they have access to All workspace members have the same capabilities within a workspace. ### How it fits together An agency running OSWS might set up: - A workspace per client (e.g., "Sweet Candies", "Nordic Bikes") - Agency devs as members of each workspace they manage - The client invited to their workspace, so they can use the AI for daily updates (adding articles, changing hours) - Quota limits per workspace (1 project, 1 deployment for basic clients; more for premium) A team might set up: - One shared workspace for the team, everyone as members - The team lead as instance admin ## Architecture ``` data/ system.sqlite # Users, workspaces, access grants workspaces/ {workspaceId}/ osws.sqlite # Projects, files, templates, skills projects/ {projectId}/ database.sqlite # User-defined project databases deployments/ {deploymentId}/ runtime.sqlite # Published deployment runtime analytics.sqlite # Published deployment analytics public/ deployments/ {deploymentId}/ # Published static files ``` **system.sqlite** is the only shared database. It stores user accounts, workspace definitions, access grants (who can access which workspace), and deployment routing. **Per-workspace osws.sqlite** contains everything within a workspace. The schema is identical to single-user mode. Isolation is physical (separate files), not logical. ## URL Structure All workspace pages use the `/w/{workspaceId}/` prefix: ``` /w/{workspaceId}/projects /w/{workspaceId}/deployments /w/{workspaceId}/dashboard /w/{workspaceId}/settings ``` API routes follow the same pattern: ``` /api/w/{workspaceId}/sync/projects /api/w/{workspaceId}/deployments /api/w/{workspaceId}/shell/execute ``` System-wide admin pages (no workspace context): ``` /admin/users /admin/workspaces /admin/login ``` ## Setup ### 1. Initial Setup On a fresh install with `NEXT_PUBLIC_SERVER_MODE=true`: 1. Visit `/admin` -- you'll be redirected to a registration page 2. Create the admin account (email + password) 3. You're in. The first user automatically becomes admin with an unlimited workspace. No `ADMIN_PASSWORD` env var is needed for new installs. The legacy admin password only works as a bootstrap mechanism when no user accounts exist. ### 2. Configure Environment Add to your `.env` alongside standard server mode variables: | Variable | Default | Description | |----------|---------|-------------| | `REGISTRATION_MODE` | `closed` | `open` = users can self-register. `closed` = admin creates accounts | | `NEXT_PUBLIC_REGISTRATION_MODE` | `closed` | Client-side mirror (controls register link visibility) | | `INSTANCE_API_KEY` | *(none)* | Admin API accepts `x-instance-api-key` header for programmatic access | See **[Server Mode](?doc=server-mode)** for the full variable list. ### 3. Choose How Users Join **Open registration** (`REGISTRATION_MODE=open`): Users visit `/admin/register`, create an account, and get a default workspace automatically. **Admin-managed** (default): Admin creates users and workspaces via `/admin/users` and `/admin/workspaces`, then grants access. ### 4. Create Workspaces **Via admin UI** at `/admin/workspaces`: - Click "New Workspace", set a name and assign an owner - Expand a workspace row to see members, add or remove access - Edit quotas (max projects, deployments, storage) per workspace **Via admin API**: ``` POST /api/admin/workspaces { "name": "Sweet Candies", "ownerEmail": "dev@agency.com" } ``` ### 5. Grant Access **Via admin UI**: Expand a workspace, click "Add Member", enter email and role. **Via admin API**: ``` POST /api/admin/workspaces/{id}/access { "email": "client@sweetcandies.com", "role": "editor" } ``` ## Admin API Reference All admin routes require an admin session or the `x-instance-api-key` header. ### Workspace Management ``` GET /api/admin/workspaces -- list all workspaces with stats POST /api/admin/workspaces -- create workspace GET /api/admin/workspaces/{id} -- workspace detail + members PUT /api/admin/workspaces/{id} -- update (name, quotas) DELETE /api/admin/workspaces/{id} -- delete workspace POST /api/admin/workspaces/{id}/access -- grant user access DELETE /api/admin/workspaces/{id}/access -- revoke user access POST /api/admin/workspaces/{id}/repair -- detect and fix data issues ``` ### User Management ``` GET /api/admin/users -- list all users with their workspaces POST /api/admin/users -- create user account GET /api/admin/users/{id} -- user detail + workspaces PUT /api/admin/users/{id} -- update (display name, active) DELETE /api/admin/users/{id} -- deactivate user ``` ### User's Own Workspaces ``` GET /api/workspaces -- list workspaces the current user has access to ``` ## Quotas Each workspace has configurable limits. Defaults: - 3 projects - 1 published deployment - 100 MB storage Enforced at: - **Project creation** — rejects sync push when at project limit - **Deployment publishing** — rejects publish when at deployment limit - **File sync** — rejects file push when storage limit reached A warning banner appears in the workspace UI when storage usage exceeds 80%. Configurable per-workspace via the admin UI or API. An agency might give basic clients 1 project / 1 deployment and premium clients 10 / 5. ## Upgrading from Single-User Mode Existing single-user instances automatically migrate when multitenancy is enabled: 1. On first login, a default workspace is created with unlimited quotas 2. Existing projects, deployments, templates, and skills are copied from `data/osws.sqlite` to the workspace 3. Project databases from `data/projects/` are copied to the workspace If migration doesn't complete (e.g., already logged in when workspace was created), a "Workspace Setup Required" dialog offers to re-login and retry. Manual repair is available via: ``` POST /api/admin/workspaces/{id}/repair ``` ## Security - **Physical isolation**: Each workspace has its own SQLite file. No cross-workspace data leakage possible from missing query filters. - **Role-based access**: Every workspace API request verifies the user has sufficient access via `verifyWorkspaceAccess()`. - **Path validation**: Workspace IDs validated as UUIDs before file path construction. - **Timing-safe auth**: API key and password comparisons use constant-time operations. - **Statement blocking**: ATTACH, DETACH, PRAGMA, VACUUM blocked in user-facing SQL execution. - **Session validation**: Deactivated users' sessions invalidated on next request. ## Browser Mode Compatibility All multitenancy code is in server mode code paths, gated by `NEXT_PUBLIC_SERVER_MODE`. Browser mode (IndexedDB, client-side only) is completely unaffected.