Base module reference
Base module reference
The base layer (redelay/js-admin-nuxt4) ships these modules. Every project admin inherits all of them automatically — remove entries from the sidebar by overriding navigation, or disable a module by omitting its source (fork-and-trim).
| Module | Sidebar | Pages | Backed by |
|---|---|---|---|
auth | (hidden — layout handles) | /login, /logout, /forgot-password | go-framework/modules/auth — POST /auth/login, /auth/refresh, /auth/revoke |
users | Users → All Users | /users, /users/:id, /users/groups, /users/groups/:id | go-framework/modules/users/admin — /admin/users/* |
notifications | (top-bar bell) | /system/status | go-modules/notifications — /notifications/* (SSE) |
settings | System → Settings | /settings/:group/:subgroup? | go-framework/modules/settings/admin — /admin/settings/* |
flows | Flows → All Flows / Templates / Deployments | /flows, /flows/new, /flows/:id, /flows/:id/versions/:vid, /flows/templates, /flows/deployments, /flows/deployments/:id | go-flowdsl/flowexec/module/admin — /flows, /runs, /deployments |
ai | System → AI | /ai/usage, /ai/breakdowns, /ai/pricing | go-ai/ledger/admin — /admin/llm/* |
profiles | System → Profiles | /profiles, /profiles/:module/:kind/:id | go-framework/modules/settings/admin — /admin/profiles/* |
search | System → Search | /search, /search/:index | go-modules/search/admin — /admin/search/* |
dashboard | (home) | / (redirects to /dashboard), /dashboard | /health + aggregates from the above |
modules | System → Modules | /modules (module browser) | go-framework/modules/modspec — /modules.json |
media | Media → Library / Storage | /media, /media/dashboard | (adapter — wires into your storage module) |
AI modules
Three related framework modules surface in the admin:
ai-llm— the provider registry. Reads every supported provider's credentials from env + admin settings and builds every provider that has credentials on Startup. Admin groups under/admin/settings/ai-llm:openai,anthropic,gemini,ovh,ollama,defaults. Each provider group has an api-key / base-url / default-model input that pre-populates with the current env value so operators can see what's wired up without digging through shell configs.ai-guard— builds aguard.Guardbackend (Qwen3Guard-Gen on OVH is free) fromGUARD_PROVIDERenv + admin settings. Theredelay/llm-guardFlowDSL router node consumes it.ledger— mounts/admin/llm/usage,/admin/llm/breakdowns,/admin/llm/pricing. The admin UI's System → AI section renders charts + an editable pricing table over this. Pricing updates take effect on the next LLM call — no restart.
Settings resolution — DB > ENV > YAML default
Every module ships a settings: block in its module.yaml. Each SettingField can declare an env_var: that names the environment variable used as a fallback when no admin-edited DB row exists. The settings.Service (in go-framework/modules/settings) resolves every read through three layers:
- DB — explicit admin-edited value in the
_settingsMongoDB collection. - ENV — value of
SettingField.EnvVarwhen set in the process environment. - Default — the YAML
default:on the field.
The admin API's POST /admin/settings/get delegates to the service, so GET /admin/settings/schemas + POST /admin/settings/get together tell the admin UI both the schema AND the current effective value for every key — no blank fields for env-backed configuration on first boot. Writing a value goes through the same service, which also publishes a settings.updated event on the EventBus so peer workers invalidate their local resolver cache — no container restart needed for a cluster-wide refresh.
By default, the ENV fallback uses the convention {MODULE_ID}_{KEY} — both uppercased, with hyphens in the module id replaced by underscores. Only declare env_var: when you need a non-conventional name (legacy vars, third-party conventions):
settings:
id: mymodule
groups:
- id: mymodule.defaults
settings:
- key: api_key
label: API key
type: string
# No env_var — service reads MYMODULE_API_KEY automatically.
default: ""
- key: license_key
label: Legacy license key
type: string
# Non-conventional name — declare explicitly.
env_var: LEGACY_LICENSE_KEY
default: ""
Worked examples from the tree:
| Module | Key | Implicit env | env_var declared? |
|---|---|---|---|
flowstudio | embed_url | FLOWSTUDIO_EMBED_URL | no |
flowstudio | ui_path | FLOWSTUDIO_UI_PATH | no |
flowstudio | license_key | FLOWSTUDIO_LICENSE_KEY | yes → FLOWDSL_LICENSE_KEY |
search | index_prefix | SEARCH_INDEX_PREFIX | no |
search | qdrant_url | SEARCH_QDRANT_URL | yes → QDRANT_URL |
ai-llm | openai_api_key | AI_LLM_OPENAI_API_KEY | yes → OPENAI_API_KEY |
ai-guard | block_flagged | AI_GUARD_BLOCK_FLAGGED | yes → GUARD_BLOCK_FLAGGED |
No Go code is ever needed for the fallback — the settings.Service handles both the convention and the explicit override.
Vector search module
search — pluggable backend (Qdrant today, OpenSearch planned), index CRUD under /admin/search/*, semantic query under /search/*, FlowDSL nodes redelay/search-upsert + redelay/search-query. Embedding provider/model are runtime-switchable via admin settings, so the same deployment can move between OVH bge-m3 (€0.01/M) and local Ollama without redeploying.
FlowDSL Studio settings (admin-editable)
The flowstudio module (served on admin-api at /flowdsl) reads three settings at request time — edits take effect on the next page load without a restart:
| Setting | Purpose |
|---|---|
flowstudio.license_key | Runner-tier license key. When set, the Studio enables live flow execution and run-event tailing. Empty means viewer-only. |
flowstudio.embed_url | CDN or self-hosted base URL for the FlowDSL Studio JS/CSS bundle. Point at a local dev build for offline work. |
flowstudio.ui_path | Mount path (default /flowdsl). Change only if you reverse-proxy the admin on a non-standard prefix — the admin UI reads this to build deep-link URLs. |
Empty settings fall back to env defaults (FLOWDSL_LICENSE_KEY, FLOWSTUDIO_EMBED_URL, FLOWSTUDIO_UI_PATH).
Studio deep-linking
Any admin UI button can open the Flow Studio pre-selected on a specific flow, version, template, or deployment by appending query params:
http://admin.yourapp.com/flowdsl?flowID=flow.xxxx&versionID=ver.yyyy
http://admin.yourapp.com/flowdsl?templateID=default
http://admin.yourapp.com/flowdsl?deploymentID=dep.zzzz
The Go shell parses these into a window.__FLOWSTUDIO__.initial block; the hosted Studio app also reads window.location.search directly. Use the useFlowStudioLink() composable from the base layer's flows module to generate links from project admin pages:
const { linkTo, openFlow, openTemplate, openDeployment } = useFlowStudioLink()
// In a template:
<UButton :to="linkTo({ flowID, versionID })" target="_blank" external>
Open in Studio
</UButton>
// Or programmatically:
openFlow(flowID, versionID)
linkTo reads the admin-api URL from runtimeConfig.public.apiBaseUrl and the mount path from runtimeConfig.public.flowdslUiPath (default /flowdsl, overridable via NUXT_PUBLIC_FLOWDSL_UI_PATH).
Shared components
| Component | Purpose |
|---|---|
<EmptyState> | Consistent "nothing here yet" card. Props: icon, title, description, bare, compact; slot actions. |
<ResourceTable> | Generic list wrapper with pagination, row actions, empty/loading states. |
<ResourceDetailPage> | Generic detail+edit page driven by ResourceConfig<T>. |
<ResourceForm> | Auto-renders a form from a FormSection[] config. Used inside ResourceDetailPage. |
<ResourcePageHeader> | Back button + title + description + actions slot. |
<FlowStudioEmbed> | Reusable Flow Studio widget wrapper with SSE run-event feed. |
<SystemHealthWidget> | Compact /health summary tile — used on the dashboard home. |
Shared composables
| Composable | Purpose |
|---|---|
useApiFetch / $apiFetch | Auth'd fetch wrappers. Auto-imported. |
useResourceList, useResourceForm, useResourceApi | Generic list/form state + CRUD operations. |
useModuleNavigation | Merged navigation tree from all loaded modules. |
useModules | Module registry + defineRedelayModule() runtime helpers. |
useLoadingBar | Global top-of-page progress bar. |
useRelation | Many-to-many relation helpers (user ↔ group, etc.). |
Dashboard layout
layouts/dashboard.vue owns the sidebar + mobile topbar + session-expired modal. All pages with layout: 'dashboard' (the default for authenticated routes) sit inside it. Don't reach into it directly — extend via module navigation.
Runtime config keys
| Key | Default | Purpose |
|---|---|---|
NUXT_API_URL | http://localhost:8888 | Admin-api host seen by the browser |
NUXT_API_INTERNAL_URL | — | Admin-api host seen by Nuxt server (SSR proxy) |
NUXT_STANDALONE | unset | Set to 1 when running the base layer alone; loads its own CSS |
NUXT_PUBLIC_FLOWDSL_EMBED_URL | https://studio.flowdsl.com/embed/v1 | Flow Studio embed bundle location |
NUXT_PUBLIC_FLOWDSL_LICENSE_KEY | unset | License key — unlocks runner tier in the embed |