Skip to content

feat: add auth template schema files and update core config#12

Merged
weroperking merged 2 commits intomainfrom
feature/new-changes-20260220
Feb 20, 2026
Merged

feat: add auth template schema files and update core config#12
weroperking merged 2 commits intomainfrom
feature/new-changes-20260220

Conversation

@weroperking
Copy link
Copy Markdown
Owner

@weroperking weroperking commented Feb 20, 2026

This PR adds auth template schema files and updates core config.

Summary by CodeRabbit

  • New Features

    • Added database initialization with SQLite + ORM and public auth tables
    • Introduced reusable schema helpers and a users table for audit/soft-delete
  • New Features / Validation

    • Added provider-specific configuration validation with clearer, targeted error messages
  • Chores

    • Minor type-safety tweak in focus handling
    • Clarified an inline TODO comment wording

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 20, 2026

📝 Walkthrough

Walkthrough

Adds Turso-specific cross-field validation to core config schema, a small type-safety tweak in dashboard logs focus handling, a comment TODO in a provider interface, and new authentication database wiring and SQLite schema helpers (Bun + Drizzle) in the auth template.

Changes

Cohort / File(s) Summary
Dashboard type-safety
betterbase/apps/dashboard/src/app/(dashboard)/logs/page.tsx
Narrowed focus-management assignment to `document.activeElement as HTMLElement
Core config & provider types
betterbase/packages/core/src/config/schema.ts, betterbase/packages/core/src/providers/types.ts
Added .superRefine validation to BetterBaseConfigSchema enforcing Turso-specific required fields; changed an inline comment to a TODO on ProviderAdapter.getMigrationsDriver() (signature unchanged).
Auth DB wiring & schema
betterbase/templates/auth/src/db/index.ts, betterbase/templates/auth/src/db/schema.ts
New Bun+SQLite Drizzle DB initializer exporting db and auth tables; new reusable schema helpers (uuid, timestamps, statusEnum, softDelete) and users table definition.

Sequence Diagram(s)

sequenceDiagram
  participant Env as Env (DB_PATH)
  participant AuthInit as Auth DB init
  participant BunDB as Bun SQLite DB
  participant Drizzle as Drizzle ORM
  participant Schema as Auth Schema (users/sessions/accounts)

  Env->>AuthInit: read DB_PATH (or default ./data/auth.db)
  AuthInit->>BunDB: create/open SQLite DB (create: true)
  BunDB->>Drizzle: provide DB connection
  AuthInit->>Drizzle: create Drizzle instance with merged schema
  Drizzle->>Schema: bind tables (users, sessions, accounts)
  AuthInit->>Consumers: export `db`, `users`, `sessions`, `accounts`
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰 I hopped in code, with whiskers bright,

Merged schemas, tables shining white.
A safer focus, a TODO nudge,
Bun and Drizzle help auth budge —
Hooray! A little rabbit dance tonight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main changes: adding auth template schema files and updating core config. It accurately reflects the primary objectives of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/new-changes-20260220

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
betterbase/packages/core/src/config/schema.ts (1)

16-17: LGTM — consider optional Zod cross-validation for provider-specific required fields.

All three connection fields (connectionString, url, authToken) are fully optional with no mutual dependency enforced at the schema level. A turso provider needs url+authToken; other providers need connectionString. Without a refinement, a misconfigured BetterBaseConfig won't be caught until runtime inside the provider adapter.

♻️ Example: enforce connection fields per provider type via .superRefine()
  provider: z.object({
    type: ProviderTypeSchema,
    connectionString: z.string().optional(),
    url: z.string().optional(),           // Turso - libSQL connection URL
    authToken: z.string().optional(),     // Turso - auth token for managed DB
- }),
+ }).superRefine((data, ctx) => {
+   if (data.type === 'turso') {
+     if (!data.url) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'url is required for turso', path: ['url'] });
+     if (!data.authToken) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'authToken is required for turso', path: ['authToken'] });
+   } else if (data.type !== 'managed') {
+     if (!data.connectionString) ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'connectionString is required for this provider', path: ['connectionString'] });
+   }
+ }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/packages/core/src/config/schema.ts` around lines 16 - 17, Add a
Zod .superRefine() to the existing config schema to enforce provider-specific
required fields: when provider === 'turso' require both url and authToken to be
present and non-empty; for other providers require connectionString; emit clear
refinement errors pointing to the missing fields (e.g., add issues for "url" and
"authToken" or "connectionString"). Update the schema that declares
connectionString, url, and authToken to include this .superRefine() logic so
misconfigured BetterBaseConfig values are caught at validation time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@betterbase/templates/auth/src/db/index.ts`:
- Around line 3-4: The Drizzle schema passed to drizzle(sqlite, { schema }) only
includes the ./schema namespace and omits sessions and accounts from
./auth-schema, causing db.query.sessions and db.query.accounts to be undefined;
fix by importing the users table explicitly (e.g., import { users } from
'./schema') and import the auth tables (e.g., import * as authSchema from
'./auth-schema' or import { sessions, accounts } from './auth-schema'), then
pass a merged schema object to drizzle such as drizzle(sqlite, { schema: { ...{
users }, ...authSchema } }) so that sessions and accounts are registered with
Drizzle and relational queries work.

In `@betterbase/templates/auth/src/db/schema.ts`:
- Around line 24-29: The timestamps definition uses client-side hooks
($defaultFn/$onUpdate) but lacks NOT NULL constraints, so update the timestamps
object (createdAt and updatedAt properties defined via text('created_at') and
text('updated_at')) to include .notNull() on both columns while preserving their
existing $defaultFn and $onUpdate calls so the generated DDL enforces NOT NULL
at the database level.
- Around line 44-50: The users table definition (users) is missing the
BetterAuth-required emailVerified field and uses a plural table name; add an
emailVerified column to the sqliteTable('users') definition (matching
BetterAuth's expected type/nullable behavior) and then update the BetterAuth
adapter wiring (drizzleAdapter / betterAuth config) to map the plural users
table to the expected user schema name and register status/deletedAt as
additionalFields in the user config so the adapter sees the correct schema
mapping and extra fields.

---

Nitpick comments:
In `@betterbase/packages/core/src/config/schema.ts`:
- Around line 16-17: Add a Zod .superRefine() to the existing config schema to
enforce provider-specific required fields: when provider === 'turso' require
both url and authToken to be present and non-empty; for other providers require
connectionString; emit clear refinement errors pointing to the missing fields
(e.g., add issues for "url" and "authToken" or "connectionString"). Update the
schema that declares connectionString, url, and authToken to include this
.superRefine() logic so misconfigured BetterBaseConfig values are caught at
validation time.

Comment thread betterbase/templates/auth/src/db/index.ts
Comment thread betterbase/templates/auth/src/db/schema.ts
Comment on lines +44 to +50
export const users = sqliteTable('users', {
id: uuid(),
email: text('email').notNull().unique(),
name: text('name'),
status: statusEnum(),
...timestamps,
...softDelete,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

users table is missing BetterAuth-required emailVerified field and uses plural table name.

BetterAuth's core schema has four essential tables — user, session, account, verification — each with fixed required fields. The user table requires an emailVerified column. Without it, the BetterAuth Drizzle adapter will either error or silently skip email verification state, breaking auth flows.

Additionally, the Drizzle adapter expects the schema you define to match BetterAuth's expected table names; if your Drizzle schema maps the user table to users, you need to manually pass the schema and map it to the user table in the adapter config.

🔧 Proposed fix — add emailVerified and register as BetterAuth additionalFields
 export const users = sqliteTable('users', {
   id: uuid(),
   email: text('email').notNull().unique(),
+  emailVerified: integer('email_verified', { mode: 'boolean' }).notNull().default(false),
   name: text('name'),
   status: statusEnum(),
   ...timestamps,
   ...softDelete,
 });

And in the BetterAuth config wire up the adapter with the plural-name mapping and declare status/deletedAt as additionalFields:

// auth.ts
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { db, users, sessions, accounts } from './db';

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'sqlite',
    schema: { user: users, session: sessions, account: accounts },
  }),
  user: {
    additionalFields: {
      status: { type: 'string', defaultValue: 'active' },
      deletedAt: { type: 'string', required: false },
    },
  },
});

Based on learnings: "Applies to **/auth/**/*.{ts,tsx}: Use BetterAuth for authentication implementation direction."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const users = sqliteTable('users', {
id: uuid(),
email: text('email').notNull().unique(),
name: text('name'),
status: statusEnum(),
...timestamps,
...softDelete,
export const users = sqliteTable('users', {
id: uuid(),
email: text('email').notNull().unique(),
emailVerified: integer('email_verified', { mode: 'boolean' }).notNull().default(false),
name: text('name'),
status: statusEnum(),
...timestamps,
...softDelete,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/templates/auth/src/db/schema.ts` around lines 44 - 50, The users
table definition (users) is missing the BetterAuth-required emailVerified field
and uses a plural table name; add an emailVerified column to the
sqliteTable('users') definition (matching BetterAuth's expected type/nullable
behavior) and then update the BetterAuth adapter wiring (drizzleAdapter /
betterAuth config) to map the plural users table to the expected user schema
name and register status/deletedAt as additionalFields in the user config so the
adapter sees the correct schema mapping and extra fields.

- Add Turso-specific validation in BetterBaseConfigSchema
- Improve auth template db schema with proper user table
- Merge all schemas for Drizzle in auth template
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
betterbase/templates/auth/src/db/index.ts (1)

3-3: import * spreads non-table helpers into the Drizzle schema.

./schema exports utility helpers (uuid, timestamps, statusEnum, softDelete) alongside the users table. Spreading them all into fullSchema works because Drizzle silently ignores non-table entries, but it muddies the schema object. A named import keeps intent clear:

♻️ Suggested change
-import * as schema from './schema';
-import { sessions, accounts } from './auth-schema';
+import { users } from './schema';
+import * as authSchema from './auth-schema';

 // Merge all schemas for Drizzle
 const fullSchema = {
-  ...schema,
-  sessions,
-  accounts,
+  users,
+  ...authSchema,
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/templates/auth/src/db/index.ts` at line 3, The import currently
uses a namespace import "schema" from './schema' and then spreads it into
fullSchema, which mixes non-table helpers (uuid, timestamps, statusEnum,
softDelete) with table definitions (users); change the import to a named import
that only brings in the table exports you intend to include in fullSchema (e.g.,
import { users } from './schema') and keep utility helpers (uuid, timestamps,
statusEnum, softDelete) as separate named imports if needed elsewhere so
fullSchema only contains table definitions and not helper utilities.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@betterbase/templates/auth/src/db/index.ts`:
- Around line 15-17: The code constructs DB_PATH and immediately instantiates
Database (sqlite) which will fail if parent directories don't exist; before
calling new Database(DB_PATH, ...) ensure the parent directory of DB_PATH exists
(use path.dirname(DB_PATH)) and create it with fs.mkdirSync or await
fs.promises.mkdir(dir, { recursive: true }) and handle errors, then instantiate
sqlite = new Database(DB_PATH, { create: true }); update the module where
DB_PATH, sqlite and Database are defined so the directory creation runs
synchronously or before sqlite is assigned.

---

Nitpick comments:
In `@betterbase/templates/auth/src/db/index.ts`:
- Line 3: The import currently uses a namespace import "schema" from './schema'
and then spreads it into fullSchema, which mixes non-table helpers (uuid,
timestamps, statusEnum, softDelete) with table definitions (users); change the
import to a named import that only brings in the table exports you intend to
include in fullSchema (e.g., import { users } from './schema') and keep utility
helpers (uuid, timestamps, statusEnum, softDelete) as separate named imports if
needed elsewhere so fullSchema only contains table definitions and not helper
utilities.

Comment on lines +15 to +17
const DB_PATH = process.env.DB_PATH || './data/auth.db';

const sqlite = new Database(DB_PATH, { create: true });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Parent directory may not exist on first run.

new Database(DB_PATH, { create: true }) creates the .db file but won't create intermediate directories. If ./data/ doesn't exist, this will throw an ENOENT error. For a template that newcomers will clone and run, consider ensuring the directory exists:

💡 Suggested safeguard
+import { mkdirSync } from 'node:fs';
+import { dirname } from 'node:path';
+
 const DB_PATH = process.env.DB_PATH || './data/auth.db';
+mkdirSync(dirname(DB_PATH), { recursive: true });
 const sqlite = new Database(DB_PATH, { create: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const DB_PATH = process.env.DB_PATH || './data/auth.db';
const sqlite = new Database(DB_PATH, { create: true });
import { mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
const DB_PATH = process.env.DB_PATH || './data/auth.db';
mkdirSync(dirname(DB_PATH), { recursive: true });
const sqlite = new Database(DB_PATH, { create: true });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@betterbase/templates/auth/src/db/index.ts` around lines 15 - 17, The code
constructs DB_PATH and immediately instantiates Database (sqlite) which will
fail if parent directories don't exist; before calling new Database(DB_PATH,
...) ensure the parent directory of DB_PATH exists (use path.dirname(DB_PATH))
and create it with fs.mkdirSync or await fs.promises.mkdir(dir, { recursive:
true }) and handle errors, then instantiate sqlite = new Database(DB_PATH, {
create: true }); update the module where DB_PATH, sqlite and Database are
defined so the directory creation runs synchronously or before sqlite is
assigned.

@weroperking weroperking merged commit beaa02c into main Feb 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant