Overview
Backend is powered by Convex functions for locking, versioning, conflicts, comments, and real-time collaboration. Call functions from the browser using the Convex client; there is no REST surface.
How to call: Use identifiers like files:finalizeUpload, locks:get, versions:list.
Auth: Authentication is via Clerk. See config:auth below and the meta-based Clerk setup in the app.
Auth & Session
| Type | Identifier | Description |
|---|---|---|
| QUERY | config:auth | Returns { requiresInvitation: boolean } |
| N/A | Clerk JS | Loaded via CDN by /js/clerk-loader.js using meta tags clerk-publishable-key and clerk-frontend-api. |
Invitations
| Type | Identifier | Args | Notes |
|---|---|---|---|
| MUTATION | invitations:send | { email, invitedBy?, workspace? } | Creates or reuses a pending invite. |
| QUERY | invitations:list | { status?, workspace?, limit? } | Filter by status all|pending|accepted. |
| QUERY | invitations:validate | { invitationCode } | Pre-auth validation for signup flows. |
| MUTATION | invitations:accept | { invitationCode } | Marks the invite as accepted. |
Workspaces & Presence
| Type | Identifier | Args | Description |
|---|---|---|---|
| QUERY | workspaces:list | {} | List all workspaces |
| MUTATION | workspaces:create | { name, creatorEmail?, invitedBy? } | Create a workspace (auto-add creator) |
| QUERY | workspaces:listForEmail | { email } | List workspaces a user belongs to |
| MUTATION | presence:heartbeat | { workspace, username } | Mark user online |
| QUERY | presence:list | { workspace } | List online users |
Files & Uploads (Convex)
| Type | Identifier | Args | Description |
|---|---|---|---|
| ACTION | files:generateUploadUrl | {} | Get a one-time upload URL |
| MUTATION | files:finalizeUpload | { workspace, owner, path, storageId, baseVersion?, size?, contentType?, sha256?, lockPath? } | Finalize upload; detects conflicts |
| ACTION | files:getDownloadUrl | { storageId } | Temporary download URL |
| QUERY | files:list | { workspace, owner? } | List files |
| MUTATION | files:remove | { workspace, path } | Soft-delete (Trash) |
Example: Upload with baseVersion
// Using Convex browser client
const convex = getConvexClient();
const { url } = await convex.action('files:generateUploadUrl', {});
await fetch(url, { method: 'POST', headers: { 'Content-Type': file.type }, body: file });
await convex.mutation('files:finalizeUpload', {
workspace: 'default', owner: 'alice', path: `default/alice/${file.name}`,
storageId, baseVersion: 'PREVIOUS_ETAG', contentType: file.type, lockPath: `default/alice/${file.name}`
});
History & Conflicts (Convex)
| Type | Identifier | Args | Description |
|---|---|---|---|
| QUERY | versions:list | { path } | List versions for a file |
| MUTATION | versions:revert | { path, versionId, author } | Revert to a previous version |
| QUERY | conflicts:list | { workspace } | List active conflicts |
| MUTATION | conflicts:resolve | { workspace, baseName, acceptedPath, author } | Resolve a conflict |
Comments (Convex)
| Type | Identifier | Args | Description |
|---|---|---|---|
| QUERY | comments:list | { path, limit? } | List comments |
| MUTATION | comments:create | { path, author, body } | Add a comment |
Locks (Convex)
| Type | Identifier | Args | Description |
|---|---|---|---|
| QUERY | locks:get | { path } | Check current lock |
| MUTATION | locks:lock | { path, owner, ttlMs? } | Acquire/refresh a lock |
| MUTATION | locks:unlock | { path, lockId } | Release a lock |
| MUTATION | locks:requestEdit | { path, from } | Ask current owner for edit access |
| QUERY | locks:listRequests | { workspace, to, sinceMs? } | Subscribe for incoming edit requests |
Trash
| Type | Identifier | Args | Description |
|---|---|---|---|
| QUERY | trash:list | { workspace, owner, limit? } | List soft-deleted items |
| MUTATION | trash:restore | { id } | Restore a file |
Admin & Users
| Type | Identifier | Args | Description |
|---|---|---|---|
| MUTATION | users:syncFromIdentity | { email?, username?, isAnonymous? } | Upsert current user |
| QUERY | users:getByEmail | { email } | Fetch user record |
Errors & Status Codes
- 400: Missing or invalid parameters
- 401/403: Unauthorized (protected routes)
- 404: Not found
- 409/423: Conflict or Locked (locks, uploads)
- 413: Payload too large (upload)
- 415: Unsupported type (text preview)
- 429: Rate limited
- 500: Server error
- 503: Database unavailable (user endpoints)