Remove --force-recreate from docker compose up so Postgres persists across deploys unless its image or config actually changed. Add Auth Smoke checks before declaring deploy success: - SeedAudit owner_created key must exist in DB - Owner login flow must return 401 (invalid_credentials) — proving auth pipeline is functional and DB is reachable Deploy fails (exit 1) if any smoke check fails (fail-closed). 46 lines changed in deploy-nexus.sh.
Nexus
Nexus is the operations platform for the Noveria ecosystem. OpenClaw is an adapter-backed agent runtime, not a dependency of the frontend or domain model.
📋 Architektur-Review (2026-06-22): Board-first Orchestrierung, sichere Backend-Brücke und Gateway-Integration geprüft. Siehe
docs/architecture-board-first-orchestration.md
CI runs automatically on every push. CD runs inside the green CI run on main or can be triggered manually (workflow_dispatch). Deploy reads
VERSIONbut does not mutate Git or create tags. Rollback and database backup are separate manual workflows. See phases/deployment.md for full CD documentation.
Current foundation
- Vue 3, TypeScript, Pinia, Vue Router and Tailwind CSS
- ASP.NET Core 10 REST API (Minimal API pattern)
- Entity Framework Core and PostgreSQL
- JWT owner authentication with rotating refresh sessions
IAgentRuntimeabstraction with an OpenClaw adapter (Ollama and NVIDIA removed — OpenClaw-only)- Responsive dark-mode operations dashboard
- Traefik reverse-proxy with Let's Encrypt TLS on
nexus.noveria.net
Local/container start
cp .env.template .env
# Replace every placeholder, especially POSTGRES_PASSWORD, JWT_KEY and BOOTSTRAP_OWNER_EMAIL.
docker compose up --build -d
curl http://127.0.0.1:18880/health
On an empty database the API creates exactly one owner from BOOTSTRAP_OWNER_EMAIL,
derives the initial display name from that email, and logs a generated temporary password once.
After first seed the password lives only in PostgreSQL. Existing databases are
never overwritten by the bootstrap process.
The API is exposed via Traefik reverse-proxy with automatic Let's Encrypt TLS. Health checks, rate limiting, and security headers are active.
Workspace mounts
The API container mounts agent workspaces from the host for file browsing
and the config editor. These are mounted under /mnt/workspace-{agentId}:
| Host path | Container mount |
|---|---|
/home/projekte_bao/openclaw/data/openclaw/workspace-iris |
/mnt/workspace-iris |
/home/projekte_bao/openclaw/data/openclaw/workspace-programmer |
/mnt/workspace-programmer |
/home/projekte_bao/openclaw/data/openclaw/workspace-reviewer |
/mnt/workspace-reviewer |
/home/projekte_bao/openclaw/data/openclaw/workspace-architekt |
/mnt/workspace-architekt |
/home/projekte_bao/openclaw/data/openclaw/workspace-researcher |
/mnt/workspace-researcher |
/home/projekte_bao/openclaw/data/openclaw/workspace-executor |
/mnt/workspace-executor |
Frontend architecture
Source layout
frontend/src/
├── App.vue # Root shell with sidebar + standalone views
├── main.ts # App bootstrap
├── router.ts # Vue Router config
├── types/
│ ├── index.ts # Re-exports
│ ├── agent.ts # AgentInfo, AgentDetail, TeamMember
│ ├── config.ts # ConfigFileInfo, SecurityStatus
│ ├── dashboard.ts # OperationsSnapshot, RuntimeStatus, etc.
│ └── project.ts # MemoryFile, DocFile types
├── stores/
│ ├── auth.ts # Auth store (JWT, login/refresh/logout)
│ └── operations.ts # Operations store (snapshot, CRUD, approve/reject)
├── services/
│ └── api.ts # Authenticated fetch wrapper (auto-refresh)
├── composables/
│ └── useTime.ts # Greeting composable (Morgen/Tag/Abend)
├── views/
│ ├── LoginView.vue
│ ├── DashboardView.vue # New dashboard (Phase 2)
│ ├── ProjectDetailView.vue
│ ├── SettingsView.vue
│ ├── MemoryView.vue
│ ├── DocsView.vue
│ ├── TeamView.vue
│ ├── SecurityView.vue
│ ├── IncidentsView.vue
│ ├── CalendarView.vue
│ ├── AgentDetailView.vue
│ └── AgentsIndexView.vue
├── components/
│ ├── layout/
│ │ ├── AppSidebar.vue
│ │ └── AppHeader.vue
│ └── dashboard/ # New dashboard components (Phase 2)
│ ├── IrisPanel.vue # Agent overview + metrics + chat
│ ├── OperationsFeed.vue # Live activity feed with filters
│ ├── AgendaPanel.vue # Daily agenda with checkboxes + localStorage
│ ├── ActiveInitiatives.vue # Project cards with progress
│ └── RecentlyFinished.vue # Quick status chips
└── ModuleView.vue
App.vue standaloneViews whitelist
New views must be registered in the standaloneViews computed property in
App.vue (line ~34). Without this entry, RouterView will not render the
component — the route is valid but the template stays empty.
New dashboard (Phase 2)
The dashboard was redesigned with a three-column layout:
- IrisPanel — Agent avatar/greeting, metrics counters (open tasks, blocked, overdue, today), AI suggestions, quick action buttons, and an inline chat box.
- OperationsFeed — Searchable/filterable activity feed with colour-coded status dots and yesterday/today/week grouping.
- AgendaPanel — Daily agenda with checkable items persisted in
localStorageunder keynexus-agenda-done. Items are sectioned into "Heute", "Morgen", and "Überfällig". - ActiveInitiatives — Project initiative cards with progress bars, status badges (healthy/attention/blocked/paused/completed), and last activity timestamps.
- RecentlyFinished — Horizontally scrollable chip list of recently completed items.
Authentication
- Passwords use versioned PBKDF2-SHA256 hashes with random salts and 210,000 iterations.
- Access tokens expire after 15 minutes and are held only in browser memory.
- Refresh tokens are random, stored only as SHA-256 hashes in PostgreSQL, rotated on use and checked for reuse.
- The browser receives the refresh token only as a
HttpOnly,Secure,SameSite=Strictcookie. - Login and refresh endpoints are rate-limited per forwarded client IP (5 attempts/minute).
- All
/api/v1operations routes require a valid access token;/healthremains public. - Swagger is enabled only in the Development environment.
- CSRF protection via
X-CSRF-TOKENheader andnexus-csrfcookie (not HttpOnly).
Security
- Never commit
.env. - Generate
JWT_KEYfrom at least 32 random bytes. - Rotate any credential that has appeared in chat before using it.
- Do not expose PostgreSQL or the API container directly.
- Keep OpenClaw behind the
IAgentRuntimecontract. - Keep the API reachable only through the bundled web proxy or another trusted reverse proxy.
Frontend routes (SPA)
The SPA uses history-mode routes. Standalone views (whitelisted in App.vue):
| Route | View | Description |
|---|---|---|
/login |
LoginView | Owner login |
/dashboard |
DashboardView | Operations snapshot with IrisPanel, Feed, Agenda |
/memory |
MemoryView | Memory file browser with search |
/docs |
DocsView | Documentation file browser |
/team |
TeamView | Agent team org map |
/security |
SecurityView | Security status center |
/projects/:id |
ProjectDetailView | Project detail |
/incidents |
IncidentsView | Incident diary |
/calendar |
CalendarView | Cron/scheduler overview |
/agents |
AgentsIndexView | Agent inventory |
/agents/:id |
AgentDetailView | Agent detail + config editor |
/settings |
SettingsView | Profile + password management |
Legacy ModuleView routes (not standalone, rendered through ModuleView.vue):
| Route | Name | Description |
|---|---|---|
/projects |
Projects | Project portfolio |
/tasks |
Task Board | Task board with visible parent/child agent flow |
/models |
Models | Provider routing status |
/activity |
Activity | Audit timeline |
/chat |
Mobile Chat | Owner-chat preview |
API endpoints
MCP Agent Data Plane
Nexus exposes an MCP endpoint at /mcp for agent-facing board operations.
It uses the official ModelContextProtocol.AspNetCore SDK with stateless
streamable HTTP transport. Tools are a thin facade over ITaskBridgeService;
they must not duplicate board business logic.
Auth follows the bridge rules: requests provide X-Agent-Id and/or
X-Nexus-Api-Key. Secrets stay in OpenClaw/Gateway config and are never
embedded in frontend code.
Registered tools:
| Tool | Purpose |
|---|---|
nexus_get_board |
Full task board |
nexus_agent_overview |
Waiting/stale workflow overview |
nexus_get_task |
Single task |
nexus_get_children |
Child tasks for a parent |
nexus_get_activity |
Task activity history |
nexus_create_task |
Create parent/standalone task |
nexus_create_child_task |
Create visible delegation child task |
nexus_update_status |
Update status using the canonical enum only |
nexus_append_activity |
Append checkpoint/activity |
nexus_handoff |
Handoff to a known agent |
The compatible /api/bridge HTTP facade remains available for internal
diagnostics and transition clients. New agent integrations should use MCP;
/api/dashboard is UI/admin surface, not an agent contract.
Mission Control Gateway Plane
Nexus keeps the Browser -> Nexus -> OpenClaw boundary: the frontend never talks
to OpenClaw directly. Read-only Gateway status is exposed through
GET /api/dashboard/gateway; it reports reachability, discovered Gateway
version and the optional Integrations:OpenClaw:RequiredVersion pin. A set pin
does not mutate production config, but makes protocol drift visible in the UI.
Agent activity shown as "Thinking" is redacted before display. Lines containing token, password, bearer, authorization, API key or secret markers are replaced with a redaction marker. Persisted audit-worthy events should be written as short Activity entries, not raw session transcripts.
Nexus activity updates stream live through the Dashboard SSE channel and are
filtered by explicit agentIds. Gateway session history is read-only fallback
data: it is fetched on demand, redacted before display and not persisted as a
long-term raw transcript. Agent "Now" and "Today" summaries are deterministic
derivations from redacted Nexus activity plus redacted Gateway history; Nexus
does not call an LLM to summarize this feed.
Config writes and approval actions are owner-only. Config saves validate before
replacement, keep a .bak when an existing file is replaced, write audit events
without file contents or secrets and return structured validation, backup
and reloadCheck results. Workspace Markdown hot reload is currently reported
truthfully as not_supported; JSON validation exists in the save path but JSON
files are not exposed unless they are explicitly allowlisted for editing.
Backend Bridge (Agent-zu-Backend, NICHT Frontend)
Der /api/bridge/ Pfad ist ein strukturierter MCP-artiger Kommando-Adapter für die
Agent-zu-Backend-Kommunikation. Kein Frontend-Code ruft diese Endpunkte auf.
Auth: X-Agent-Id Header, X-Nexus-Api-Key, oder JWT. Rate-Limited (30/min).
| Methode | Pfad | Kommando | Beschreibung |
|---|---|---|---|
GET |
/api/bridge/health |
— | Bridge-Health-Check |
POST |
/api/bridge/tasks |
create_task |
Neue Top-Level-Task erstellen |
POST |
/api/bridge/tasks/{id}/children |
create_child_task |
Child-Task unter Parent erstellen |
PATCH |
/api/bridge/tasks/{id}/status |
update_status |
Task-Status ändern |
POST |
/api/bridge/tasks/{id}/activity |
append_activity |
Aktivitätseintrag anhängen |
POST |
/api/bridge/tasks/{id}/handoff |
handoff |
Task an anderen Agent übergeben |
GET |
/api/bridge/board |
get_board |
Vollständiges Task-Board |
GET |
/api/bridge/tasks/{id} |
get_task |
Einzelne Task abrufen |
GET |
/api/bridge/tasks/{id}/children |
get_children |
Child-Tasks abrufen |
GET |
/api/bridge/tasks/{id}/activity |
get_activity |
Task-Aktivität abrufen |
GET |
/api/bridge/agent-overview |
get_agent_overview |
Agent-Workflow-Übersicht |
Response-Format (TaskBridgeCommandResponse):
{
"ok": true,
"command": "create_task",
"data": { ... },
"error": null,
"timestamp": "2026-06-22T15:30:00.000Z"
}
Health & Auth (public or rate-limited)
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/health |
No | Health check with runtime + PostgreSQL |
GET |
/api/v1/auth/csrf |
No | Get CSRF token |
POST |
/api/v1/auth/login |
No (rate-limited) | Login with email/password |
POST |
/api/v1/auth/refresh |
No (rate-limited) | Refresh access token |
POST |
/api/v1/auth/logout |
No | Clear refresh token |
GET |
/api/v1/auth/me |
Yes | Current user info |
PATCH |
/api/v1/auth/profile |
Yes | Update display name |
POST |
/api/v1/auth/change-password |
Yes | Change password (min 10 chars) |
Operations
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/operations/snapshot |
Full operations snapshot (runtime, agents, projects, tasks, activity, metrics) |
Parent/Child task flow
The Task Board now models OpenClaw delegation as a visible parent/child flow:
- Iris keeps the parent task
In progresswhile delegated work is running. - Delegated agent work is represented as visible child tasks linked via
parentTaskId. - Child tasks use the normal visible states (
Backlog,In progress,Review,Blocked,Done) instead of a separate hidden delegation lane. - Agent progress hints on parent tasks derive from recent activity and child-task status summaries.
- Full workflow documentation:
docs/openclaw-task-board-flow.md
Projects
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/projects |
List all projects |
POST |
/api/v1/projects |
Create project |
GET |
/api/v1/projects/{id} |
Get project detail |
PATCH |
/api/v1/projects/{id} |
Update project (name, description, status) |
DELETE |
/api/v1/projects/{id} |
Delete or archive project (archives if has tasks) |
Tasks
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/tasks |
List all tasks |
POST |
/api/v1/tasks |
Create task |
GET |
/api/v1/tasks/pending-approval |
Owner-only pending approvals |
PATCH |
/api/v1/tasks/{id} |
Update task (title, priority, projectId) |
PATCH |
/api/v1/tasks/{id}/state |
Update task state |
POST |
/api/v1/tasks/{id}/approve |
Owner-only approve task (in-progress -> done) |
POST |
/api/v1/tasks/{id}/reject |
Owner-only reject task (in-progress -> backlog) |
DELETE |
/api/v1/tasks/{id} |
Delete task (only done/backlog states) |
Agents
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/agents |
List all agents |
GET |
/api/v1/agents/{id} |
Agent detail (with sub-agents, identity) |
GET |
/api/v1/agents/{id}/activity |
Agent-specific activity (last 50) |
GET |
/api/v1/agents/{id}/summary |
Redacted deterministic Now/Today summary |
POST |
/api/v1/agents/{id}/command |
Send command to agent |
GET |
/api/v1/agents/{id}/config |
List agent config files (IDENTITY.md, SOUL.md, etc.) |
GET |
/api/v1/agents/{id}/config/{fileName} |
Read config file content |
PUT |
/api/v1/agents/{id}/config/{fileName} |
Owner-only validated config save with backup/audit/reload result |
Memory & Docs
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/memory |
List memory files (daily + MEMORY.md) |
GET |
/api/v1/memory/search?q= |
Full-text search in memory files |
GET |
/api/v1/memory/{name} |
Get memory file content |
GET |
/api/v1/docs |
List documentation files by category |
GET |
/api/v1/docs/{**path} |
Get doc file content (catch-all) |
Activity & Team
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/activity |
Paginated activity feed (supports type, sort, page, pageSize) |
GET |
/api/v1/routing |
Model routing status |
GET |
/api/v1/team |
Team org map with identity excerpts |
GET |
/api/v1/incidents |
List incident diary entries |
GET |
/api/v1/incidents/{name} |
Get incident detail |
GET |
/api/v1/security/status |
Security configuration status |
Calendar (Scheduler)
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/calendar |
Cron job overview (gateway or fallback) |
GET |
/api/v1/calendar/upcoming |
Upcoming cron jobs |
Chat
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/v1/chat |
Yes (rate-limited) | Route message through IAgentRuntime |
Project and task mutations create activity records. The API applies committed EF Core migrations after PostgreSQL becomes healthy. No destructive endpoints are implemented on the data layer.
State machine (tasks)
Tasks follow a simple state machine:
Backlog → In progress → Done
Backlog → Blocked → In progress / Done
- Only
In progressorBlockedtasks can be approved (→ Done) or rejected (→ Backlog). - Only
DoneorBacklogtasks can be deleted.
Runtime chat and model routing
POST /api/v1/chat routes authenticated owner messages through the
IAgentRuntime contract. The browser never receives a Gateway password or model
provider key. Conversation IDs are stable per browser and Iris is the default
agent target.
The configured model-routing policy routes through the OpenClaw Gateway only. Ollama and NVIDIA providers have been removed. Currently active models:
| Agent | Model |
|---|---|
| Iris | openai/gpt-5.4 |
| Programmer, Executor | deepseek/deepseek-v4-flash |
| Reviewer, Architekt, Researcher | deepseek/deepseek-v4-pro |
Claude models (Sonnet 4.6, Opus 4.6/4.7/4.8) are available via claude-cli backend.
The Settings module reports runtime and provider state without exposing credentials.
CI/CD
CI — Automatic
Every push to main triggers .gitea/workflows/ci.yaml:
- Backend: .NET restore → build → test
- Frontend: pnpm install → type-check → test → build
- Security: Scan for hardcoded secrets in source code
CI must never break. If it does, Reviewer fixes.
CD — Auto + Manual (CD v4)
Deployment can happen automatically or manually:
Auto-Deploy (after successful CI jobs on main)
- Runs as the final
Deploy Nexusjob in.gitea/workflows/ci.yaml - Starts only after backend, frontend, and security jobs succeed on
main - Deploys the current
mainversion after CI succeeds. - This replaces
workflow_run, which did not create deploy runs in this Gitea 1.26.3 installation. - The deploy script reads
VERSION; it does not mutate Git, bump versions, or create tags
Manual Deploy (workflow_dispatch)
- DevOps triggers
Deploy Nexus Manualin Gitea Actions - Workflow validates
VERSION, builds and deploysmain - Health check + smoke test verify the deployment
Rollback (workflow_dispatch)
- DevOps triggers
Rollback to Previous Versionin Gitea Actions - Enters target git tag (e.g.
v0.2.49) + confirmationROLLBACK - Workflow checks out the tag, rebuilds with
--no-cache, redeploys - Health check + smoke test verify the rollback
Database Backup (workflow_dispatch)
- DevOps triggers
Database Backupin Gitea Actions - Optionally also copies backup to a host path (
/home/projekte_bao/backups) - Workflow dumps PostgreSQL via
pg_dumpall, gzips, and uploads as a Gitea artifact - Artifacts are retained for 90 days (configurable)
- Optional nightly schedule (uncomment the cron trigger in
backup.yaml)
Failure Handling
When deploy or rollback fails:
- DevOps (Architekt) analyses the error
- Reviewer (Code-Fixer) fixes the problem
- DevOps re-deploys to verify the fix
The workflow outputs a formatted handoff message with the job URL.
Full CD documentation: phases/deployment.md