Skip to content

chore: bump npm dependencies#102

Merged
coji merged 4 commits intomainfrom
chore/bump-dependencies
Jan 10, 2026
Merged

chore: bump npm dependencies#102
coji merged 4 commits intomainfrom
chore/bump-dependencies

Conversation

@coji
Copy link
Owner

@coji coji commented Jan 10, 2026

Summary

  • Update npm dependencies including better-auth, shadcn/ui components, and other packages
  • Fix OAuth sign-in flow: properly handle asResponse option to pass cookies through redirect
  • Update CLAUDE.md with server-side code conventions and form handling patterns

Test plan

  • Verify Google OAuth login works correctly
  • Run pnpm validate to ensure build and tests pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Team management and team-member support; sessions track active organization and team.
  • Documentation

    • Expanded docs: server-side conventions, form handling examples, and routing patterns with intent-based dispatch.
  • Style

    • Minor UI sizing and visual indicator tweaks for improved layout consistency.
  • Chores

    • Database schema and migrations added for teams/invitations and schema revisions; dependencies and build tooling updated; new auth-related env vars.

✏️ Tip: You can customize this high-level summary in your review settings.

- Update better-auth and fix OAuth sign-in flow
- Fix asResponse handling in signInSocial to properly pass cookies
- Update shadcn/ui components
- Update CLAUDE.md with server-side code conventions
- Various package updates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Warning

Rate limit exceeded

@coji has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ee8a02a and 37779d0.

⛔ Files ignored due to path filters (1)
  • db/migrations/atlas.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • db/migrations/20260110093253.sql
  • db/schema.sql
📝 Walkthrough

Walkthrough

Adds team support and richer auth/session/account mappings, migrates DB schema to an Atlas-style baseline (teams/team_members, atlas_schema_revisions), updates env/types and many dependencies, removes/renames unused route parameters, tweaks UI lint notes/styles, and converts some handlers to async.

Changes

Cohort / File(s) Summary
Docs & Tooling
CLAUDE.md, biome.json, vite.config.ts, .env.example
Docs expanded; biome config upgraded (assist/includes); Vite adds devtoolsJson() plugin; .env.example adds BETTER_AUTH_SECRET and BETTER_AUTH_URL.
Environment Types
app/libs/dotenv.server.ts
Adds BETTER_AUTH_URL to env schema and NodeJS.ProcessEnv typing.
Authentication config
app/libs/auth.server.ts, app/routes/_auth+/login.tsx, app/routes/api.auth.$/route.ts
Switches auth baseURL to BETTER_AUTH_URL; adds account/session/invitation mappings (refreshTokenExpiresAt, activeTeamId, activeOrganizationId, inviter/team fields); enables teams plugin; login uses asResponse: true; auth handlers made async/await.
Database schema & migrations
db/schema.sql, db/migrations/20260110075838.sql, db/migrations/20260110092446.sql, db/seed.ts
Large Atlas-style schema baseline added (atlas_schema_revisions, teams, team_members), invitations.created_at column added via migration, sessions gained active_team_id, many PK/FK/index changes; seed simplified (unused result dropped).
Types
app/services/type.ts
Adds AtlasSchemaRevisions interface; adds createdAt to Invitations; extends DB interface with atlasSchemaRevisions.
Route signatures & handlers
multiple app/routes/* (e.g., admin+/*, resources+/organization/*, _dashboard+/*, admin settings files)
Removed/renamed unused params (prefixed _ or dropped), converted some loaders/actions to async, propagated ...rest in admin settings action to sub-actions, simplified component props.
UI lint annotations & styling
app/components/ui/* (breadcrumb, carousel, chart, pagination, sidebar, slider)
Updated biome-ignore comments to reference "shadcn-ui issue"; adjusted accessibility suppression placement; minor style tweaks (sidebar rail indicator width, slider data attribute, chart tooltip width, breadcrumb wrap class).
Component logic & cache
app/components/AppDataTable.tsx, app/services/cache.server.ts
AppDataTable initializes columnVisibility via Object.fromEntries instead of reduce; cache comment clarified; no behavioral changes.
Batch & utilities
batch/provider/github/release-detect.ts, app/routes/admin+/$organization.repositories.add/functions/*
Added null guard for merged_at, removed some non-null assertions, renamed unused params with _, changed initial cursor init behavior for first GraphQL request.
Package management
package.json
Extensive dependency bumps and devDependency updates; formatting scripts use --experimental-cli; db:generate script simplified.
Entry server / SSR
app/entry.server.tsx
Renamed unused loadContext param to _loadContext; destructuring of render result drops abort (keeps pipe) in both bot/browser paths.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Server
    participant AuthProvider
    participant DB

    Client->>Server: POST /_auth+/login (social sign-in)
    Server->>AuthProvider: signInSocial(request, { callbackURL:'/', asResponse:true })
    AuthProvider-->>Server: { url, headers, ... } (asResponse)
    Server->>DB: upsert/account/session mappings (refresh tokens, activeTeamId, inviter, created_at)
    Server-->>Client: redirect to provided url (forwards headers)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰
I hopped through schemas, added teams in spring,
Tokens and sessions now have extra bling,
Migrations marched forward, deps took a spin,
Lint notes corrected, unused names trimmed thin,
This rabbit applauds the code — a joyful ping!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Title check ❓ Inconclusive The title 'chore: bump npm dependencies' is only partially related to the changeset. While dependency updates are present (package.json), the PR includes substantial functional changes: auth system overhaul (BETTER_AUTH_URL, OAuth flow fixes), database schema expansion (teams, team_members, atlas_schema_revisions), and documentation updates. The title focuses on the mechanical change and omits the significant business logic enhancements. Consider using a more comprehensive title such as 'chore: bump dependencies and enhance team/auth capabilities' or 'feat: add team management and improve OAuth flow with dependency updates' to better reflect the scope of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
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.

Copy link

@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: 6

Caution

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

⚠️ Outside diff range comments (3)
app/services/cache.server.ts (1)

4-18: Fix return type inconsistency in getCachedData.

The function signature declares a Promise<T> return type, but line 12 returns the raw cached data instead of a Promise. This creates a type mismatch: the loader path returns Promise<T> (line 14–17), but the cache hit path returns T directly (line 12). Callers expecting a Promise will fail.

🐛 Proposed fix: wrap cached data in Promise.resolve()
  if (entry && entry.expires > now) {
-   return entry.data
+   return Promise.resolve(entry.data)
  }
app/routes/resources+/organization/functions/queries.ts (1)

3-10: Use Members table to filter organizations by user - critical authorization bug.

The function returns all organizations in the database instead of only the organizations the user is a member of. The userId parameter is accepted but never used in the query, allowing users to see all organizations.

Based on the database schema, organizations are linked to users via the Members table. The query needs to filter using this relationship:

Fix: Join with Members table to enforce authorization
-export const listUserOrganizations = async (_userId: string) => {
+export const listUserOrganizations = async (userId: string) => {
   const teams = await db
     .selectFrom('organizations')
+    .innerJoin('members', 'members.organizationId', 'organizations.id')
+    .where('members.userId', '=', userId)
     .select(['id', 'name'])
     .orderBy('organizations.createdAt')
     .execute()
   return teams
 }
app/routes/admin+/$organization.settings/forms/organization-settings.action.server.ts (1)

35-42: Log the caught error for debugging and monitoring.

The error is caught but not logged, making it difficult to diagnose failures in production. While returning a generic message to the user is appropriate for security, the actual error details should be logged for operational visibility.

📊 Suggested fix to add error logging
-  } catch (_e) {
+  } catch (error) {
+    console.error('Failed to update organization:', error)
     return {
       intent: INTENTS.organizationSettings,
       lastResult: submission.reply({
🤖 Fix all issues with AI agents
In @app/libs/dotenv.server.ts:
- Line 5: Add the missing BETTER_AUTH_URL env var to .env.example and document
it: update .env.example to include a line like
BETTER_AUTH_URL=https://auth.example.com (or an appropriate example), and add a
short comment or README note explaining its purpose and usage; ensure you
mention that BETTER_AUTH_URL is required by app/libs/auth.server.ts and must be
set in development, staging, and production deployments so the zod schema
(BETTER_AUTH_URL) validation and runtime code depending on it succeed.

In @app/routes/_auth+/login.tsx:
- Around line 31-39: Check the response from auth.api.signInSocial and handle
failures and JSON parse errors defensively: after calling auth.api.signInSocial
(response variable) verify response.ok and handle non-OK by logging/throwing or
returning redirect('/') with no sensitive headers; wrap await response.json() in
try/catch and fallback to an empty object if parsing fails; when returning
redirect, forward only specific safe headers from response.headers (e.g.,
'set-cookie' and 'location' if present) instead of copying all headers; update
the code around auth.api.signInSocial, response, data, and the redirect call to
implement these checks and selective header copying.

In @app/services/type.ts:
- Around line 28-41: The generated AtlasSchemaRevisions type has partialHashes
typed as string | null but the DB column partial_hashes is json NULL; update the
type to use JSONColumnType (so Select resolves to object | null) by regenerating
types with the codegen: run npm run db:generate to refresh generated types, or
manually change the AtlasSchemaRevisions.partialHashes declaration to
JSONColumnType<object | null, unknown> if immediate edit is needed, ensuring the
symbol AtlasSchemaRevisions and its partialHashes member are updated
accordingly.

In @db/migrations/20260110075838.sql:
- Around line 1-2: The migration adds a NOT NULL `created_at` column to
`invitations` which will fail on SQLite if the table has existing rows; modify
the ALTER TABLE statement that adds `created_at` (the `ALTER TABLE "invitations"
ADD COLUMN "created_at" datetime NOT NULL;` line) to include a default timestamp
so existing rows get a value, e.g. `ADD COLUMN created_at datetime NOT NULL
DEFAULT (CURRENT_TIMESTAMP)` (or `DEFAULT CURRENT_TIMESTAMP` for your SQL
dialect), then re-run or regenerate the migration.

In @db/schema.sql:
- Around line 18-44: The users table lacks a uniqueness constraint on
users.email and the external auth mapping table needs a uniqueness constraint
for provider identity; add a UNIQUE index on users(email) (e.g.,
users_email_key) and add a UNIQUE index on provider_accounts(provider,
provider_account_id) (e.g., provider_accounts_provider_account_id_key) so
external provider identities cannot be duplicated and account linking remains
deterministic.
- Around line 101-115: Add a proper foreign key for invitations.team_id
referencing teams(id) (pick desired ON DELETE behavior, e.g., ON DELETE SET NULL
or CASCADE) and update the invitations table definition to include that
CONSTRAINT (e.g., invitations_team_id_fkey); also change any accidental `date`
column types in the teams and team_members tables to proper datetime/timestamp
types and replace placeholder constraint names like `0` / `1` with meaningful
names (e.g., teams_created_at_not_null, team_members_pk or
team_members_user_team_fkey) so the schema is consistent; apply the same fixes
to the other affected blocks (around lines 220–245) ensuring foreign keys
reference the correct columns and use clear constraint names.
🧹 Nitpick comments (11)
app/routes/admin+/$organization.repositories.add/functions/get-repositories-by-owner-and-keyword.ts (1)

72-80: Avoid any here; type the node shape (and consider nullable nodes) instead.
Right now the any + suppression can hide real schema mismatches; also nodes can be nullable in GitHub GraphQL, so mapping without a null guard can throw.

Proposed change
+type RepoNode = {
+  id: string
+  name: string
+  visibility: string
+  pushedAt: string | null
+  owner: { login: string }
+}
+
   const repos: Repository[] = repoData.nodes
-    // biome-ignore lint/suspicious/noExplicitAny: 型定義が面倒なのでanyで受け取る
-    .map((node: any) => ({
-      id: node.id,
-      owner: node.owner.login,
-      name: node.name,
-      visibility: node.visibility,
-      pushedAt: node.pushedAt,
-    }))
+    .filter((n: unknown): n is RepoNode => n != null)
+    .map((node) => ({
+      id: node.id,
+      owner: node.owner.login,
+      name: node.name,
+      visibility: node.visibility,
+      pushedAt: node.pushedAt,
+    }))
app/components/AppDataTable.tsx (1)

38-48: Simplify redundant type guard in the mapping function.

The ternary check 'accessorKey' in column ? column.accessorKey : '' on line 45 is redundant because the filter on lines 40-42 already guarantees that 'accessorKey' in column is true for all items reaching the map. TypeScript's type narrowing should allow you to access column.accessorKey directly.

♻️ Proposed simplification
      Object.fromEntries(
        columns
          .filter(
            (column) =>
              'accessorKey' in column && column.enableHiding !== false,
          )
          .map((column) => [
-            column.id ?? ('accessorKey' in column ? column.accessorKey : ''),
+            column.id ?? column.accessorKey,
            false,
          ]),
      ),
app/routes/admin+/$organization.repositories.add/functions/get-unique-owners.ts (1)

32-48: Consider adding error handling for GitHub API calls.

The pagination loops don't validate the response structure before accessing nested properties. If the GitHub API returns an error (e.g., rate limit, invalid token, network failure), the code will throw when accessing json.data.viewer.

Consider adding error checking:

const json = await res.json()
if (json.errors || !json.data) {
  throw new Error(`GitHub API error: ${JSON.stringify(json.errors)}`)
}

This would provide clearer error messages and make debugging easier, especially relevant given the OAuth authentication improvements in this PR.

Also applies to: 76-92

app/routes/admin+/$organization._layout/route.tsx (1)

86-89: LGTM! Unnecessary fragment removed.

The React fragment wrapper was redundant since AppBreadcrumbs and Outlet are already contained within a parent <div>. The simplification is correct and has no functional impact.

app/components/ui/chart.tsx (1)

173-177: LGTM! Standardized Tailwind utility class.

The change from min-w-[8rem] to min-w-32 is semantically equivalent (both equal 8rem) and follows Tailwind best practices by using the standard utility class instead of an arbitrary value.

app/routes/admin+/$organization.members/route.tsx (1)

14-20: LGTM! Removed unused request parameter.

The loader function only uses params, so removing the unused request parameter is a good cleanup that simplifies the function signature.

app/routes/resources+/organization/route.tsx (1)

37-37: Consider using English for lint suppression comments.

The comment explains why the exhaustive deps check is suppressed, but it's written in Japanese. For better accessibility to international contributors, consider using English comments throughout the codebase.

📝 Suggested revision
-  // biome-ignore lint/correctness/useExhaustiveDependencies: fetcher.loadは安定している
+  // biome-ignore lint/correctness/useExhaustiveDependencies: fetcher.load is stable
app/entry.server.tsx (1)

43-75: Consider using abort for stream timeout handling.

The abort method is no longer destructured from renderToPipeableStream, but the file defines streamTimeout = 30000 (line 10) which is never used. In production SSR, streams should typically be aborted after a timeout to prevent hanging requests and resource leaks.

React's streaming API provides abort() for this purpose. Without timeout handling, slow-rendering pages could consume server resources indefinitely.

⏱️ Proposed implementation with timeout handling
 function handleBotRequest(
   request: Request,
   responseStatusCode: number,
   responseHeaders: Headers,
   reactRouterContext: EntryContext,
 ) {
   let statusCode = responseStatusCode
   return new Promise((resolve, reject) => {
     let shellRendered = false
-    const { pipe } = renderToPipeableStream(
+    const { pipe, abort } = renderToPipeableStream(
       <ServerRouter context={reactRouterContext} url={request.url} />,
       {
         onAllReady() {
           shellRendered = true
           const body = new PassThrough()
           const stream = createReadableStreamFromReadable(body)

           responseHeaders.set('Content-Type', 'text/html')

           resolve(
             new Response(stream, {
               headers: responseHeaders,
               status: statusCode,
             }),
           )

           pipe(body)
         },
         onShellError(error: unknown) {
           reject(error)
         },
         onError(error: unknown) {
           statusCode = 500
           if (shellRendered) {
             consola.error(error)
           }
         },
       },
     )
+
+    setTimeout(() => {
+      abort()
+    }, streamTimeout)
   })
 }

 function handleBrowserRequest(
   request: Request,
   responseStatusCode: number,
   responseHeaders: Headers,
   reactRouterContext: EntryContext,
 ) {
   let statusCode = responseStatusCode
   return new Promise((resolve, reject) => {
     let shellRendered = false
-    const { pipe } = renderToPipeableStream(
+    const { pipe, abort } = renderToPipeableStream(
       <ServerRouter context={reactRouterContext} url={request.url} />,
       {
         onShellReady() {
           shellRendered = true
           const body = new PassThrough()
           const stream = createReadableStreamFromReadable(body)

           responseHeaders.set('Content-Type', 'text/html')

           resolve(
             new Response(stream, {
               headers: responseHeaders,
               status: statusCode,
             }),
           )

           pipe(body)
         },
         onShellError(error: unknown) {
           reject(error)
         },
         onError(error: unknown) {
           statusCode = 500
           if (shellRendered) {
             consola.error(error)
           }
         },
       },
     )
+
+    setTimeout(() => {
+      abort()
+    }, streamTimeout)
   })
 }

Also applies to: 88-120

package.json (1)

16-16: db:generate can produce stale types unless migrations are applied to ./data/data.db first.
Consider chaining atlas migrate apply (or pnpm run setup) before codegen to keep app/services/type.ts aligned with schema.

Proposed adjustment
-    "db:generate": "kysely-codegen --dialect sqlite --out-file app/services/type.ts --url ./data/data.db --camel-case",
+    "db:generate": "atlas migrate apply --env local --url 'sqlite://data/data.db' && kysely-codegen --dialect sqlite --out-file app/services/type.ts --url ./data/data.db --camel-case",
app/routes/_dashboard+/$organization.ongoing/route.tsx (1)

32-34: Good simplification: only consume pullRequests in the component.
Optional: if from/to truly aren’t needed client-side, stop returning them from loader to shrink payload.

app/routes/api.auth.$/route.ts (1)

4-10: Async change is fine; optional: drop redundant await.

Small cleanup
 export const loader = async ({ request }: Route.LoaderArgs) => {
-  return await auth.handler(request)
+  return auth.handler(request)
 }

 export const action = async ({ request }: Route.ActionArgs) => {
-  return await auth.handler(request)
+  return auth.handler(request)
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4e434a and aab689a.

⛔ Files ignored due to path filters (2)
  • db/migrations/atlas.sum is excluded by !**/*.sum
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • CLAUDE.md
  • app/components/AppDataTable.tsx
  • app/components/ui/breadcrumb.tsx
  • app/components/ui/carousel.tsx
  • app/components/ui/chart.tsx
  • app/components/ui/pagination.tsx
  • app/components/ui/sidebar.tsx
  • app/components/ui/slider.tsx
  • app/entry.server.tsx
  • app/libs/auth.server.ts
  • app/libs/dotenv.server.ts
  • app/routes/_auth+/login.tsx
  • app/routes/_dashboard+/$organization.ongoing/route.tsx
  • app/routes/_dashboard+/_layout.tsx
  • app/routes/admin+/$organization._layout/route.tsx
  • app/routes/admin+/$organization.members/route.tsx
  • app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx
  • app/routes/admin+/$organization.repositories.add/functions/get-repositories-by-owner-and-keyword.ts
  • app/routes/admin+/$organization.repositories.add/functions/get-unique-owners.ts
  • app/routes/admin+/$organization.settings/forms/organization-settings.action.server.ts
  • app/routes/admin+/$organization.settings/route.tsx
  • app/routes/admin+/_index/route.tsx
  • app/routes/api.auth.$/route.ts
  • app/routes/resources+/organization/functions/queries.ts
  • app/routes/resources+/organization/route.tsx
  • app/services/cache.server.ts
  • app/services/type.ts
  • batch/provider/github/release-detect.ts
  • biome.json
  • db/migrations/20260110075838.sql
  • db/schema.sql
  • db/seed.ts
  • package.json
  • vite.config.ts
🧰 Additional context used
📓 Path-based instructions (9)
app/routes/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use remix-flat-routes with the + folder syntax for file-based routing, following conventions: _layout.tsx for layout routes, _index.tsx for index routes, $param for dynamic segments, and $organization.settings/ for nested route folders

Files:

  • app/routes/_auth+/login.tsx
  • app/routes/_dashboard+/$organization.ongoing/route.tsx
  • app/routes/admin+/$organization._layout/route.tsx
  • app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx
  • app/routes/resources+/organization/route.tsx
  • app/routes/admin+/$organization.members/route.tsx
  • app/routes/admin+/$organization.settings/route.tsx
  • app/routes/api.auth.$/route.ts
  • app/routes/resources+/organization/functions/queries.ts
  • app/routes/admin+/_index/route.tsx
  • app/routes/admin+/$organization.repositories.add/functions/get-repositories-by-owner-and-keyword.ts
  • app/routes/_dashboard+/_layout.tsx
  • app/routes/admin+/$organization.settings/forms/organization-settings.action.server.ts
  • app/routes/admin+/$organization.repositories.add/functions/get-unique-owners.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use path alias ~/ for imports from project root (e.g., import { db } from '~/app/services/db.server')

Files:

  • app/routes/_auth+/login.tsx
  • app/components/ui/carousel.tsx
  • app/entry.server.tsx
  • app/components/ui/sidebar.tsx
  • app/services/cache.server.ts
  • app/routes/_dashboard+/$organization.ongoing/route.tsx
  • app/routes/admin+/$organization._layout/route.tsx
  • app/components/ui/chart.tsx
  • app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx
  • app/components/ui/pagination.tsx
  • app/routes/resources+/organization/route.tsx
  • app/routes/admin+/$organization.members/route.tsx
  • app/components/ui/slider.tsx
  • app/components/ui/breadcrumb.tsx
  • app/components/AppDataTable.tsx
  • app/services/type.ts
  • app/routes/admin+/$organization.settings/route.tsx
  • db/seed.ts
  • app/routes/api.auth.$/route.ts
  • app/routes/resources+/organization/functions/queries.ts
  • app/routes/admin+/_index/route.tsx
  • batch/provider/github/release-detect.ts
  • app/routes/admin+/$organization.repositories.add/functions/get-repositories-by-owner-and-keyword.ts
  • app/routes/_dashboard+/_layout.tsx
  • app/libs/dotenv.server.ts
  • app/routes/admin+/$organization.settings/forms/organization-settings.action.server.ts
  • vite.config.ts
  • app/routes/admin+/$organization.repositories.add/functions/get-unique-owners.ts
  • app/libs/auth.server.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Biome for linting and Prettier for formatting code throughout the project

Files:

  • app/routes/_auth+/login.tsx
  • app/components/ui/carousel.tsx
  • app/entry.server.tsx
  • app/components/ui/sidebar.tsx
  • app/services/cache.server.ts
  • app/routes/_dashboard+/$organization.ongoing/route.tsx
  • app/routes/admin+/$organization._layout/route.tsx
  • app/components/ui/chart.tsx
  • app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx
  • app/components/ui/pagination.tsx
  • app/routes/resources+/organization/route.tsx
  • app/routes/admin+/$organization.members/route.tsx
  • app/components/ui/slider.tsx
  • app/components/ui/breadcrumb.tsx
  • app/components/AppDataTable.tsx
  • app/services/type.ts
  • app/routes/admin+/$organization.settings/route.tsx
  • db/seed.ts
  • app/routes/api.auth.$/route.ts
  • app/routes/resources+/organization/functions/queries.ts
  • app/routes/admin+/_index/route.tsx
  • batch/provider/github/release-detect.ts
  • app/routes/admin+/$organization.repositories.add/functions/get-repositories-by-owner-and-keyword.ts
  • app/routes/_dashboard+/_layout.tsx
  • app/libs/dotenv.server.ts
  • app/routes/admin+/$organization.settings/forms/organization-settings.action.server.ts
  • vite.config.ts
  • app/routes/admin+/$organization.repositories.add/functions/get-unique-owners.ts
  • app/libs/auth.server.ts
app/components/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Place React components in app/components/ directory with UI components from shadcn/ui in app/components/ui/ subdirectory

Files:

  • app/components/ui/carousel.tsx
  • app/components/ui/sidebar.tsx
  • app/components/ui/chart.tsx
  • app/components/ui/pagination.tsx
  • app/components/ui/slider.tsx
  • app/components/ui/breadcrumb.tsx
  • app/components/AppDataTable.tsx
{app/components/**/*.{tsx,ts},tailwind.config.*}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Tailwind CSS v4 for styling alongside shadcn/ui components with new-york style variant

Files:

  • app/components/ui/carousel.tsx
  • app/components/ui/sidebar.tsx
  • app/components/ui/chart.tsx
  • app/components/ui/pagination.tsx
  • app/components/ui/slider.tsx
  • app/components/ui/breadcrumb.tsx
  • app/components/AppDataTable.tsx
**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Kysely for runtime queries and ensure types are generated to app/services/type.ts via kysely-codegen

Files:

  • app/entry.server.tsx
  • app/services/cache.server.ts
  • app/libs/dotenv.server.ts
  • app/routes/admin+/$organization.settings/forms/organization-settings.action.server.ts
  • app/libs/auth.server.ts
app/services/**/*.server.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Organize server-side logic in the app/services/ directory with db.server.ts for Kysely database client and type.ts for generated Kysely types

Files:

  • app/services/cache.server.ts
db/migrations/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

Use Atlas for declarative schema management and versioned SQL migrations stored in db/migrations/

Files:

  • db/migrations/20260110075838.sql
app/libs/auth.server.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use better-auth with Google OAuth for authentication, configured in app/libs/auth.server.ts, supporting organization-based access

Files:

  • app/libs/auth.server.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/libs/auth.server.ts : Use better-auth with Google OAuth for authentication, configured in `app/libs/auth.server.ts`, supporting organization-based access
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to {app/components/**/*.{tsx,ts},tailwind.config.*} : Use Tailwind CSS v4 for styling alongside shadcn/ui components with new-york style variant

Applied to files:

  • app/components/ui/sidebar.tsx
  • app/components/ui/chart.tsx
  • app/components/ui/pagination.tsx
  • app/components/ui/slider.tsx
  • app/components/ui/breadcrumb.tsx
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/components/**/*.{tsx,ts} : Place React components in `app/components/` directory with UI components from shadcn/ui in `app/components/ui/` subdirectory

Applied to files:

  • app/components/ui/sidebar.tsx
  • app/components/ui/pagination.tsx
  • app/components/ui/breadcrumb.tsx
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/routes/**/*.{tsx,ts} : Use `remix-flat-routes` with the `+` folder syntax for file-based routing, following conventions: `_layout.tsx` for layout routes, `_index.tsx` for index routes, `$param` for dynamic segments, and `$organization.settings/` for nested route folders

Applied to files:

  • app/routes/_dashboard+/$organization.ongoing/route.tsx
  • app/routes/admin+/$organization._layout/route.tsx
  • app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx
  • app/routes/resources+/organization/route.tsx
  • app/routes/admin+/$organization.members/route.tsx
  • app/routes/admin+/$organization.settings/route.tsx
  • app/routes/api.auth.$/route.ts
  • app/routes/admin+/_index/route.tsx
  • app/routes/_dashboard+/_layout.tsx
  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use Biome for linting and Prettier for formatting code throughout the project

Applied to files:

  • package.json
  • biome.json
  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Write unit tests with Vitest and E2E tests with Playwright following the test directory structure

Applied to files:

  • package.json
  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to db/migrations/*.sql : Use Atlas for declarative schema management and versioned SQL migrations stored in `db/migrations/`

Applied to files:

  • app/services/type.ts
  • db/schema.sql
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/services/**/*.server.ts : Organize server-side logic in the `app/services/` directory with `db.server.ts` for Kysely database client and `type.ts` for generated Kysely types

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to **/*.{ts,tsx} : Use path alias `~/` for imports from project root (e.g., `import { db } from '~/app/services/db.server'`)

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to **/*.server.{ts,tsx} : Use Kysely for runtime queries and ensure types are generated to `app/services/type.ts` via kysely-codegen

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to batch/commands/*.{ts,js} : Implement batch processing CLI commands in `batch/commands/` directory following the pattern of fetch, report, and upsert operations for GitHub data synchronization

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/libs/auth.server.ts : Use better-auth with Google OAuth for authentication, configured in `app/libs/auth.server.ts`, supporting organization-based access

Applied to files:

  • app/libs/auth.server.ts
🧬 Code graph analysis (7)
app/routes/_auth+/login.tsx (1)
app/libs/auth.server.ts (1)
  • auth (8-150)
app/routes/resources+/organization/route.tsx (2)
app/libs/utils.ts (1)
  • cn (4-6)
app/components/ui/dropdown-menu.tsx (1)
  • DropdownMenuContent (242-242)
app/routes/admin+/$organization.settings/route.tsx (1)
app/routes/admin+/$organization.settings/types.ts (1)
  • intentsSchema (42-42)
db/seed.ts (1)
app/services/db.server.ts (1)
  • db (23-27)
app/routes/api.auth.$/route.ts (5)
app/routes/_dashboard+/_layout.tsx (1)
  • loader (11-14)
app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx (1)
  • loader (25-81)
app/routes/admin+/$organization.settings/route.tsx (1)
  • loader (27-43)
app/routes/resources+/organization/route.tsx (1)
  • loader (18-23)
app/routes/healthcheck.tsx (1)
  • loader (5-24)
app/routes/admin+/_index/route.tsx (6)
app/routes/_auth+/login.tsx (1)
  • loader (14-21)
app/routes/_dashboard+/_layout.tsx (1)
  • loader (11-14)
app/routes/api.auth.$/route.ts (1)
  • loader (4-6)
app/routes/resources+/organization/route.tsx (1)
  • loader (18-23)
app/routes/admin+/_layout.tsx (1)
  • loader (12-14)
app/root.tsx (1)
  • loader (25-28)
batch/provider/github/release-detect.ts (1)
batch/provider/github/model.ts (1)
  • ShapedGitHubPullRequest (15-33)
🪛 ast-grep (0.40.4)
app/components/ui/chart.tsx

[warning] 81-81: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🔇 Additional comments (37)
app/services/cache.server.ts (1)

1-1: Improved lint suppression comment.

The updated Biome-ignore comment now clearly explains the rationale for using any in the cache store.

app/routes/admin+/$organization.repositories.add/functions/get-unique-owners.ts (1)

16-16: LGTM! Clean refactor of cursor initialization.

Removing the explicit = undefined initialization is correct and follows best practices. Uninitialized variables are undefined by default, so this change is semantically equivalent while being more concise.

Also applies to: 60-60

batch/provider/github/release-detect.ts (4)

18-19: LGTM: Appropriate linting suppression.

The biome-ignore comment correctly documents that merged_at is guaranteed to be non-null due to the filter on line 16.


58-58: LGTM: Unused parameter correctly marked.

The underscore prefix correctly indicates this parameter is intentionally unused, maintaining API consistency with findReleaseDateByBranch so both functions can be called uniformly from findReleaseDate.


63-63: LGTM: Good defensive programming.

The early null guard prevents potential issues when pr.merged_at is used in the dayjs comparison on line 71.


68-68: No action needed. The committed_at field in ShapedGitHubTag is typed as a required string field, making the removed non-null assertions unnecessary and the change safe.

Likely an incorrect or invalid review comment.

app/components/ui/slider.tsx (2)

32-32: LGTM! Tailwind v4 syntax migration.

The data attribute syntax has been correctly updated to Tailwind CSS v4 format (removing brackets). This aligns with the project's coding guidelines.


53-53: LGTM! Improved lint suppression comment.

Adding "shadcn-ui issue" provides better context for why the array index key is acceptable in this shadcn/ui component.

db/seed.ts (1)

11-23: LGTM! Cleanup of unused variable.

Removing the unused user variable assignment while retaining the insertion operation is appropriate cleanup. The seed operation still executes correctly and will throw on errors.

app/components/ui/carousel.tsx (2)

121-121: LGTM! Improved lint suppression documentation.

The biome-ignore comment now clearly documents that the non-semantic element usage is a shadcn/ui pattern, providing helpful context for future maintainers.


161-161: LGTM! Consistent lint suppression documentation.

This change maintains consistency with the carousel container comment above, clearly documenting the shadcn/ui pattern.

vite.config.ts (1)

8-8: The vite-plugin-devtools-json package is already listed in devDependencies (version 1.0.0) and is properly configured.

app/components/ui/breadcrumb.tsx (2)

16-16: LGTM! Typo fix in CSS utility.

The correction from wrap-bre ak-word to wrap-break-word fixes an invalid CSS class name.


52-65: Acknowledge accessibility concerns with BreadcrumbPage.

The component uses role="link" on a non-focusable <span>, which violates accessibility guidelines. While the biome-ignore comments acknowledge this as a shadcn-ui upstream issue, be aware that current breadcrumb pages are not keyboard-accessible.

Consider tracking the upstream shadcn-ui issue to adopt a fix when available, or override with a semantic element if keyboard navigation is required.

app/components/ui/chart.tsx (1)

70-102: Acknowledge safe usage of dangerouslySetInnerHTML for CSS injection.

The dynamic CSS generation uses dangerouslySetInnerHTML to inject chart color variables. The content is constructed from the config object, which should only contain sanitized color values. As long as the ChartConfig values don't originate from unsanitized user input, this usage is safe.

Based on learnings, this follows the shadcn-ui component pattern.

app/routes/admin+/$organization.settings/route.tsx (1)

45-74: Remove unnecessary context and rest parameter forwarding—sub-actions don't use them.

The sub-actions (organizationSettingsAction, integrationSettingsAction, exportSettingsAction, deleteOrganizationAction) only accept { request, params } and do not use the context or additional properties being passed via ...rest. Pass only the parameters each sub-action actually needs: { request, params }.

Likely an incorrect or invalid review comment.

app/components/ui/pagination.tsx (1)

13-16: LGTM! Clear lint suppression rationale.

The updated comments clarify that these accessibility lint rules are being suppressed due to upstream shadcn-ui issues, which is helpful for future maintainers.

CLAUDE.md (3)

62-62: Good clarification on code fence language.

Specifying text makes the syntax highlighting behavior explicit.


121-121: More accurate path alias description.

Clarifying that ~/ imports from the app/ directory (rather than "project root") is more precise and helpful.


128-154: Excellent addition of server-side conventions and form handling patterns.

These new sections provide valuable context for:

  • Server-only file naming conventions
  • Type-safe form validation approach
  • Intent-based action dispatch pattern

The concrete code examples make these patterns easy to follow.

app/routes/admin+/$organization.repositories.$repository.$pull/route.tsx (1)

25-25: LGTM! Good cleanup of unused parameter.

The request parameter was not used in the loader body, so removing it simplifies the function signature.

biome.json (1)

2-6: Apply Biome migration tool and verify all checks pass after upgrade.

This major version upgrade (1.7.2 → 2.3.11) introduces breaking changes. The includes field format change is confirmed as part of the migration. Rather than manual verification, Biome provides an automated migration: run biome migrate --write to handle config transformations automatically.

After migration, test thoroughly:

  • Run pnpm lint (biome check) to catch any new rule changes
  • Run pnpm format and review formatting differences (JSON trailing comma behavior changed)
  • Verify any rules you relied on for CI are still at "error" severity (some rules were promoted/demoted between versions)
  • Review the updated biome.json to ensure assist.actions.source.organizeImports and other config sections match your project needs
app/routes/resources+/organization/route.tsx (1)

55-55: LGTM! Good use of standard Tailwind spacing classes.

Replacing arbitrary values (w-[10rem], w-[12rem]) with standard Tailwind spacing scale classes (w-40, w-48) improves consistency and maintainability.

Also applies to: 65-65

app/components/ui/sidebar.tsx (2)

86-86: LGTM! Improved lint suppression context.

The updated comments reference "shadcn-ui issue," providing better context for why these lint rules are suppressed. This aligns with the pattern applied across other UI components in this PR.

Also applies to: 93-93, 118-118


294-294: LGTM! Consistent use of Tailwind spacing scale.

Replacing the arbitrary width value after:w-[2px] with the standard Tailwind class after:w-0.5 (equivalent to 2px) improves consistency with Tailwind conventions.

app/routes/admin+/_index/route.tsx (1)

14-16: LGTM! Valid simplification of unused parameter.

The request parameter has been correctly removed since it's not used in the loader body. Authentication is handled by the parent layout route (admin+/_layout.tsx calls requireSuperAdmin(request)), so this simplification is appropriate and aligns with the broader PR pattern.

app/entry.server.tsx (1)

17-17: LGTM! Correct use of unused parameter convention.

The _ prefix correctly indicates that loadContext is intentionally unused, improving code clarity.

app/routes/_dashboard+/_layout.tsx (1)

11-14: Simplify the loader to only perform authentication without returning unused data.

The layout component doesn't consume loaderData.user, and no child routes access this data via useRouteLoaderData() or similar hooks. The loader's purpose is purely authentication through the requireUser side effect. Remove the unused user return value.

app/services/type.ts (2)

73-82: Invitations.createdAt addition is consistent with the new created_at column.
Since this file is generated, keep changes driven via schema/migrations/codegen inputs only.


184-199: Adding DB.atlasSchemaRevisions is good (enables typed access to Atlas metadata).

package.json (2)

27-143: Run pnpm validate and pnpm test:e2e before merging to catch dependency incompatibilities.

The validation pipeline already covers linting, formatting, type checking, and unit tests. E2E tests with Playwright provide additional confidence for larger dependency changes that may introduce subtle runtime issues.


12-13: The --experimental-cli flag in Prettier 3.7.4 is supported and stable. It was introduced in Prettier 3.6 as the high-performance CLI variant and remains available in 3.7.x releases. No action needed.

app/libs/auth.server.ts (5)

53-53: LGTM!

Adding refreshTokenExpiresAt field mapping enables proper tracking of OAuth refresh token expiration, following the established snake_case naming convention.


88-88: LGTM! Teams feature properly enabled with session tracking.

Enabling teams and adding activeTeamId to the session schema supports team-scoped operations within organizations. The corresponding database schema changes (teams, team_members tables) appear to be included in this PR.

Also applies to: 102-102


113-120: LGTM!

The teamMember schema configuration follows the same pattern as the existing member schema, mapping the essential fields for team membership tracking.


142-144: LGTM!

The additional invitation fields (createdAt, inviterId, teamId) properly support team-level invitations and invitation tracking, following the established field mapping conventions.


9-9: LGTM! Base URL configuration aligns with OAuth flow fix.

Using a dedicated BETTER_AUTH_URL environment variable allows proper configuration of the auth base URL, which is essential for cookie handling during OAuth redirects. The environment variable is properly defined in the schema with type validation via Zod.

Comment on lines +28 to +41
export interface AtlasSchemaRevisions {
applied: Generated<number>;
description: string;
error: string | null;
errorStmt: string | null;
executedAt: string;
executionTime: number;
hash: string;
operatorVersion: string;
partialHashes: string | null;
total: Generated<number>;
type: Generated<number>;
version: string;
}
Copy link

@coderabbitai coderabbitai bot Jan 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, find and read the relevant type file
fd -e ts -e tsx | grep -E "(type|schema)" | head -20

Repository: coji/upflow

Length of output: 125


🏁 Script executed:

# Look for the specific file mentioned in the review
if [ -f "app/services/type.ts" ]; then
  wc -l app/services/type.ts
fi

Repository: coji/upflow

Length of output: 79


🏁 Script executed:

# Search for schema or migration files that define the atlasSchemaRevisions table
fd -type f \( -name "*.ts" -o -name "*.sql" -o -name "*.json" \) | xargs rg -l "atlasSchemaRevisions|atlas_schema_revisions" 2>/dev/null | head -20

Repository: coji/upflow

Length of output: 286


🏁 Script executed:

# Search for kyrsel-codegen configuration
fd -type f \( -name "*.config.*" -o -name ".kyrsel*" -o -name "codegen*" \) 2>/dev/null

Repository: coji/upflow

Length of output: 37


🏁 Script executed:

# Read the relevant section of type.ts
sed -n '28,41p' app/services/type.ts

Repository: coji/upflow

Length of output: 397


🏁 Script executed:

# Also read the full AtlasSchemaRevisions interface to see context
sed -n '1,50p' app/services/type.ts

Repository: coji/upflow

Length of output: 1257


🏁 Script executed:

# Find the schema definition for atlasSchemaRevisions
rg -A 20 "atlasSchemaRevisions|atlas_schema_revisions|CREATE TABLE.*atlas" db/schema.sql

Repository: coji/upflow

Length of output: 701


🏁 Script executed:

# Search for any comments or documentation about how this was generated
head -20 app/services/type.ts

Repository: coji/upflow

Length of output: 564


🏁 Script executed:

# Check if there are other JSON columns in the schema and their types
rg "json" db/schema.sql -i

Repository: coji/upflow

Length of output: 84


🏁 Script executed:

# Search for usage of partialHashes in the codebase
rg "partialHashes" --type ts --type tsx -A 3 -B 3

Repository: coji/upflow

Length of output: 82


🏁 Script executed:

# Check if there are any other generated interfaces with json columns
rg "json" app/services/type.ts -i

Repository: coji/upflow

Length of output: 37


🏁 Script executed:

# Search for kysely configuration or type generation config
fd -type f -name "*.config.*" -o -name "*.json" | xargs rg -l "kysely" 2>/dev/null

Repository: coji/upflow

Length of output: 498


🏁 Script executed:

# Check package.json for kysely configuration
cat package.json | head -100

Repository: coji/upflow

Length of output: 3775


🏁 Script executed:

# Also search for any kysely.config or codegen config
rg "kysely" package.json

Repository: coji/upflow

Length of output: 230


🏁 Script executed:

# Search for usage of partialHashes without type flag
rg "partialHashes" -A 3 -B 3

Repository: coji/upflow

Length of output: 375


🌐 Web query:

kysely-codegen 0.19.0 sqlite JSON column type generation how are json columns typed

💡 Result:

kysely-codegen (v0.19.0) emits Kysely's JSONColumnType for JSON columns. That means the generated column type uses Kysely's JSONColumnType<Select,Insert,Update> (select is an object|null by constraint; insert/update default to string). See Kysely's JSONColumnType docs and the kysely-codegen readme/release notes. [1][2]

Sources:

  • Kysely JSONColumnType docs. [1]
  • kysely-codegen README / release (v0.19.0). [2]

Regenerate types for partialHashes—the field should use JSONColumnType, not string | null.

The schema defines partial_hashes as json NULL, but the generated type shows partialHashes: string | null. According to kysely-codegen v0.19.0 documentation, JSON columns should be typed with JSONColumnType (where Select type is object | null, not string). Run npm run db:generate to regenerate the types.

🤖 Prompt for AI Agents
In @app/services/type.ts around lines 28 - 41, The generated
AtlasSchemaRevisions type has partialHashes typed as string | null but the DB
column partial_hashes is json NULL; update the type to use JSONColumnType (so
Select resolves to object | null) by regenerating types with the codegen: run
npm run db:generate to refresh generated types, or manually change the
AtlasSchemaRevisions.partialHashes declaration to JSONColumnType<object | null,
unknown> if immediate edit is needed, ensuring the symbol AtlasSchemaRevisions
and its partialHashes member are updated accordingly.

Copy link
Owner Author

Choose a reason for hiding this comment

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

This is expected behavior. The type.ts is auto-generated by kysely-codegen from the database schema. The atlas_schema_revisions table is created by Atlas itself during migration, and its type generation is handled automatically. No manual changes needed.

Copy link

Choose a reason for hiding this comment

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

@coji, thank you for the clarification! I understand now that the atlas_schema_revisions table and its type generation are managed by Atlas itself, and the output from kysely-codegen is expected as-is. I appreciate you explaining the automatic nature of this workflow.


✏️ Learnings added
Learnt from: coji
Repo: coji/upflow PR: 102
File: app/services/type.ts:28-41
Timestamp: 2026-01-10T09:36:07.102Z
Learning: The `atlas_schema_revisions` table in `db/schema.sql` is created and managed by Atlas during migrations. Its types in `app/services/type.ts` are auto-generated by kysely-codegen, and the generated types (including JSON columns typed as `string | null`) are expected behavior and should not be manually modified.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to **/*.server.{ts,tsx} : Use Kysely for runtime queries and ensure types are generated to `app/services/type.ts` via kysely-codegen

Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to db/migrations/*.sql : Use Atlas for declarative schema management and versioned SQL migrations stored in `db/migrations/`

Copy link

@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: 0

🧹 Nitpick comments (1)
.env.example (1)

6-7: Consider reordering environment variables alphabetically.

The new keys BETTER_AUTH_SECRET and BETTER_AUTH_URL should appear before DATABASE_URL to maintain alphabetical order, which improves consistency and makes it easier to locate variables in larger .env.example files.

♻️ Proposed reordering
+BETTER_AUTH_SECRET=super-duper-auth-secret
+BETTER_AUTH_URL=http://localhost:5173
 DATABASE_URL="file:../data/data.db"
 SESSION_SECRET="super-duper-s3cret"
 GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
 GOOGLE_CLIENT_SECRET=your-client-secret
 INTEGRATION_PRIVATE_TOKEN=glpat-abcdefghijklmnopqrst
-BETTER_AUTH_SECRET=super-duper-auth-secret
-BETTER_AUTH_URL=http://localhost:5173
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aab689a and d6187f1.

📒 Files selected for processing (1)
  • .env.example
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/libs/auth.server.ts : Use better-auth with Google OAuth for authentication, configured in `app/libs/auth.server.ts`, supporting organization-based access

Applied to files:

  • .env.example
🪛 dotenv-linter (4.0.0)
.env.example

[warning] 6-6: [UnorderedKey] The BETTER_AUTH_SECRET key should go before the DATABASE_URL key

(UnorderedKey)


[warning] 7-7: [UnorderedKey] The BETTER_AUTH_URL key should go before the DATABASE_URL key

(UnorderedKey)

coji and others added 2 commits January 10, 2026 18:27
- Add error handling for OAuth sign-in failure
- Fix migration DEFAULT for invitations.created_at column
- Add UNIQUE index on users.email per better-auth schema

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add FK constraint for invitations.team_id -> teams(id)
- Rename constraint names from '0', '1' to meaningful names:
  - teams: teams_organization_id_fkey
  - team_members: team_members_user_id_fkey, team_members_team_id_fkey
- Add UNIQUE index on users.email per better-auth schema
- Add DEFAULT (CURRENT_TIMESTAMP) for invitations.created_at
- Add error handling for OAuth sign-in failure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coji coji force-pushed the chore/bump-dependencies branch from c0b1895 to 37779d0 Compare January 10, 2026 09:33
Copy link

@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: 6

🤖 Fix all issues with AI agents
In @app/routes/_auth+/login.tsx:
- Around line 36-41: Wrap the JSON parsing of response in a try/catch and
validate the parsed object before using it: after confirming response.ok,
attempt to parse response.json() inside a try block, verify the result is an
object with a string url (e.g., const data = await response.json(); if (!data ||
typeof data.url !== 'string') throw new Error('Invalid OAuth response')); on
parse or validation failure throw a Response with an appropriate status (e.g.,
502) and message so the login flow fails gracefully; otherwise call
redirect(data.url || '/', { headers: response.headers }).

In @db/migrations/20260110092446.sql:
- Around line 56-69: The migration for table `team_members` uses non-descriptive
FK constraint names (`0`, `1`) and defines `created_at` as `date` instead of
`datetime`; update the FOREIGN KEY constraints to meaningful names such as
`team_members_user_id_fkey` for the FK on `user_id` and
`team_members_team_id_fkey` for the FK on `team_id`, and change the `created_at`
column type from `date` to `datetime` to match other tables (ensure the
constraints still reference `users(id)` and `teams(id)` with ON DELETE CASCADE /
ON UPDATE NO ACTION).
- Around line 44-55: Update the teams table timestamp columns to use datetime
instead of date: change the column definitions for created_at (keep NOT NULL)
and updated_at (keep NULL) from `date` to `datetime` so they match other tables'
precision; leave the PRIMARY KEY, FOREIGN KEY constraint (`CONSTRAINT 0` on
`organization_id`), and the `teams_organization_id_idx` index unchanged.

In @db/schema.sql:
- Around line 222-233: The teams table uses date for timestamps and a
non-descriptive FK name: change `created_at` and `updated_at` column types in
the `teams` CREATE TABLE to `datetime` (preserve NOT NULL for `created_at` and
NULL for `updated_at`), and rename the foreign key constraint `0` to a
meaningful name such as `teams_organization_id_fkey` that references
`organizations(id)` with the same ON UPDATE/ON DELETE actions; keep the existing
index `teams_organization_id_idx` as-is.
- Line 112: The invitations.created_at column is missing a DEFAULT
(CURRENT_TIMESTAMP) which makes inserts require explicit timestamps and causes
the TypeScript Invitations.createdAt to be a plain string instead of
Generated<string>; update the schema to add DEFAULT (CURRENT_TIMESTAMP) to the
`created_at` definition for the invitations table (and update any migration/sql
that creates that table), and adjust the TypeScript DB model type for
Invitations.createdAt to Generated<string> to match other entities —
alternatively, if you intentionally require application-supplied timestamps, add
a brief comment in the schema and keep Invitations.createdAt as a non-generated
string but ensure all insert code sets the timestamp.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6187f1 and ee8a02a.

⛔ Files ignored due to path filters (1)
  • db/migrations/atlas.sum is excluded by !**/*.sum
📒 Files selected for processing (4)
  • app/routes/_auth+/login.tsx
  • db/migrations/20260110075838.sql
  • db/migrations/20260110092446.sql
  • db/schema.sql
🧰 Additional context used
📓 Path-based instructions (4)
app/routes/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Use remix-flat-routes with the + folder syntax for file-based routing, following conventions: _layout.tsx for layout routes, _index.tsx for index routes, $param for dynamic segments, and $organization.settings/ for nested route folders

Files:

  • app/routes/_auth+/login.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use path alias ~/ for imports from project root (e.g., import { db } from '~/app/services/db.server')

Files:

  • app/routes/_auth+/login.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Biome for linting and Prettier for formatting code throughout the project

Files:

  • app/routes/_auth+/login.tsx
db/migrations/*.sql

📄 CodeRabbit inference engine (CLAUDE.md)

Use Atlas for declarative schema management and versioned SQL migrations stored in db/migrations/

Files:

  • db/migrations/20260110092446.sql
  • db/migrations/20260110075838.sql
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to db/migrations/*.sql : Use Atlas for declarative schema management and versioned SQL migrations stored in `db/migrations/`
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/libs/auth.server.ts : Use better-auth with Google OAuth for authentication, configured in `app/libs/auth.server.ts`, supporting organization-based access

Applied to files:

  • app/routes/_auth+/login.tsx
📚 Learning: 2025-12-24T14:54:35.860Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to db/migrations/*.sql : Use Atlas for declarative schema management and versioned SQL migrations stored in `db/migrations/`

Applied to files:

  • db/migrations/20260110092446.sql
  • db/schema.sql
🧬 Code graph analysis (1)
app/routes/_auth+/login.tsx (1)
app/libs/auth.server.ts (1)
  • auth (8-150)
🔇 Additional comments (4)
app/routes/_auth+/login.tsx (1)

31-34: LGTM! The asResponse pattern is correct for better-auth v1.4.10.

The use of asResponse: true properly enables capture of the full Response object, allowing proper cookie and header handling through the OAuth redirect flow.

db/migrations/20260110075838.sql (1)

1-2: LGTM! Migration syntax is correct.

The migration correctly adds the created_at column with a DEFAULT value, preparing the invitations table for the subsequent schema restructuring in migration 20260110092446.sql.

db/migrations/20260110092446.sql (1)

1-71: LGTM! Atlas migration structure is correct.

The migration properly follows Atlas conventions by disabling/re-enabling foreign key constraints, creating the atlas_schema_revisions tracking table, and using a recreate pattern for the invitations table restructuring.

Based on learnings, this aligns with using Atlas for declarative schema management.

db/schema.sql (1)

1-247: LGTM! Schema structure follows Atlas conventions.

The schema.sql file serves as the declarative schema baseline for Atlas migrations, with proper table definitions, primary keys, foreign keys, and indexes throughout.

Based on learnings, this aligns with using Atlas for declarative schema management.

Comment on lines +36 to +41
if (!response.ok) {
throw new Response('OAuth sign-in failed', { status: response.status })
}

const data = await response.json()
return redirect(data.url || '/', { headers: response.headers })
Copy link

@coderabbitai coderabbitai bot Jan 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error handling for JSON parsing.

The HTTP-level error handling is good, but the JSON parsing on line 40 lacks error handling. If the response body is malformed or not valid JSON, it will throw an unhandled error and break the login flow.

🛡️ Proposed fix with error handling and type safety
  if (!response.ok) {
    throw new Response('OAuth sign-in failed', { status: response.status })
  }

- const data = await response.json()
- return redirect(data.url || '/', { headers: response.headers })
+ let data: { url?: string }
+ try {
+   data = await response.json()
+ } catch {
+   throw new Response('Invalid OAuth response', { status: 500 })
+ }
+ 
+ if (typeof data.url !== 'string') {
+   throw new Response('Missing redirect URL in OAuth response', { status: 500 })
+ }
+ 
+ return redirect(data.url || '/', { headers: response.headers })

This adds:

  1. Try-catch around JSON parsing to handle malformed responses
  2. Type annotation and runtime validation for the response structure
  3. Clear error messages for debugging
📝 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
if (!response.ok) {
throw new Response('OAuth sign-in failed', { status: response.status })
}
const data = await response.json()
return redirect(data.url || '/', { headers: response.headers })
if (!response.ok) {
throw new Response('OAuth sign-in failed', { status: response.status })
}
let data: { url?: string }
try {
data = await response.json()
} catch {
throw new Response('Invalid OAuth response', { status: 500 })
}
if (typeof data.url !== 'string') {
throw new Response('Missing redirect URL in OAuth response', { status: 500 })
}
return redirect(data.url || '/', { headers: response.headers })
🤖 Prompt for AI Agents
In @app/routes/_auth+/login.tsx around lines 36 - 41, Wrap the JSON parsing of
response in a try/catch and validate the parsed object before using it: after
confirming response.ok, attempt to parse response.json() inside a try block,
verify the result is an object with a string url (e.g., const data = await
response.json(); if (!data || typeof data.url !== 'string') throw new
Error('Invalid OAuth response')); on parse or validation failure throw a
Response with an appropriate status (e.g., 502) and message so the login flow
fails gracefully; otherwise call redirect(data.url || '/', { headers:
response.headers }).

Copy link
Owner Author

Choose a reason for hiding this comment

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

The response.ok check added in commit 37779d0 handles HTTP-level errors before attempting JSON parsing. If the response is not OK, we throw early with the status code. The JSON parsing itself is expected to succeed for valid responses from better-auth.

Copy link

Choose a reason for hiding this comment

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

@coji, thank you for the explanation. You're right that the response.ok check provides protection at the HTTP level, and trusting better-auth to return well-formed JSON for successful responses is a reasonable design decision. I appreciate you clarifying the rationale behind this approach.


🧠 Learnings used
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to app/libs/auth.server.ts : Use better-auth with Google OAuth for authentication, configured in `app/libs/auth.server.ts`, supporting organization-based access

Comment on lines +44 to +55
-- Create "teams" table
CREATE TABLE `teams` (
`id` text NOT NULL,
`name` text NOT NULL,
`organization_id` text NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "teams_organization_id_idx" to table: "teams"
CREATE INDEX `teams_organization_id_idx` ON `teams` (`organization_id`);
Copy link

@coderabbitai coderabbitai bot Jan 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Inconsistent timestamp type: use datetime instead of date.

Lines 49-50 define created_at and updated_at as date type, but all other tables in the schema use datetime for timestamp columns (e.g., users.created_at, organizations.created_at). Using date loses time-of-day precision.

📅 Proposed fix to use datetime consistently
 CREATE TABLE `teams` (
   `id` text NOT NULL,
   `name` text NOT NULL,
   `organization_id` text NOT NULL,
-  `created_at` date NOT NULL,
-  `updated_at` date NULL,
+  `created_at` datetime NOT NULL,
+  `updated_at` datetime NULL,
   PRIMARY KEY (`id`),
   CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
 );
📝 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
-- Create "teams" table
CREATE TABLE `teams` (
`id` text NOT NULL,
`name` text NOT NULL,
`organization_id` text NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "teams_organization_id_idx" to table: "teams"
CREATE INDEX `teams_organization_id_idx` ON `teams` (`organization_id`);
-- Create "teams" table
CREATE TABLE `teams` (
`id` text NOT NULL,
`name` text NOT NULL,
`organization_id` text NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "teams_organization_id_idx" to table: "teams"
CREATE INDEX `teams_organization_id_idx` ON `teams` (`organization_id`);
🤖 Prompt for AI Agents
In @db/migrations/20260110092446.sql around lines 44 - 55, Update the teams
table timestamp columns to use datetime instead of date: change the column
definitions for created_at (keep NOT NULL) and updated_at (keep NULL) from
`date` to `datetime` so they match other tables' precision; leave the PRIMARY
KEY, FOREIGN KEY constraint (`CONSTRAINT 0` on `organization_id`), and the
`teams_organization_id_idx` index unchanged.

Copy link
Owner Author

Choose a reason for hiding this comment

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

The migrations have been consolidated into a single file (20260110093253.sql). The date type for teams.created_at and team_members.created_at matches better-auth's official schema definition.

Copy link

Choose a reason for hiding this comment

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

@coji, thank you for the clarification! You're absolutely right—better-auth's official schema defines team_members.createdAt as type "Date", so using date for the teams and team_members timestamps is the correct approach to maintain compatibility with their schema definition.

I appreciate you pointing out that the migrations have been consolidated. Following the official better-auth schema is the right call here.


✏️ Learnings added
Learnt from: coji
Repo: coji/upflow PR: 102
File: db/migrations/20260110092446.sql:44-55
Timestamp: 2026-01-10T09:38:03.079Z
Learning: In the coji/upflow repository, the `teams` and `team_members` tables use the `date` type for `created_at` and `updated_at` fields to match better-auth's official organization plugin schema definition, which specifies these as Date types rather than datetime.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to db/migrations/*.sql : Use Atlas for declarative schema management and versioned SQL migrations stored in `db/migrations/`

Learnt from: coji
Repo: coji/upflow PR: 102
File: app/services/type.ts:28-41
Timestamp: 2026-01-10T09:36:07.102Z
Learning: The `atlas_schema_revisions` table in `db/schema.sql` is created and managed by Atlas during migrations. Its types in `app/services/type.ts` are auto-generated by kysely-codegen, and the generated types (including JSON columns typed as `string | null`) are expected behavior and should not be manually modified.

Comment on lines +222 to +233
-- Create "teams" table
CREATE TABLE `teams` (
`id` text NOT NULL,
`name` text NOT NULL,
`organization_id` text NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "teams_organization_id_idx" to table: "teams"
CREATE INDEX `teams_organization_id_idx` ON `teams` (`organization_id`);
Copy link

@coderabbitai coderabbitai bot Jan 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Inconsistent timestamp type: use datetime instead of date.

Lines 227-228 define created_at and updated_at as date, but this is inconsistent with all other tables that use datetime for timestamps (e.g., users.created_at on line 28, organizations.created_at on line 40). The date type loses time-of-day precision.

Additionally, line 230 uses a non-descriptive FK constraint name 0 instead of something meaningful like teams_organization_id_fkey.

🔧 Proposed fixes for consistency
 CREATE TABLE `teams` (
   `id` text NOT NULL,
   `name` text NOT NULL,
   `organization_id` text NOT NULL,
-  `created_at` date NOT NULL,
-  `updated_at` date NULL,
+  `created_at` datetime NOT NULL,
+  `updated_at` datetime NULL,
   PRIMARY KEY (`id`),
-  CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
+  CONSTRAINT `teams_organization_id_fkey` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
 );
📝 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
-- Create "teams" table
CREATE TABLE `teams` (
`id` text NOT NULL,
`name` text NOT NULL,
`organization_id` text NOT NULL,
`created_at` date NOT NULL,
`updated_at` date NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "teams_organization_id_idx" to table: "teams"
CREATE INDEX `teams_organization_id_idx` ON `teams` (`organization_id`);
-- Create "teams" table
CREATE TABLE `teams` (
`id` text NOT NULL,
`name` text NOT NULL,
`organization_id` text NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NULL,
PRIMARY KEY (`id`),
CONSTRAINT `teams_organization_id_fkey` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "teams_organization_id_idx" to table: "teams"
CREATE INDEX `teams_organization_id_idx` ON `teams` (`organization_id`);
🤖 Prompt for AI Agents
In @db/schema.sql around lines 222 - 233, The teams table uses date for
timestamps and a non-descriptive FK name: change `created_at` and `updated_at`
column types in the `teams` CREATE TABLE to `datetime` (preserve NOT NULL for
`created_at` and NULL for `updated_at`), and rename the foreign key constraint
`0` to a meaningful name such as `teams_organization_id_fkey` that references
`organizations(id)` with the same ON UPDATE/ON DELETE actions; keep the existing
index `teams_organization_id_idx` as-is.

Copy link
Owner Author

Choose a reason for hiding this comment

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

The date type for teams.created_at and team_members.created_at is intentional - it matches better-auth's official organization plugin schema definition.

Copy link

Choose a reason for hiding this comment

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

@coji, thank you for clarifying! I see this aligns with the learnings already captured about better-auth's organization plugin schema using date types for those timestamp fields. I appreciate the context.

The FK constraint name 0 on line 230 still appears unusual (compared to other descriptive constraint names like teams_organization_id_fkey pattern used elsewhere), but if this is Atlas-generated output, it may be handled by the migration tooling.


🧠 Learnings used
Learnt from: coji
Repo: coji/upflow PR: 102
File: app/services/type.ts:28-41
Timestamp: 2026-01-10T09:36:07.102Z
Learning: The `atlas_schema_revisions` table in `db/schema.sql` is created and managed by Atlas during migrations. Its types in `app/services/type.ts` are auto-generated by kysely-codegen, and the generated types (including JSON columns typed as `string | null`) are expected behavior and should not be manually modified.

Learnt from: coji
Repo: coji/upflow PR: 102
File: db/migrations/20260110092446.sql:44-55
Timestamp: 2026-01-10T09:38:03.079Z
Learning: In the coji/upflow repository, the `teams` and `team_members` tables use the `date` type for `created_at` and `updated_at` fields to match better-auth's official organization plugin schema definition, which specifies these as Date types rather than datetime.

Learnt from: coji
Repo: coji/upflow PR: 102
File: db/migrations/20260110092446.sql:56-69
Timestamp: 2026-01-10T09:38:06.866Z
Learning: In migrations involving better-auth schema (teams, team_members tables), `created_at` and `updated_at` fields use the `date` type instead of `datetime` to match better-auth's official schema convention.

Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T14:54:35.860Z
Learning: Applies to db/migrations/*.sql : Use Atlas for declarative schema management and versioned SQL migrations stored in `db/migrations/`

Comment on lines +234 to +247
-- Create "team_members" table
CREATE TABLE `team_members` (
`id` text NOT NULL,
`team_id` text NOT NULL,
`user_id` text NOT NULL,
`created_at` date NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT `1` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "team_members_team_id_idx" to table: "team_members"
CREATE INDEX `team_members_team_id_idx` ON `team_members` (`team_id`);
-- Create index "team_members_user_id_idx" to table: "team_members"
CREATE INDEX `team_members_user_id_idx` ON `team_members` (`user_id`);
Copy link

@coderabbitai coderabbitai bot Jan 10, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Two issues: non-descriptive FK constraint names and inconsistent timestamp type.

  1. FK constraint names (lines 241-242): Constraints named 0 and 1 make debugging and maintenance difficult. Use descriptive names like team_members_user_id_fkey and team_members_team_id_fkey.

  2. Timestamp type (line 239): created_at is defined as date instead of datetime, inconsistent with other tables in the schema.

🔧 Proposed fixes
 CREATE TABLE `team_members` (
   `id` text NOT NULL,
   `team_id` text NOT NULL,
   `user_id` text NOT NULL,
-  `created_at` date NULL,
+  `created_at` datetime NULL,
   PRIMARY KEY (`id`),
-  CONSTRAINT `0` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
-  CONSTRAINT `1` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
+  CONSTRAINT `team_members_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
+  CONSTRAINT `team_members_team_id_fkey` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
 );
📝 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
-- Create "team_members" table
CREATE TABLE `team_members` (
`id` text NOT NULL,
`team_id` text NOT NULL,
`user_id` text NOT NULL,
`created_at` date NULL,
PRIMARY KEY (`id`),
CONSTRAINT `0` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT `1` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "team_members_team_id_idx" to table: "team_members"
CREATE INDEX `team_members_team_id_idx` ON `team_members` (`team_id`);
-- Create index "team_members_user_id_idx" to table: "team_members"
CREATE INDEX `team_members_user_id_idx` ON `team_members` (`user_id`);
-- Create "team_members" table
CREATE TABLE `team_members` (
`id` text NOT NULL,
`team_id` text NOT NULL,
`user_id` text NOT NULL,
`created_at` datetime NULL,
PRIMARY KEY (`id`),
CONSTRAINT `team_members_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT `team_members_team_id_fkey` FOREIGN KEY (`team_id`) REFERENCES `teams` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE
);
-- Create index "team_members_team_id_idx" to table: "team_members"
CREATE INDEX `team_members_team_id_idx` ON `team_members` (`team_id`);
-- Create index "team_members_user_id_idx" to table: "team_members"
CREATE INDEX `team_members_user_id_idx` ON `team_members` (`user_id`);

Copy link
Owner Author

Choose a reason for hiding this comment

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

Fixed in migration 20260110093253.sql:

  • teams: constraint renamed to teams_organization_id_fkey
  • team_members: constraints renamed to team_members_user_id_fkey and team_members_team_id_fkey

The date type matches better-auth's official schema.

Copy link

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@coji have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 14 seconds before sending another message.

@coji coji merged commit 12db33c into main Jan 10, 2026
10 checks passed
@coji coji deleted the chore/bump-dependencies branch January 10, 2026 09:39
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