feat(#37-41): Add domains, ideas, relationships, agents, widgets schema

Schema additions for issues #37-41:

New models:
- Domain (#37): Life domains (work, marriage, homelab, etc.)
- Idea (#38): Brain dumps with pgvector embeddings
- Relationship (#39): Generic entity linking (blocks, depends_on)
- Agent (#40): ClawdBot agent tracking with metrics
- AgentSession (#40): Conversation session tracking
- WidgetDefinition (#41): HUD widget registry
- UserLayout (#41): Per-user dashboard configuration

Updated models:
- Task, Event, Project: Added domainId foreign key
- User, Workspace: Added new relations

New enums:
- IdeaStatus: CAPTURED, PROCESSING, ACTIONABLE, ARCHIVED, DISCARDED
- RelationshipType: BLOCKS, BLOCKED_BY, DEPENDS_ON, etc.
- AgentStatus: IDLE, WORKING, WAITING, ERROR, TERMINATED
- EntityType: Added IDEA, DOMAIN

Migration: 20260129182803_add_domains_ideas_agents_widgets
This commit is contained in:
Jason Woltje
2026-01-29 12:29:21 -06:00
parent a220c2dc0a
commit 973502f26e
308 changed files with 18374 additions and 113 deletions

View File

@@ -0,0 +1,467 @@
# Activity Logging API
The Activity Logging API provides comprehensive audit trail and activity tracking functionality for the Mosaic Stack platform. It logs user actions, workspace changes, task/event modifications, and authentication events.
## Overview
Activity logs are automatically created for:
- **CRUD Operations**: Task, event, project, and workspace modifications
- **Authentication Events**: Login, logout, password resets
- **User Actions**: Task assignments, workspace member changes
- **System Events**: Configuration updates, permission changes
All activity logs are workspace-scoped and support multi-tenant isolation through Row-Level Security (RLS).
## Endpoints
### List Activity Logs
```
GET /api/activity
```
Get a paginated list of activity logs with optional filters.
**Query Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `workspaceId` | UUID | Yes | Workspace to filter by |
| `userId` | UUID | No | Filter by user who performed the action |
| `action` | ActivityAction | No | Filter by action type (CREATED, UPDATED, etc.) |
| `entityType` | EntityType | No | Filter by entity type (TASK, EVENT, etc.) |
| `entityId` | UUID | No | Filter by specific entity |
| `startDate` | ISO 8601 | No | Filter activities after this date |
| `endDate` | ISO 8601 | No | Filter activities before this date |
| `page` | Number | No | Page number (default: 1) |
| `limit` | Number | No | Items per page (default: 50, max: 100) |
**Response:**
```json
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"workspaceId": "660e8400-e29b-41d4-a716-446655440001",
"userId": "770e8400-e29b-41d4-a716-446655440002",
"action": "CREATED",
"entityType": "TASK",
"entityId": "880e8400-e29b-41d4-a716-446655440003",
"details": {
"title": "New Task",
"status": "NOT_STARTED"
},
"ipAddress": "192.168.1.1",
"userAgent": "Mozilla/5.0...",
"createdAt": "2024-01-28T12:00:00Z",
"user": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "John Doe",
"email": "john@example.com"
}
}
],
"meta": {
"total": 150,
"page": 1,
"limit": 50,
"totalPages": 3
}
}
```
**Example Requests:**
```bash
# Get all activities in a workspace
GET /api/activity?workspaceId=660e8400-e29b-41d4-a716-446655440001
# Get activities for a specific user
GET /api/activity?workspaceId=660e8400-e29b-41d4-a716-446655440001&userId=770e8400-e29b-41d4-a716-446655440002
# Get task creation events
GET /api/activity?workspaceId=660e8400-e29b-41d4-a716-446655440001&action=CREATED&entityType=TASK
# Get activities in date range
GET /api/activity?workspaceId=660e8400-e29b-41d4-a716-446655440001&startDate=2024-01-01&endDate=2024-01-31
# Paginate results
GET /api/activity?workspaceId=660e8400-e29b-41d4-a716-446655440001&page=2&limit=25
```
---
### Get Single Activity Log
```
GET /api/activity/:id
```
Retrieve a single activity log entry by ID.
**Path Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | UUID | Yes | Activity log ID |
**Query Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `workspaceId` | UUID | Yes | Workspace ID (for multi-tenant isolation) |
**Response:**
```json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"workspaceId": "660e8400-e29b-41d4-a716-446655440001",
"userId": "770e8400-e29b-41d4-a716-446655440002",
"action": "UPDATED",
"entityType": "TASK",
"entityId": "880e8400-e29b-41d4-a716-446655440003",
"details": {
"changes": {
"status": "IN_PROGRESS"
}
},
"ipAddress": "192.168.1.1",
"userAgent": "Mozilla/5.0...",
"createdAt": "2024-01-28T12:00:00Z",
"user": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "John Doe",
"email": "john@example.com"
}
}
```
**Example Request:**
```bash
GET /api/activity/550e8400-e29b-41d4-a716-446655440000?workspaceId=660e8400-e29b-41d4-a716-446655440001
```
---
### Get Entity Audit Trail
```
GET /api/activity/audit/:entityType/:entityId
```
Retrieve complete audit trail for a specific entity (task, event, project, etc.).
**Path Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `entityType` | EntityType | Yes | Type of entity (TASK, EVENT, PROJECT, WORKSPACE, USER) |
| `entityId` | UUID | Yes | Entity ID |
**Query Parameters:**
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `workspaceId` | UUID | Yes | Workspace ID (for multi-tenant isolation) |
**Response:**
Returns array of activity logs in chronological order (oldest first).
```json
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"workspaceId": "660e8400-e29b-41d4-a716-446655440001",
"userId": "770e8400-e29b-41d4-a716-446655440002",
"action": "CREATED",
"entityType": "TASK",
"entityId": "880e8400-e29b-41d4-a716-446655440003",
"details": {
"title": "New Task"
},
"createdAt": "2024-01-28T10:00:00Z",
"user": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "John Doe",
"email": "john@example.com"
}
},
{
"id": "660e8400-e29b-41d4-a716-446655440004",
"workspaceId": "660e8400-e29b-41d4-a716-446655440001",
"userId": "770e8400-e29b-41d4-a716-446655440005",
"action": "UPDATED",
"entityType": "TASK",
"entityId": "880e8400-e29b-41d4-a716-446655440003",
"details": {
"changes": {
"status": "IN_PROGRESS"
}
},
"createdAt": "2024-01-28T12:00:00Z",
"user": {
"id": "770e8400-e29b-41d4-a716-446655440005",
"name": "Jane Smith",
"email": "jane@example.com"
}
}
]
```
**Example Requests:**
```bash
# Get audit trail for a task
GET /api/activity/audit/TASK/880e8400-e29b-41d4-a716-446655440003?workspaceId=660e8400-e29b-41d4-a716-446655440001
# Get audit trail for a project
GET /api/activity/audit/PROJECT/990e8400-e29b-41d4-a716-446655440006?workspaceId=660e8400-e29b-41d4-a716-446655440001
# Get audit trail for a workspace
GET /api/activity/audit/WORKSPACE/660e8400-e29b-41d4-a716-446655440001?workspaceId=660e8400-e29b-41d4-a716-446655440001
```
---
## Enums
### ActivityAction
Actions that can be logged:
- `CREATED` - Entity was created
- `UPDATED` - Entity was updated
- `DELETED` - Entity was deleted
- `COMPLETED` - Task or project was completed
- `ASSIGNED` - Task was assigned to a user
- `COMMENTED` - Comment was added (future use)
- `LOGIN` - User logged in
- `LOGOUT` - User logged out
- `PASSWORD_RESET` - Password was reset
- `EMAIL_VERIFIED` - Email was verified
### EntityType
Types of entities that can be tracked:
- `TASK` - Task entity
- `EVENT` - Calendar event
- `PROJECT` - Project
- `WORKSPACE` - Workspace
- `USER` - User profile
---
## Automatic Logging
The Activity Logging system includes an interceptor that automatically logs:
- **POST requests** → `CREATED` action
- **PATCH/PUT requests** → `UPDATED` action
- **DELETE requests** → `DELETED` action
The interceptor extracts:
- User information from the authenticated session
- Workspace context from request
- IP address and user agent from HTTP headers
- Entity ID from route parameters or response
---
## Manual Logging
For custom logging scenarios, use the `ActivityService` helper methods:
```typescript
import { ActivityService } from '@/activity/activity.service';
@Injectable()
export class TaskService {
constructor(private activityService: ActivityService) {}
async createTask(data, userId, workspaceId) {
const task = await this.prisma.task.create({ data });
// Log task creation
await this.activityService.logTaskCreated(
workspaceId,
userId,
task.id,
{ title: task.title }
);
return task;
}
}
```
### Available Helper Methods
#### Task Activities
- `logTaskCreated(workspaceId, userId, taskId, details?)`
- `logTaskUpdated(workspaceId, userId, taskId, details?)`
- `logTaskDeleted(workspaceId, userId, taskId, details?)`
- `logTaskCompleted(workspaceId, userId, taskId, details?)`
- `logTaskAssigned(workspaceId, userId, taskId, assigneeId)`
#### Event Activities
- `logEventCreated(workspaceId, userId, eventId, details?)`
- `logEventUpdated(workspaceId, userId, eventId, details?)`
- `logEventDeleted(workspaceId, userId, eventId, details?)`
#### Project Activities
- `logProjectCreated(workspaceId, userId, projectId, details?)`
- `logProjectUpdated(workspaceId, userId, projectId, details?)`
- `logProjectDeleted(workspaceId, userId, projectId, details?)`
#### Workspace Activities
- `logWorkspaceCreated(workspaceId, userId, details?)`
- `logWorkspaceUpdated(workspaceId, userId, details?)`
- `logWorkspaceMemberAdded(workspaceId, userId, memberId, role)`
- `logWorkspaceMemberRemoved(workspaceId, userId, memberId)`
#### User Activities
- `logUserUpdated(workspaceId, userId, details?)`
---
## Security & Privacy
### Multi-Tenant Isolation
All activity logs are scoped to workspaces using Row-Level Security (RLS). Users can only access activity logs for workspaces they belong to.
### Data Retention
Activity logs are retained indefinitely by default. Consider implementing a retention policy based on:
- Compliance requirements
- Storage constraints
- Business needs
### Sensitive Data
Activity logs should NOT contain:
- Passwords or authentication tokens
- Credit card information
- Personal health information
- Other sensitive PII
Store only metadata needed for audit purposes. Use the `details` field for non-sensitive context.
---
## Best Practices
### 1. Use Descriptive Details
Include enough context to understand what changed:
```typescript
// Good
await activityService.logTaskUpdated(workspaceId, userId, taskId, {
changes: {
status: { from: 'NOT_STARTED', to: 'IN_PROGRESS' },
assignee: { from: null, to: 'user-456' }
}
});
// Less useful
await activityService.logTaskUpdated(workspaceId, userId, taskId);
```
### 2. Log Business-Critical Actions
Prioritize logging actions that:
- Change permissions or access control
- Delete data
- Modify billing or subscription
- Export data
- Change security settings
### 3. Query Efficiently
Use appropriate filters to reduce data transfer:
```typescript
// Efficient - filters at database level
const activities = await fetch('/api/activity?workspaceId=xxx&entityType=TASK&page=1&limit=50');
// Inefficient - transfers all data then filters
const activities = await fetch('/api/activity?workspaceId=xxx');
const taskActivities = activities.filter(a => a.entityType === 'TASK');
```
### 4. Display User-Friendly Activity Feeds
Transform activity logs into human-readable messages:
```typescript
function formatActivityMessage(activity: ActivityLog) {
const { user, action, entityType, details } = activity;
switch (action) {
case 'CREATED':
return `${user.name} created ${entityType.toLowerCase()} "${details.title}"`;
case 'UPDATED':
return `${user.name} updated ${entityType.toLowerCase()}`;
case 'DELETED':
return `${user.name} deleted ${entityType.toLowerCase()}`;
default:
return `${user.name} performed ${action}`;
}
}
```
---
## Error Handling
Activity logging failures should NOT block the primary operation. The interceptor and service methods handle errors gracefully:
```typescript
try {
await activityService.logActivity(data);
} catch (error) {
// Log error but don't throw
logger.error('Failed to log activity', error);
}
```
If activity logging is critical for compliance, implement synchronous validation before the operation completes.
---
## Performance Considerations
### Indexing
The following indexes optimize common queries:
- `workspaceId` - Filter by workspace
- `workspaceId + createdAt` - Recent activities per workspace
- `entityType + entityId` - Audit trail queries
- `userId` - User activity history
- `action` - Filter by action type
### Pagination
Always use pagination for activity queries. Default limit is 50 items, maximum is 100.
### Background Processing
For high-volume systems, consider:
- Async activity logging with message queues
- Batch inserts for multiple activities
- Separate read replicas for reporting
---
## Related Documentation
- [Authentication API](../2-authentication/README.md)
- [API Conventions](../1-conventions/README.md)
- [Database Schema](../../3-architecture/2-database/README.md)