feat: enhance audit logging, add MCP settings, and production docker setup
continuous-integration/drone/push Build is passing

- Implemented comprehensive audit logging for Tasks, Users, Settings, Goals, Labels, AI Chat, and Rewards.
- Added Admin UI for MCP Server settings and Audit Logs.
- Created docker-compose-production.yml with Traefik configuration.
- Fixed backend bugs (missing storage methods, route closure).
- Added Audit Logging Guidelines.
This commit is contained in:
2025-12-15 15:53:31 +01:00
parent fdf321cde9
commit d1736c5991
35 changed files with 5165 additions and 499 deletions
+56
View File
@@ -57,6 +57,8 @@ export const tasks = pgTable("tasks", {
labelId: varchar("label_id").references(() => labels.id),
energyLevel: text("energy_level").default("medium"), // 'low' | 'medium' | 'high'
estimatedDuration: integer("estimated_duration"), // in minutes
parentTaskId: varchar("parent_task_id").references((): any => tasks.id), // Self-reference for subtasks
startDate: timestamp("start_date"), // For multi-day tasks
dependencies: text("dependencies").array(), // Array of task IDs
userId: varchar("user_id").references(() => users.id), // Added for ownership
});
@@ -108,6 +110,7 @@ export const insertLabelSchema = createInsertSchema(labels).omit({
export const insertTaskSchema = createInsertSchema(tasks, {
dueDate: z.coerce.date().nullable(),
startDate: z.coerce.date().nullable(),
}).omit({
id: true,
userId: true, // We will set this server-side
@@ -250,3 +253,56 @@ export type InsertPasswordResetToken = z.infer<typeof insertPasswordResetTokenSc
export type PasswordResetToken = typeof passwordResetTokens.$inferSelect;
export type InsertUserReward = z.infer<typeof insertUserRewardSchema>;
// AI Chat Tables
export const conversations = pgTable("conversations", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
userId: varchar("user_id").references(() => users.id).notNull(),
title: text("title").notNull(),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(),
});
export const messages = pgTable("messages", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
conversationId: varchar("conversation_id").references(() => conversations.id).notNull(),
role: text("role").notNull(), // 'user' | 'assistant' | 'system'
content: text("content").notNull(),
createdAt: timestamp("created_at").defaultNow(),
});
export const insertConversationSchema = createInsertSchema(conversations).omit({
id: true,
createdAt: true,
updatedAt: true,
});
export const insertMessageSchema = createInsertSchema(messages).omit({
id: true,
createdAt: true,
});
export type InsertConversation = z.infer<typeof insertConversationSchema>;
export type Conversation = typeof conversations.$inferSelect;
export type InsertMessage = z.infer<typeof insertMessageSchema>;
export type Message = typeof messages.$inferSelect;
// Audit Logging
export const auditLogs = pgTable("audit_logs", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
userId: varchar("user_id").references(() => users.id), // Nullable if system action (though usually we track actor)
action: text("action").notNull(), // 'CREATE', 'UPDATE', 'DELETE', 'LOGIN', etc.
entityType: text("entity_type").notNull(), // 'TASK', 'GOAL', 'USER', 'SYSTEM'
entityId: text("entity_id"), // ID of the modified entity
details: json("details"), // JSON object with changed fields
source: text("source").notNull().default("USER"), // 'USER' | 'AI' | 'SYSTEM'
createdAt: timestamp("created_at").defaultNow(),
});
export const insertAuditLogSchema = createInsertSchema(auditLogs).omit({
id: true,
createdAt: true,
});
export type InsertAuditLog = z.infer<typeof insertAuditLogSchema>;
export type AuditLog = typeof auditLogs.$inferSelect;