38 KiB
Requirements: Multi-User RBAC Upgrade — agent-platform
Date: 2026-07-08 Status: Final Draft v3 Author: Requirements Analyst
1. Problem & Goal
The agent-platform currently uses a static Bearer token (AUTH_TOKEN) with no user management. All token holders have full admin access. The goal is to add multi-user support with role-based access control (RBAC), user administration, groups, conversation sharing, per-user/per-group tool permissions, per-user/per-group agent visibility, LLM token quotas, concurrent sessions, configurable password policy, GDPR data retention, full mobile responsiveness, Alembic DB migrations, and per-user audit trails — while maintaining backward compatibility for existing API clients and hardening existing MCP tools.
2. User Stories
| ID | Story |
|---|---|
| US-01 | As an admin, I want to log in with username+password so I can access the platform securely. |
| US-02 | As any user, I want to log out so my session is terminated. |
| US-03 | As an admin, I want to create/edit/disable/delete users so I can control who has access. |
| US-04 | As an admin, I want to assign roles to users so permissions are managed centrally. |
| US-05 | As a user (editor/admin), I want to chat with agents according to my permissions. |
| US-06 | As a user, I want to view audit logs if my role permits it. |
| US-07 | As an admin, I want to manage agents (CRUD) while lower roles cannot. |
| US-08 | As an API client, I want to keep using my Bearer token so existing integrations don't break. |
| US-09 | As any user, I want to see only UI elements my role permits so the interface is clean. |
| US-10 | As an admin, I want to view my own profile and change my password. |
| US-11 | As an admin, I want to create and manage groups so I can organize users and assign shared permissions. |
| US-12 | As a user, I want to share a conversation with another user or group so we can collaborate. |
| US-13 | As an admin, I want to configure which tools are available to which users/groups so tool access is fine-grained. |
| US-14 | As a viewer, I want to view shared conversations but not start new ones. |
| US-15 | As an admin, I want a first-login setup wizard to set my username and password on initial deployment. |
| US-16 | As an admin, I want to set token quotas per user so LLM costs are controlled. |
| US-17 | As a user, I want to see my token usage so I know how much budget I have left. |
| US-18 | As an admin, I want to assign agents to specific users or groups so not everyone sees all agents. |
| US-19 | As an admin, I want to deactivate or delete users with proper data handling so compliance is maintained. |
| US-20 | As an admin, I want to configure password rules (length, complexity) so security policies are enforced. |
| US-21 | As a user, I want to have multiple concurrent sessions (e.g. desktop + mobile) and revoke them independently. |
| US-22 | As an admin, I want to revoke any user's sessions so I can force logout if needed. |
| US-23 | As a user, I want audit logs filtered to what I am allowed to see so data access is properly scoped. |
| US-24 | As a developer, I want complete OpenAPI documentation so I can integrate with the API. |
| US-25 | As a user, I want the platform to be fully usable on mobile so I can work from any device. |
| US-26 | As an admin, I want to export and anonymize user data so GDPR compliance is maintained. |
3. Roles & Permissions Matrix
Roles define the baseline permission level. Groups add fine-grained control on top.
| Resource / Action | admin | editor | viewer |
|---|---|---|---|
| Agents — create/update/delete | YES | YES | NO |
| Agents — view/list | YES | assigned | assigned |
| Agents — assign to users/groups | YES | NO | NO |
| Chat — start conversation | YES | YES | NO |
| Chat — view own conversations | YES | YES | YES |
| Chat — view shared conversations | YES | YES | YES |
| Chat — view all conversations | YES | NO | NO |
| Chat — share conversation | YES | YES | NO |
| Tools — view/list | YES | YES | YES |
| Tools — use (per tool) | per perm | per perm | per perm |
| Tools — configure permissions | YES | NO | NO |
| Audit — view (all entries) | YES | NO | NO |
| Audit — view (own + shared conv) | YES | YES | NO |
| Audit — view (own only) | YES | YES | YES |
| Users — CRUD | YES | NO | NO |
| Groups — CRUD | YES | NO | NO |
| Settings — system config | YES | NO | NO |
| Token quotas — set/view | YES | NO | NO |
| Token usage — view own | YES | YES | YES |
| Sessions — manage own | YES | YES | YES |
| Sessions — manage others | YES | NO | NO |
| Password policy — configure | YES | NO | NO |
| Data retention — configure | YES | NO | NO |
| User data — export/anonymize | YES | NO | NO |
Roles defined:
- admin — full access, user/group management, system settings, tool/agent permissions, token quotas, password policy, data retention
- editor — agent CRUD, chat (start+share), audit (own+shared), no user/group management
- viewer — read-only: view assigned agents, view shared conversations, view tools, view own audit entries; no new chats, no management
Agent visibility: Not global by default. Agents can be assigned to users OR groups. See [F-RBAC-21] Agent Visibility.
Tool access: Not role-only. Each tool can be allowed/denied per user AND per group. See [F-RBAC-15] Tool Permission Management.
4. Authentication Model
- Login method: username + password (argon2id hashing)
- Session management: HTTP-only, Secure, SameSite=Lax cookies (server-side session in sessions table)
- Concurrent sessions: Multiple sessions per user allowed. Each session has independent cookie. Session list visible to user (can revoke others). Admin can revoke any user's sessions. See [F-RBAC-24].
- Session timeout: Configurable via SESSION_TIMEOUT_HOURS env var, default 24h. Rationale: prevents stale sessions on shared/insecure devices while not interrupting active work sessions. 24h balances security and usability.
- Token compatibility: existing Bearer token (AUTH_TOKEN) remains valid for API access; maps to a virtual admin identity
- Registration: admin-only invite (no open registration)
- Bootstrap admin: First-login setup wizard — on first launch with no users in DB, redirect to /setup page where admin sets username + password. AUTH_TOKEN still required to access the setup page (proves deployment ownership).
- Password policy: Configurable. See [F-RBAC-23].
- Password reset: NOT in v1 scope (see Non-Goals)
- Failed login logging: Yes — all auth events (login, logout, failed login, session revoke) logged in audit table with user_id. See S5 security fix.
5. Data Model Changes
users table (new)
CREATE TABLE users (
id TEXT PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
email TEXT,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'viewer', -- admin|editor|viewer
enabled INTEGER NOT NULL DEFAULT 1,
token_quota_daily INTEGER, -- NULL = unlimited
token_quota_monthly INTEGER, -- NULL = unlimited
created_at TEXT NOT NULL,
last_login TEXT
);
groups table (new)
CREATE TABLE groups (
id TEXT PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
description TEXT,
created_at TEXT NOT NULL
);
user_groups table (new)
CREATE TABLE user_groups (
user_id TEXT NOT NULL REFERENCES users(id),
group_id TEXT NOT NULL REFERENCES groups(id),
PRIMARY KEY (user_id, group_id)
);
conversation_shares table (new)
CREATE TABLE conversation_shares (
id TEXT PRIMARY KEY,
conversation_id TEXT NOT NULL REFERENCES conversations(id),
shared_with_user_id TEXT REFERENCES users(id),
shared_with_group_id TEXT REFERENCES groups(id),
shared_by TEXT NOT NULL REFERENCES users(id),
permission TEXT NOT NULL DEFAULT 'read', -- read|write
created_at TEXT NOT NULL,
CHECK (
(shared_with_user_id IS NOT NULL AND shared_with_group_id IS NULL) OR
(shared_with_user_id IS NULL AND shared_with_group_id IS NOT NULL)
)
);
tool_permissions table (new)
CREATE TABLE tool_permissions (
id TEXT PRIMARY KEY,
tool_name TEXT NOT NULL,
user_id TEXT REFERENCES users(id),
group_id TEXT REFERENCES groups(id),
allowed INTEGER NOT NULL DEFAULT 1, -- 1=allow, 0=deny
created_at TEXT NOT NULL,
CHECK (
(user_id IS NOT NULL AND group_id IS NULL) OR
(user_id IS NULL AND group_id IS NOT NULL)
)
);
agent_assignments table (new)
CREATE TABLE agent_assignments (
id TEXT PRIMARY KEY,
agent_id TEXT NOT NULL REFERENCES agents(id),
user_id TEXT REFERENCES users(id),
group_id TEXT REFERENCES groups(id),
created_at TEXT NOT NULL,
CHECK (
(user_id IS NOT NULL AND group_id IS NULL) OR
(user_id IS NULL AND group_id IS NOT NULL)
)
);
user_token_usage table (new)
CREATE TABLE user_token_usage (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id),
tokens_used INTEGER NOT NULL,
model TEXT NOT NULL,
period TEXT NOT NULL, -- daily|monthly
period_key TEXT NOT NULL, -- e.g. '2026-07-08' or '2026-07'
created_at TEXT NOT NULL
);
settings table (new — key-value store for configurable settings)
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at TEXT NOT NULL,
updated_by TEXT REFERENCES users(id)
);
Default settings rows:
password_min_length= '8'password_require_uppercase= 'true'password_require_lowercase= 'true'password_require_digit= 'true'password_require_special= 'false'data_retention_days= '365'
audit table (modified)
- Add column user_id TEXT (nullable for legacy entries)
- Existing rows: user_id = NULL (displayed as 'system/legacy')
- New rows: user_id = authenticated user's ID or 'SYSTEM' for Bearer token
- All auth events logged: login, logout, failed login, session revoke
sessions table (existing, repurposed)
- Add columns: user_id TEXT, expires_at TEXT, session_type TEXT ('api'|'browser'), ip_address TEXT, user_agent TEXT
conversations table (modified)
- Add column owner_id TEXT (references users.id, nullable for legacy conversations)
Migration strategy (Alembic)
Tool: Alembic for all schema migrations. No raw CREATE TABLE IF NOT EXISTS.
Initial migration (alembic revision 001):
- Create tables: users, groups, user_groups, conversation_shares, tool_permissions, agent_assignments, user_token_usage, settings
- Add columns to existing tables: audit.user_id, sessions.user_id/expires_at/ session_type/ip_address/user_agent, conversations.owner_id
- Insert default settings rows
- Insert bootstrap admin via /setup wizard (application-level, not migration)
Conversation owner migration (alembic revision 002, post-setup):
- After bootstrap admin is created via /setup wizard:
UPDATE conversations SET owner_id = <admin_user_id> WHERE owner_id IS NULL - All legacy conversations assigned to bootstrap admin
Migration runbook (3-phase — revision 002 is a DATA migration requiring application context):
alembic upgrade 001— creates schema (tables, columns, default settings). NO data changes.- Start application — redirects to /setup if no users exist
- Admin sets username + password via /setup (requires AUTH_TOKEN Bearer) — creates bootstrap admin user
alembic upgrade 002— assigns orphan conversations:UPDATE conversations SET owner_id = <admin_user_id> WHERE owner_id IS NULL. Requires admin user to exist (created in step 3).- AUTH_TOKEN continues to work — resolved as virtual admin user
- No data loss; all existing agents/conversations/messages preserved
- Rollback:
alembic downgrade -1(reverts last migration);alembic downgrade 001(reverts schema migration only)
6. UI Changes
[F-RBAC-01] Login Page
Anforderung: Server-rendered login form at /login. POST submits credentials, sets HTTP-only cookie on success, redirects to dashboard.
Test Scenarios:
- Happy Path: Valid credentials submitted -> 302 redirect to /, cookie session_id set with HttpOnly+Secure flags.
- Edge Case: Wrong password -> 401, login page re-rendered with error message, no cookie set.
- Edge Case: Disabled user attempts login -> 403, error 'account disabled', no session created.
[F-RBAC-02] Logout
Anforderung: POST /logout destroys session, clears cookie, redirects to /login.
Test Scenarios:
- Happy Path: Authenticated user clicks logout -> session row deleted, cookie cleared, redirect to /login.
- Edge Case: Unauthenticated POST to /logout -> 302 to /login, no error.
[F-RBAC-03] User Management Page (admin only)
Anforderung: /users page with table of all users, create/edit/disable/delete actions, role assignment, group membership management, token quota setting. Admin-only.
Test Scenarios:
- Happy Path: Admin navigates to /users -> sees table with all users, can create new user with role 'editor'.
- Edge Case: Viewer navigates to /users -> 403 forbidden, no user data exposed.
- Integration: Admin disables a user -> that user's next request gets 401 and redirect to /login.
[F-RBAC-04] Role-Based UI Visibility
Anforderung: Jinja2 templates conditionally render admin controls based on the current user's role. All pages fully responsive (mobile-first).
Test Scenarios:
- Happy Path: Viewer sees dashboard -> no admin nav links, no delete buttons rendered in HTML.
- Happy Path: Admin sees dashboard -> all management links present.
- Edge Case: Viewer manually requests DELETE /api/agents -> 403 from middleware.
[F-RBAC-05] User Profile / Settings Page
Anforderung: /profile page showing username, email, role (read-only), group memberships (read-only), password change form, token usage summary, active sessions list with revoke buttons.
Test Scenarios:
- Happy Path: User submits new password (current+new) -> password_hash updated, next login works with new password.
- Edge Case: Wrong current password -> 401, error message, password not changed.
[F-RBAC-06] First-Login Setup Wizard
Anforderung: On first boot with empty users table, redirect all requests to /setup. Page requires AUTH_TOKEN as Bearer to access. Admin sets username + password. After setup, redirect to /login.
Test Scenarios:
- Happy Path: Fresh deploy -> any URL redirects to /setup -> admin sets username+password -> redirect to /login.
- Edge Case: /setup accessed after users exist -> redirect to /login.
- Edge Case: /setup without AUTH_TOKEN Bearer -> 401.
[F-RBAC-13] Group Management Page (admin only)
Anforderung: /groups page with table of all groups, create/edit/delete actions, and member assignment. Admin-only. Users can be in multiple groups.
Test Scenarios:
- Happy Path: Admin creates group 'Developers', adds 2 users -> group visible in table with member count.
- Edge Case: Editor navigates to /groups -> 403 forbidden.
- Integration: Admin deletes a group -> shares with that group removed, group memberships removed (cascade).
[F-RBAC-14] Conversation Sharing
Anforderung: On any conversation the user owns, a 'Share' button opens a dialog to share with a specific user or group, with read or write permission. Shared conversations appear in a 'Shared with me' section.
Test Scenarios:
- Happy Path: User shares conversation with another user (read) -> recipient sees conversation in 'Shared with me', can view but not send messages.
- Happy Path: User shares conversation with group (write) -> all group members can send messages.
- Edge Case: Viewer tries to share -> 403.
- Integration: Owner removes share -> recipient loses access immediately.
7. API Changes
Standard Error Response Schema
All error responses (401/403/400/404/409/429/500) use a uniform JSON body:
{
"error_code": "forbidden",
"message": "You do not have permission to access this resource.",
"details": {"required_role": "admin", "current_role": "viewer"}
}
| Field | Type | Required | Description |
|---|---|---|---|
error_code |
string | YES | Machine-readable error identifier (e.g. unauthorized, forbidden, validation_error, not_found, conflict, rate_limited, internal_error) |
message |
string | YES | Human-readable error message in English |
details |
object | NO | Optional structured details (e.g. validation field errors, required vs. current role) |
This schema is enforced on all new endpoints and documented in the OpenAPI spec (see F-RBAC-27).
[F-RBAC-07] Auth Endpoints
Anforderung: POST /api/auth/login, POST /api/auth/logout, GET /api/auth/me. Login returns user info + sets cookie. /me returns current user identity including groups and token usage.
Test Scenarios:
- Happy Path: POST /api/auth/login with valid JSON -> 200, {user_id, username, role, groups[]}, cookie set.
- Edge Case: GET /api/auth/me without auth -> 401.
- Integration: After login, GET /api/auth/me with cookie -> 200, returns user data with groups + token usage.
[F-RBAC-08] User CRUD Endpoints (admin only)
Anforderung: GET/POST/PUT/DELETE /api/users — admin-only. Includes group membership, token quota setting, disable/delete with proper data handling.
Test Scenarios:
- Happy Path: Admin POST /api/users with valid data -> 201, new user created with hashed password.
- Edge Case: Editor GET /api/users -> 403.
- Edge Case: Admin DELETE own account -> 400, 'cannot delete yourself'.
[F-RBAC-09] Group CRUD Endpoints (admin only)
Anforderung: GET/POST/PUT/DELETE /api/groups. POST /api/groups/{id}/members, DELETE /api/groups/{id}/members/{user_id} for membership. Group deletion cascades: removes conversation_shares and user_groups entries for that group.
Test Scenarios:
- Happy Path: Admin POST /api/groups -> 201, new group created.
- Happy Path: Admin POST /api/groups/{id}/members with user_id -> 200, user added.
- Edge Case: Editor POST /api/groups -> 403.
[F-RBAC-10] Conversation Share Endpoints
Anforderung: POST /api/conversations/{id}/shares, DELETE .../{share_id}. Owner or admin only. Bulk revoke: DELETE /api/conversations/{id}/shares (all).
Test Scenarios:
- Happy Path: Owner POST share with user_id+permission=read -> 201.
- Happy Path: Owner POST share with group_id+permission=write -> 201.
- Edge Case: Non-owner non-admin POST share -> 403.
- Edge Case: Owner DELETE all shares -> 200, all recipients lose access.
[F-RBAC-11] Permission Middleware
Anforderung: FastAPI dependency checking user role, agent assignment, tool permission on every protected endpoint. Bearer token = virtual admin. Agent access: user must be assigned directly or via group. Admin sees all agents.
Test Scenarios:
- Happy Path: Viewer with cookie calls DELETE /api/agents/{id} -> 403.
- Happy Path: Bearer token calls DELETE /api/agents/{id} -> 200.
- Edge Case: No auth on protected endpoint -> 401.
[F-RBAC-12] Bearer Token Backward Compatibility
Anforderung: AUTH_TOKEN env var still accepted as Bearer header. Resolved as virtual admin user. No existing API client breaks.
Test Scenarios:
- Happy Path: Bearer AUTH_TOKEN on /api/agents -> 200, full admin access.
- Integration: Bearer token audit entries logged with user_id='SYSTEM'.
[F-RBAC-15] Tool Permission Management
Anforderung: Admin configures per-tool permissions per user and per group. GET/POST/PUT/DELETE /api/tools/permissions. Resolution: user-level -> group-level -> role default (editor: allow, viewer: deny). New users inherit role default.
Test Scenarios:
- Happy Path: Admin denies tool 'http_get' for user X -> user X cannot use http_get in chat.
- Happy Path: Admin allows tool 'calculate' for group 'Devs' -> members can use calculate.
- Edge Case: No explicit permission -> default applies (editor: allow, viewer: deny).
[F-RBAC-20] LLM Token Quota System
Anforderung: Each user has configurable token quota (daily/monthly) set by admin. user_token_usage table tracks tokens per user per period. Soft limit: warning at 80%. Hard limit: block new chat messages at 100%. User sees usage in profile. Admin sees all users' usage. Users without quota (NULL) = unlimited.
Test Scenarios:
- Happy Path: Admin sets daily quota 10000 for user X -> user X uses 8000 tokens -> warning shown. Uses 10000 -> next chat message blocked with 'quota exceeded'.
- Edge Case: User with NULL quota -> unlimited, no warnings, no blocks.
- Integration: Admin views /api/users/{id}/usage -> returns daily+monthly totals.
[F-RBAC-21] Agent Visibility per User/Group
Anforderung: Agents can be assigned to users OR groups via agent_assignments table. Only assigned users (or group members) can see/use agents. Admin sees all. Unassigned agents = admin only. Assignment managed via /api/agents/{id}/assignments.
Test Scenarios:
- Happy Path: Admin assigns agent A to user X -> user X sees agent A in dashboard, can chat.
- Happy Path: Admin assigns agent B to group 'Devs' -> group members see agent B.
- Edge Case: User Y (not assigned to agent A) -> agent A not visible in UI or API.
- Edge Case: Agent with no assignments -> only admin sees it.
[F-RBAC-22] User Deactivation vs Deletion
Anforderung: Admin can deactivate (enabled=false) or delete users. Deactivate: sessions invalidated, no new logins, conversations preserved (owner_id kept), audit entries preserved. Delete: conversations transferred to admin (owner_id = admin), shares removed, group memberships removed, audit entries preserved with user_id reference (not anonymized on delete — anonymization is separate GDPR action). Admin chooses deactivate or delete in UI.
Test Scenarios:
- Happy Path: Admin deactivates user X -> user X sessions deleted, login returns 403, conversations preserved with owner_id=X.
- Happy Path: Admin deletes user Y -> user Y conversations owner_id set to admin, shares removed, group memberships removed, audit entries preserved.
- Edge Case: Admin tries to delete self -> 400, 'cannot delete yourself'.
[F-RBAC-23] Password Policy (Configurable)
Anforderung: Password rules stored in settings table (min_length default=8, require_uppercase, require_lowercase, require_digit, require_special default=false). Admin configures via PUT /api/settings/password-policy. Enforced on user creation, password change, and setup wizard.
Test Scenarios:
- Happy Path: Admin sets min_length=12, require_special=true -> new user with password 'short1!' -> 400 (too short). Password 'Longenough1!' -> 201.
- Edge Case: User changes password to one that fails policy -> 400 with specific validation error.
- Integration: Policy change does not affect existing passwords (only future sets).
[F-RBAC-24] Concurrent Sessions
Anforderung: Multiple sessions per user allowed. Each session has independent cookie/token. User sees session list in /profile (IP, user_agent, created_at) and can revoke others. Admin can revoke any user's sessions via /api/users/{id}/sessions.
Test Scenarios:
- Happy Path: User logs in from desktop, then from mobile -> 2 active sessions, both work independently.
- Happy Path: User revokes mobile session from desktop -> mobile session invalidated, desktop still works.
- Integration: Admin revokes all sessions for user X -> user X gets 401 on next request.
[F-RBAC-25] Audit Visibility per Role
Anforderung: Admin sees all audit entries. Editor sees own entries + entries for conversations they have access to. Viewer sees own entries only. API filters automatically based on role. UI shows filtered audit log.
Test Scenarios:
- Happy Path: Admin GET /api/audit -> all entries returned.
- Happy Path: Editor GET /api/audit -> only own entries + entries for accessible conversations.
- Edge Case: Viewer GET /api/audit -> only own entries (e.g. own login/logout events).
[F-RBAC-26] OpenAPI Documentation
Anforderung: Every endpoint has complete OpenAPI schema via FastAPI auto-gen. /docs (Swagger UI) and /redoc available. All new endpoints have request/response schemas, error codes (401/403/400/429/500), auth requirements documented. OpenAPI spec tested: verify all endpoints have descriptions and schemas.
Test Scenarios:
- Happy Path: GET /openapi.json -> valid OpenAPI 3.1 spec with all endpoints documented.
- Happy Path: GET /docs -> Swagger UI renders, all endpoints visible with schemas.
- Edge Case: New endpoint without description -> test fails (CI check).
[F-RBAC-27] GDPR / Data Retention
Anforderung: User data (username, email, password_hash, audit entries) subject to data_retention_days setting (default 365). Admin can export user data as JSON via GET /api/users/{id}/export. Admin can anonymize deleted user data (replace username/email with 'anonymized', keep audit entries with anonymized user_id). Export includes: profile, conversations (owned), audit entries, token usage.
Test Scenarios:
- Happy Path: Admin GET /api/users/{id}/export -> JSON with user profile, conversations, audit entries, token usage.
- Happy Path: Admin anonymizes user X -> username='anonymized', email='anonymized', password_hash removed, audit entries preserved with user_id=X.
- Edge Case: Non-admin GET /api/users/{id}/export -> 403.
8. Security Requirements
[F-RBAC-16] Password Hashing (argon2id)
Anforderung: All passwords hashed with argon2id. No plaintext storage.
Test Scenarios:
- Happy Path: Create user with password 'test123' -> DB stores argon2id hash, not plaintext.
- Edge Case: Login with correct password -> succeeds; wrong password -> fails.
[F-RBAC-17] Login Rate Limiting + Auth Event Logging
Anforderung: Max 5 failed login attempts per IP per 60 seconds -> 429 for 60s. All auth events (login, logout, failed login, session revoke) logged in audit table with user_id, ip_address, user_agent.
Test Scenarios:
- Happy Path: 5 wrong passwords in 60s -> 6th attempt 429. Audit has 5 'login_failed' entries.
- Edge Case: 4 wrong + 1 correct -> no rate limit, user logged in, 'login' event in audit.
[F-RBAC-18] CSRF Protection
Anforderung: All cookie-authenticated state-changing requests require CSRF token. Bearer token requests exempt.
Test Scenarios:
- Happy Path: Form POST with valid CSRF token -> succeeds.
- Edge Case: Form POST without CSRF token -> 403.
[F-RBAC-19] Session Expiry (Configurable)
Anforderung: Browser sessions expire after SESSION_TIMEOUT_HOURS (default 24h). Expired sessions redirect to /login. Bearer tokens have no expiry.
Test Scenarios:
- Happy Path: Session idle >24h -> next request 401, redirect to /login.
- Edge Case: Active session within 24h -> normal access.
- Edge Case: SESSION_TIMEOUT_HOURS=2 -> sessions expire after 2h.
S2: http_get Tool Hardening
Anforderung: Disable follow_redirects (prevent SSRF via redirect). Add DNS pinning: resolve hostname once at first call, pin IP for subsequent calls in same session. Non-admin users cannot use http_get unless explicitly permitted via tool_permissions.
Test Scenarios:
- Happy Path: http_get to http://example.com -> follows no redirects, returns 200 from pinned IP.
- Edge Case: http_get to URL that redirects -> redirect not followed, original response returned.
- Edge Case: Non-admin user without http_get permission -> tool blocked.
S3: list_env Tool Hardening
Anforderung: Admin-only by default. Mask-whitelist expanded. Non-admin users see only non-sensitive vars (e.g. PATH, LANG). Sensitive vars (tokens, keys, passwords) hidden for non-admins. Admin sees all.
Test Scenarios:
- Happy Path: Admin calls list_env -> sees all env vars including AUTH_TOKEN (masked).
- Edge Case: Non-admin calls list_env -> sees only PATH, LANG, HOME, etc. No tokens/keys.
- Edge Case: Non-admin without list_env permission -> tool blocked.
S5: Auth Event Audit Logging
Anforderung: All auth events written to audit table: login (success), login (failed), logout, session revoke, session expiry. Each entry has user_id, ip_address, user_agent, timestamp.
Test Scenarios:
- Happy Path: User logs in -> audit entry: action='login', user_id=X, ip=..., user_agent=...
- Happy Path: User logs out -> audit entry: action='logout', user_id=X.
- Edge Case: Failed login -> audit entry: action='login_failed', user_id=NULL, details={username, ip}.
9. Non-Goals (v1)
- NO OAuth/SSO integration (SAML, OIDC, Google/GitHub login)
- NO Multi-tenant isolation (single-tenant only)
- NO 2FA/MFA (TOTP, WebAuthn)
- NO Per-user API key management (AUTH_TOKEN remains global)
- NO Password reset / forgot-password email flow
- NO User registration / self-signup
- NO Session refresh tokens / sliding window renewal
- NO Webhook notifications for user/group events
- NO Email notifications (user create/disable, share notifications)
- NO Conversation transfer of ownership (except on user deletion)
- NO Real-time collaboration (concurrent editing of same conversation)
- NO Token quota rollover (unused quota does not carry over)
10. Acceptance Criteria (Summary)
| Criterion | Verification |
|---|---|
| Login works with username+password | Manual test on staging: login, access dashboard |
| First-login setup wizard works | Fresh DB -> /setup -> set credentials -> login works |
| Logout clears session | Manual test: logout, verify redirect + no access |
| 3 roles enforced | API test: each role gets correct 200/403 on all endpoints |
| Viewer cannot start new chats | API test: viewer POST /api/chat -> 403 |
| Bearer token still works | curl with AUTH_TOKEN on /api/agents -> 200 |
| User management admin-only | Browser test: viewer gets 403 on /users |
| Group management admin-only | Browser test: editor gets 403 on /groups |
| Groups: create, add members, multiple per user | API test: create group, add user, verify |
| Conversation sharing (user read) | Share -> recipient views, cannot send |
| Conversation sharing (group write) | Share -> all group members can send |
| Tool permissions per user | Deny tool for user -> blocked in chat |
| Tool permissions per group | Allow tool for group -> members can use |
| Agent visibility per user | Assign agent -> user sees it, unassigned don't |
| Agent visibility per group | Assign agent to group -> members see it |
| Token quota enforced | Set quota -> user hits limit -> blocked |
| Token usage visible | User sees own usage in profile |
| User deactivation preserves data | Deactivate -> sessions killed, convs preserved |
| User deletion transfers convs | Delete -> convs to admin, shares removed |
| Password policy enforced | Set min_length=12 -> short password rejected |
| Concurrent sessions work | Login from 2 devices -> both work, revoke one |
| Admin can revoke sessions | Admin revokes user sessions -> user gets 401 |
| Audit filtered by role | Viewer sees own only, editor sees own+shared |
| OpenAPI spec complete | GET /openapi.json -> all endpoints documented |
| Swagger UI works | GET /docs -> all endpoints visible with schemas |
| Mobile responsive | Test at 320px, 768px, 1024px -> all pages usable |
| HTMX works on touch | Tap buttons on mobile -> actions work |
| GDPR export | Admin exports user data -> JSON with all data |
| GDPR anonymize | Admin anonymizes -> username/email anonymized |
| Data retention configurable | Set 30 days -> old audit entries flagged |
| Audit logs show user_id | Create agent as user -> audit has user_id |
| Failed logins in audit | Wrong password -> 'login_failed' in audit |
| Passwords argon2id hashed | DB inspection: no plaintext |
| Rate limiting on login | 6 rapid wrong -> 429 on 6th |
| CSRF on form POSTs | Form POST without token -> 403 |
| Session expires (configurable) | Set 1h -> wait 1h -> expired |
| http_get hardened | No redirect following, DNS pinning works |
| list_env hardened | Non-admin sees only non-sensitive vars |
| Auth events logged | Login/logout/failed/revoke in audit |
| Alembic migrations work | alembic upgrade head -> all tables created |
| Migration rollback works | alembic downgrade -1 -> reverts cleanly |
| All existing endpoints still function | Full regression: agents CRUD, chat, tools, audit |
| No data loss on migration | Existing agents/conversations preserved |
11. Assumptions
- Single instance deployment (no horizontal scaling needed for sessions)
- SQLite remains the database (no migration to PostgreSQL needed)
- AUTH_TOKEN continues to be set in environment for backward compatibility
- Jinja2+HTMX stack stays — no SPA framework introduction
- Existing MCP tools container and FastMCP integration unchanged (tools themselves are hardened)
- staging.agent-platform.media-on.de remains the test environment
- argon2id available via argon2-cffi Python package
- Alembic available and configured for SQLite + aiosqlite
- User count is small (<50), no pagination needed for user/group lists in v1
- Conversation sharing is opt-in; conversations are private by default
- Tool permission resolution: user-level > group-level > role default
- Agent visibility: unassigned agents = admin only; admin always sees all agents
- Token quota: NULL = unlimited; quota tracks LLM tokens (prompt+completion)
- Mobile responsiveness uses CSS media queries + HTMX touch-compatible interactions
- GDPR anonymization keeps audit trail intact (user_id preserved, PII replaced)
- Data retention is advisory (admin sees expired entries, manual purge or scheduled cleanup post-v1)
12. Resolved Decisions
| # | Question | Decision | Rationale |
|---|---|---|---|
| Q1 | Conversation visibility for editor | Shareable with users/groups | User wants sharing + groups; private by default |
| Q2 | Viewer can start new chats? | No — strictly read-only | User: 'viewer kann nur sehen' |
| Q3 | Session timeout needed? | Yes, configurable, default 24h | Security best practice; 24h balances security/usability |
| Q4 | Bootstrap admin password | First-login setup wizard | Better UX; AUTH_TOKEN guards setup page |
| Q5 | Failed logins in audit? | Yes | User confirmed |
| Q6 | Email notifications? | No | User: 'erstmal nein' |
| Q7 | Tool visibility per role? | Per-user AND per-group | User wants fine-grained control |
| Q8 | Bulk 'unshare all'? | Yes | Owner/admin can revoke all shares at once |
| Q9 | Group deletion cascades to shares? | Yes | Shares + memberships removed on group delete |
| Q10 | Default tool perms for new users? | Inherit role default | Editor: allow all; viewer: deny all |
13. Open Questions
All open questions resolved. No remaining open questions.
14. Discovery Checklist (20 Categories)
| # | Category | Status | Notes |
|---|---|---|---|
| 1 | Auth | ja | Login/logout/RBAC/session/setup wizard/concurrent sessions/password policy |
| 2 | Daten | ja | User/group/agent_assignment/tool_perm/share/token_usage/settings + Alembic migrations |
| 3 | Fehler | ja | 401/403/400/429 responses, login error messages, OpenAPI error schemas |
| 4 | Skalierung | nein | Single instance, <50 users, SQLite sufficient |
| 5 | Sicherheit | ja | argon2id, CSRF, rate limiting, session expiry, S2/S3/S5 tool hardening, GDPR |
| 6 | UX | ja | Login, setup wizard, role-based UI, profile, groups, sharing, mobile responsive |
| 7 | Infrastruktur | nein | Unchanged — existing Docker/staging; Alembic adds migration tooling |
| 8 | Multi-User | ja | RBAC + groups + sharing + agent visibility + tool perms + token quotas + concurrent sessions |
| 9 | Migration | ja | Alembic revisions, conversation owner assignment, setup wizard, rollback runbook |
| 10 | Mobile | ja | Full mobile responsive at 320/768/1024px, HTMX touch-compatible |
| 11 | Integration | nein | No external integrations added in this phase |
| 12 | Compliance | ja | Audit trail with user_id, GDPR export/anonymize, data retention setting |
| 13 | Performance | nein | Small user base, existing performance adequate |
| 14 | i18n | nein | German/English not required for v1 |
| 15 | Accessibility | spaeter | Login form has labels/ARIA; full WCAG audit deferred |
| 16 | Analytics | nein | No usage tracking added (token usage is operational, not analytics) |
| 17 | Environments | ja | Staging for testing, production via existing Docker, Alembic runbook |
| 18 | Dokumentation | ja | OpenAPI/Swagger complete, all endpoints documented |
| 19 | Testing | ja | Manual + curl tests defined in acceptance criteria; OpenAPI spec testable |
| 20 | Naming/Branding | nein | Existing project name/branding unchanged |
| 21 | Scheduling | nein | No background jobs/cron needed for RBAC (data retention purge post-v1) |
15. Feature Test Coverage
| Feature ID | Feature | Test Count |
|---|---|---|
| F-RBAC-01 | Login Page | 3 |
| F-RBAC-02 | Logout | 2 |
| F-RBAC-03 | User Management Page | 3 |
| F-RBAC-04 | Role-Based UI Visibility | 3 |
| F-RBAC-05 | Profile / Settings Page | 2 |
| F-RBAC-06 | First-Login Setup Wizard | 3 |
| F-RBAC-07 | Auth Endpoints | 3 |
| F-RBAC-08 | User CRUD Endpoints | 3 |
| F-RBAC-09 | Group CRUD Endpoints | 3 |
| F-RBAC-10 | Conversation Share Endpoints | 4 |
| F-RBAC-11 | Permission Middleware | 3 |
| F-RBAC-12 | Bearer Token Compat | 2 |
| F-RBAC-13 | Group Management Page | 3 |
| F-RBAC-14 | Conversation Sharing UI | 4 |
| F-RBAC-15 | Tool Permission Management | 3 |
| F-RBAC-16 | Password Hashing (argon2id) | 2 |
| F-RBAC-17 | Rate Limiting + Auth Event Logging | 2 |
| F-RBAC-18 | CSRF Protection | 2 |
| F-RBAC-19 | Session Expiry (Configurable) | 3 |
| F-RBAC-20 | LLM Token Quota System | 3 |
| F-RBAC-21 | Agent Visibility per User/Group | 4 |
| F-RBAC-22 | User Deactivation vs Deletion | 3 |
| F-RBAC-23 | Password Policy (Configurable) | 3 |
| F-RBAC-24 | Concurrent Sessions | 3 |
| F-RBAC-25 | Audit Visibility per Role | 3 |
| F-RBAC-26 | OpenAPI Documentation | 3 |
| F-RBAC-27 | GDPR / Data Retention | 3 |
| S2 | http_get Tool Hardening | 3 |
| S3 | list_env Tool Hardening | 3 |
| S5 | Auth Event Audit Logging | 3 |
Total: 27 RBAC features + 3 security fixes = 30 items, all with test scenarios, 87 total test scenarios
DISCOVERY_CHECK: categories=20/20, features_with_ids=27/27, test_scenarios=27/27, constraints=Y, non_goals=Y, domain=Y, ready_for_ui=Y