fix: no user ever had a username, so people search found nobody

Root cause of "still cannot find users": username was optional in
better-auth's schema and no signup form or settings page ever set it,
but search/profile/follow all key on username, not user id. Every
account now gets a unique one auto-generated (from name/email) in the
user.create.before hook — covers email/password and OAuth signups.
Added a one-off db:backfill-usernames script for accounts created
before this fix and ran it against the current database.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-13 17:26:12 +02:00
parent 79cdb8cd04
commit 2ee99ea463
8 changed files with 112 additions and 5 deletions
+1
View File
@@ -13,6 +13,7 @@
"migrate": "drizzle-kit migrate",
"studio": "drizzle-kit studio",
"seed": "tsx src/seed.ts",
"backfill-usernames": "tsx src/backfill-usernames.ts",
"typecheck": "tsc --noEmit"
},
"dependencies": {
+51
View File
@@ -0,0 +1,51 @@
import { db } from "./client";
import { users } from "./schema";
import { eq, isNull } from "drizzle-orm";
// Mirrors apps/web/lib/username.ts's slugify — duplicated rather than shared
// since packages/db doesn't depend on apps/web. Kept intentionally simple.
function slugify(seed: string): string {
const base = seed
.split("@")[0]!
.toLowerCase()
.replace(/[^a-z0-9_]/g, "")
.slice(0, 20);
return base.length >= 3 ? base : `${base}user`.slice(0, 20);
}
async function backfillUsernames() {
const rows = await db.query.users.findMany({
where: isNull(users.username),
columns: { id: true, name: true, email: true },
});
console.log(`${rows.length} user(s) missing a username.`);
const taken = new Set(
(await db.query.users.findMany({ columns: { username: true } }))
.map((u) => u.username)
.filter((u): u is string => !!u)
);
for (const row of rows) {
const base = slugify(row.name || row.email);
let candidate = base;
let suffix = 0;
while (taken.has(candidate)) {
suffix += 1;
candidate = `${base}${suffix}`.slice(0, 20);
}
taken.add(candidate);
await db.update(users).set({ username: candidate }).where(eq(users.id, row.id));
console.log(` ${row.email} -> @${candidate}`);
}
console.log("Backfill complete.");
process.exit(0);
}
backfillUsernames().catch((err) => {
console.error(err);
process.exit(1);
});