Apps
Register and manage apps in the Atrium directory — environments, visibility, contacts, hosting.
The app registry is the catalog Atrium renders as the launcher.
Every entry has a slug (immutable primary key), a tile glyph, one or more
environments (URLs you can launch into), a category, visibility
rules, and directory metadata that surfaces in /ask answers and
locked-card tooltips.
Registering an app
/admin → Register app. The form auto-derives a slug from the name
(Sentry → sentry); override with the small slug input below if you
need a different one. Slug is the primary key — once set, it can't be
renamed without re-registering. To rename: register a fresh slug, copy
metadata, delete the old one.
The form pulls every Zitadel project the OMMAX org owns and surfaces
the unregistered ones as one-click suggestion chips above the form.
Click + Brievcase to prefill name + Zitadel project ID in one step.
Environments — one slug, many URLs
Each environment is a row of { label, url, variant, visibility, hostedOn }.
Examples:
Prod https://app.delphi-dialogue.com prod DISCOVERABLE Dokploy / Hetzner
Staging https://staging.delphi.ommax-int… staging SECRET Azure
visibility is per-row:
- DISCOVERABLE — anyone reaching the launcher sees the URL.
- SECRET — only users with a Zitadel grant on the app's project see the URL. Users without the grant still see the card (if the app's card-level visibility allows) but won't see this URL.
hostedOn is free-form and informational — surfaces in /ask answers
and the per-environment hint text. Tomorrow's iteration will offer Dokploy
auto-detect via the Dokploy API and a hostname match.
Card-level visibility
Two states:
- Show locked card to non-grantees — the tile renders with a "request access" hint for users without a Zitadel grant. Used for apps you want to advertise across OMMAX.
- Hide card entirely from non-grantees — non-grantees never see the tile. Used for sensitive surfaces.
The card-level setting only matters when every environment is SECRET (or there are none). If at least one env is DISCOVERABLE, the card shows regardless.
Categories
| Category | Examples |
|---|---|
| OMMAX App | atrium · opes · delphi · slideshop · brievcase |
| Client Showcase | bkk-linde · dein-deal · rsm-copilot |
| Infrastructure | zitadel · dokploy · sentry · litellm · aws |
| External | harvest · aikido · bitbucket |
| Shared Credential | plunk · oxylabs · apify · github · anthropic |
The category drives the filter chips at the top of /admin → Apps and
the section ordering on the home launcher. Admin+ can change categories;
app owners cannot.
Directory metadata
Four fields surface in /ask answers and tooltips:
- Audience — "HR + hiring managers", "Tech team + AI users"
- Scope — what the tool is for, what's acceptable use
- Where stored (for SHARED_CREDENTIAL) / Where hosted (others)
- How to request — concrete steps to gain access
These aren't required, but every app benefits from at least an audience
- scope. The AI assistant uses them to answer "who's allowed to use X?" and "how do I get into Y?" without making things up.
Self-reference — the Atrium row
The atrium slug is registered like any other app. Three deliberate
quirks:
- Inverted card in
/admin— lime fill, navy text, "You are here" pill. Reads as "this IS the directory" rather than one of 24 entries. - Hidden from
/api/me— the launcher never lists Atrium because clicking it would link you to where you already are. - Searchable in
/ask— the AI assistant still finds it when asked "what is Atrium?".
If you ever stand up a second Atrium with a different slug, none of
those quirks fire — the special case is hardcoded to id === 'atrium'.
Per-app management
/admin/apps/[slug] is the manage page. Sections:
- Identity — name, description, icon (browse via the searchable picker, ~150 lucide glyphs + 7 OMMAX-brand SVGs), tile background, category, card-level visibility.
- Environments — same per-row UI as the register form.
- Zitadel project — search/pick. Super-admin only — re-mapping changes who can access the card. Other roles see the current value but can't change it.
- Directory metadata — audience, scope, where hosted/stored, how to request.
- Contacts — repeating rows of
{ name, email, role }. First entry is the primary; legacycontactPerson/contactEmailfields stay in sync for older readers.
The save bar at the bottom shows "Saved Ns ago" after a successful PATCH. Below that, super-admins see a destructive-zone delete that requires typing the exact slug to confirm.