Skip to content

Conversation

Brendonovich
Copy link
Member

@Brendonovich Brendonovich commented Oct 14, 2025

Hopefully will help with out video delete problems

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability of sign-up tracking.
    • More consistent handling when removing invites and members.
    • Stabilized video upload progress updates and post-upload cleanup.
  • Refactor

    • Standardized database result handling across actions.
    • Migrated core database integration to MySQL.
  • Chores

    • Switched environment config to a new MySQL connection URL.
    • Added mysql2 runtime dependency.
  • Configuration

    • Middleware now explicitly targets the Node.js runtime.

Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

Switched drizzle backend from PlanetScale to mysql2 and renamed environment secret/variable to DATABASE_URL_MYSQL. Updated DB call result handling to destructure first element and use affectedRows. Added runtime: "nodejs" to middleware config and adjusted video upload progress to insert when update affects zero rows.

Changes

Cohort / File(s) Summary of changes
DB integration migration
packages/database/index.ts, packages/database/auth/drizzle-adapter.ts, packages/database/package.json, infra/sst.config.ts
Replace planetscale drizzle integration with mysql2; change adapter parameter type to MySql2Database; add mysql2 dependency; rename/use secret/env to DATABASE_URL_MYSQL and update vercel variable/secrets accordingly.
DB result handling (actions & API)
apps/web/actions/analytics/track-user-signed-up.ts, apps/web/actions/organization/remove-invite.ts, apps/web/actions/organization/remove-member.ts, apps/web/app/api/desktop/[...route]/video.ts, apps/web/app/api/upload/[...route]/multipart.ts
Destructure DB results as [result] and replace rowsAffected checks with result.affectedRows; simplify post-operation existence/success guards; in video progress route, insert a videoUploads row when update affects zero rows.
Middleware config
apps/web/middleware.ts
Add runtime: "nodejs" to exported config declarations (no other behavior changes).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant API as Video Progress API
  participant DB as DB (mysql2 + drizzle)

  Note over API: Update progress
  Client->>API: PATCH /api/desktop/.../video (progress)
  API->>DB: UPDATE videoUploads SET progress=...
  DB-->>API: [result] { affectedRows: N }

  alt N > 0
    API-->>Client: 204 No Content
  else N == 0
    Note over API,DB: No matching row — insert new upload record
    API->>DB: INSERT INTO videoUploads (...)
    DB-->>API: insert result
    API-->>Client: 201 Created
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

Thump-thump I hop across the branch of code,
Swapped the planets for MySQL on the road.
I check affectedRows with a twitch of my nose,
If none were touched, I plant rows where it grows.
Runtime set to node — carrot deploys in tow. 🥕

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 succinctly describes the primary change—switching to a MySQL database driver—using clear and concise phrasing that directly reflects the core modifications in the pull request.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mysql-driver

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bdefea and bdc9ccb.

📒 Files selected for processing (1)
  • packages/database/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • packages/database/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • packages/database/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • packages/database/index.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (1)
packages/database/index.ts (1)

10-23: LGTM: Caching and helper utilities are correctly implemented.

The memoization pattern for the drizzle client and the updateIfDefined helper are correctly implemented. The COALESCE helper will be useful for MySQL column updates.


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
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
infra/sst.config.ts (1)

177-177: Remove outdated DATABASE_URL_HTTP reference and sync environment types

  • In infra/sst-env.d.ts (line 27), remove or rename the DATABASE_URL_HTTP entry so it matches the newly added DATABASE_URL_MYSQL in infra/sst.config.ts.
  • Confirm DATABASE_URL_MYSQL is provisioned in all SST environments (staging, production) before deploying this change.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55ff581 and 2bdefea.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • apps/web/actions/analytics/track-user-signed-up.ts (2 hunks)
  • apps/web/actions/organization/remove-invite.ts (2 hunks)
  • apps/web/actions/organization/remove-member.ts (2 hunks)
  • apps/web/app/api/desktop/[...route]/video.ts (2 hunks)
  • apps/web/app/api/upload/[...route]/multipart.ts (2 hunks)
  • apps/web/middleware.ts (1 hunks)
  • infra/sst.config.ts (1 hunks)
  • packages/database/auth/drizzle-adapter.ts (1 hunks)
  • packages/database/index.ts (1 hunks)
  • packages/database/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/api/upload/[...route]/multipart.ts
  • apps/web/app/api/desktop/[...route]/video.ts
  • apps/web/actions/organization/remove-invite.ts
  • apps/web/actions/analytics/track-user-signed-up.ts
  • apps/web/middleware.ts
  • apps/web/actions/organization/remove-member.ts
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/api/upload/[...route]/multipart.ts
  • apps/web/app/api/desktop/[...route]/video.ts
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/api/upload/[...route]/multipart.ts
  • apps/web/app/api/desktop/[...route]/video.ts
  • apps/web/actions/organization/remove-invite.ts
  • apps/web/actions/analytics/track-user-signed-up.ts
  • apps/web/middleware.ts
  • apps/web/actions/organization/remove-member.ts
  • infra/sst.config.ts
  • packages/database/auth/drizzle-adapter.ts
  • packages/database/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/api/upload/[...route]/multipart.ts
  • apps/web/app/api/desktop/[...route]/video.ts
  • apps/web/actions/organization/remove-invite.ts
  • apps/web/actions/analytics/track-user-signed-up.ts
  • apps/web/middleware.ts
  • apps/web/actions/organization/remove-member.ts
  • infra/sst.config.ts
  • packages/database/auth/drizzle-adapter.ts
  • packages/database/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/api/upload/[...route]/multipart.ts
  • apps/web/app/api/desktop/[...route]/video.ts
  • apps/web/actions/organization/remove-invite.ts
  • apps/web/actions/analytics/track-user-signed-up.ts
  • apps/web/middleware.ts
  • apps/web/actions/organization/remove-member.ts
  • infra/sst.config.ts
  • packages/database/auth/drizzle-adapter.ts
  • packages/database/index.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/api/upload/[...route]/multipart.ts
  • apps/web/app/api/desktop/[...route]/video.ts
  • apps/web/actions/organization/remove-invite.ts
  • apps/web/actions/analytics/track-user-signed-up.ts
  • apps/web/middleware.ts
  • apps/web/actions/organization/remove-member.ts
apps/web/actions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

All Groq/OpenAI calls must be implemented in Next.js Server Actions under apps/web/actions; do not place AI calls elsewhere

Files:

  • apps/web/actions/organization/remove-invite.ts
  • apps/web/actions/analytics/track-user-signed-up.ts
  • apps/web/actions/organization/remove-member.ts
🧬 Code graph analysis (6)
apps/web/app/api/upload/[...route]/multipart.ts (1)
packages/database/index.ts (1)
  • db (13-20)
apps/web/app/api/desktop/[...route]/video.ts (1)
packages/database/index.ts (1)
  • db (13-20)
apps/web/actions/organization/remove-invite.ts (1)
packages/database/index.ts (1)
  • db (13-20)
apps/web/actions/analytics/track-user-signed-up.ts (1)
packages/database/index.ts (1)
  • db (13-20)
apps/web/actions/organization/remove-member.ts (1)
packages/database/index.ts (1)
  • db (13-20)
packages/database/auth/drizzle-adapter.ts (1)
packages/database/index.ts (1)
  • db (13-20)
🪛 GitHub Check: Typecheck
packages/database/index.ts

[failure] 8-8:
Argument of type '[string | undefined]' is not assignable to parameter of type '[string | AnyMySql2Connection] | [string | AnyMySql2Connection, MySql2DrizzleConfig<Record<string, never>>] | [...]'.


[failure] 8-8:
Argument of type '[string | undefined]' is not assignable to parameter of type '[string | AnyMySql2Connection] | [string | AnyMySql2Connection, MySql2DrizzleConfig<Record<string, never>>] | [...]'.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (11)
packages/database/package.json (2)

32-32: LGTM! mysql2 dependency added.

The mysql2 dependency has been correctly added to support the migration from PlanetScale to a MySQL2-based backend.


23-25: Remove @mattrax/mysql-planetscale—unused in code; keep @planetscale/database (still imported in packages/database/index.ts) until the mysql2 migration is complete.

apps/web/middleware.ts (1)

120-121: LGTM! Node.js runtime required for mysql2.

The addition of runtime: "nodejs" is necessary because mysql2 requires Node.js-specific features and cannot run in Edge runtime. This aligns with the migration to mysql2 in the database layer.

packages/database/index.ts (1)

5-5: LGTM! Correct import for mysql2.

The import has been correctly updated to use drizzle-orm/mysql2 instead of the PlanetScale-specific driver.

apps/web/app/api/desktop/[...route]/video.ts (1)

351-371: LGTM! Correct result handling for mysql2.

The changes correctly adapt to mysql2's result structure:

  • Destructuring [result] extracts the first element from the result array
  • Using result.affectedRows (mysql2 property) instead of result.rowsAffected
  • Adding an insert fallback when no rows are affected provides upsert-like behavior

This pattern is consistent across the codebase changes in this PR.

apps/web/actions/organization/remove-invite.ts (1)

34-43: LGTM! Consistent result handling for mysql2.

The changes correctly update the delete result handling to match mysql2's structure:

  • Destructuring [result] from the delete operation
  • Using result.affectedRows instead of result.rowsAffected
  • Simplified error handling with a single-line guard

This aligns with the pattern used throughout this PR.

apps/web/actions/analytics/track-user-signed-up.ts (1)

36-45: LGTM! Correct result handling for mysql2.

The update result handling has been correctly adapted:

  • Destructuring [result] from the update operation
  • Using result.affectedRows to determine if the update succeeded

This ensures the tracking event only fires when the database update actually modifies a row, maintaining correct idempotency.

packages/database/auth/drizzle-adapter.ts (2)

4-4: LGTM! Correct type import for mysql2.

The import has been correctly updated to use MySql2Database type from drizzle-orm/mysql2 instead of PlanetScale-specific types.


10-10: LGTM! Adapter signature updated for mysql2.

The function signature has been correctly updated to accept MySql2Database instead of PlanetScaleDatabase. The adapter logic remains unchanged because drizzle-orm provides compatible interfaces across MySQL drivers.

apps/web/app/api/upload/[...route]/multipart.ts (1)

303-322: LGTM! Consistent result handling for mysql2.

The update result handling has been correctly adapted to mysql2:

  • Destructuring [result] from the update operation
  • Using result.affectedRows to verify the update succeeded
  • Conditionally deleting videoUploads only when the update affected rows

The authentication check (line 318 comment) remains valid: if affectedRows > 0, the user owns the video and the update succeeded.

apps/web/actions/organization/remove-member.ts (1)

54-63: Delete result destructuring is correct for MySQL. Drizzle’s mysql2 adapter always returns an array whose first element is a metadata object containing affectedRows, so const [result] = await db().delete(...); is safe.

{ key: "CAP_AWS_BUCKET", value: recordingsBucket.bucket },
{ key: "NEXT_PUBLIC_CAP_AWS_BUCKET", value: recordingsBucket.bucket },
{ key: "DATABASE_URL", value: secrets.DATABASE_URL_HTTP.value },
{ key: "DATABASE_URL_MYSQL", value: secrets.DATABASE_URL_MYSQL.value },
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Verify environment variable name expected by the application.

The Vercel environment variable is being set with key DATABASE_URL_MYSQL, but application code typically expects DATABASE_URL. On line 291, the workflow cluster is configured with DATABASE_URL: secrets.DATABASE_URL_MYSQL.value, suggesting the application expects DATABASE_URL as the key.

Apply this diff if the application expects DATABASE_URL:

-			{ key: "DATABASE_URL_MYSQL", value: secrets.DATABASE_URL_MYSQL.value },
+			{ key: "DATABASE_URL", value: secrets.DATABASE_URL_MYSQL.value },

Alternatively, if the application has been updated to use DATABASE_URL_MYSQL, verify with:

#!/bin/bash
# Description: Check which environment variable name is used in the application code

echo "=== Searching for DATABASE_URL usage in application code ==="
rg -n "process\.env\.DATABASE_URL[^_]|DATABASE_URL[^_]" apps/web/ packages/database/ --type ts

echo "=== Searching for DATABASE_URL_MYSQL usage ==="
rg -n "process\.env\.DATABASE_URL_MYSQL|DATABASE_URL_MYSQL" apps/web/ packages/database/ --type ts
🤖 Prompt for AI Agents
In infra/sst.config.ts around line 52, the environment variable key is set to
DATABASE_URL_MYSQL but the application (and another workflow entry at line 291)
expects DATABASE_URL; change the key to DATABASE_URL while keeping the secret
value (e.g., { key: "DATABASE_URL", value: secrets.DATABASE_URL_MYSQL.value })
and ensure any other env entries or workflow configs use the same DATABASE_URL
name so they match the application; if instead the app truly uses
DATABASE_URL_MYSQL, update the other workflow/config at line 291 to use
DATABASE_URL_MYSQL consistently.

Comment on lines 7 to 9
function createDrizzle() {
const URL = process.env.DATABASE_URL!;

let fetchHandler: Promise<Config["fetch"]> | undefined;

if (URL.startsWith("mysql://")) {
fetchHandler = import("@mattrax/mysql-planetscale").then((m) =>
m.createFetchHandler(URL),
);
}

const connection = new Client({
url: URL,
fetch: async (input, init) => {
return await ((await fetchHandler) || fetch)(input, init);
},
});

return drizzle(connection);
return drizzle(process.env.DATABASE_URL_MYSQL);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix: DATABASE_URL_MYSQL must be validated as non-undefined.

Line 8 passes process.env.DATABASE_URL_MYSQL directly to drizzle(), but this value could be undefined. TypeScript correctly flags this as a type error. If the environment variable is missing, the application will fail at runtime with cryptic errors.

Apply this diff to ensure the environment variable exists:

 function createDrizzle() {
-	return drizzle(process.env.DATABASE_URL_MYSQL);
+	const url = process.env.DATABASE_URL_MYSQL;
+	if (!url) {
+		throw new Error("DATABASE_URL_MYSQL environment variable is not set");
+	}
+	return drizzle(url);
 }

Alternatively, if you're using a validated environment helper (like @cap/env), use that instead:

import { serverEnv } from "@cap/env";

function createDrizzle() {
	return drizzle(serverEnv().DATABASE_URL_MYSQL);
}
🧰 Tools
🪛 GitHub Check: Typecheck

[failure] 8-8:
Argument of type '[string | undefined]' is not assignable to parameter of type '[string | AnyMySql2Connection] | [string | AnyMySql2Connection, MySql2DrizzleConfig<Record<string, never>>] | [...]'.


[failure] 8-8:
Argument of type '[string | undefined]' is not assignable to parameter of type '[string | AnyMySql2Connection] | [string | AnyMySql2Connection, MySql2DrizzleConfig<Record<string, never>>] | [...]'.

🤖 Prompt for AI Agents
In packages/database/index.ts around lines 7 to 9, the call
drizzle(process.env.DATABASE_URL_MYSQL) may receive undefined; validate the
environment variable before passing it. Update the function to read the variable
into a local const, throw a clear error if it's undefined or empty, and then
pass that validated string to drizzle (or replace with your validated env helper
like serverEnv().DATABASE_URL_MYSQL if available).

@Brendonovich Brendonovich merged commit 8efc75f into main Oct 14, 2025
15 checks 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