feat: enhance user schema with PGP encryption, GDPR fields, and 2FA support

This commit is contained in:
Mathis HERRIOT
2026-01-05 14:14:42 +01:00
parent eefe2906ed
commit 381ca24501

View File

@@ -1,21 +1,45 @@
import {pgTable, varchar, timestamp, uuid, pgEnum, index} from 'drizzle-orm/pg-core'; import {pgTable, varchar, timestamp, uuid, pgEnum, index, boolean, customType} from 'drizzle-orm/pg-core';
// Type personnalisé pour les données chiffrées PGP (stockées en bytea dans Postgres)
const pgpEncrypted = customType<{ data: string; driverData: string }>({
dataType() {
return 'bytea';
},
});
export const userStatus = pgEnum("user_status", ["active", "verification", "suspended", "pending", "deleted"]) export const userStatus = pgEnum("user_status", ["active", "verification", "suspended", "pending", "deleted"])
export const users = pgTable('users', { export const users = pgTable('users', {
status: userStatus('status').default('pending').notNull(),
uuid: uuid().primaryKey().defaultRandom(), uuid: uuid().primaryKey().defaultRandom(),
email: varchar('email', { length: 128 }).notNull().unique(), status: userStatus('status').default('pending').notNull(),
username: varchar('username', { length: 32 }).notNull().unique(),
// Données Personnelles (PII) - Chiffrées nativement
email: pgpEncrypted('email').notNull(),
emailHash: varchar('email_hash', { length: 64 }).notNull().unique(), // Indexé pour recherche rapide et unicité
displayName: varchar('display_name', { length: 32 }), displayName: varchar('display_name', { length: 32 }),
username: varchar('username', { length: 32 }).notNull().unique(),
passwordHash: varchar('password_hash', { length: 72 }).notNull(), passwordHash: varchar('password_hash', { length: 72 }).notNull(),
// Sécurité
twoFactorSecret: pgpEncrypted('two_factor_secret'),
isTwoFactorEnabled: boolean('is_two_factor_enabled').notNull().default(false),
// RGPD & Conformité
termsVersion: varchar('terms_version', { length: 16 }), // Version des CGU acceptées
privacyVersion: varchar('privacy_version', { length: 16 }), // Version de la Privacy Policy acceptée
gdprAcceptedAt: timestamp('gdpr_accepted_at', { withTimezone: true }),
// Dates de cycle de vie (Standards Entreprise)
lastLoginAt: timestamp('last_login_at', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
gdprAcceptation: timestamp('gdpr_acceptation', { withTimezone: true }), deletedAt: timestamp('deleted_at', { withTimezone: true }), // Soft delete (Droit à l'oubli)
}, (table) => ({ }, (table) => ({
uuidIdx: index('users_uuid_idx').on(table.uuid), uuidIdx: index('users_uuid_idx').on(table.uuid),
emailIdx: index('users_email_idx').on(table.email), emailHashIdx: index('users_email_hash_idx').on(table.emailHash),
usernameIdx: index('users_username_idx').on(table.username), usernameIdx: index('users_username_idx').on(table.username),
statusIdx: index('users_status_idx').on(table.status),
})); }));
export type UserInDb = typeof users.$inferSelect; export type UserInDb = typeof users.$inferSelect;