{
  "slug": "auth",
  "runtimes": {
    "node": {
      "frameworks": {
        "express": {
          "databases": {
            "mysql": {
              "orms": {
                "drizzle": {
                  "templates": {
                    "index": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/drizzle/migrations\",\n  schema: \"./src/drizzle/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\nexport * from \"./schemas/refresh-token.schema\";\nexport * from \"./schemas/otp.schema\";\nexport * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\nimport { sessions } from \"./session.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens),\n  sessions: many(sessions)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = mysqlTable(\n  \"sessions\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 255 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\nexport const sessionsRelations = relations(sessions, ({ one }) => ({\n  user: one(users, {\n    fields: [sessions.userId],\n    references: [users.id]\n  })\n}));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = mysqlTable(\n  \"refresh_tokens\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => {\n  return {\n    user: one(users, {\n      fields: [refreshTokens.userId],\n      references: [users.id]\n    })\n  };\n});\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  mysqlEnum,\n  index\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nconst OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport const otps = mysqlTable(\n  \"otps\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\", {\n      mode: \"date\"\n    }).notNull(),\n    type: mysqlEnum(\"type\", OTP_TYPES).notNull(),\n    expiresAt: timestamp(\"expires_at\", { mode: \"date\" }).notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\", { mode: \"date\" }),\n    attempts: int(\"attempts\").default(0).notNull(),\n    maxAttempts: int(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/drizzle/migrations\",\n  schema: \"./src/drizzle/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\nexport * from \"./schemas/refresh-token.schema\";\nexport * from \"./schemas/otp.schema\";\nexport * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\nimport { sessions } from \"./session.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens),\n  sessions: many(sessions)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  mysqlTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = mysqlTable(\n  \"sessions\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\nexport const sessionsRelations = relations(sessions, ({ one }) => ({\n  user: one(users, {\n    fields: [sessions.userId],\n    references: [users.id]\n  })\n}));\n\n//? Session type\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = mysqlTable(\n  \"refresh_tokens\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => {\n  return {\n    user: one(users, {\n      fields: [refreshTokens.userId],\n      references: [users.id]\n    })\n  };\n});\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  mysqlEnum,\n  index\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nconst OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport const otps = mysqlTable(\n  \"otps\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\", {\n      mode: \"date\"\n    }).notNull(),\n    type: mysqlEnum(\"type\", OTP_TYPES).notNull(),\n    expiresAt: timestamp(\"expires_at\", { mode: \"date\" }).notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\", { mode: \"date\" }),\n    attempts: int(\"attempts\").default(0).notNull(),\n    maxAttempts: int(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "otp": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  mysqlEnum,\n  index\n} from \"drizzle-orm/mysql-core\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\n\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n\nexport const otps = mysqlTable(\n  \"otps\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\").notNull(),\n    type: mysqlEnum(\"type\", OTP_TYPES).notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: int(\"attempts\").default(0).notNull(),\n    maxAttempts: int(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  mysqlEnum,\n  index\n} from \"drizzle-orm/mysql-core\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\n\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n\nexport const otps = mysqlTable(\n  \"otps\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\").notNull(),\n    type: mysqlEnum(\"type\", OTP_TYPES).notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: int(\"attempts\").default(0).notNull(),\n    maxAttempts: int(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "user": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    // OAuth Provider\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    // Profile\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    // Auth Metadata\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    // Soft Delete\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n    updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    // OAuth Provider\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    // Profile\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    // Auth Metadata\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    // Soft Delete\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n    updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "session": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  mysqlTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\n// import { users } from \"./user.schema\";\n\nconst timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n\nexport const sessions = mysqlTable(\n  \"sessions\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    // userId: int(\"user_id\")\n    //   .references(() => users.id, { onDelete: \"cascade\" })\n    //   .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    // index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\n// export const sessionsRelations = relations(sessions, ({ one }) => ({\n//   user: one(users, {\n//     fields: [sessions.userId],\n//     references: [users.id]\n//   })\n// }));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\n\n//? you should have users table\n// import { users } from \"./user.schema\";\n\nconst timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n\nexport const sessions = mysqlTable(\n  \"sessions\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    // userId: int(\"user_id\")\n    //   .references(() => users.id, { onDelete: \"cascade\" })\n    //   .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    // index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n    // index(\"userId_isActive_idx\").on(table.userId, table.isActive),\n    // index(\"userId_lastUsedAt_idx\").on(table.userId, table.lastUsedAt)\n  ]\n);\n\n//? relations between user and session\n// export const sessionsRelations = relations(sessions, ({ one }) => ({\n//   user: one(users, {\n//     fields: [sessions.userId],\n//     references: [users.id]\n//   })\n// }));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "refresh-token": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens, timestamps } from \"./refresh-token.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between user and refresh tokens. One user can have many refresh tokens. (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { users } from \"./user.schema\";\nimport { relations } from \"drizzle-orm\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n\nexport const refreshTokens = mysqlTable(\n  \"refresh_tokens\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\n\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => ({\n  user: one(users, {\n    fields: [refreshTokens.userId],\n    references: [users.id]\n  })\n}));\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens, timestamps } from \"./refresh-token.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between user and refresh tokens. One user can have many refresh tokens. (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n\nexport const refreshTokens = mysqlTable(\n  \"refresh_tokens\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\n\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => ({\n  user: one(users, {\n    fields: [refreshTokens.userId],\n    references: [users.id]\n  })\n}));\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "dependencies": {
                    "runtime": [
                      "mysql2",
                      "drizzle-orm"
                    ],
                    "dev": [
                      "drizzle-kit"
                    ]
                  }
                }
              }
            },
            "postgresql": {
              "orms": {
                "drizzle": {
                  "templates": {
                    "index": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\nexport * from \"./schemas/refresh-token.schema\";\nexport * from \"./schemas/otp.schema\";\nexport * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  json,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\nimport { sessions } from \"./session.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between:\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens),\n  sessions: many(sessions)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = pgTable(\n  \"sessions\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive),\n    index(\"userId_isActive_idx\").on(table.userId, table.isActive),\n    index(\"userId_lastUsedAt_idx\").on(table.userId, table.lastUsedAt)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\nexport const sessionsRelations = relations(sessions, ({ one }) => ({\n  user: one(users, {\n    fields: [sessions.userId],\n    references: [users.id]\n  })\n}));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = pgTable(\n  \"refresh_tokens\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => {\n  return {\n    user: one(users, {\n      fields: [refreshTokens.userId],\n      references: [users.id]\n    })\n  };\n});\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  pgTable,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  pgEnum,\n  index,\n  serial\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nexport const otpTypeEnum = pgEnum(\"otp_type\", [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n]);\n\nexport const otps = pgTable(\n  \"otps\",\n  {\n    id: serial(\"id\").primaryKey(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\").notNull(),\n    type: otpTypeEnum(\"type\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: integer(\"attempts\").default(0).notNull(),\n    maxAttempts: integer(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\nexport * from \"./schemas/refresh-token.schema\";\nexport * from \"./schemas/otp.schema\";\nexport * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  json,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\nimport { sessions } from \"./session.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between:\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens),\n  sessions: many(sessions)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = pgTable(\n  \"sessions\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\nexport const sessionsRelations = relations(sessions, ({ one }) => ({\n  user: one(users, {\n    fields: [sessions.userId],\n    references: [users.id]\n  })\n}));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = pgTable(\n  \"refresh_tokens\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => {\n  return {\n    user: one(users, {\n      fields: [refreshTokens.userId],\n      references: [users.id]\n    })\n  };\n});\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  pgEnum,\n  index\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nexport const otpTypeEnum = pgEnum(\"otp_type\", [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n]);\n\nexport const otps = pgTable(\n  \"otps\",\n  {\n    id: serial(\"id\").primaryKey(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\").notNull(),\n    type: otpTypeEnum(\"type\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: integer(\"attempts\").default(0).notNull(),\n    maxAttempts: integer(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "otp": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  pgEnum,\n  index\n} from \"drizzle-orm/pg-core\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\n\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport const otpTypeEnum = pgEnum(\"otp_type\", OTP_TYPES);\n\nconst timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n\nexport const otps = pgTable(\n  \"otps\",\n  {\n    id: serial(\"id\").primaryKey(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\", {\n      mode: \"string\"\n    }).notNull(),\n    type: otpTypeEnum(\"type\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: integer(\"attempts\").default(0).notNull(),\n    maxAttempts: integer(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/otp.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  pgEnum,\n  index\n} from \"drizzle-orm/pg-core\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\n\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport const otpTypeEnum = pgEnum(\"otp_type\", OTP_TYPES);\n\nconst timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n\nexport const otps = pgTable(\n  \"otps\",\n  {\n    id: serial(\"id\").primaryKey(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\", {\n      mode: \"string\"\n    }).notNull(),\n    type: otpTypeEnum(\"type\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: integer(\"attempts\").default(0).notNull(),\n    maxAttempts: integer(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "user": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  jsonb,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\", { mode: \"string\" }).defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\", { mode: \"string\" })\n    .defaultNow()\n    .$onUpdate(() => new Date().toISOString())\n    .notNull()\n};\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    // OAuth Provider\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    // Profile\n    avatar: jsonb(\"avatar\").$type<IAvatar>(),\n\n    // Auth Metadata\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    // Soft Delete\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    //? Timestamps\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"provider_idx\").on(table.provider, table.providerId),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  jsonb,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\", { mode: \"string\" }).defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\", { mode: \"string\" })\n    .defaultNow()\n    .$onUpdate(() => new Date().toISOString())\n    .notNull()\n};\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    // OAuth Provider\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    // Profile\n    avatar: jsonb(\"avatar\").$type<IAvatar>(),\n\n    // Auth Metadata\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    // Soft Delete\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    //? Timestamps\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"provider_idx\").on(table.provider, table.providerId),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "session": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\n// import { users } from \"./user.schema\";\n\nconst timestamps = {\n  createdAt: timestamp(\"created_at\", { mode: \"string\" }).defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\", { mode: \"string\" })\n    .defaultNow()\n    .$onUpdate(() => new Date().toISOString())\n    .notNull()\n};\n\nexport const sessions = pgTable(\n  \"sessions\",\n  {\n    id: serial(\"id\").primaryKey(),\n    // userId: integer(\"user_id\")\n    //   .references(() => users.id, { onDelete: \"cascade\" })\n    //   .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\", { mode: \"string\" })\n      .defaultNow()\n      .notNull(),\n    expiresAt: timestamp(\"expires_at\", { mode: \"string\" }).notNull(),\n    ...timestamps\n  },\n  table => [\n    // index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\n// export const sessionsRelations = relations(sessions, ({ one }) => ({\n//   user: one(users, {\n//     fields: [sessions.userId],\n//     references: [users.id]\n//   })\n// }));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/session.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\n// import { users } from \"./user.schema\";\n\nconst timestamps = {\n  createdAt: timestamp(\"created_at\", { mode: \"string\" }).defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\", { mode: \"string\" })\n    .defaultNow()\n    .$onUpdate(() => new Date().toISOString())\n    .notNull()\n};\n\nexport const sessions = pgTable(\n  \"sessions\",\n  {\n    id: serial(\"id\").primaryKey(),\n    // userId: integer(\"user_id\")\n    //   .references(() => users.id, { onDelete: \"cascade\" })\n    //   .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\", { mode: \"string\" })\n      .defaultNow()\n      .notNull(),\n    expiresAt: timestamp(\"expires_at\", { mode: \"string\" }).notNull(),\n    ...timestamps\n  },\n  table => [\n    // index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\n// export const sessionsRelations = relations(sessions, ({ one }) => ({\n//   user: one(users, {\n//     fields: [sessions.userId],\n//     references: [users.id]\n//   })\n// }));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "refresh-token": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  json,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./refresh-token.schema\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between user and refresh tokens. One user can have many refresh tokens. (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { users } from \"./user.schema\";\nimport { relations } from \"drizzle-orm\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n\nexport const refreshTokens = pgTable(\n  \"refresh_tokens\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\n\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => ({\n  user: one(users, {\n    fields: [refreshTokens.userId],\n    references: [users.id]\n  })\n}));\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  json,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./refresh-token.schema\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? One user can have many refresh tokens. (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/drizzle/schemas/refresh-token.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n\nexport const refreshTokens = pgTable(\n  \"refresh_tokens\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\n\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => ({\n  user: one(users, {\n    fields: [refreshTokens.userId],\n    references: [users.id]\n  })\n}));\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "dependencies": {
                    "runtime": [
                      "pg",
                      "drizzle-orm"
                    ],
                    "dev": [
                      "@types/pg",
                      "drizzle-kit"
                    ]
                  }
                }
              }
            },
            "mongodb": {
              "orms": {
                "mongoose": {
                  "templates": {
                    "index": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date | null;\n  reActivateAvailableAt?: Date | null;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date,\n      default: null\n    },\n    reActivateAvailableAt: {\n      type: Date,\n      default: null\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/session.model.ts",
                              "content": "import mongoose, { Document, Schema, Model } from \"mongoose\";\n\nexport interface ISession extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  ip?: string;\n  userAgent?: string;\n  isActive: boolean;\n  lastUsedAt: Date;\n  expiresAt: Date;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst SESSION_EXPIRES_IN = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nconst sessionSchema: Schema<ISession> = new Schema(\n  {\n    userId: {\n      type: mongoose.Schema.Types.ObjectId,\n      ref: \"User\",\n      required: true,\n      index: true\n    },\n    tokenHash: {\n      type: String,\n      required: true,\n      unique: true,\n      index: true\n    },\n    ip: { type: String },\n    userAgent: { type: String },\n    isActive: {\n      type: Boolean,\n      default: true,\n      index: true\n    },\n    lastUsedAt: {\n      type: Date,\n      default: Date.now\n    },\n    expiresAt: {\n      type: Date,\n      required: true\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Supporting indexes\nsessionSchema.index({ userId: 1, isActive: 1 });\nsessionSchema.index({ userId: 1, lastUsedAt: -1 });\nsessionSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: SESSION_EXPIRES_IN / 1000 } // 7 days\n); // ttl index\n\nconst Session: Model<ISession> =\n  mongoose.models.Session || mongoose.model<ISession>(\"Session\", sessionSchema);\n\nexport default Session;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/refresh-token.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRefreshToken extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  expiresAt: Date;\n  isRevoked: boolean;\n  revokedAt?: Date;\n  replacedByTokenHash?: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst refreshTokenSchema = new Schema<IRefreshToken>(\n  {\n    userId: {\n      type: Schema.Types.ObjectId,\n      ref: \"User\",\n      required: [true, \"User ID is required\"]\n    },\n    tokenHash: {\n      type: String,\n      required: [true, \"Token hash is required\"],\n      select: false // Secure by default\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isRevoked: {\n      type: Boolean,\n      default: false\n    },\n    revokedAt: {\n      type: Date\n    },\n    replacedByTokenHash: {\n      type: String,\n      select: false\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\nrefreshTokenSchema.index({ userId: 1 });\nrefreshTokenSchema.index({ tokenHash: 1 });\nrefreshTokenSchema.index({ isRevoked: 1 });\nrefreshTokenSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: REFRESH_TOKEN_EXPIRY / 1000 } // 7 days\n);\n\nconst RefreshToken: Model<IRefreshToken> =\n  mongoose.models.RefreshToken ||\n  mongoose.model<IRefreshToken>(\"RefreshToken\", refreshTokenSchema);\n\nexport default RefreshToken;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/otp.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\nexport const NEXT_OTP_DELAY = 1 * 60 * 1000; // 1 minute\nexport const OTP_CODE_LENGTH = 6 as const;\nexport const OTP_EXPIRES_IN = 5 * 60 * 1000; // 5 minutes\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\n//? otp interface\nexport interface IOtp extends Document {\n  _id: mongoose.Types.ObjectId;\n  email: string;\n  otpHashCode: string;\n  nextResendAllowedAt: Date;\n  type: OTPType;\n  expiresAt: Date;\n  isUsed: boolean;\n  usedAt?: Date;\n  attempts: number;\n  maxAttempts: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\n//? otp schema\nconst otpSchema = new Schema<IOtp>(\n  {\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      lowercase: true,\n      trim: true\n    },\n    otpHashCode: {\n      type: String,\n      required: [true, \"OTP hash code is required\"],\n      select: false // Never return OTP hash code in queries by default\n    },\n    nextResendAllowedAt: {\n      type: Date,\n      required: [true, \"Next resend allowed at is required\"]\n    },\n    type: {\n      type: String,\n      enum: OTP_TYPES,\n      required: [true, \"OTP type is required\"]\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isUsed: {\n      type: Boolean,\n      default: false\n    },\n    usedAt: {\n      type: Date\n    },\n    attempts: {\n      type: Number,\n      default: 0\n    },\n    maxAttempts: {\n      type: Number,\n      default: OTP_MAX_ATTEMPTS // Prevent brute force attacks\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\notpSchema.index({ email: 1, type: 1 }); // Quick lookup by email and type\notpSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: OTP_EXPIRES_IN / 1000 } // 5 minutes\n); // ttl index\n\nconst Otp: Model<IOtp> =\n  mongoose.models.Otp || mongoose.model<IOtp>(\"Otp\", otpSchema);\n\nexport default Otp;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/modules/auth/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date | null;\n  reActivateAvailableAt?: Date | null;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date,\n      default: null\n    },\n    reActivateAvailableAt: {\n      type: Date,\n      default: null\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/modules/auth/session.model.ts",
                              "content": "import mongoose, { Document, Schema, Model } from \"mongoose\";\n\nexport interface ISession extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  ip?: string;\n  userAgent?: string;\n  isActive: boolean;\n  lastUsedAt: Date;\n  expiresAt: Date;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst SESSION_EXPIRES_IN = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nconst sessionSchema: Schema<ISession> = new Schema(\n  {\n    userId: {\n      type: mongoose.Schema.Types.ObjectId,\n      ref: \"User\",\n      required: true,\n      index: true\n    },\n    tokenHash: {\n      type: String,\n      required: true,\n      unique: true,\n      index: true\n    },\n    ip: { type: String },\n    userAgent: { type: String },\n    isActive: {\n      type: Boolean,\n      default: true,\n      index: true\n    },\n    lastUsedAt: {\n      type: Date,\n      default: Date.now\n    },\n    expiresAt: {\n      type: Date,\n      required: true\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Supporting indexes\nsessionSchema.index({ userId: 1, isActive: 1 });\nsessionSchema.index({ userId: 1, lastUsedAt: -1 });\nsessionSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: SESSION_EXPIRES_IN / 1000 } // 7 days\n); // ttl index\n\nconst Session: Model<ISession> =\n  mongoose.models.Session || mongoose.model<ISession>(\"Session\", sessionSchema);\n\nexport default Session;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/modules/auth/refresh-token.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRefreshToken extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  expiresAt: Date;\n  isRevoked: boolean;\n  revokedAt?: Date;\n  replacedByTokenHash?: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst refreshTokenSchema = new Schema<IRefreshToken>(\n  {\n    userId: {\n      type: Schema.Types.ObjectId,\n      ref: \"User\",\n      required: [true, \"User ID is required\"]\n    },\n    tokenHash: {\n      type: String,\n      required: [true, \"Token hash is required\"],\n      select: false // Secure by default\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isRevoked: {\n      type: Boolean,\n      default: false\n    },\n    revokedAt: {\n      type: Date\n    },\n    replacedByTokenHash: {\n      type: String,\n      select: false\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\nrefreshTokenSchema.index({ userId: 1 });\nrefreshTokenSchema.index({ tokenHash: 1 });\nrefreshTokenSchema.index({ isRevoked: 1 });\nrefreshTokenSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: REFRESH_TOKEN_EXPIRY / 1000 } // 7 days\n);\n\nconst RefreshToken: Model<IRefreshToken> =\n  mongoose.models.RefreshToken ||\n  mongoose.model<IRefreshToken>(\"RefreshToken\", refreshTokenSchema);\n\nexport default RefreshToken;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/modules/auth/otp.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\nexport const NEXT_OTP_DELAY = 1 * 60 * 1000; // 1 minute\nexport const OTP_CODE_LENGTH = 6 as const;\nexport const OTP_EXPIRES_IN = 5 * 60 * 1000; // 5 minutes\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\n//? otp interface\nexport interface IOtp extends Document {\n  _id: mongoose.Types.ObjectId;\n  email: string;\n  otpHashCode: string;\n  nextResendAllowedAt: Date;\n  type: OTPType;\n  expiresAt: Date;\n  isUsed: boolean;\n  usedAt?: Date;\n  attempts: number;\n  maxAttempts: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\n//? otp schema\nconst otpSchema = new Schema<IOtp>(\n  {\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      lowercase: true,\n      trim: true\n    },\n    otpHashCode: {\n      type: String,\n      required: [true, \"OTP hash code is required\"],\n      select: false // Never return OTP hash code in queries by default\n    },\n    nextResendAllowedAt: {\n      type: Date,\n      required: [true, \"Next resend allowed at is required\"]\n    },\n    type: {\n      type: String,\n      enum: OTP_TYPES,\n      required: [true, \"OTP type is required\"]\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isUsed: {\n      type: Boolean,\n      default: false\n    },\n    usedAt: {\n      type: Date\n    },\n    attempts: {\n      type: Number,\n      default: 0\n    },\n    maxAttempts: {\n      type: Number,\n      default: OTP_MAX_ATTEMPTS // Prevent brute force attacks\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\notpSchema.index({ email: 1, type: 1 }); // Quick lookup by email and type\notpSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: OTP_EXPIRES_IN / 1000 } // 5 minutes\n); // ttl index\n\nconst Otp: Model<IOtp> =\n  mongoose.models.Otp || mongoose.model<IOtp>(\"Otp\", otpSchema);\n\nexport default Otp;\n"
                            }
                          ]
                        }
                      }
                    },
                    "otp": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/otp.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\n\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\n//? otp interface\nexport interface IOtp extends Document {\n  _id: mongoose.Types.ObjectId;\n  email: string;\n  otpHashCode: string;\n  contextToken: string;\n  nextResendAllowedAt: Date;\n  type: OTPType;\n  expiresAt: Date;\n  isUsed: boolean;\n  usedAt?: Date;\n  attempts: number;\n  maxAttempts: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\n//? otp schema\nconst otpSchema = new Schema<IOtp>(\n  {\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      lowercase: true,\n      trim: true\n    },\n    otpHashCode: {\n      type: String,\n      required: [true, \"OTP hash code is required\"],\n      select: false // Never return OTP hash code in queries by default\n    },\n    contextToken: {\n      type: String,\n      required: [true, \"Context token is required\"]\n    },\n    nextResendAllowedAt: {\n      type: Date,\n      required: [true, \"Next resend allowed at is required\"]\n    },\n    type: {\n      type: String,\n      enum: OTP_TYPES,\n      required: [true, \"OTP type is required\"]\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"],\n      index: { expires: 0 } // TTL index - MongoDB auto-deletes expired docs\n    },\n    isUsed: {\n      type: Boolean,\n      default: false\n    },\n    usedAt: {\n      type: Date\n    },\n    attempts: {\n      type: Number,\n      default: 0\n    },\n    maxAttempts: {\n      type: Number,\n      default: OTP_MAX_ATTEMPTS // Prevent brute force attacks\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\notpSchema.index({ email: 1, type: 1 }); // Quick lookup by email and type\notpSchema.index({ expiresAt: 1 }); // TTL index for auto-cleanup\notpSchema.index({ isUsed: 1 }); // Filter used vs unused OTPs\n\nconst Otp: Model<IOtp> =\n  mongoose.models.Otp || mongoose.model<IOtp>(\"Otp\", otpSchema);\n\nexport default Otp;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/modules/otp/otp.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\n\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\n//? otp interface\nexport interface IOtp extends Document {\n  _id: mongoose.Types.ObjectId;\n  email: string;\n  otpHashCode: string;\n  contextToken: string;\n  nextResendAllowedAt: Date;\n  type: OTPType;\n  expiresAt: Date;\n  isUsed: boolean;\n  usedAt?: Date;\n  attempts: number;\n  maxAttempts: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\n//? otp schema\nconst otpSchema = new Schema<IOtp>(\n  {\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      lowercase: true,\n      trim: true\n    },\n    otpHashCode: {\n      type: String,\n      required: [true, \"OTP hash code is required\"],\n      select: false // Never return OTP hash code in queries by default\n    },\n    contextToken: {\n      type: String,\n      required: [true, \"Context token is required\"]\n    },\n    nextResendAllowedAt: {\n      type: Date,\n      required: [true, \"Next resend allowed at is required\"]\n    },\n    type: {\n      type: String,\n      enum: OTP_TYPES,\n      required: [true, \"OTP type is required\"]\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"],\n      index: { expires: 0 } // TTL index - MongoDB auto-deletes expired docs\n    },\n    isUsed: {\n      type: Boolean,\n      default: false\n    },\n    usedAt: {\n      type: Date\n    },\n    attempts: {\n      type: Number,\n      default: 0\n    },\n    maxAttempts: {\n      type: Number,\n      default: OTP_MAX_ATTEMPTS // Prevent brute force attacks\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\notpSchema.index({ email: 1, type: 1 }); // Quick lookup by email and type\notpSchema.index({ expiresAt: 1 }); // TTL index for auto-cleanup\notpSchema.index({ isUsed: 1 }); // Filter used vs unused OTPs\n\nconst Otp: Model<IOtp> =\n  mongoose.models.Otp || mongoose.model<IOtp>(\"Otp\", otpSchema);\n\nexport default Otp;\n"
                            }
                          ]
                        }
                      }
                    },
                    "user": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date;\n  reActivateAvailableAt?: Date;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date\n    },\n    reActivateAvailableAt: {\n      type: Date\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/modules/user/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date;\n  reActivateAvailableAt?: Date;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date\n    },\n    reActivateAvailableAt: {\n      type: Date\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            }
                          ]
                        }
                      }
                    },
                    "session": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date;\n  reActivateAvailableAt?: Date;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date\n    },\n    reActivateAvailableAt: {\n      type: Date\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/session.model.ts",
                              "content": "import mongoose, { Document, Schema, Model } from \"mongoose\";\n\nexport interface ISession extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  ip?: string;\n  userAgent?: string;\n  isActive: boolean;\n  lastUsedAt: Date;\n  expiresAt: Date;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst SESSION_EXPIRES_IN = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nconst sessionSchema: Schema<ISession> = new Schema(\n  {\n    userId: {\n      type: mongoose.Schema.Types.ObjectId,\n      ref: \"User\",\n      required: true,\n      index: true\n    },\n    tokenHash: {\n      type: String,\n      required: true,\n      unique: true,\n      index: true\n    },\n    ip: { type: String },\n    userAgent: { type: String },\n    isActive: {\n      type: Boolean,\n      default: true,\n      index: true\n    },\n    lastUsedAt: {\n      type: Date,\n      default: Date.now\n    },\n    expiresAt: {\n      type: Date,\n      required: true\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Supporting indexes (non-TTL)\nsessionSchema.index({ userId: 1, isActive: 1 });\nsessionSchema.index({ userId: 1, lastUsedAt: -1 });\nsessionSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: SESSION_EXPIRES_IN / 1000 } // 7 days\n); // ttl index\n\nconst Session: Model<ISession> =\n  mongoose.models.Session || mongoose.model<ISession>(\"Session\", sessionSchema);\n\nexport default Session;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/modules/user/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date;\n  reActivateAvailableAt?: Date;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date\n    },\n    reActivateAvailableAt: {\n      type: Date\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/modules/auth/session.model.ts",
                              "content": "import mongoose, { Document, Schema, Model } from \"mongoose\";\n\nexport interface ISession extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  ip?: string;\n  userAgent?: string;\n  isActive: boolean;\n  lastUsedAt: Date;\n  expiresAt: Date;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst sessionSchema: Schema<ISession> = new Schema(\n  {\n    userId: {\n      type: mongoose.Schema.Types.ObjectId,\n      ref: \"User\",\n      required: true,\n      index: true\n    },\n    tokenHash: {\n      type: String,\n      required: true,\n      unique: true,\n      index: true\n    },\n    ip: { type: String },\n    userAgent: { type: String },\n    isActive: {\n      type: Boolean,\n      default: true,\n      index: true\n    },\n    lastUsedAt: {\n      type: Date,\n      default: Date.now\n    },\n    expiresAt: {\n      type: Date,\n      required: true,\n      index: { expires: 0 } // TTL fires exactly at expiresAt\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Supporting indexes (non-TTL)\nsessionSchema.index({ userId: 1, isActive: 1 });\nsessionSchema.index({ userId: 1, lastUsedAt: -1 });\n\nconst Session: Model<ISession> =\n  mongoose.models.Session || mongoose.model<ISession>(\"Session\", sessionSchema);\n\nexport default Session;\n"
                            }
                          ]
                        }
                      }
                    },
                    "refresh-token": {
                      "architectures": {
                        "mvc": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/refresh-token.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRefreshToken extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  expiresAt: Date;\n  isRevoked: boolean;\n  revokedAt?: Date;\n  replacedByTokenHash?: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst refreshTokenSchema = new Schema<IRefreshToken>(\n  {\n    userId: {\n      type: Schema.Types.ObjectId,\n      ref: \"User\",\n      required: [true, \"User ID is required\"]\n    },\n    tokenHash: {\n      type: String,\n      required: [true, \"Token hash is required\"],\n      select: false // Secure by default\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isRevoked: {\n      type: Boolean,\n      default: false\n    },\n    revokedAt: {\n      type: Date\n    },\n    replacedByTokenHash: {\n      type: String,\n      select: false\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\nrefreshTokenSchema.index({ userId: 1 });\nrefreshTokenSchema.index({ tokenHash: 1 });\nrefreshTokenSchema.index({ isRevoked: 1 });\nrefreshTokenSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: REFRESH_TOKEN_EXPIRY / 1000 } // 7 days\n);\n\nconst RefreshToken: Model<IRefreshToken> =\n  mongoose.models.RefreshToken ||\n  mongoose.model<IRefreshToken>(\"RefreshToken\", refreshTokenSchema);\n\nexport default RefreshToken;\n"
                            }
                          ]
                        },
                        "feature": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/modules/otp/refresh-token.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRefreshToken extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  expiresAt: Date;\n  isRevoked: boolean;\n  revokedAt?: Date;\n  replacedByTokenHash?: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst refreshTokenSchema = new Schema<IRefreshToken>(\n  {\n    userId: {\n      type: Schema.Types.ObjectId,\n      ref: \"User\",\n      required: [true, \"User ID is required\"]\n    },\n    tokenHash: {\n      type: String,\n      required: [true, \"Token hash is required\"],\n      select: false // Secure by default\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isRevoked: {\n      type: Boolean,\n      default: false\n    },\n    revokedAt: {\n      type: Date\n    },\n    replacedByTokenHash: {\n      type: String,\n      select: false\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\nrefreshTokenSchema.index({ userId: 1 });\nrefreshTokenSchema.index({ tokenHash: 1 });\nrefreshTokenSchema.index({ isRevoked: 1 });\nrefreshTokenSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: REFRESH_TOKEN_EXPIRY / 1000 } // 7 days\n);\n\nconst RefreshToken: Model<IRefreshToken> =\n  mongoose.models.RefreshToken ||\n  mongoose.model<IRefreshToken>(\"RefreshToken\", refreshTokenSchema);\n\nexport default RefreshToken;\n"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "dependencies": {
                    "runtime": [
                      "mongoose"
                    ],
                    "dev": []
                  }
                }
              }
            }
          }
        },
        "nextjs": {
          "databases": {
            "mysql": {
              "orms": {
                "drizzle": {
                  "templates": {
                    "index": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\nexport * from \"./schemas/refresh-token.schema\";\nexport * from \"./schemas/otp.schema\";\nexport * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\nimport { sessions } from \"./session.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens),\n  sessions: many(sessions)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/session.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = mysqlTable(\n  \"sessions\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 255 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\nexport const sessionsRelations = relations(sessions, ({ one }) => ({\n  user: one(users, {\n    fields: [sessions.userId],\n    references: [users.id]\n  })\n}));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/refresh-token.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = mysqlTable(\n  \"refresh_tokens\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => {\n  return {\n    user: one(users, {\n      fields: [refreshTokens.userId],\n      references: [users.id]\n    })\n  };\n});\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/otp.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  mysqlEnum,\n  index\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nconst OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport const otps = mysqlTable(\n  \"otps\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\", {\n      mode: \"date\"\n    }).notNull(),\n    type: mysqlEnum(\"type\", OTP_TYPES).notNull(),\n    expiresAt: timestamp(\"expires_at\", { mode: \"date\" }).notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\", { mode: \"date\" }),\n    attempts: int(\"attempts\").default(0).notNull(),\n    maxAttempts: int(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "otp": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/otp.schema\";"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/otp.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  mysqlEnum,\n  index\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nconst OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\n\nexport const otps = mysqlTable(\n  \"otps\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\", {\n      mode: \"date\"\n    }).notNull(),\n    type: mysqlEnum(\"type\", OTP_TYPES).notNull(),\n    expiresAt: timestamp(\"expires_at\", { mode: \"date\" }).notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\", { mode: \"date\" }),\n    attempts: int(\"attempts\").default(0).notNull(),\n    maxAttempts: int(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "user": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/user.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  int,\n  json,\n  uniqueIndex,\n  index,\n  mysqlEnum\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const users = mysqlTable(\n  \"users\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: mysqlEnum(\"role\", [\"user\", \"admin\"]).default(\"user\").notNull(),\n\n    provider: mysqlEnum(\"provider\", [\"local\", \"google\", \"github\"])\n      .default(\"local\")\n      .notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: int(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            }
                          ]
                        }
                      }
                    },
                    "session": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/session.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = mysqlTable(\n  \"sessions\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      // .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 255 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  (table) => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive)\n  ]\n);\n\n//TODO: Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            }
                          ]
                        }
                      }
                    },
                    "refresh-token": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"mysql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/refresh-token.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/mysql-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\").defaultNow().onUpdateNow().notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/refresh-token.schema.ts",
                              "content": "import {\n  mysqlTable,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  int\n} from \"drizzle-orm/mysql-core\";\nimport { relations } from \"drizzle-orm\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = mysqlTable(\n  \"refresh_tokens\",\n  {\n    id: int(\"id\").primaryKey().autoincrement(),\n    userId: int(\"user_id\")\n      // .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  (table) => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//TODO: Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\n\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "dependencies": {
                    "runtime": [
                      "mysql2",
                      "drizzle-orm"
                    ],
                    "dev": [
                      "drizzle-kit"
                    ]
                  }
                }
              }
            },
            "postgresql": {
              "orms": {
                "drizzle": {
                  "templates": {
                    "index": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"postgresql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/user.schema\";\nexport * from \"./schemas/refresh-token.schema\";\nexport * from \"./schemas/otp.schema\";\nexport * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  json,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\nimport { refreshTokens } from \"./refresh-token.schema\";\nimport { sessions } from \"./session.schema\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//? Relations between:\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\nexport const usersRelations = relations(users, ({ many }) => ({\n  refreshTokens: many(refreshTokens),\n  sessions: many(sessions)\n}));\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/session.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = pgTable(\n  \"sessions\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive),\n    index(\"userId_isActive_idx\").on(table.userId, table.isActive),\n    index(\"userId_lastUsedAt_idx\").on(table.userId, table.lastUsedAt)\n  ]\n);\n\n//? Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\nexport const sessionsRelations = relations(sessions, ({ one }) => ({\n  user: one(users, {\n    fields: [sessions.userId],\n    references: [users.id]\n  })\n}));\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/refresh-token.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { relations } from \"drizzle-orm\";\nimport { users } from \"./user.schema\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = pgTable(\n  \"refresh_tokens\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//? Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\nexport const refreshTokensRelations = relations(refreshTokens, ({ one }) => {\n  return {\n    user: one(users, {\n      fields: [refreshTokens.userId],\n      references: [users.id]\n    })\n  };\n});\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/otp.schema.ts",
                              "content": "import {\n  pgTable,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  pgEnum,\n  index,\n  serial\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nexport const otpTypeEnum = pgEnum(\"otp_type\", [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n]);\n\nexport const otps = pgTable(\n  \"otps\",\n  {\n    id: serial(\"id\").primaryKey(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\").notNull(),\n    type: otpTypeEnum(\"type\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: integer(\"attempts\").default(0).notNull(),\n    maxAttempts: integer(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "otp": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"postgresql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/otp.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/otp.schema.ts",
                              "content": "import {\n  pgTable,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  pgEnum,\n  index,\n  serial\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\n\nconst OTP_MAX_ATTEMPTS = 5;\n\nexport const otpTypeEnum = pgEnum(\"otp_type\", [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n]);\n\nexport const otps = pgTable(\n  \"otps\",\n  {\n    id: serial(\"id\").primaryKey(),\n    email: varchar(\"email\", { length: 255 }).notNull(),\n    otpHashCode: varchar(\"otp_hash_code\", { length: 255 }).notNull(),\n    nextResendAllowedAt: timestamp(\"next_resend_allowed_at\").notNull(),\n    type: otpTypeEnum(\"type\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isUsed: boolean(\"is_used\").default(false).notNull(),\n    usedAt: timestamp(\"used_at\"),\n    attempts: integer(\"attempts\").default(0).notNull(),\n    maxAttempts: integer(\"max_attempts\").default(OTP_MAX_ATTEMPTS).notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"email_type_idx\").on(table.email, table.type),\n    index(\"expires_at_idx\").on(table.expiresAt),\n    index(\"is_used_idx\").on(table.isUsed)\n  ]\n);\n\nexport type Otp = typeof otps.$inferSelect;\nexport type NewOtp = typeof otps.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    },
                    "user": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"postgresql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/user.schema\";"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/user.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  integer,\n  json,\n  uniqueIndex,\n  index,\n  pgEnum\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\nimport { relations } from \"drizzle-orm\";\n\nexport interface IAvatar {\n  public_id?: string;\n  url: string;\n  size?: number;\n}\n\nexport const roleEnum = pgEnum(\"role\", [\"user\", \"admin\"]);\nexport const providerEnum = pgEnum(\"provider\", [\"local\", \"google\", \"github\"]);\n\nexport const users = pgTable(\n  \"users\",\n  {\n    id: serial(\"id\").primaryKey(),\n    name: varchar(\"name\", { length: 100 }).notNull(),\n    email: varchar(\"email\", { length: 255 }).notNull().unique(),\n    password: varchar(\"password\", { length: 255 }),\n    role: roleEnum(\"role\").default(\"user\").notNull(),\n\n    provider: providerEnum(\"provider\").default(\"local\").notNull(),\n    providerId: varchar(\"provider_id\", { length: 255 }),\n\n    avatar: json(\"avatar\").$type<IAvatar>(),\n\n    isEmailVerified: boolean(\"is_email_verified\").default(false).notNull(),\n    lastLoginAt: timestamp(\"last_login_at\"),\n    failedLoginAttempts: integer(\"failed_login_attempts\").default(0).notNull(),\n    lockUntil: timestamp(\"lock_until\"),\n\n    isDeleted: boolean(\"is_deleted\").default(false).notNull(),\n    deletedAt: timestamp(\"deleted_at\"),\n    reActivateAvailableAt: timestamp(\"re_activate_available_at\"),\n\n    ...timestamps\n  },\n  table => [\n    uniqueIndex(\"email_idx\").on(table.email),\n    index(\"role_idx\").on(table.role),\n    index(\"is_deleted_idx\").on(table.isDeleted)\n  ]\n);\n\n//TODO: Relations between:\n//? i. user and refresh tokens.\n//? ii. user and sessions.\n//? (One-to-Many)\n\n//? User type\nexport type User = typeof users.$inferSelect;\nexport type NewUser = typeof users.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            }
                          ]
                        }
                      }
                    },
                    "session": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"postgresql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/session.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/session.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  timestamp,\n  boolean,\n  index,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const sessions = pgTable(\n  \"sessions\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      // .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: varchar(\"token_hash\", { length: 255 }).notNull().unique(),\n    ip: varchar(\"ip\", { length: 45 }),\n    userAgent: varchar(\"user_agent\", { length: 512 }),\n    isActive: boolean(\"is_active\").default(true).notNull(),\n    lastUsedAt: timestamp(\"last_used_at\").defaultNow().notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    ...timestamps\n  },\n  table => [\n    index(\"userId_idx\").on(table.userId),\n    index(\"tokenHash_idx\").on(table.tokenHash),\n    index(\"isActive_idx\").on(table.isActive),\n    index(\"userId_isActive_idx\").on(table.userId, table.isActive),\n    index(\"userId_lastUsedAt_idx\").on(table.userId, table.lastUsedAt)\n  ]\n);\n\n//TODO: Relations between session and users.\n//? Many sessions can be associated with one user.\n//? (Many-to-One)\n\n\nexport type Session = typeof sessions.$inferSelect;\nexport type NewSession = typeof sessions.$inferInsert;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            }
                          ]
                        }
                      }
                    },
                    "refresh-token": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "drizzle.config.ts",
                              "content": "import { Config, defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n  out: \"./src/db/migrations\",\n  schema: \"./src/db/index.ts\",\n  dialect: \"postgresql\",\n  dbCredentials: {\n    url: process.env.DATABASE_URL!\n  },\n  verbose: true,\n  strict: true\n}) satisfies Config;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/index.ts",
                              "content": "export * from \"./schemas/refresh-token.schema\";\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/schema.helper.ts",
                              "content": "import { timestamp } from \"drizzle-orm/pg-core\";\n\nexport const timestamps = {\n  createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n  updatedAt: timestamp(\"updated_at\")\n    .defaultNow()\n    .$onUpdate(() => new Date())\n    .notNull()\n};\n"
                            },
                            {
                              "type": "file",
                              "path": "src/db/schemas/refresh-token.schema.ts",
                              "content": "import {\n  pgTable,\n  serial,\n  varchar,\n  boolean,\n  timestamp,\n  index,\n  text,\n  integer\n} from \"drizzle-orm/pg-core\";\nimport { timestamps } from \"./schema.helper\";\n\nexport const refreshTokens = pgTable(\n  \"refresh_tokens\",\n  {\n    id: serial(\"id\").primaryKey(),\n    userId: integer(\"user_id\")\n      // .references(() => users.id, { onDelete: \"cascade\" })\n      .notNull(),\n    tokenHash: text(\"token_hash\").notNull(),\n    expiresAt: timestamp(\"expires_at\").notNull(),\n    isRevoked: boolean(\"is_revoked\").default(false).notNull(),\n    revokedAt: timestamp(\"revoked_at\"),\n    replacedByTokenHash: varchar(\"replaced_by_token_hash\", { length: 255 }),\n    ...timestamps\n  },\n  table => [\n    index(\"user_id_idx\").on(table.userId),\n    index(\"token_hash_idx\").on(table.tokenHash),\n    index(\"is_revoked_idx\").on(table.isRevoked),\n    index(\"expires_at_idx\").on(table.expiresAt)\n  ]\n);\n\n//TODO: Relations between user and refresh tokens.\n//? Many refresh tokens can be associated with one user.\n//? (Many-to-One)\n\n\n//? Refresh Token type\nexport type RefreshToken = typeof refreshTokens.$inferSelect;\nexport type NewRefreshToken = typeof refreshTokens.$inferInsert;\n"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "dependencies": {
                    "runtime": [
                      "pg",
                      "drizzle-orm"
                    ],
                    "dev": [
                      "@types/pg",
                      "drizzle-kit"
                    ]
                  }
                }
              }
            },
            "mongodb": {
              "orms": {
                "mongoose": {
                  "templates": {
                    "index": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date | null;\n  reActivateAvailableAt?: Date | null;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date,\n      default: null\n    },\n    reActivateAvailableAt: {\n      type: Date,\n      default: null\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/session.model.ts",
                              "content": "import mongoose, { Document, Schema, Model } from \"mongoose\";\n\nexport interface ISession extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  ip?: string;\n  userAgent?: string;\n  isActive: boolean;\n  lastUsedAt: Date;\n  expiresAt: Date;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst SESSION_EXPIRES_IN = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nconst sessionSchema: Schema<ISession> = new Schema(\n  {\n    userId: {\n      type: mongoose.Schema.Types.ObjectId,\n      ref: \"User\",\n      required: true,\n      index: true\n    },\n    tokenHash: {\n      type: String,\n      required: true,\n      unique: true,\n      index: true\n    },\n    ip: { type: String },\n    userAgent: { type: String },\n    isActive: {\n      type: Boolean,\n      default: true,\n      index: true\n    },\n    lastUsedAt: {\n      type: Date,\n      default: Date.now\n    },\n    expiresAt: {\n      type: Date,\n      required: true\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Supporting indexes\nsessionSchema.index({ userId: 1, isActive: 1 });\nsessionSchema.index({ userId: 1, lastUsedAt: -1 });\nsessionSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: SESSION_EXPIRES_IN / 1000 } // 7 days\n); // ttl index\n\nconst Session: Model<ISession> =\n  mongoose.models.Session || mongoose.model<ISession>(\"Session\", sessionSchema);\n\nexport default Session;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/refresh-token.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRefreshToken extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  expiresAt: Date;\n  isRevoked: boolean;\n  revokedAt?: Date;\n  replacedByTokenHash?: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst refreshTokenSchema = new Schema<IRefreshToken>(\n  {\n    userId: {\n      type: Schema.Types.ObjectId,\n      ref: \"User\",\n      required: [true, \"User ID is required\"]\n    },\n    tokenHash: {\n      type: String,\n      required: [true, \"Token hash is required\"],\n      select: false // Secure by default\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isRevoked: {\n      type: Boolean,\n      default: false\n    },\n    revokedAt: {\n      type: Date\n    },\n    replacedByTokenHash: {\n      type: String,\n      select: false\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\nrefreshTokenSchema.index({ userId: 1 });\nrefreshTokenSchema.index({ tokenHash: 1 });\nrefreshTokenSchema.index({ isRevoked: 1 });\nrefreshTokenSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: REFRESH_TOKEN_EXPIRY / 1000 } // 7 days\n);\n\nconst RefreshToken: Model<IRefreshToken> =\n  mongoose.models.RefreshToken ||\n  mongoose.model<IRefreshToken>(\"RefreshToken\", refreshTokenSchema);\n\nexport default RefreshToken;\n"
                            },
                            {
                              "type": "file",
                              "path": "src/models/otp.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\nexport const NEXT_OTP_DELAY = 1 * 60 * 1000; // 1 minute\nexport const OTP_CODE_LENGTH = 6 as const;\nexport const OTP_EXPIRES_IN = 5 * 60 * 1000; // 5 minutes\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\n//? otp interface\nexport interface IOtp extends Document {\n  _id: mongoose.Types.ObjectId;\n  email: string;\n  otpHashCode: string;\n  nextResendAllowedAt: Date;\n  type: OTPType;\n  expiresAt: Date;\n  isUsed: boolean;\n  usedAt?: Date;\n  attempts: number;\n  maxAttempts: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\n//? otp schema\nconst otpSchema = new Schema<IOtp>(\n  {\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      lowercase: true,\n      trim: true\n    },\n    otpHashCode: {\n      type: String,\n      required: [true, \"OTP hash code is required\"],\n      select: false // Never return OTP hash code in queries by default\n    },\n    nextResendAllowedAt: {\n      type: Date,\n      required: [true, \"Next resend allowed at is required\"]\n    },\n    type: {\n      type: String,\n      enum: OTP_TYPES,\n      required: [true, \"OTP type is required\"]\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isUsed: {\n      type: Boolean,\n      default: false\n    },\n    usedAt: {\n      type: Date\n    },\n    attempts: {\n      type: Number,\n      default: 0\n    },\n    maxAttempts: {\n      type: Number,\n      default: OTP_MAX_ATTEMPTS // Prevent brute force attacks\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\notpSchema.index({ email: 1, type: 1 }); // Quick lookup by email and type\notpSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: OTP_EXPIRES_IN / 1000 } // 5 minutes\n); // ttl index\n\nconst Otp: Model<IOtp> =\n  mongoose.models.Otp || mongoose.model<IOtp>(\"Otp\", otpSchema);\n\nexport default Otp;\n"
                            }
                          ]
                        }
                      }
                    },
                    "otp": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/otp.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const OTP_MAX_ATTEMPTS = 5;\nexport const OTP_TYPES = [\n  \"signin\",\n  \"email-verification\",\n  \"password-reset\",\n  \"password-change\"\n] as const;\nexport const NEXT_OTP_DELAY = 1 * 60 * 1000; // 1 minute\nexport const OTP_CODE_LENGTH = 6 as const;\nexport const OTP_EXPIRES_IN = 5 * 60 * 1000; // 5 minutes\n\nexport type OTPType = (typeof OTP_TYPES)[number];\n\n//? otp interface\nexport interface IOtp extends Document {\n  _id: mongoose.Types.ObjectId;\n  email: string;\n  otpHashCode: string;\n  nextResendAllowedAt: Date;\n  type: OTPType;\n  expiresAt: Date;\n  isUsed: boolean;\n  usedAt?: Date;\n  attempts: number;\n  maxAttempts: number;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\n//? otp schema\nconst otpSchema = new Schema<IOtp>(\n  {\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      lowercase: true,\n      trim: true\n    },\n    otpHashCode: {\n      type: String,\n      required: [true, \"OTP hash code is required\"],\n      select: false // Never return OTP hash code in queries by default\n    },\n    nextResendAllowedAt: {\n      type: Date,\n      required: [true, \"Next resend allowed at is required\"]\n    },\n    type: {\n      type: String,\n      enum: OTP_TYPES,\n      required: [true, \"OTP type is required\"]\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isUsed: {\n      type: Boolean,\n      default: false\n    },\n    usedAt: {\n      type: Date\n    },\n    attempts: {\n      type: Number,\n      default: 0\n    },\n    maxAttempts: {\n      type: Number,\n      default: OTP_MAX_ATTEMPTS // Prevent brute force attacks\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\notpSchema.index({ email: 1, type: 1 }); // Quick lookup by email and type\notpSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: OTP_EXPIRES_IN / 1000 } // 5 minutes\n); // ttl index\n\nconst Otp: Model<IOtp> =\n  mongoose.models.Otp || mongoose.model<IOtp>(\"Otp\", otpSchema);\n\nexport default Otp;\n"
                            }
                          ]
                        }
                      }
                    },
                    "user": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/user.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport interface IAvatar {\n  public_id: string;\n  url: string;\n  size: number;\n}\n\nexport interface IUser extends Document {\n  _id: mongoose.Types.ObjectId;\n  name: string;\n  email: string;\n  password?: string;\n  role: \"user\" | \"admin\";\n  isEmailVerified: boolean;\n  lastLoginAt?: Date;\n  failedLoginAttempts: number;\n  lockUntil?: Date;\n  avatar?: IAvatar;\n\n  provider: \"local\" | \"google\" | \"github\";\n  providerId?: string;\n\n  isDeleted: boolean;\n  deletedAt?: Date;\n  reActivateAvailableAt?: Date;\n\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst userSchema = new Schema<IUser>(\n  {\n    name: {\n      type: String,\n      required: [true, \"Name is required\"],\n      trim: true\n    },\n    email: {\n      type: String,\n      required: [true, \"Email is required\"],\n      unique: true,\n      lowercase: true,\n      trim: true\n    },\n    password: {\n      type: String,\n      select: false,\n      default: null\n    },\n    provider: {\n      type: String,\n      enum: [\"local\", \"google\", \"github\"],\n      default: \"local\"\n    },\n    providerId: {\n      type: String,\n      default: null\n    },\n    role: {\n      type: String,\n      enum: [\"user\", \"admin\"],\n      default: \"user\"\n    },\n    avatar: {\n      public_id: String,\n      url: String,\n      size: Number\n    },\n    isEmailVerified: {\n      type: Boolean,\n      default: false\n    },\n    lastLoginAt: {\n      type: Date\n    },\n    failedLoginAttempts: {\n      type: Number,\n      required: true,\n      default: 0\n    },\n    lockUntil: {\n      type: Date\n    },\n    isDeleted: {\n      type: Boolean,\n      default: false\n    },\n    deletedAt: {\n      type: Date\n    },\n    reActivateAvailableAt: {\n      type: Date\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Performance Indexes\n\nuserSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth\nuserSchema.index({ role: 1 });\nuserSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries\n\nconst User: Model<IUser> =\n  mongoose.models.User || mongoose.model<IUser>(\"User\", userSchema);\n\nexport default User;\n"
                            }
                          ]
                        }
                      }
                    },
                    "session": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/session.model.ts",
                              "content": "import mongoose, { Document, Schema, Model } from \"mongoose\";\n\nexport interface ISession extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  ip?: string;\n  userAgent?: string;\n  isActive: boolean;\n  lastUsedAt: Date;\n  expiresAt: Date;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst SESSION_EXPIRES_IN = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nconst sessionSchema: Schema<ISession> = new Schema(\n  {\n    userId: {\n      type: mongoose.Schema.Types.ObjectId,\n      ref: \"User\",\n      required: true,\n      index: true\n    },\n    tokenHash: {\n      type: String,\n      required: true,\n      unique: true,\n      index: true\n    },\n    ip: { type: String },\n    userAgent: { type: String },\n    isActive: {\n      type: Boolean,\n      default: true,\n      index: true\n    },\n    lastUsedAt: {\n      type: Date,\n      default: Date.now\n    },\n    expiresAt: {\n      type: Date,\n      required: true\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\n// Supporting indexes\nsessionSchema.index({ userId: 1, isActive: 1 });\nsessionSchema.index({ userId: 1, lastUsedAt: -1 });\nsessionSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: SESSION_EXPIRES_IN / 1000 } // 7 days\n); // ttl index\n\nconst Session: Model<ISession> =\n  mongoose.models.Session || mongoose.model<ISession>(\"Session\", sessionSchema);\n\nexport default Session;\n"
                            }
                          ]
                        }
                      }
                    },
                    "refresh-token": {
                      "architectures": {
                        "file-api": {
                          "files": [
                            {
                              "type": "file",
                              "path": "src/models/refresh-token.model.ts",
                              "content": "import mongoose, { Document, Model, Schema } from \"mongoose\";\n\nexport const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days\n\nexport interface IRefreshToken extends Document {\n  _id: mongoose.Types.ObjectId;\n  userId: mongoose.Types.ObjectId;\n  tokenHash: string;\n  expiresAt: Date;\n  isRevoked: boolean;\n  revokedAt?: Date;\n  replacedByTokenHash?: string;\n  createdAt: Date;\n  updatedAt: Date;\n}\n\nconst refreshTokenSchema = new Schema<IRefreshToken>(\n  {\n    userId: {\n      type: Schema.Types.ObjectId,\n      ref: \"User\",\n      required: [true, \"User ID is required\"]\n    },\n    tokenHash: {\n      type: String,\n      required: [true, \"Token hash is required\"],\n      select: false // Secure by default\n    },\n    expiresAt: {\n      type: Date,\n      required: [true, \"Expiration time is required\"]\n    },\n    isRevoked: {\n      type: Boolean,\n      default: false\n    },\n    revokedAt: {\n      type: Date\n    },\n    replacedByTokenHash: {\n      type: String,\n      select: false\n    }\n  },\n  {\n    timestamps: true\n  }\n);\n\nrefreshTokenSchema.index({ userId: 1 });\nrefreshTokenSchema.index({ tokenHash: 1 });\nrefreshTokenSchema.index({ isRevoked: 1 });\nrefreshTokenSchema.index(\n  { createdAt: 1 },\n  { expireAfterSeconds: REFRESH_TOKEN_EXPIRY / 1000 } // 7 days\n);\n\nconst RefreshToken: Model<IRefreshToken> =\n  mongoose.models.RefreshToken ||\n  mongoose.model<IRefreshToken>(\"RefreshToken\", refreshTokenSchema);\n\nexport default RefreshToken;\n"
                            }
                          ]
                        }
                      }
                    }
                  },
                  "dependencies": {
                    "runtime": [
                      "mongoose"
                    ],
                    "dev": []
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
