Files
memegoat/backend/src/database/schemas/users.ts
Mathis HERRIOT a30113e8e2 feat(users): add avatar and bio support, improve user profile handling
Introduce `avatarUrl` and `bio` fields in the user schema. Update repository, service, and controller to handle avatar uploads, processing, and bio updates. Add S3 integration for avatar storage and enhance user data handling for private and public profiles.
2026-01-14 21:42:46 +01:00

69 lines
2.3 KiB
TypeScript

import {
boolean,
index,
pgEnum,
pgTable,
timestamp,
uuid,
varchar,
} from "drizzle-orm/pg-core";
import { pgpEncrypted, withAutomaticPgpDecrypt } from "./pgp";
export const userStatus = pgEnum("user_status", [
"active",
"verification",
"suspended",
"pending",
"deleted",
]);
export const users = pgTable(
"users",
{
uuid: uuid().primaryKey().defaultRandom(),
status: userStatus("status").default("pending").notNull(),
// 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 }),
username: varchar("username", { length: 32 }).notNull().unique(),
passwordHash: varchar("password_hash", { length: 100 }).notNull(),
avatarUrl: varchar("avatar_url", { length: 512 }),
bio: varchar("bio", { length: 255 }),
// 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(),
updatedAt: timestamp("updated_at", { withTimezone: true })
.notNull()
.defaultNow(),
deletedAt: timestamp("deleted_at", { withTimezone: true }), // Soft delete (Droit à l'oubli)
},
(table) => ({
uuidIdx: index("users_uuid_idx").on(table.uuid),
emailHashIdx: index("users_email_hash_idx").on(table.emailHash),
usernameIdx: index("users_username_idx").on(table.username),
statusIdx: index("users_status_idx").on(table.status),
}),
);
// Application du déchiffrement automatique pour les colonnes PGP
withAutomaticPgpDecrypt(users.email);
withAutomaticPgpDecrypt(users.twoFactorSecret);
export type UserInDb = typeof users.$inferSelect;
export type NewUserInDb = typeof users.$inferInsert;