User Profile System
Comprehensive user profile management for the Norns platform.
Overview
The User Profile System provides identity management, preference configuration, and behavioral insights for Norns users. It separates authentication (Zitadel) from application-level profile data.
| Component | Purpose |
|---|---|
| Profile API | Bifrost API endpoints for profile CRUD |
| Admin UI | Norns Admin profile management pages |
| Insights Pipeline | Automated behavioral pattern extraction |
| ContextService | Runtime context assembly from profile data |
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ USER PROFILE SYSTEM │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
│ │ Norns Admin │───▶│ Bifrost API │───▶│ PostgreSQL │ │
│ │ /profile │ │ /profile/* │ │ (ravenmaskos) │ │
│ └──────────────┘ └──────────────┘ │ ├─ users │ │
│ │ │ ├─ user_channel_ids │ │
│ │ │ ├─ user_permissions │ │
│ │ │ └─ user_insights │ │
│ ┌──────────────┐ │ └──────────────────────┘ │
│ │ n8n Workflow │───────────┤ │ │
│ │ (Scheduled) │ │ │ │
│ └──────────────┘ ▼ │ │
│ ┌──────────────┐ │ │
│ │ContextService│◀──────────────┘ │
│ │ (Runtime) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Database Schema
Core Tables
| Table | Purpose |
|---|---|
users | Core identity + JSONB preferences |
user_channel_identifiers | Multi-channel identity (Slack, phone, etc.) |
user_permissions | Domain-level access control |
user_profile_insights | System-derived behavioral patterns |
Key Columns in users
-- Identity
preferred_name VARCHAR(100)
bio TEXT
avatar_url TEXT
timezone VARCHAR(50)
-- JSONB Preferences
voice_settings JSONB -- {tts_voice_id, provider, speed, language}
response_preferences JSONB -- {verbosity, formality, humor_level, use_emoji}
context_settings JSONB -- {default_domain, work_hours, auto_switching}
notification_preferences JSONB
Channel Identifiers
Unified multi-channel identity resolution:
CREATE TABLE user_channel_identifiers (
identifier_id UUID PRIMARY KEY,
user_id UUID REFERENCES users(user_id),
identifier_type VARCHAR(50), -- 'slack', 'phone', 'telegram'
identifier_value VARCHAR(255),
is_primary BOOLEAN,
is_verified BOOLEAN,
metadata JSONB
);
Bifrost API Endpoints
Profile Management
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/v1/profile | Full profile |
| PATCH | /api/v1/profile | Update profile fields |
| GET | /api/v1/profile/preferences/response | Response preferences |
| PATCH | /api/v1/profile/preferences/response | Update response prefs |
| GET | /api/v1/profile/preferences/context | Context settings |
| PATCH | /api/v1/profile/preferences/context | Update context settings |
| GET | /api/v1/profile/preferences/voice | Voice settings |
| PATCH | /api/v1/profile/preferences/voice | Update voice settings |
Channels & Domains
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/v1/profile/channels | List connected channels |
| POST | /api/v1/profile/channels | Add channel identifier |
| DELETE | /api/v1/profile/channels/{id} | Remove channel |
| GET | /api/v1/profile/domains | List accessible domains |
| PATCH | /api/v1/profile/domains/{id}/default | Set default domain |
Insights
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/v1/profile/insights | Get user insights (read-only) |
| POST | /api/v1/profile/insights/extract | Trigger extraction for user |
| POST | /api/v1/profile/insights/extract-all | Batch extraction (API key) |
Insights Pipeline
Automated extraction of behavioral patterns from interaction data.
Pipeline Components
n8n Workflow (every 6 hours)
│
▼
Bifrost API (/insights/extract-all)
│
▼
PostgreSQL Functions
├── extract_peak_hours_insight()
├── extract_domain_focus_insight()
├── extract_channel_preference_insight()
├── extract_common_intents_insight()
├── extract_activity_trend_insight()
└── extract_weekday_pattern_insight()
│
▼
user_profile_insights table
Insight Types
| Type | Key | Description |
|---|---|---|
| usage_pattern | peak_hours | Hourly interaction distribution |
| usage_pattern | domain_focus | Domain usage percentages |
| usage_pattern | channel_preference | Slack vs web usage |
| usage_pattern | activity_trend | Increasing/stable/decreasing |
| usage_pattern | weekday_distribution | Day-of-week patterns |
| interaction_style | common_intents | Top interaction intents |
Sample Insights Output
{
"peak_hours": {"1": 217, "0": 102, "21": 72},
"channel_preference": {"slack": 96.61, "web": 3.39},
"activity_trend": {
"trend": "increasing",
"avg_daily": 48.5,
"period_days": 30
}
}
n8n Workflow
- Workflow ID:
iPnizTIsYMMcrsZn - Name: User Insights Pipeline
- Schedule: Every 6 hours
- Action: POST to Bifrost API with API key
Norns Admin Profile Page
Access
Navigate to norns.ravenhelm.dev/profile
Tabs
| Tab | Purpose |
|---|---|
| Identity | Display name, preferred name, avatar, bio, timezone |
| Preferences | Response style, context settings, notifications |
| Channels | Connected Slack, phone, email identifiers |
| Domains | View domain access, set default |
| Insights | Read-only behavioral patterns |
Data Boundaries
User-Editable:
- Core identity (name, avatar, bio, timezone)
- Response preferences (verbosity, formality, humor)
- Voice settings (provider, voice, speed)
- Context settings (default domain, work hours)
- Notification preferences
- Channel identifiers
System-Managed (Read-Only):
- Usage patterns and insights
- Confidence scores
- Derived-from counts
ContextService Integration
The ContextService uses profile data for runtime context assembly:
# context_service.py
async def _resolve_user(self, identifier: str) -> UserIdentity:
# Lookup via user_channel_identifiers table
row = await self.db.fetchrow(
"SELECT * FROM resolve_user_by_identifier($1)",
identifier
)
return UserIdentity(
response_preferences=ResponsePreferences(**row["response_preferences"]),
context_settings=ContextSettings(**row["context_settings"]),
# ... other fields
)
Context Rules Derivation
User preferences influence runtime behavior:
| Preference | Effect |
|---|---|
verbosity: concise | Sets brief_mode: true |
work_hours_start/end | Determines is_work_hours |
auto_domain_switching | Switches to ravenhelm during work |
default_domain | Used when no context suggests domain |
Quick Commands
# Test profile API
curl -s https://bifrost-api.ravenhelm.dev/api/v1/profile \
-H "X-User-ID: 701973d2-57e4-4c84-a2ec-ded996dcf676"
# Trigger insight extraction
curl -s -X POST https://bifrost-api.ravenhelm.dev/api/v1/profile/insights/extract \
-H "X-User-ID: 701973d2-57e4-4c84-a2ec-ded996dcf676"
# View insights in database
docker exec postgres psql -U ravenhelm -d ravenmaskos -c \
"SELECT insight_type, insight_key, confidence_score
FROM user_profile_insights
WHERE user_id = '701973d2-57e4-4c84-a2ec-ded996dcf676';"
# Check n8n workflow status
curl -s https://n8n.ravenhelm.dev/api/v1/workflows/iPnizTIsYMMcrsZn \
-H "X-N8N-API-KEY: $N8N_API_KEY" | jq '.active'
Migrations
Profile system migrations in ~/ravenhelm/services/ravenmaskos-db/schema/:
| Migration | Purpose |
|---|---|
005_user_profile.sql | Profile schema extensions |
006_insights_pipeline.sql | Insight extraction functions |
Related
- Norns Admin - Admin UI
- Norns Memory System - Memory architecture
- Bifrost MCP Gateway - API gateway
- Identity Management - Zitadel SSO