Skip to content

Docs + seed script: non-prod DB workflow#141

Merged
cursor[bot] merged 4 commits into
mainfrom
issue-138-environment-matrix
Apr 16, 2026
Merged

Docs + seed script: non-prod DB workflow#141
cursor[bot] merged 4 commits into
mainfrom
issue-138-environment-matrix

Conversation

@auerbachb
Copy link
Copy Markdown
Owner

@auerbachb auerbachb commented Apr 16, 2026

Summary

Adds a concrete non-production database workflow end to end:

  • Documents Neon environment topology and Vercel env scoping for Production / Preview / Local in README.md.
  • Adds a new non-production seed runbook in README.md.
  • Introduces scripts/seed.ts and npm run db:seed for deterministic fixture data with safety guards:
    • refuses to run unless SEED_CONFIRM=still-point-nonprod
    • refuses to run when NODE_ENV=production
  • Keeps credentials out of git; docs use env var names and placeholders only.

Closes #138
Refs #1

Test plan

  • npx tsc --noEmit passes
  • npm run db:seed fails safely without confirmation (SEED_CONFIRM) as expected
  • README instructions include db:seed flow and non-production-only safety notes
  • No tracked .env* files were modified

Made with Cursor

Summary by CodeRabbit

  • Documentation

    • Expanded environment setup, deployment/runbook, preview vs production guidance, tooling commands, troubleshooting, seed-data workflow, and an environment matrix.
  • Chores

    • Added optional environment variables for testing and an optional friendship flag for buddy videos; clarified runtime DB variable usage and JWT guidance.
  • New Features

    • Added a guarded seed command to safely populate non-production databases with demo users, sessions, thoughts, and friendships.

Document Production, Preview, and Local mapping for Neon, Vercel env
scopes, Daily, and optional BUDDY_REQUIRE_FRIENDSHIP. Clarify that
POSTGRES_URL_TEST is not read by the app. Note vercel.json ignoreCommand
and common failure modes. Extend .env.example with optional vars.

Closes #138

Made-with: Cursor
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
still-point Ready Ready Preview, Comment Apr 16, 2026 6:07pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

Added two optional env vars to .env.example, expanded README with a detailed environment/runbook and tooling guidance, added db:seed npm script and tsx devDependency, and introduced scripts/seed.ts — a guarded, idempotent DB seeding script for non-production Neon databases.

Changes

Cohort / File(s) Summary
Environment config
\.env\.example
Clarified POSTGRES_URL comment (runtime + drizzle-kit). Added commented optional entries: POSTGRES_URL_TEST= and BUDDY_REQUIRE_FRIENDSHIP=.
Documentation
README\.md
Rewrote local setup and env guidance with explicit placeholders (POSTGRES_URL_TEST, POSTGRES_URL, JWT_SECRET). Added env vars table (POSTGRES_URL, POSTGRES_URL_TEST, JWT_SECRET, DAILY_API_KEY, BUDDY_REQUIRE_FRIENDSHIP), non-production Neon topology notes, seed-data workflow with safety guards, an environment matrix/runbook, Vercel preview tooling commands, and a common failure-modes table.
Scripts & Tooling
package\.json, scripts/seed\.ts
Added db:seed script (tsx scripts/seed.ts) and tsx devDependency. New scripts/seed.ts enforces runtime guards (no prod, SEED_CONFIRM, POSTGRES_URL present, Neon hostname check), runs an idempotent transaction to delete/insert seed users (bcrypt-hashed password), insert sessions and thoughts, and upsert a friendship.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Env as Environment
  participant Script as Seed Script
  participant DB as Database (Neon)
  Dev->>Script: run `npm run db:seed` / `tsx scripts/seed.ts`
  Script->>Env: read NODE_ENV, SEED_CONFIRM, POSTGRES_URL
  Env-->>Script: return values
  Script->>Script: validate (not prod, confirmation token, POSTGRES_URL present, Neon hostname)
  alt validation fails
    Script->>Dev: log error and exit(1)
  else validation passes
    Script->>DB: begin transaction
    DB-->>Script: tx started
    Script->>DB: delete existing seed users by email
    Script->>DB: insert seed users (bcrypt-hashed password)
    Script->>DB: query inserted user ids
    Script->>DB: insert sessions and thoughts
    Script->>DB: upsert friendship (on conflict do nothing)
    DB-->>Script: commit
    Script->>Dev: log success
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇✨ I nibble envs and plant a seed,
With guards to keep prod safe indeed.
Friends and sessions, thoughts aligned,
Non‑prod blossoms, tidy, kind.
Hooray for docs that guide the trail!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding documentation and a seed script for non-production database workflow.
Linked Issues check ✅ Passed The PR fulfills all acceptance criteria from issue #138: environment matrix table, documentation of all required/optional variables, Neon topology, common failure modes, vercel.json clarification, and no committed secrets.
Out of Scope Changes check ✅ Passed All changes directly support the stated objective of providing a non-production database workflow with documentation and safety-guarded seed script; no extraneous modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

📋 Issue Planner

Built with CodeRabbit's Coding Plans for faster development and fewer bugs.

View plan used: #138

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-138-environment-matrix

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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Line 64: The README and .env.example disagree on how to generate JWT_SECRET;
standardize both to the same command. Replace the `openssl rand -hex 32` entry
in README (the JWT_SECRET row referencing src/lib/auth.ts and src/middleware.ts)
with the same command used in .env.example (`openssl rand -base64 32`), or
vice‑versa if you prefer hex—ensure both README and .env.example use the
identical command so JWT_SECRET generation is consistent.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8fce13e2-cf22-4858-b573-cb7aec23d778

📥 Commits

Reviewing files that changed from the base of the PR and between 4fa6dd9 and 10e39a0.

📒 Files selected for processing (2)
  • .env.example
  • README.md

Comment thread README.md Outdated
Add an idempotent seed script with explicit non-production confirmation so dev and preview environments can be populated safely without touching production data.

Made-with: Cursor
@auerbachb auerbachb changed the title Docs: environment matrix runbook (Prod / Preview / Local) Docs + seed script: non-prod DB workflow Apr 16, 2026
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/seed.ts`:
- Around line 26-38: Add an explicit DB-target safety guard before any writes by
validating the POSTGRES_URL value against an allowed DB host/database or
requiring an explicit override env var; after the existing NODE_ENV and
CONFIRMATION_KEY checks (around the POSTGRES_URL check), parse
process.env.POSTGRES_URL and either (a) enforce it does not match production
host/database patterns (e.g., disallow production host or prod DB name) or (b)
require an additional env flag like DB_ALLOW_TARGET or DB_TARGET_CONFIRM that
equals the expected host/db string before proceeding. Use the existing symbols
POSTGRES_URL, CONFIRMATION_KEY and REQUIRED_CONFIRMATION and fail fast with a
clear Error if the DB target is not explicitly approved.
- Around line 41-172: Wrap the entire seed flow (from the initial select/delete
of users through inserting sessions, thoughts and friendships) inside a single
database transaction by calling db.transaction(async (tx) => { ... }) and
replace usages of db with the transactional handle tx (so
select/insert/delete/returning use tx). Also change the friendship
check-then-insert to a race-safe operation inside that same transaction—either
perform an upsert/insert with conflict handling (e.g.,
.insert(friendships).values(...).onConflict([friendships.user1Id,
friendships.user2Id]).doNothing()) or perform the existence check and insert
using tx to ensure atomicity; ensure all references to users, sessions, thoughts
and friendships use the transactional tx handle.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 018f8968-61c3-459a-b31a-ee8dd661f65c

📥 Commits

Reviewing files that changed from the base of the PR and between 10e39a0 and 5e70398.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • README.md
  • package.json
  • scripts/seed.ts
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md

Comment thread scripts/seed.ts
Comment thread scripts/seed.ts Outdated
Align README JWT generation with .env.example and document additional seed safety guards.

Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
Co-authored-by: Bretton Auerbach <auerbachb@users.noreply.github.com>
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.

🧹 Nitpick comments (2)
scripts/seed.ts (2)

71-71: Consider omitting the explicit type annotation for tx.

The AppDb type is technically incorrect for the transaction callback parameter—Drizzle provides a transaction-specific type. It works here due to structural typing, but omitting the annotation lets TypeScript infer the correct type.

♻️ Suggested change
-  await db.transaction(async (tx: AppDb) => {
+  await db.transaction(async (tx) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/seed.ts` at line 71, The transaction callback uses an explicit,
incorrect AppDb annotation on the parameter (async (tx: AppDb) => ...)—remove
the explicit type so TypeScript/Drizzle can infer the transaction-specific type;
update the db.transaction call to use async (tx) => { ... } (or omit the
annotation) and leave rest of the logic unchanged to avoid the structural-typing
mismatch.

81-81: Consider moving password hashing outside the transaction.

bcrypt.hash with cost factor 12 is CPU-bound and can take 250–500ms. Performing it inside the transaction holds the connection open during that work. For a seed script this is acceptable, but moving it before db.transaction() would minimize transaction duration.

♻️ Suggested change
   assertNeonNonProdPostgresUrl(postgresUrl);

   const seedEmails = seedUsers.map((user) => user.email);
+  const passwordHash = await bcrypt.hash("SeedPassword123!", 12);

   await db.transaction(async (tx: AppDb) => {
     const existing = await tx
       .select({ id: users.id })
       .from(users)
       .where(inArray(users.email, seedEmails));

     if (existing.length > 0) {
       await tx.delete(users).where(inArray(users.id, existing.map((row) => row.id)));
     }

-    const passwordHash = await bcrypt.hash("SeedPassword123!", 12);
     await tx.insert(users).values(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/seed.ts` at line 81, Move the CPU-bound bcrypt.hash call out of the
transaction to avoid holding the DB connection during hashing: compute
passwordHash = await bcrypt.hash("SeedPassword123!", 12) before invoking
db.transaction(), then pass the precomputed passwordHash into the transaction
block where user creation or inserts occur (referencing passwordHash,
bcrypt.hash and db.transaction()) so the transaction only covers the DB
operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/seed.ts`:
- Line 71: The transaction callback uses an explicit, incorrect AppDb annotation
on the parameter (async (tx: AppDb) => ...)—remove the explicit type so
TypeScript/Drizzle can infer the transaction-specific type; update the
db.transaction call to use async (tx) => { ... } (or omit the annotation) and
leave rest of the logic unchanged to avoid the structural-typing mismatch.
- Line 81: Move the CPU-bound bcrypt.hash call out of the transaction to avoid
holding the DB connection during hashing: compute passwordHash = await
bcrypt.hash("SeedPassword123!", 12) before invoking db.transaction(), then pass
the precomputed passwordHash into the transaction block where user creation or
inserts occur (referencing passwordHash, bcrypt.hash and db.transaction()) so
the transaction only covers the DB operations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1032a619-ca68-4866-9e82-a569d8c4f051

📥 Commits

Reviewing files that changed from the base of the PR and between f320185 and 236af9f.

📒 Files selected for processing (1)
  • scripts/seed.ts

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.

Docs: Environment matrix runbook (Production / Preview / Local)

2 participants