import { boolean, int, mysqlEnum, mysqlTable, text, timestamp, varchar, json, } from "drizzle-orm/mysql-core"; // ─── Utilisateurs (Manus OAuth + locaux) ──────────────────────────────────── export const users = mysqlTable("users", { id: int("id").autoincrement().primaryKey(), openId: varchar("openId", { length: 64 }).notNull().unique(), name: text("name"), email: varchar("email", { length: 320 }), loginMethod: varchar("loginMethod", { length: 64 }), role: mysqlEnum("role", ["user", "admin"]).default("user").notNull(), createdAt: timestamp("createdAt").defaultNow().notNull(), updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(), lastSignedIn: timestamp("lastSignedIn").defaultNow().notNull(), }); export type User = typeof users.$inferSelect; export type InsertUser = typeof users.$inferInsert; // ─── Utilisateurs locaux (auth interne) ───────────────────────────────────── export const localUsers = mysqlTable("local_users", { id: int("id").autoincrement().primaryKey(), name: varchar("name", { length: 255 }).notNull(), username: varchar("username", { length: 128 }).unique(), email: varchar("email", { length: 320 }), passwordHash: varchar("passwordHash", { length: 255 }).notNull(), role: mysqlEnum("role", ["admin", "user", "readonly"]).default("user").notNull(), isActive: boolean("isActive").default(true).notNull(), createdAt: timestamp("createdAt").defaultNow().notNull(), updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(), lastSignedIn: timestamp("lastSignedIn"), }); export type LocalUser = typeof localUsers.$inferSelect; export type InsertLocalUser = typeof localUsers.$inferInsert; // ─── Paramètres de l'application ──────────────────────────────────────────── export const appSettings = mysqlTable("app_settings", { id: int("id").autoincrement().primaryKey(), key: varchar("key", { length: 128 }).notNull().unique(), value: text("value"), updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(), }); export type AppSetting = typeof appSettings.$inferSelect; export type InsertAppSetting = typeof appSettings.$inferInsert; // ─── Entrées de veille stratégique ────────────────────────────────────────── export const veilleItems = mysqlTable("veille_items", { id: int("id").autoincrement().primaryKey(), // Clé de déduplication : hash du titre + lien dedupKey: varchar("dedupKey", { length: 64 }).notNull().unique(), titre: text("titre").notNull(), categorie: varchar("categorie", { length: 128 }), niveau: varchar("niveau", { length: 128 }), territoire: varchar("territoire", { length: 255 }), resume: text("resume"), source: varchar("source", { length: 512 }), passage: text("passage"), lien: text("lien"), // Type de veille (feuille d'origine) typeVeille: mysqlEnum("typeVeille", ["reglementaire", "concurrentielle", "technologique", "generale"]).notNull(), // Date extraite de la colonne Source (qui contient parfois une date ISO) datePublication: timestamp("datePublication"), importedAt: timestamp("importedAt").defaultNow().notNull(), }); export type VeilleItem = typeof veilleItems.$inferSelect; export type InsertVeilleItem = typeof veilleItems.$inferInsert; // ─── Entrées des appels à projets ──────────────────────────────────────────── export const aapItems = mysqlTable("aap_items", { id: int("id").autoincrement().primaryKey(), dedupKey: varchar("dedupKey", { length: 64 }).notNull().unique(), titre: text("titre").notNull(), categorie: mysqlEnum("categorie", ["Handicap", "PA", "Enfance", "Précarité", "Sanitaire", "Autre"]).notNull(), region: varchar("region", { length: 255 }), departement: varchar("departement", { length: 255 }), dateCloture: timestamp("dateCloture"), datePublication: timestamp("datePublication"), lien: text("lien"), importedAt: timestamp("importedAt").defaultNow().notNull(), }); export type AapItem = typeof aapItems.$inferSelect; export type InsertAapItem = typeof aapItems.$inferInsert; // ─── Logs d'import ─────────────────────────────────────────────────────────── export const importLogs = mysqlTable("import_logs", { id: int("id").autoincrement().primaryKey(), fileType: mysqlEnum("fileType", ["veille", "aap"]).notNull(), source: varchar("source", { length: 512 }), status: mysqlEnum("status", ["success", "partial", "error"]).notNull(), totalRows: int("totalRows").default(0), newRows: int("newRows").default(0), skippedRows: int("skippedRows").default(0), errorMessage: text("errorMessage"), details: json("details"), startedAt: timestamp("startedAt").defaultNow().notNull(), completedAt: timestamp("completedAt"), }); export type ImportLog = typeof importLogs.$inferSelect; export type InsertImportLog = typeof importLogs.$inferInsert; // ─── Boîte à idées ─────────────────────────────────────────────────────────── export const ideas = mysqlTable("ideas", { id: int("id").autoincrement().primaryKey(), userId: int("userId").notNull(), userName: varchar("userName", { length: 255 }).notNull(), titre: varchar("titre", { length: 512 }).notNull(), message: text("message").notNull(), statut: mysqlEnum("statut", ["ouvert", "en_cours", "resolu", "ferme"]).default("ouvert").notNull(), reponseAdmin: text("reponseAdmin"), reponduPar: varchar("reponduPar", { length: 255 }), reponduAt: timestamp("reponduAt"), createdAt: timestamp("createdAt").defaultNow().notNull(), updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(), }); export type Idea = typeof ideas.$inferSelect; export type InsertIdea = typeof ideas.$inferInsert; // ─── Flux RSS ──────────────────────────────────────────────────────────────────────────────────── export const rssFeeds = mysqlTable("rss_feeds", { id: int("id").autoincrement().primaryKey(), // URL du flux RSS url: text("url").notNull(), // Nom descriptif du flux name: varchar("name", { length: 255 }).notNull(), // Type de contenu alimenté par ce flux feedType: mysqlEnum("feedType", ["veille", "aap"]).notNull(), // Pour les flux de type veille : type de veille par défaut defaultTypeVeille: mysqlEnum("defaultTypeVeille", ["reglementaire", "concurrentielle", "technologique", "generale"]), // Pour les flux de type aap : catégorie par défaut defaultCategorieAap: mysqlEnum("defaultCategorieAap", ["Handicap", "PA", "Enfance", "Précarité", "Sanitaire", "Autre"]), // Règles d'automatisme JSON : [{keyword, typeVeille|categorieAap}] autoRules: json("autoRules"), // Actif ou non isActive: boolean("isActive").default(true).notNull(), // Dernière lecture réussie lastFetchedAt: timestamp("lastFetchedAt"), // Dernier statut de lecture lastFetchStatus: mysqlEnum("lastFetchStatus", ["ok", "error", "pending"]).default("pending"), lastFetchError: text("lastFetchError"), createdAt: timestamp("createdAt").defaultNow().notNull(), updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(), }); export type RssFeed = typeof rssFeeds.$inferSelect; export type InsertRssFeed = typeof rssFeeds.$inferInsert; // Paramètres globaux RSS (fréquence de lecture, etc.) export const rssSettings = mysqlTable("rss_settings", { id: int("id").autoincrement().primaryKey(), // Fréquence de lecture en minutes (ex: 60, 360, 1440) fetchIntervalMinutes: int("fetchIntervalMinutes").default(360).notNull(), // Heure de lecture automatique (format HH:MM, si mode planifié) scheduledTime: varchar("scheduledTime", { length: 5 }).default("06:00"), // Mode : interval (toutes les N minutes) ou scheduled (heure fixe) fetchMode: mysqlEnum("fetchMode", ["interval", "scheduled"]).default("scheduled").notNull(), // Activer/désactiver la lecture automatique autoFetchEnabled: boolean("autoFetchEnabled").default(true).notNull(), updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(), }); export type RssSettings = typeof rssSettings.$inferSelect; export type InsertRssSettings = typeof rssSettings.$inferInsert;