- deploy.yaml now triggers automatically after successful CI completion - Adds workflow_run event listener for 'CI - Build & Test' - Guards deploy to only run when CI conclusion == success - Preserves manual workflow_dispatch for targeted deploys - Adds CI/CD note to README
12 KiB
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/CD auto-deploy enabled — every push to main triggers build → test → deploy.
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 adapterIModelProviderabstractions for Ollama and NVIDIA- Responsive dark-mode operations dashboard
- Container-only entry point on
127.0.0.1:18880
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 14
characters. Existing databases are never overwritten by the bootstrap process.
The web service is loopback-only. Public reverse-proxy activation for
nexus.noveria.net remains a separate infrastructure change and must terminate
TLS before forwarding to port 18880.
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 |
|---|---|
/opt/openclaw/data/openclaw/workspace-iris |
/mnt/workspace-iris |
/opt/openclaw/data/openclaw/workspace-programmer |
/mnt/workspace-programmer |
/opt/openclaw/data/openclaw/workspace-reviewer |
/mnt/workspace-reviewer |
/opt/openclaw/data/openclaw/workspace-architekt |
/mnt/workspace-architekt |
/opt/openclaw/data/openclaw/workspace-researcher |
/mnt/workspace-researcher |
/opt/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 is:
qwen3:4bthrough Ollama for routine and monitoring workmoonshotai/kimi-k2.6through NVIDIA for primary workgpt-5.5through OpenClaw for strategic and critical review
The Settings module reports runtime and provider state without exposing credentials.