185 lines
8.7 KiB
TypeScript
185 lines
8.7 KiB
TypeScript
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;
|