diff --git a/README.md b/README.md index f944adb..64f1dbe 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ adapter-backed agent runtime, not a dependency of the frontend or domain model. ## Current foundation - Vue 3, TypeScript, Pinia, Vue Router and Tailwind CSS -- ASP.NET Core 10 REST API +- ASP.NET Core 10 REST API (Minimal API pattern) - Entity Framework Core and PostgreSQL - JWT owner authentication with rotating refresh sessions - `IAgentRuntime` abstraction with an OpenClaw adapter @@ -32,17 +32,101 @@ 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`. -## Authentication +## 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 + `localStorage` under key `nexus-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=Strict` cookie. -- Login and refresh endpoints are rate-limited per forwarded client IP. +- Login and refresh endpoints are rate-limited per forwarded client IP (5 attempts/minute). - All `/api/v1` operations routes require a valid access token; `/health` remains public. - Swagger is enabled only in the Development environment. +- CSRF protection via `X-CSRF-TOKEN` header and `nexus-csrf` cookie (not HttpOnly). -## Security +### Security - Never commit `.env`. - Generate `JWT_KEY` from at least 32 random bytes. @@ -51,38 +135,140 @@ TLS before forwarding to port `18880`. - Keep OpenClaw behind the `IAgentRuntime` contract. - Keep the API reachable only through the bundled web proxy or another trusted reverse proxy. -## Implemented Phase 1 modules +## Frontend routes (SPA) -The SPA uses history-mode routes: +The SPA uses history-mode routes. Standalone views (whitelisted in App.vue): -- `/login` owner login -- `/dashboard` operations snapshot -- `/projects` project portfolio -- `/tasks` task board -- `/agents` runtime and agent inventory -- `/models` provider routing status -- `/activity` audit timeline -- `/chat` mobile owner-chat preview -- `/settings` runtime and provider overview +| 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 | -The API currently exposes: +Legacy ModuleView routes (not standalone, rendered through `ModuleView.vue`): -- `POST /api/v1/auth/login` -- `POST /api/v1/auth/refresh` -- `POST /api/v1/auth/logout` -- `GET /api/v1/auth/me` -- `GET /api/v1/operations/snapshot` -- `GET|POST /api/v1/projects` -- `GET|POST /api/v1/tasks` -- `PATCH /api/v1/tasks/{id}/state` -- `GET /api/v1/activity` -- `GET /api/v1/agents` -- `GET /api/v1/models` -- `GET /health` +| 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. +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 progress` or `Blocked` tasks can be approved (→ Done) or rejected (→ Backlog). +- Only `Done` or `Backlog` tasks can be deleted. ## Runtime chat and model routing