feat: implement user activity stream and multiple API improvements
Activity Stream: - Add UserActivity model with ActivityType enum to track user actions - Create activity logging service with fire-and-forget pattern - Add /api/user/activity endpoint with cursor pagination - Add cleanup cron job for 90-day activity retention - Integrate activity logging into 18 mutation API routes - Add DashboardActivityStream component with virtualized rendering API Improvements: - Add distributed rate limiting via Vercel KV (with in-memory fallback) - Add rate limiting to chat endpoint (30 req/min) - Optimize BM25 search with database-level pre-filtering - Fix JSON parse crash in search endpoint - Add pagination to collection tools response (toolsLimit/toolsOffset) - Add take limits to agent detail query to prevent excessive data fetch - Fix hardcoded tool count calculation in agents dashboard Schema Extraction: - Add schemaExtractionAttemptAt and schemaExtractionError fields - Separate rate limiting for failed (1 min) vs successful (1 hour) attempts - Allow retry of failed extractions Standardization: - Create api-response.ts with standardized response helpers - Add apiSuccess, apiError, apiNotFound, apiForbidden, etc. - Update agents routes to use standardized format Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
9f254a5ae8
commit
d6de3e025a
26 changed files with 1448 additions and 146 deletions
|
|
@ -72,9 +72,11 @@ model Tool {
|
|||
aiAgent Json? @map("ai_agent") @db.JsonB // @deprecated - will be auto-extracted in future
|
||||
|
||||
// Schema Extraction Fields
|
||||
inputSchema Json? @map("input_schema") @db.JsonB // Full JSON Schema from executor
|
||||
schemaSource String? @map("schema_source") @db.VarChar(20) // 'extracted' | 'author' | null
|
||||
schemaExtractedAt DateTime? @map("schema_extracted_at")
|
||||
inputSchema Json? @map("input_schema") @db.JsonB // Full JSON Schema from executor
|
||||
schemaSource String? @map("schema_source") @db.VarChar(20) // 'extracted' | 'author' | null
|
||||
schemaExtractedAt DateTime? @map("schema_extracted_at") // Only updated on successful extraction
|
||||
schemaExtractionAttemptAt DateTime? @map("schema_extraction_attempt_at") // Updated on every attempt (for rate limiting)
|
||||
schemaExtractionError String? @map("schema_extraction_error") @db.Text // Error message from last failed attempt
|
||||
|
||||
// Tool Discovery Fields
|
||||
toolDiscoverySource String? @map("tool_discovery_source") @db.VarChar(20) // 'auto' | 'manual' | null
|
||||
|
|
@ -342,6 +344,7 @@ model User {
|
|||
toolLikes ToolLike[]
|
||||
collectionLikes CollectionLike[]
|
||||
agentLikes AgentLike[]
|
||||
activities UserActivity[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
|
@ -713,3 +716,62 @@ model AgentLike {
|
|||
@@index([userId])
|
||||
@@map("agent_likes")
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Activity Stream Models
|
||||
// ============================================================================
|
||||
|
||||
/// Activity type enum - types of user activities tracked
|
||||
enum ActivityType {
|
||||
AGENT_CREATED
|
||||
AGENT_UPDATED
|
||||
AGENT_DELETED
|
||||
AGENT_TOOL_ADDED
|
||||
AGENT_TOOL_REMOVED
|
||||
AGENT_COLLECTION_ADDED
|
||||
AGENT_COLLECTION_REMOVED
|
||||
COLLECTION_CREATED
|
||||
COLLECTION_UPDATED
|
||||
COLLECTION_DELETED
|
||||
COLLECTION_TOOL_ADDED
|
||||
COLLECTION_TOOL_REMOVED
|
||||
TOOL_LIKED
|
||||
TOOL_UNLIKED
|
||||
COLLECTION_LIKED
|
||||
COLLECTION_UNLIKED
|
||||
AGENT_LIKED
|
||||
AGENT_UNLIKED
|
||||
}
|
||||
|
||||
/// UserActivity - tracks user actions for activity stream
|
||||
model UserActivity {
|
||||
id String @id @default(cuid())
|
||||
|
||||
// Owner relationship
|
||||
userId String @map("user_id")
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Activity type
|
||||
type ActivityType
|
||||
|
||||
// Optional entity references (for linking to entities if they still exist)
|
||||
agentId String? @map("agent_id")
|
||||
collectionId String? @map("collection_id")
|
||||
toolId String? @map("tool_id")
|
||||
|
||||
// Denormalized fields (stored at creation time for display even after entity deletion)
|
||||
targetName String @map("target_name") @db.VarChar(200)
|
||||
targetType String @map("target_type") @db.VarChar(50) // 'agent' | 'collection' | 'tool'
|
||||
|
||||
// Additional context (e.g., toolName when adding to collection)
|
||||
metadata Json? @db.JsonB
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@index([userId])
|
||||
@@index([userId, createdAt])
|
||||
@@index([type])
|
||||
@@index([createdAt])
|
||||
@@map("user_activities")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue