app¶
The studio dashboard. See Web App for the concepts. Route modules are numerous and change often — this page documents the stable spine.
Bootstrap¶
app.main ¶
Context builders¶
app.context ¶
AlcContextMiddleware ¶
Pure ASGI middleware (NOT BaseHTTPMiddleware — streaming responses must render inside the bound context) that:
- activates the alc request context for /c/{company_id}[/project/{pid}] URLs so every model-layer path lookup grounds to the URL, and
- 307-redirects legacy /project/..., /ide/..., /upload/... URLs to the owning company's /c/{cid}/... equivalent (method + body preserved).
default_company_id ¶
The company a context-less request should ground to: this browser's remembered choice (cookie) if still valid, else the global boot default. Read-only — never writes config.
Source code in app\context.py
default_project_id ¶
This browser's remembered project for company_id (cookie) if it still exists on that company, else the company's last-known project. Read-only.
Source code in app\context.py
company_prefix ¶
The canonical URL prefix for the ACTIVE company (/c/{company_id}).
Request-scoped inside a request; the persisted default elsewhere. Shared by
python URL builders and (via template_helpers) every Jinja template.
Source code in app\context.py
accessible_companies ¶
CFG.companies filtered to what the current identity may see: org-linked companies need membership, unlinked local companies stay open.
Source code in app\context.py
get_deadline_context ¶
Reads render state from app.state — no circular imports needed.
Source code in app\context.py
get_dashboard_context ¶
Standard studio context for every page.
Pure READ: grounded by the request's URL context (AlcContextMiddleware), never syncs POM or writes config. Two tabs on different companies each get their own context.
Source code in app\context.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
resolve_asset_code ¶
Navigation registry¶
app.navigation ¶
Workspace (view-mode) + sidebar navigation registry.
A workspace is a function, not a role: "what am I here to do?" — work my tasks, browse the project, plan it, or read the dashboard. It controls WHAT shows up in the production sidebar (and eventually per-workspace landing pages), never what a user is allowed to do. Roles (WorkOS admin/member) come in later only to pick a sensible DEFAULT workspace and, eventually, which workspaces are offered — anyone can switch from the header, and the choice persists per-browser in a cookie.
Add workspaces or retag items here; templates render from this registry and need no edits.
ToolPath
dataclass
¶
Where a sidebar tool lives, for deep-link restore.
path is the tool's canonical sub-path relative to its scope root: for a
project tool everything after /c/{cid}/project/{pid}/; for a company
tool everything after /c/{cid}/. scope selects which. Matching is
segment-prefixed — an incoming URL belongs to this tool when its sub-path
equals path or extends it on a segment boundary, so a deep view like
scenes/010/read still restores the Scenes tool and its lens.
label and icon are the tool's human identity — the name and Font Awesome
glyph the sidebar shows. Carried here so a page can be REFERENCED as data
(e.g. a walkthrough step that links to "the My Tasks page" and has Alchemy
confirm it) instead of every referrer re-typing the label. label falls
back to a title-cased id; icon to a generic page glyph.
page_catalog ¶
(nav_id, ToolPath) for every linkable Alchemy page, in sidebar order — the set a walkthrough step may point at. Ordered by the sidebar SECTIONS so the picker reads top-to-bottom the way the app does; anything not in a section trails at the end.
Source code in app\navigation.py
page ¶
The page a nav id names, or None — the confirmation gate. A step's page reference is valid exactly when this returns a ToolPath.
restore_segments ¶
Head segments the shell may boot for a scope, derived from TOOL_PATHS.
Replaces the old hand-kept _NAV_SEGMENTS allowlist — a permissive first gate
(per-tool matching happens in resolve_tool).
Source code in app\navigation.py
resolve_tool ¶
The sidebar item id owning an incoming sub-path (already stripped of the scope root), by longest segment-prefix. None when no tool claims it.
Source code in app\navigation.py
restore_view_mode ¶
The workspace lens to render the restored shell in: keep the user's current one when it already shows this tool, else fall to the first workspace (switcher order) that does. Unregistered tools leave the current mode untouched, so nothing regresses for paths outside the registry.
Source code in app\navigation.py
visible_nav ¶
Sidebar item ids the given workspace sees. Any unknown mode (stale cookie) sees everything; filtering must fail open.
Source code in app\navigation.py
default_view_mode ¶
The workspace a user lands on before they've ever touched the switcher.
This is the seam where roles meet workspaces: org admins (and local/ no-auth solo studios) land on Browse; plain members land on My Tasks.
Source code in app\navigation.py
resolve_view_mode ¶
URL ?view= wins (so a workspace is linkable / Ctrl+click-openable in a
new tab); then the cookie choice; then the identity default.
Source code in app\navigation.py
nav_context ¶
Template context for the header switcher + workspace-filtered sidebar.