feat: Implement AI Chat Agent, Email Notifications, and UI enhancements
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-12-12 08:35:48 +01:00
parent ccfb674318
commit 5d8976b1cd
58 changed files with 7867 additions and 844 deletions
+41 -1
View File
@@ -1,5 +1,5 @@
import { sql } from "drizzle-orm";
import { pgTable, text, varchar, timestamp, integer, boolean } from "drizzle-orm/pg-core";
import { pgTable, text, varchar, timestamp, integer, boolean, json } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { z } from "zod";
@@ -16,6 +16,8 @@ export const users = pgTable("users", {
lastTaskDate: timestamp("last_task_date"),
showOnLeaderboard: boolean("show_on_leaderboard").notNull().default(false), // Privacy setting
isSearchable: boolean("is_searchable").notNull().default(false), // Privacy setting
apiKey: text("api_key"), // For MCP Server access
aiEnabled: boolean("ai_enabled").notNull().default(true), // Feature flag per user
});
export const systemSettings = pgTable("system_settings", {
@@ -29,6 +31,16 @@ export const labels = pgTable("labels", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
name: text("name").notNull(),
color: text("color").notNull(),
creatorId: varchar("creator_id").references(() => users.id), // Added creator ownership
});
export const sharedLabels = pgTable("shared_labels", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
labelId: varchar("label_id").references(() => labels.id).notNull(),
sharedByUserId: varchar("shared_by_user_id").references(() => users.id).notNull(),
sharedWithUserId: varchar("shared_with_user_id").references(() => users.id).notNull(),
permission: text("permission").notNull().default("read"), // 'read' | 'write'
createdAt: timestamp("created_at").defaultNow(),
});
export const tasks = pgTable("tasks", {
@@ -72,6 +84,7 @@ export const insertUserSchema = createInsertSchema(users).pick({
email: true,
showOnLeaderboard: true,
isSearchable: true,
aiEnabled: true,
});
export const registerSchema = insertUserSchema;
@@ -79,6 +92,7 @@ export const registerSchema = insertUserSchema;
export const loginSchema = z.object({
username: z.string().min(1, "Username is required"),
password: z.string().min(1, "Password is required"),
rememberMe: z.boolean().optional(),
});
export type LoginUser = z.infer<typeof loginSchema>;
@@ -117,6 +131,7 @@ export type InsertSystemSettings = z.infer<typeof insertSystemSettingsSchema>;
export type SystemSettings = typeof systemSettings.$inferSelect;
export type InsertLabel = z.infer<typeof insertLabelSchema>;
export type Label = typeof labels.$inferSelect;
export type SharedLabel = typeof sharedLabels.$inferSelect;
export type InsertTask = z.infer<typeof insertTaskSchema>;
export type Task = typeof tasks.$inferSelect;
export type InsertSharedTask = z.infer<typeof insertSharedTaskSchema>;
@@ -187,6 +202,7 @@ export const rewards = pgTable("rewards", {
icon: text("icon").notNull(),
type: text("type").notNull().default("virtual"), // 'virtual', 'real_world', 'feature_unlock'
isSystem: boolean("is_system").default(true),
userId: varchar("user_id").references(() => users.id), // Nullable for system rewards
});
export const userRewards = pgTable("user_rewards", {
@@ -209,4 +225,28 @@ export const insertUserRewardSchema = createInsertSchema(userRewards).omit({
purchasedAt: true,
});
// Session table (managed by connect-pg-simple but defined here to avoid drizzle-kit deletion)
export const session = pgTable("session", {
sid: varchar("sid").primaryKey(),
sess: json("sess").notNull(),
expire: timestamp("expire", { precision: 6 }).notNull(),
});
export const passwordResetTokens = pgTable("password_reset_tokens", {
id: varchar("id").primaryKey().default(sql`gen_random_uuid()`),
userId: varchar("user_id").references(() => users.id).notNull(),
token: text("token").notNull().unique(),
expiresAt: timestamp("expires_at").notNull(),
isUsed: boolean("is_used").default(false),
createdAt: timestamp("created_at").defaultNow(),
});
export const insertPasswordResetTokenSchema = createInsertSchema(passwordResetTokens).omit({
id: true,
createdAt: true,
});
export type InsertPasswordResetToken = z.infer<typeof insertPasswordResetTokenSchema>;
export type PasswordResetToken = typeof passwordResetTokens.$inferSelect;
export type InsertUserReward = z.infer<typeof insertUserRewardSchema>;