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.
CI runs automatically on every push. CD can run automatically after successful CI on main (patch-bump default) or can be triggered manually (workflow_dispatch) with full parameter control. Main deploys bump/tag a release; arbitrary
git_refdeploys stay read-only. 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.example .env
# Replace every placeholder, especially POSTGRES_PASSWORD, JWT_KEY,
# OWNER_EMAIL and OWNER_PASSWORD.
docker compose up --build -d
curl http://127.0.0.1:18880/health
On an empty database the API creates exactly one owner from OWNER_EMAIL,
OWNER_PASSWORD and OWNER_DISPLAY_NAME. The password must contain at least 10
characters. 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 |
/models |
Models | Provider routing status |
/activity |
Activity | Audit timeline |
/chat |
Mobile Chat | Owner-chat preview |
API endpoints
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) |
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 |
Tasks in progress older than 1 hour |
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 |
Approve task (in-progress → done) |
POST |
/api/v1/tasks/{id}/reject |
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) |
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} |
Save config file (atomic write) |
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 v3)
Deployment can happen automatically or manually:
Auto-Deploy (after successful CI on main)
- Triggered by
workflow_runafterCI - Build & Testsucceeds onmain - Uses safe defaults:
patchbump, all services, main ref - Skips automatically if the triggering commit contains
[skip ci](version-bump commits) - The version-bump commit itself uses
[skip ci]→ no infinite CI→Deploy→Bump→CI loops
Manual Deploy (workflow_dispatch)
- DevOps triggers
Deploy to Productionin Gitea Actions (or Iris auto-approves) - Chooses version bump type: patch (default) / minor / major
- Optionally scopes to a single service or specific git ref
- Workflow bumps VERSION, creates git tag, builds and deploys
- 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