Skip to content

Add one-click local dev login with PGlite setup#47

Open
leoisadev1 wants to merge 5 commits into
Boring-Software-Inc:mainfrom
leoisadev1:t3code/6399234f
Open

Add one-click local dev login with PGlite setup#47
leoisadev1 wants to merge 5 commits into
Boring-Software-Inc:mainfrom
leoisadev1:t3code/6399234f

Conversation

@leoisadev1

@leoisadev1 leoisadev1 commented May 30, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR makes the app runnable in local development without setting up OAuth apps or a local Postgres server. It adds one dev-only login path, backs local development with PGlite when DATABASE_URL is blank, and seeds a realistic workspace so the authenticated app has usable content right away.

What gets added:

  • A single Login as dev button on the local development login page.
  • A local-only /api/dev/login endpoint that creates the example dev user, signs them in, seeds demo data, and redirects into the normal authenticated app.
  • A shared dev seed script used by both the button and CLI.
  • Demo content for the dev workspace: user, org, repo, rules, workflow, onboarding state, allow/block lists, vouch requests, and example events.
  • A file-backed PGlite database fallback at .tripwire/pglite when DATABASE_URL is blank outside production.

How it works locally:

  1. Leave DATABASE_URL= blank.
  2. Run pnpm db:push; Drizzle uses PGlite automatically and creates .tripwire/pglite.
  3. Start the app and click Login as dev.
  4. The app signs in dev@tripwire.local, seeds the example workspace, and lands in the normal authenticated app.

Production behavior is unchanged: DATABASE_URL is still required when NODE_ENV=production.

Review and security fixes included:

  • Workspace seeding runs in a database transaction.
  • Dev login no longer deletes an existing user if the credential account is missing.
  • Server-side seed errors are returned from /api/dev/login and shown in the UI.
  • The dev seed CLI exits cleanly after seeding the PGlite database.
  • Drizzle config paths are anchored to the repo/app directories so PGlite uses the same store from root or app commands.
  • Rerunning the seed restores the canonical onboarding demo state.
  • Seeded event cleanup is scoped to the demo repo.
  • The loading state for Login as dev is spinner-only, and the button copy now reads Login as dev.
  • Package specs that were using latest are pinned, and the lockfile was regenerated so the PR does not introduce the unrelated Socket entities obfuscation alerts.

Screenshots

Dev login button:

Dev login button

After dev login:

After dev login

Verification

  • git diff --check
  • pnpm install --frozen-lockfile --ignore-scripts
  • pnpm format:check -- apps/web/package.json package.json pnpm-lock.yaml
  • pnpm format:check -- apps/web/drizzle.config.ts apps/web/src/lib/dev-seed.ts
  • pnpm --filter @tripwire/web lint
  • pnpm --filter @tripwire/db typecheck
  • pnpm --filter @tripwire/web typecheck
  • DATABASE_URL= pnpm db:push
  • DATABASE_URL= pnpm db:push from apps/web
  • DATABASE_URL= NODE_ENV=development pnpm --filter @tripwire/web dev:seed-login

@vercel

vercel Bot commented May 30, 2026

Copy link
Copy Markdown

@leoisadev1 is attempting to deploy a commit to the Bounty Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a complete development-only login system that allows developers to authenticate without GitHub OAuth in development environments. It adds foundational seeding utilities for creating dev users and workspaces, a new POST API endpoint at /api/dev/login that orchestrates user validation and workspace provisioning, UI integration in the login page to support a dev login button with error handling, auth provider configuration to enable email/password authentication in dev mode, and CLI helpers including an npm script and seed script to initialize the dev environment.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: enabling one-click dev login locally with PGlite as a fallback database, which is the core feature enabling local development without OAuth or Postgres.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/web/src/routes/api/dev/login.ts (1)

8-17: 💤 Low value

Consider wrapping seeding calls in try/catch for better error messages.

If ensureDevLoginUser or seedDevWorkspace throw, the error propagates as a 500 with a potentially cryptic stack trace. Catching and returning a structured error improves the dev experience.

♻️ Proposed error handling
 async function postDevLogin({ request }: { request: Request }) {
   if (process.env.NODE_ENV !== "development") {
     return Response.json({ error: "Not found" }, { status: 404 })
   }
 
+  try {
     await ensureDevLoginUser(request.headers)
     await seedDevWorkspace()
 
     return signInDevLoginUser(request.headers)
+  } catch (error) {
+    return Response.json(
+      { error: error instanceof Error ? error.message : "Dev login failed" },
+      { status: 500 }
+    )
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/routes/api/dev/login.ts` around lines 8 - 17, The postDevLogin
flow currently lets errors from ensureDevLoginUser or seedDevWorkspace bubble
up; wrap the calls to ensureDevLoginUser(request.headers) and seedDevWorkspace()
inside a try/catch in postDevLogin so any thrown error is caught and you return
a structured Response.json with a clear message, the error.message (or
stringified error) and an appropriate status (e.g., 500); keep
signInDevLoginUser(request.headers) outside the catch so it only runs on success
and reference the functions postDevLogin, ensureDevLoginUser, seedDevWorkspace,
and signInDevLoginUser when making the change.
apps/web/src/lib/dev-seed.ts (1)

167-477: ⚖️ Poor tradeoff

Wrap workspace seeding in a transaction.

If any upsert/insert fails mid-flow (e.g., repo creation throws), earlier changes remain committed, leaving the database in an inconsistent state. Wrapping in a transaction ensures atomicity.

♻️ Proposed transaction wrapper
 export async function seedDevWorkspace() {
   if (process.env.NODE_ENV !== "development") {
     throw new Error("Dev seed is only available in development.")
   }
 
+  return db.transaction(async (tx) => {
     const [devUser] = await tx
       .select({ id: user.id })
       .from(user)
       .where(eq(user.email, DEV_LOGIN_EMAIL))
       .limit(1)
 
     if (!devUser) {
       throw new Error("Create the dev user before seeding workspace data.")
     }
 
     const now = new Date()
 
     // ... rest of the function body, replacing `db` with `tx` ...
 
     return {
       userId: devUser.id,
       orgId: DEV_BA_ORG_ID,
       repoId: repo.id,
     }
+  })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/lib/dev-seed.ts` around lines 167 - 477, seedDevWorkspace
performs many inserts/updates independently so partial failures leave the DB
inconsistent; wrap the entire body of seedDevWorkspace in a single transaction
using the database client's transaction API (e.g., db.transaction(async (tx) =>
{ ... })) and run all DB calls inside that transaction (replace uses of db with
tx for operations on organization, member, organizations, repositories,
ruleConfigs, userPreferences, onboardingState, workflows, customRules,
whitelistEntries, blacklistEntries, events, etc.), ensure you return the result
from inside the transaction and re-throw any caught errors so the transaction
rolls back on failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/layout/auth/login-page.tsx`:
- Around line 43-45: Replace the hardcoded error throw in the dev-login path so
it uses the server's response body: when checking seedResponse.ok in the login
routine (the branch that currently throws "Dev login is only available while
running locally."), await seedResponse.json(), extract the server's
error/message field (e.g., error or message) and include that text in the thrown
Error so the real seeding failure is surfaced instead of the generic message.

In `@apps/web/src/lib/dev-seed.ts`:
- Around line 115-127: The current logic deletes a user record if a matching
credential account is missing (see variables existing, db, account,
credentialAccount, user), which can remove OAuth users who never had a
credential provider; instead, stop deleting and either throw a clear error or
skip re-creation: detect that credentialAccount is falsy and then either throw
new Error(`User ${existing.id} has no credential account—aborting to avoid data
loss`) or simply return existing to leave the OAuth user intact; remove the
await db.delete(user).where(eq(user.id, existing.id)) call and implement one of
these safe alternatives in the same conditional block.

---

Nitpick comments:
In `@apps/web/src/lib/dev-seed.ts`:
- Around line 167-477: seedDevWorkspace performs many inserts/updates
independently so partial failures leave the DB inconsistent; wrap the entire
body of seedDevWorkspace in a single transaction using the database client's
transaction API (e.g., db.transaction(async (tx) => { ... })) and run all DB
calls inside that transaction (replace uses of db with tx for operations on
organization, member, organizations, repositories, ruleConfigs, userPreferences,
onboardingState, workflows, customRules, whitelistEntries, blacklistEntries,
events, etc.), ensure you return the result from inside the transaction and
re-throw any caught errors so the transaction rolls back on failure.

In `@apps/web/src/routes/api/dev/login.ts`:
- Around line 8-17: The postDevLogin flow currently lets errors from
ensureDevLoginUser or seedDevWorkspace bubble up; wrap the calls to
ensureDevLoginUser(request.headers) and seedDevWorkspace() inside a try/catch in
postDevLogin so any thrown error is caught and you return a structured
Response.json with a clear message, the error.message (or stringified error) and
an appropriate status (e.g., 500); keep signInDevLoginUser(request.headers)
outside the catch so it only runs on success and reference the functions
postDevLogin, ensureDevLoginUser, seedDevWorkspace, and signInDevLoginUser when
making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9a95ba6d-3de9-4e9b-9708-5876f81ffcef

📥 Commits

Reviewing files that changed from the base of the PR and between 5610f54 and 44d58f6.

⛔ Files ignored due to path filters (2)
  • screenshots/dev-login-review/01-dev-login-button.png is excluded by !**/*.png
  • screenshots/dev-login-review/02-after-dev-login.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • apps/web/package.json
  • apps/web/src/components/layout/auth/login-page.tsx
  • apps/web/src/lib/dev-router-timing.ts
  • apps/web/src/lib/dev-seed.ts
  • apps/web/src/routeTree.gen.ts
  • apps/web/src/routes/api/dev/login.ts
  • apps/web/src/scripts/seed-dev-login.ts
  • packages/auth/src/index.ts

Comment thread apps/web/src/components/layout/auth/login-page.tsx
Comment thread apps/web/src/lib/dev-seed.ts
@leoisadev1 leoisadev1 marked this pull request as draft May 30, 2026 13:22
@leoisadev1 leoisadev1 changed the title T3CODE-6399234F feat: add local dev login T3CODE-6399234F feat: add local dev login and PGlite fallback May 30, 2026
@socket-security

socket-security Bot commented May 30, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​electric-sql/​pglite@​0.4.6931009995100

View full report

@leoisadev1 leoisadev1 changed the title T3CODE-6399234F feat: add local dev login and PGlite fallback Add one-click local dev login with PGlite setup May 30, 2026
@leoisadev1 leoisadev1 marked this pull request as ready for review May 30, 2026 13:58
@ripgrim ripgrim requested review from ripgrim and removed request for ripgrim May 30, 2026 15:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
packages/db/src/connection.ts (1)

11-25: ⚡ Quick win

DEV_DATABASE_DIR definition diverges from drizzle.config.ts.

Here the dir is resolved to an absolute path from the discovered monorepo root, whereas apps/web/drizzle.config.ts uses the relative "../../.tripwire/pglite". These only coincide when drizzle-kit is invoked from apps/web. If they ever diverge, db:push will populate one PGlite store while the running app reads another. Consider sharing a single resolver/constant so the migration tool and runtime can't disagree.

Also note findMonorepoRoot silently falls back to process.cwd() when pnpm-workspace.yaml isn't found within 10 levels, which would relocate the dev DB unexpectedly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/src/connection.ts` around lines 11 - 25, The DEV_DATABASE_DIR is
computed differently than apps/web/drizzle.config.ts which leads to mismatched
dev DB locations and findMonorepoRoot silently falling back to process.cwd();
fix by extracting a single shared resolver (e.g. export function
getDevDatabaseDir or constant DEV_DATABASE_DIR from this package) and import
that same symbol in drizzle.config.ts so both runtime and migration tooling use
the identical path, and modify findMonorepoRoot to avoid using process.cwd() as
the silent fallback (use the current file directory as a safer default or
surface an error) so the dev DB location is deterministic; update references to
DEV_DATABASE_DIR and findMonorepoRoot in this file to the new shared API.
apps/web/src/lib/dev-seed.ts (1)

104-104: ⚡ Quick win

Add explicit return types for exported dev-login/seed helpers

apps/web/src/lib/dev-seed.ts is exposing these dev-login entry points; adding explicit Promise<...> return types makes their contracts stable for callers:

export async function ensureDevLoginUser(headers = new Headers()) {
  • ensureDevLoginUser: Promise<{ id: string }>
  • signInDevLoginUser: Promise<Response>
  • seedDevWorkspace: Promise<{ userId: string; orgId: string; repoId: string }>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/lib/dev-seed.ts` at line 104, Add explicit Promise return types
to the exported dev-login/seed helpers to stabilize their caller contracts:
annotate ensureDevLoginUser as Promise<{ id: string }>, signInDevLoginUser as
Promise<Response>, and seedDevWorkspace as Promise<{ userId: string; orgId:
string; repoId: string }>; update the function signatures for
ensureDevLoginUser, signInDevLoginUser, and seedDevWorkspace in
apps/web/src/lib/dev-seed.ts accordingly so their async declarations include
these explicit return types.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/drizzle.config.ts`:
- Around line 9-19: Relative paths in drizzle.config.ts (DEV_DATABASE_DIR and
env loading via process.cwd()) can resolve incorrectly if `drizzle-kit push` is
run outside apps/web; update the config so paths are anchored to a stable
location instead of process.cwd(): compute DEV_DATABASE_DIR and any
dotenv/env-file paths with path.resolve(__dirname, "...") or resolve against the
repository root, or alternatively assert process.cwd() ends with "apps/web" and
throw a clear error; refer to DEV_DATABASE_DIR and databaseUrl in
drizzle.config.ts when making this change so the dev PGlite store and env
loading always match the absolute path used in packages/db/src/connection.ts.

In `@apps/web/src/lib/dev-seed.ts`:
- Around line 442-443: The deletion currently removes events by pipelineId only
(seededPipelineIds), which can affect other repos; change the query that calls
tx.delete(events).where(inArray(events.pipelineId, seededPipelineIds)) to
include a repo filter so it only deletes rows for the demo repo (e.g., combine
the pipelineId IN check with an events.repoId === repo.id check using the query
builder's AND/and operator or a combined where clause), referencing the
seededPipelineIds array and the repo.id value so only seeded events for that
repo are removed.
- Around line 321-346: The conflict-update branch in the upsert
(onConflictDoUpdate) only sets partial fields so source, setupAnswers and
gettingStartedDismissed remain stale after reruns; update the onConflictDoUpdate
set block (the object passed to onConflictDoUpdate for target
onboardingState.userId) to also reset source, setupAnswers and
gettingStartedDismissed to the same canonical demo values used in the insert
path, and ensure updatedAt is refreshed—this keeps the demo workspace consistent
when rerunning the seed.

---

Nitpick comments:
In `@apps/web/src/lib/dev-seed.ts`:
- Line 104: Add explicit Promise return types to the exported dev-login/seed
helpers to stabilize their caller contracts: annotate ensureDevLoginUser as
Promise<{ id: string }>, signInDevLoginUser as Promise<Response>, and
seedDevWorkspace as Promise<{ userId: string; orgId: string; repoId: string }>;
update the function signatures for ensureDevLoginUser, signInDevLoginUser, and
seedDevWorkspace in apps/web/src/lib/dev-seed.ts accordingly so their async
declarations include these explicit return types.

In `@packages/db/src/connection.ts`:
- Around line 11-25: The DEV_DATABASE_DIR is computed differently than
apps/web/drizzle.config.ts which leads to mismatched dev DB locations and
findMonorepoRoot silently falling back to process.cwd(); fix by extracting a
single shared resolver (e.g. export function getDevDatabaseDir or constant
DEV_DATABASE_DIR from this package) and import that same symbol in
drizzle.config.ts so both runtime and migration tooling use the identical path,
and modify findMonorepoRoot to avoid using process.cwd() as the silent fallback
(use the current file directory as a safer default or surface an error) so the
dev DB location is deterministic; update references to DEV_DATABASE_DIR and
findMonorepoRoot in this file to the new shared API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8d5adec6-11d8-4e48-9e3a-57876a5c1883

📥 Commits

Reviewing files that changed from the base of the PR and between 44d58f6 and cc229fe.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .env.example
  • .gitignore
  • README.md
  • apps/web/drizzle.config.ts
  • apps/web/package.json
  • apps/web/src/components/layout/auth/login-page.tsx
  • apps/web/src/lib/dev-seed.ts
  • apps/web/src/routes/api/dev/login.ts
  • apps/web/src/scripts/seed-dev-login.ts
  • packages/db/package.json
  • packages/db/src/connection.ts
✅ Files skipped from review due to trivial changes (3)
  • .env.example
  • .gitignore
  • README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/src/scripts/seed-dev-login.ts
  • apps/web/src/routes/api/dev/login.ts
  • apps/web/src/components/layout/auth/login-page.tsx

Comment thread apps/web/drizzle.config.ts Outdated
Comment thread apps/web/src/lib/dev-seed.ts
Comment thread apps/web/src/lib/dev-seed.ts Outdated
@socket-security

socket-security Bot commented Jun 2, 2026

Copy link
Copy Markdown

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

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