Add one-click local dev login with PGlite setup#47
Conversation
|
@leoisadev1 is attempting to deploy a commit to the Bounty Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughThis 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)
✅ Passed checks (4 passed)
✏️ 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
apps/web/src/routes/api/dev/login.ts (1)
8-17: 💤 Low valueConsider wrapping seeding calls in try/catch for better error messages.
If
ensureDevLoginUserorseedDevWorkspacethrow, 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 tradeoffWrap 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
⛔ Files ignored due to path filters (2)
screenshots/dev-login-review/01-dev-login-button.pngis excluded by!**/*.pngscreenshots/dev-login-review/02-after-dev-login.pngis excluded by!**/*.png
📒 Files selected for processing (8)
apps/web/package.jsonapps/web/src/components/layout/auth/login-page.tsxapps/web/src/lib/dev-router-timing.tsapps/web/src/lib/dev-seed.tsapps/web/src/routeTree.gen.tsapps/web/src/routes/api/dev/login.tsapps/web/src/scripts/seed-dev-login.tspackages/auth/src/index.ts
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/db/src/connection.ts (1)
11-25: ⚡ Quick win
DEV_DATABASE_DIRdefinition diverges fromdrizzle.config.ts.Here the dir is resolved to an absolute path from the discovered monorepo root, whereas
apps/web/drizzle.config.tsuses the relative"../../.tripwire/pglite". These only coincide whendrizzle-kitis invoked fromapps/web. If they ever diverge,db:pushwill 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
findMonorepoRootsilently falls back toprocess.cwd()whenpnpm-workspace.yamlisn'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 winAdd explicit return types for exported dev-login/seed helpers
apps/web/src/lib/dev-seed.tsis exposing these dev-login entry points; adding explicitPromise<...>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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
.env.example.gitignoreREADME.mdapps/web/drizzle.config.tsapps/web/package.jsonapps/web/src/components/layout/auth/login-page.tsxapps/web/src/lib/dev-seed.tsapps/web/src/routes/api/dev/login.tsapps/web/src/scripts/seed-dev-login.tspackages/db/package.jsonpackages/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
|
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. |
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_URLis blank, and seeds a realistic workspace so the authenticated app has usable content right away.What gets added:
/api/dev/loginendpoint that creates the example dev user, signs them in, seeds demo data, and redirects into the normal authenticated app..tripwire/pglitewhenDATABASE_URLis blank outside production.How it works locally:
DATABASE_URL=blank.pnpm db:push; Drizzle uses PGlite automatically and creates.tripwire/pglite.dev@tripwire.local, seeds the example workspace, and lands in the normal authenticated app.Production behavior is unchanged:
DATABASE_URLis still required whenNODE_ENV=production.Review and security fixes included:
/api/dev/loginand shown in the UI.latestare pinned, and the lockfile was regenerated so the PR does not introduce the unrelated Socketentitiesobfuscation alerts.Screenshots
Dev login button:
After dev login:
Verification
git diff --checkpnpm install --frozen-lockfile --ignore-scriptspnpm format:check -- apps/web/package.json package.json pnpm-lock.yamlpnpm format:check -- apps/web/drizzle.config.ts apps/web/src/lib/dev-seed.tspnpm --filter @tripwire/web lintpnpm --filter @tripwire/db typecheckpnpm --filter @tripwire/web typecheckDATABASE_URL= pnpm db:pushDATABASE_URL= pnpm db:pushfromapps/webDATABASE_URL= NODE_ENV=development pnpm --filter @tripwire/web dev:seed-login