Skip to content

refactor: Prisma から Atlas + kysely-codegen への移行#101

Merged
coji merged 8 commits intomainfrom
refactor/atlas-kysely
Dec 24, 2025
Merged

refactor: Prisma から Atlas + kysely-codegen への移行#101
coji merged 8 commits intomainfrom
refactor/atlas-kysely

Conversation

@coji
Copy link
Owner

@coji coji commented Dec 24, 2025

Summary

  • Prisma を削除し、Atlas (マイグレーション) + kysely-codegen (型生成) に移行
  • Kysely はそのまま使用 (ランタイムクエリ)

Changes

追加

  • atlas.hcl - Atlas 設定ファイル
  • db/schema.sql - Declarative スキーマ定義
  • db/migrations/ - Atlas マイグレーション
  • db/seed.ts - シードデータ (prisma/seed.ts から移動)

削除

  • prisma/ ディレクトリ全体
  • app/services/prisma.server.ts
  • @prisma/client, prisma, prisma-kysely 依存関係

変更

  • 型名を複数形に統一 (OrganizationOrganizations など)
  • Dockerfile: Atlas CLI インストール追加、Prisma 削除
  • start.sh: prisma migrate deployatlas migrate apply

New Commands

pnpm setup         # マイグレーション適用 + seed
pnpm db:generate   # 型を再生成
pnpm db:migrate    # スキーマ変更からマイグレーション生成
pnpm db:apply      # マイグレーション適用

Test plan

  • pnpm validate 通過
  • Fly.io へのデプロイ確認

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Migrated database tooling from Prisma to Atlas + Kysely; updated startup and Docker flow to use Atlas migrations and new DB tooling.
    • Added a local DB schema and migrations for easier local development and one‑step setup.
    • Updated dev tooling and dependencies to support the new DB stack.
  • Refactor

    • Standardized data type names and cleaned up component interface formatting (no UI behavior changes).

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

coji and others added 6 commits December 24, 2025 23:41
- Add db/schema.sql with declarative schema definition
- Add db/migrations/ with initial migration
- Add db/seed.ts (moved from prisma/seed.ts)
- Add atlas.hcl configuration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove @prisma/client, prisma, prisma-kysely
- Add kysely-codegen for type generation
- Update scripts: setup, db:generate, db:migrate, db:apply

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove prisma/schema.prisma
- Remove prisma/migrations/
- Remove prisma/seed.ts (moved to db/)
- Remove app/services/prisma.server.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Types now use plural names (Organizations, Repositories, etc.)
- Generated with --camel-case option

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- DB.Organization -> DB.Organizations
- DB.Repository -> DB.Repositories
- DB.PullRequest -> DB.PullRequests
- DB.Integration -> DB.Integrations
- DB.ExportSetting -> DB.ExportSettings
- DB.OrganizationSetting -> DB.OrganizationSettings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Install Atlas CLI in Dockerfile
- Remove Prisma-related steps
- Update start.sh to use atlas migrate apply
- Add automatic baseline setting for existing databases

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

coderabbitai bot commented Dec 24, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Replaces Prisma with an Atlas + Kysely DB stack: removes Prisma schema, migrations and client; adds Atlas config, SQL schema and migrations; updates generated DB types (singular → plural), adjusts many function/component type signatures, and updates Docker, CI, start scripts, and package tooling.

Changes

Cohort / File(s) Summary
Docker, CI & startup
Dockerfile, .github/workflows/.../deploy.yml, start.sh, package.json
Remove Prisma install/generation; add Atlas install/usage and Kysely/codegen scripts; replace Prisma migrate calls with Atlas commands; adjust multi-stage Docker artifact references to production-deps; update tooling deps.
Atlas config & SQL migrations
atlas.hcl, db/schema.sql, db/migrations/20251224122040_initial.sql
Add Atlas environment "local", introduce new SQL schema and initial migration defining tenants, users, orgs, sessions, accounts, members, integrations, repositories, pull_requests, export/org settings, indexes and FKs.
Prisma artifacts removed
prisma/schema.prisma, prisma/migrations/... (all listed migration dirs), prisma/migrations/migration_lock.toml
Delete entire Prisma schema, generators, and all Prisma migration files and migration_lock.
DB types & service layer
app/services/type.ts, app/services/prisma.server.ts
Replace singular type aliases with pluralized interfaces (Accounts, Organizations, Repositories, etc.); update DB mapping; remove exported PrismaClient.
API / server signatures (singular → plural)
app/routes/** (multiple files, e.g., _dashboard+/*, admin+/*, resources+/*)
Update many function, handler and component prop types from DB.<Singular>/Selectable<DB.<Singular>> to pluralized DB.<Plurals>; minor formatting; one query adds .orderBy('number','desc'); update allowed fields for updateOrganizationSetting to include excludedUsers.
Batch & provider code
batch/*, batch/provider/*, batch/provider/github/*
Update batch/provider function signatures and local collection types to use pluralized DB types (Integrations, Repositories, PullRequests); no logic changes.
Components — formatting only
app/components/AppSortableHeader.tsx, app/components/ui/heading.tsx, app/components/ui/stack.tsx, app/routes/resources+/organization/route.tsx
Reformat interface/extends clauses across lines; no semantic or runtime changes.
DB codegen / tooling adjustments
package.json, .github/...
Add kysely-codegen and adjust scripts: db:generate, db:migrate, db:apply; remove prisma-related deps and scripts.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

🐰 From burrow of Prisma I bound,
Atlas maps now spread the ground,
Types went plural, migrations sing,
Kysely sprouts its tidy Spring,
I hop with joy — new seeds abound! 🌱🥕

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 accurately describes the primary change: migrating from Prisma to Atlas + kysely-codegen for database management.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 085d2ab and e47d5b8.

📒 Files selected for processing (1)
  • CLAUDE.md

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.

- Remove prisma generate steps (no longer needed)
- Replace prisma migrate reset with Atlas-based pnpm setup
- Add Atlas CLI installation step for Vitest job

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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

Caution

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

⚠️ Outside diff range comments (1)
batch/provider/github/provider.ts (1)

18-24: Incorrect invariant error messages.

Lines 22-23 check repository.repo and repository.owner but both error messages say "private token not specified". These should reflect what's actually being validated.

🔎 Proposed fix
-    invariant(repository.repo, 'private token not specified')
-    invariant(repository.owner, 'private token not specified')
+    invariant(repository.repo, 'repository repo not specified')
+    invariant(repository.owner, 'repository owner not specified')
     invariant(integration.privateToken, 'private token not specified')
🧹 Nitpick comments (7)
db/schema.sql (2)

16-25: Consider adding updated_at column for consistency.

The organizations table lacks an updated_at column while most other tables include it for audit purposes. This may cause issues if you need to track when organizations are modified.

🔎 Proposed fix
 CREATE TABLE IF NOT EXISTS "organizations" (
     "id" TEXT NOT NULL PRIMARY KEY,
     "name" TEXT NOT NULL,
     "slug" TEXT,
     "logo" TEXT,
     "created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "updated_at" DATETIME NOT NULL,
     "metadata" TEXT
 );

131-132: Redundant index on organization_id.

Line 131 creates a unique index on organization_id, which inherently provides indexing for lookups. The additional non-unique index on line 132 is redundant and wastes storage.

🔎 Proposed fix
 CREATE UNIQUE INDEX "integrations_organization_id_key" ON "integrations"("organization_id");
-CREATE INDEX "integrations_organization_id_idx" ON "integrations"("organization_id");
db/migrations/20251224122040_initial.sql (5)

38-39: Consider adding foreign key constraints for active_organization_id and impersonated_by.

These columns appear to reference organizations.id and users.id respectively, but lack FK constraints. This could lead to orphaned references if the referenced records are deleted.

If soft references are intentional (e.g., to preserve session history), consider this acceptable. Otherwise:

🔎 Proposed fix
   `impersonated_by` text NULL,
   `active_organization_id` text NULL,
   PRIMARY KEY (`id`),
-  CONSTRAINT `sessions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
+  CONSTRAINT `sessions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
+  CONSTRAINT `sessions_impersonated_by_fkey` FOREIGN KEY (`impersonated_by`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE SET NULL,
+  CONSTRAINT `sessions_active_organization_id_fkey` FOREIGN KEY (`active_organization_id`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE SET NULL

136-139: Redundant index: integrations_organization_id_idx is unnecessary.

The unique index integrations_organization_id_key (line 137) already provides efficient lookups on organization_id. The additional non-unique index (line 139) is redundant and wastes storage.

🔎 Proposed fix
 -- Create index "integrations_organization_id_key" to table: "integrations"
 CREATE UNIQUE INDEX `integrations_organization_id_key` ON `integrations` (`organization_id`);
--- Create index "integrations_organization_id_idx" to table: "integrations"
-CREATE INDEX `integrations_organization_id_idx` ON `integrations` (`organization_id`);

161-163: repo column appears redundant with repository_id FK.

The repo text column seems to duplicate data available via the repository_id foreign key (which links to repositories.repo). This could lead to data inconsistency if not kept in sync.

If this is intentional denormalization for query performance or preserving historical values, consider adding a comment in the schema. Otherwise, consider removing it.


73-83: Consider adding unique constraint on members(organization_id, user_id).

Without a unique constraint on the combination, a user could have multiple membership records for the same organization, which is likely unintended.

🔎 Proposed fix
 -- Create "members" table
 CREATE TABLE `members` (
   `id` text NOT NULL,
   `organization_id` text NOT NULL,
   `user_id` text NOT NULL,
   `role` text NOT NULL,
   `created_at` datetime NOT NULL,
   PRIMARY KEY (`id`),
   CONSTRAINT `members_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
   CONSTRAINT `members_organization_id_fkey` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
 );
+-- Create index "members_organization_id_user_id_key" to table: "members"
+CREATE UNIQUE INDEX `members_organization_id_user_id_key` ON `members` (`organization_id`, `user_id`);

45-62: Consider adding unique constraints on accounts table.

OAuth account tables typically need unique constraints to prevent duplicates:

  1. (provider_id, account_id) - ensures each provider account links to only one user
  2. Optionally (user_id, provider_id) - if users can only have one account per provider
🔎 Proposed fix
 );
+-- Create index "accounts_provider_id_account_id_key" to table: "accounts"
+CREATE UNIQUE INDEX `accounts_provider_id_account_id_key` ON `accounts` (`provider_id`, `account_id`);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 62aec87 and 58aa04a.

⛔ 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 (51)
  • Dockerfile
  • app/components/AppSortableHeader.tsx
  • app/components/ui/heading.tsx
  • app/components/ui/stack.tsx
  • app/routes/_dashboard+/$organization._index/functions/queries.ts
  • app/routes/_dashboard+/$organization.ongoing/functions/queries.ts
  • app/routes/admin+/$organization.members/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts
  • app/routes/admin+/$organization.repositories._index/queries.server.ts
  • app/routes/admin+/$organization.repositories.add/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.add/functions/queries.ts
  • app/routes/admin+/$organization.settings/forms/delete-organization.tsx
  • app/routes/admin+/$organization.settings/forms/export-settings.tsx
  • app/routes/admin+/$organization.settings/forms/integration-settings.tsx
  • app/routes/admin+/$organization.settings/forms/organization-settings.tsx
  • app/routes/admin+/$organization.settings/functions/mutations.server.ts
  • app/routes/admin+/$organization.settings/functions/queries.server.ts
  • app/routes/admin+/create/mutations.server.ts
  • app/routes/resources+/organization/route.tsx
  • app/services/prisma.server.ts
  • app/services/type.ts
  • atlas.hcl
  • batch/bizlogic/export-spreadsheet.ts
  • batch/db/mutations.ts
  • batch/db/queries.ts
  • batch/provider/github/provider.ts
  • batch/provider/github/pullrequest.ts
  • batch/provider/index.ts
  • db/migrations/20251224122040_initial.sql
  • db/schema.sql
  • db/seed.ts
  • package.json
  • prisma/migrations/20230804131847_init/migration.sql
  • prisma/migrations/20230818024457_change_number_to_int/migration.sql
  • prisma/migrations/20240129044150_snake_case_table_and_column_name/migration.sql
  • prisma/migrations/20240129070258_add_team_repository/migration.sql
  • prisma/migrations/20240420114246_fix_repository_unique_key/migration.sql
  • prisma/migrations/20240421004556_migrate_datetime_from_unix_to_iso/migration.sql
  • prisma/migrations/20250207031843_add_company_github_user/migration.sql
  • prisma/migrations/20250408033427_better_auth/migration.sql
  • prisma/migrations/20250408101920_migrate_company_to_organization_phase1/migration.sql
  • prisma/migrations/20250408102129_migrate_company_to_organization_phase3_cleanup/migration.sql
  • prisma/migrations/20251216104437_add_excluded_users_to_organization_settings/migration.sql
  • prisma/migrations/migration_lock.toml
  • prisma/schema.prisma
  • start.sh
💤 Files with no reviewable changes (14)
  • prisma/migrations/20240129070258_add_team_repository/migration.sql
  • prisma/migrations/20250408033427_better_auth/migration.sql
  • prisma/migrations/20250408102129_migrate_company_to_organization_phase3_cleanup/migration.sql
  • prisma/migrations/20251216104437_add_excluded_users_to_organization_settings/migration.sql
  • prisma/migrations/20250207031843_add_company_github_user/migration.sql
  • prisma/migrations/20230818024457_change_number_to_int/migration.sql
  • prisma/migrations/20240420114246_fix_repository_unique_key/migration.sql
  • app/services/prisma.server.ts
  • prisma/schema.prisma
  • prisma/migrations/20230804131847_init/migration.sql
  • prisma/migrations/migration_lock.toml
  • prisma/migrations/20240421004556_migrate_datetime_from_unix_to_iso/migration.sql
  • prisma/migrations/20240129044150_snake_case_table_and_column_name/migration.sql
  • prisma/migrations/20250408101920_migrate_company_to_organization_phase1/migration.sql
🧰 Additional context used
📓 Path-based instructions (6)
app/routes/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use file-based routing with remix-flat-routes convention: use _layout.tsx for layout routes, _index.tsx for index routes, $param for dynamic segments, and nested route folders like $organization.settings/

Files:

  • app/routes/admin+/$organization.settings/forms/integration-settings.tsx
  • app/routes/admin+/$organization.repositories.add/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts
  • app/routes/admin+/$organization.settings/forms/delete-organization.tsx
  • app/routes/admin+/$organization.repositories._index/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/mutations.ts
  • app/routes/_dashboard+/$organization._index/functions/queries.ts
  • app/routes/admin+/$organization.settings/forms/organization-settings.tsx
  • app/routes/admin+/create/mutations.server.ts
  • app/routes/admin+/$organization.settings/functions/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts
  • app/routes/admin+/$organization.repositories.add/functions/queries.ts
  • app/routes/admin+/$organization.members/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts
  • app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts
  • app/routes/_dashboard+/$organization.ongoing/functions/queries.ts
  • app/routes/resources+/organization/route.tsx
  • app/routes/admin+/$organization.settings/forms/export-settings.tsx
  • app/routes/admin+/$organization.settings/functions/mutations.server.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • app/routes/admin+/$organization.settings/forms/integration-settings.tsx
  • app/routes/admin+/$organization.repositories.add/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts
  • batch/provider/index.ts
  • app/routes/admin+/$organization.settings/forms/delete-organization.tsx
  • app/routes/admin+/$organization.repositories._index/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/mutations.ts
  • app/routes/_dashboard+/$organization._index/functions/queries.ts
  • app/components/ui/heading.tsx
  • app/routes/admin+/$organization.settings/forms/organization-settings.tsx
  • app/routes/admin+/create/mutations.server.ts
  • app/routes/admin+/$organization.settings/functions/queries.server.ts
  • batch/provider/github/pullrequest.ts
  • app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts
  • app/routes/admin+/$organization.repositories.add/functions/queries.ts
  • batch/provider/github/provider.ts
  • batch/db/mutations.ts
  • app/routes/admin+/$organization.members/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/mutations.ts
  • batch/db/queries.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts
  • batch/bizlogic/export-spreadsheet.ts
  • app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts
  • app/components/AppSortableHeader.tsx
  • app/routes/_dashboard+/$organization.ongoing/functions/queries.ts
  • app/routes/resources+/organization/route.tsx
  • app/services/type.ts
  • app/routes/admin+/$organization.settings/forms/export-settings.tsx
  • app/components/ui/stack.tsx
  • app/routes/admin+/$organization.settings/functions/mutations.server.ts
batch/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Organize batch processing CLI jobs in batch/ directory with separate files for commands (fetch, report, upsert) and provider integrations (GitHub API)

Files:

  • batch/provider/index.ts
  • batch/provider/github/pullrequest.ts
  • batch/provider/github/provider.ts
  • batch/db/mutations.ts
  • batch/db/queries.ts
  • batch/bizlogic/export-spreadsheet.ts
**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Kysely for runtime database queries with type-safe generated types from Prisma schema (located in app/services/type.ts)

Files:

  • app/routes/admin+/$organization.repositories._index/queries.server.ts
  • app/routes/admin+/create/mutations.server.ts
  • app/routes/admin+/$organization.settings/functions/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts
  • app/routes/admin+/$organization.members/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts
  • app/routes/admin+/$organization.settings/functions/mutations.server.ts
app/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use shadcn/ui components with new-york style and Tailwind CSS v4 for the UI

Files:

  • app/components/ui/heading.tsx
  • app/components/AppSortableHeader.tsx
  • app/components/ui/stack.tsx
app/services/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use server-side services organized in app/services/ for database clients (db.server.ts, prisma.server.ts) and type definitions (type.ts from prisma-kysely generation)

Files:

  • app/services/type.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to prisma/** : Use Prisma for schema definition, migrations, and seeding via prisma/schema.prisma and prisma/seed.ts
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to **/*.server.{ts,tsx} : Use Kysely for runtime database queries with type-safe generated types from Prisma schema (located in app/services/type.ts)
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to app/services/**/*.{ts,tsx} : Use server-side services organized in app/services/ for database clients (db.server.ts, prisma.server.ts) and type definitions (type.ts from prisma-kysely generation)
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to app/services/**/*.{ts,tsx} : Use server-side services organized in app/services/ for database clients (db.server.ts, prisma.server.ts) and type definitions (type.ts from prisma-kysely generation)

Applied to files:

  • app/routes/admin+/$organization.repositories.add/functions/mutations.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts
  • batch/provider/index.ts
  • app/routes/admin+/$organization.repositories.$repository.delete/functions/mutations.ts
  • app/routes/admin+/$organization.settings/functions/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts
  • app/routes/admin+/$organization.members/queries.server.ts
  • app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts
  • app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts
  • app/services/type.ts
  • package.json
  • app/routes/admin+/$organization.settings/functions/mutations.server.ts
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to batch/**/*.ts : Organize batch processing CLI jobs in batch/ directory with separate files for commands (fetch, report, upsert) and provider integrations (GitHub API)

Applied to files:

  • batch/provider/index.ts
  • batch/provider/github/provider.ts
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to **/*.server.{ts,tsx} : Use Kysely for runtime database queries with type-safe generated types from Prisma schema (located in app/services/type.ts)

Applied to files:

  • app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts
  • app/services/type.ts
  • package.json
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to app/components/**/*.{ts,tsx} : Use shadcn/ui components with new-york style and Tailwind CSS v4 for the UI

Applied to files:

  • app/components/AppSortableHeader.tsx
  • app/components/ui/stack.tsx
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to app/routes/**/*.{ts,tsx} : Use file-based routing with remix-flat-routes convention: use `_layout.tsx` for layout routes, `_index.tsx` for index routes, `$param` for dynamic segments, and nested route folders like `$organization.settings/`

Applied to files:

  • app/routes/resources+/organization/route.tsx
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to prisma/** : Use Prisma for schema definition, migrations, and seeding via prisma/schema.prisma and prisma/seed.ts

Applied to files:

  • package.json
  • Dockerfile
  • start.sh
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Use Biome for linting and Prettier for code formatting, with pnpm lint and pnpm format:fix commands

Applied to files:

  • package.json
  • Dockerfile
📚 Learning: 2025-12-24T12:15:11.101Z
Learnt from: CR
Repo: coji/upflow PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-24T12:15:11.101Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use Vitest for unit testing and Playwright for E2E testing

Applied to files:

  • package.json
🧬 Code graph analysis (22)
app/routes/admin+/$organization.settings/forms/integration-settings.tsx (2)
app/services/db.server.ts (1)
  • Selectable (18-18)
app/services/type.ts (1)
  • Integrations (50-56)
app/routes/admin+/$organization.repositories.add/functions/mutations.ts (2)
app/services/type.ts (2)
  • Organizations (76-83)
  • Repositories (119-130)
app/services/db.server.ts (1)
  • Insertable (18-18)
app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts (4)
app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts (1)
  • getRepository (4-20)
app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts (1)
  • getRepository (3-9)
app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts (1)
  • getRepository (3-9)
app/services/type.ts (1)
  • Repositories (119-130)
app/routes/admin+/$organization.settings/forms/delete-organization.tsx (2)
app/services/db.server.ts (1)
  • Selectable (18-18)
app/services/type.ts (1)
  • Organizations (76-83)
app/routes/admin+/$organization.repositories._index/queries.server.ts (1)
app/services/type.ts (1)
  • Organizations (76-83)
app/routes/admin+/$organization.repositories.$repository.delete/functions/mutations.ts (1)
app/services/type.ts (1)
  • Repositories (119-130)
app/routes/_dashboard+/$organization._index/functions/queries.ts (1)
app/services/type.ts (1)
  • Organizations (76-83)
app/routes/admin+/$organization.settings/forms/organization-settings.tsx (1)
app/services/type.ts (3)
  • DB (168-182)
  • Organizations (76-83)
  • OrganizationSettings (85-94)
app/routes/admin+/create/mutations.server.ts (1)
app/services/type.ts (1)
  • Organizations (76-83)
app/routes/admin+/$organization.settings/functions/queries.server.ts (3)
app/services/type.ts (1)
  • Organizations (76-83)
app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts (1)
  • getIntegration (11-19)
app/routes/admin+/$organization.repositories.add/functions/queries.ts (1)
  • getIntegration (4-23)
batch/provider/github/pullrequest.ts (2)
app/services/db.server.ts (1)
  • Selectable (18-18)
app/services/type.ts (2)
  • DB (168-182)
  • PullRequests (96-117)
app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts (4)
app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts (1)
  • getRepository (4-20)
app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts (1)
  • getRepository (3-9)
app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts (1)
  • getRepository (3-9)
app/services/type.ts (1)
  • Repositories (119-130)
app/routes/admin+/$organization.repositories.add/functions/queries.ts (3)
app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts (1)
  • getIntegration (11-19)
app/routes/admin+/$organization.settings/functions/queries.server.ts (1)
  • getIntegration (33-41)
app/services/type.ts (1)
  • Organizations (76-83)
batch/db/mutations.ts (2)
app/services/db.server.ts (2)
  • Insertable (18-18)
  • DB (18-18)
app/services/type.ts (1)
  • PullRequests (96-117)
app/routes/admin+/$organization.members/queries.server.ts (1)
app/services/type.ts (1)
  • Organizations (76-83)
app/routes/admin+/$organization.repositories.$repository.settings/functions/mutations.ts (2)
app/services/type.ts (1)
  • Repositories (119-130)
app/services/db.server.ts (1)
  • Updateable (18-18)
batch/db/queries.ts (1)
app/services/type.ts (2)
  • DB (168-182)
  • Organizations (76-83)
batch/bizlogic/export-spreadsheet.ts (2)
app/services/type.ts (1)
  • PullRequests (96-117)
app/routes/admin+/$organization.settings/forms/export-settings.tsx (1)
  • ExportSettings (28-89)
app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts (1)
app/services/type.ts (2)
  • Repositories (119-130)
  • PullRequests (96-117)
app/components/AppSortableHeader.tsx (1)
app/components/ui/button.tsx (1)
  • Button (58-58)
app/routes/_dashboard+/$organization.ongoing/functions/queries.ts (1)
app/services/type.ts (1)
  • Organizations (76-83)
app/services/type.ts (2)
app/routes/admin+/$organization.settings/forms/organization-settings.tsx (1)
  • OrganizationSettings (35-162)
app/services/db.server.ts (1)
  • DB (18-18)
🔇 Additional comments (58)
app/components/ui/stack.tsx (1)

34-37: LGTM! Formatting improvement for readability.

The interface declaration formatting has been improved by breaking the extends clause across multiple lines, making it easier to read without changing any behavior.

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

22-25: LGTM! Consistent formatting improvement.

The interface extends clause formatting matches the style improvements seen in other UI components, enhancing readability without any behavioral changes.

app/components/AppSortableHeader.tsx (1)

7-9: LGTM! Formatting consistency maintained.

The interface declaration formatting aligns with the same style improvements applied across other components in this PR, maintaining consistency.

app/routes/_dashboard+/$organization.ongoing/functions/queries.ts (1)

5-9: LGTM! Type signature updated consistently.

The parameter type has been correctly updated to use the pluralized DB.Organizations type, aligning with the Atlas migration. The query logic remains unchanged.

app/routes/admin+/$organization.members/queries.server.ts (1)

3-11: LGTM! Type signature updated consistently.

The parameter type has been correctly updated to use the pluralized DB.Organizations type, consistent with the migration to Atlas-generated types.

app/routes/admin+/$organization.repositories._index/queries.server.ts (1)

3-11: LGTM! Type signature updated consistently.

The parameter type correctly uses the pluralized DB.Organizations type, maintaining consistency with the Atlas migration.

batch/provider/github/pullrequest.ts (1)

42-42: LGTM! Type annotation updated consistently.

The array type has been correctly updated to use DB.PullRequests (plural), aligning with the migration to Atlas-generated types.

batch/provider/index.ts (1)

5-8: LGTM! Type signature updated consistently.

The parameter type has been correctly updated to use DB.Integrations (plural), maintaining consistency with the Atlas-generated types.

app/routes/admin+/$organization.repositories.add/functions/mutations.ts (1)

4-44: LGTM! Type signatures updated consistently.

Both parameter types have been correctly updated to use pluralized types (DB.Organizations and DB.Repositories), aligning with the Atlas migration. The mutation logic remains unchanged.

app/routes/admin+/$organization.repositories.$repository.delete/functions/queries.ts (1)

3-9: LGTM! Type signature updated consistently.

The parameter type has been correctly updated to use DB.Repositories (plural), maintaining consistency with the Atlas-generated types across all repository-related queries.

start.sh (1)

10-18: Database path and migration baseline are correctly configured.

The hardcoded migration baseline 20251224122040 matches the actual first migration file at db/migrations/20251224122040_initial.sql, and the database path /upflow/data/data.db aligns with the Fly.io volume mount configured in fly.toml (destination = "/upflow/data"). Both values are correctly set for the production environment.

batch/db/mutations.ts (1)

4-4: LGTM! Type update aligns with pluralization pattern.

The function signature correctly updated from Insertable<DB.PullRequest> to Insertable<DB.PullRequests>, consistent with the broader migration to pluralized DB types.

app/routes/admin+/$organization.settings/forms/delete-organization.tsx (1)

21-23: LGTM! Type update is correct.

The prop type correctly updated from Selectable<DB.Organization> to Selectable<DB.Organizations>, consistent with the pluralized DB namespace.

app/routes/admin+/$organization.settings/forms/export-settings.tsx (1)

24-26: LGTM! Type update is correct.

The prop type correctly updated from Selectable<DB.ExportSetting> to Selectable<DB.ExportSettings>, consistent with the pluralized DB namespace.

app/routes/admin+/$organization.settings/forms/integration-settings.tsx (1)

31-33: LGTM! Type update is correct.

The prop type correctly updated from Selectable<DB.Integration> to Selectable<DB.Integrations>, consistent with the pluralized DB namespace.

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

25-29: LGTM! Formatting improvement.

The interface declaration has been reformatted from a single line to multiple lines, improving readability without any semantic changes.

app/routes/admin+/$organization.repositories.$repository.delete/functions/mutations.ts (1)

3-5: LGTM! Type update is correct.

The parameter type correctly updated from DB.Repository['id'] to DB.Repositories['id'], consistent with the pluralized DB namespace.

batch/db/queries.ts (2)

4-6: LGTM! Type update is correct.

The parameter type correctly updated from DB.Organization['id'] to DB.Organizations['id'], consistent with the pluralized DB namespace.


86-88: LGTM! Type update is correct.

The parameter type correctly updated from DB.Organization['id'] to DB.Organizations['id'], consistent with the pluralized DB namespace.

atlas.hcl (1)

1-12: LGTM! Atlas setup is complete and verified.

The Atlas configuration for the local environment is well-structured. All referenced files exist: db/schema.sql, the db/migrations directory with migration files (e.g., 20251224122040_initial.sql), and the atlas.hcl configuration itself. The SQLite in-memory dev database is appropriate for local development.

app/routes/_dashboard+/$organization._index/functions/queries.ts (1)

5-10: LGTM! Type annotation updated correctly.

The parameter type change from DB.Organization['id'] to DB.Organizations['id'] correctly aligns with the broader migration to pluralized DB type names throughout the codebase.

app/routes/admin+/create/mutations.server.ts (1)

3-9: LGTM! Parameter types updated correctly.

The parameter type updates from DB.Organization['id'] and DB.Organization['name'] to DB.Organizations['id'] and DB.Organizations['name'] correctly align with the pluralized DB type system.

app/routes/admin+/$organization.repositories.$repository._index/queries.server.ts (2)

3-9: LGTM! Type annotation updated correctly.

The parameter type change from DB.Repository['id'] to DB.Repositories['id'] correctly aligns with the pluralized DB type system.


11-18: Ordering implementation is correct and matches UI expectations.

The .orderBy('number', 'desc') change is properly implemented at the database query level. The consuming component in route.tsx renders the pulls directly without client-side reordering, relying entirely on the database order. Descending by PR number (newest first) is a standard and appropriate ordering for pull request lists, and no component assumptions are broken by this change.

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

35-41: LGTM! Component prop types updated correctly.

The prop type changes from Selectable<DB.Organization> to Selectable<DB.Organizations> and Selectable<DB.OrganizationSetting> to Selectable<DB.OrganizationSettings> correctly align with the pluralized DB type system.

app/routes/admin+/$organization.repositories.add/functions/queries.ts (2)

4-23: LGTM! Type annotations and formatting updated correctly.

The parameter type changes from DB.Organization['id'] to DB.Organizations['id'] correctly align with the pluralized DB type system. The multi-line parameter formatting improves readability and is consistent with similar functions across the codebase.


25-33: LGTM! Type annotation updated correctly.

The parameter type change from DB.Organization['id'] to DB.Organizations['id'] correctly aligns with the pluralized DB type system.

app/routes/admin+/$organization.repositories.$repository.settings/functions/mutations.ts (1)

3-12: LGTM! Function signature updated correctly.

The parameter type changes from DB.Repository['id'] to DB.Repositories['id'] and from Updateable<DB.Repository> to Updateable<DB.Repositories> correctly align with the pluralized DB type system.

package.json (3)

15-18: LGTM! Database workflow successfully migrated to Atlas/Kysely.

The new scripts correctly implement the Atlas/Kysely workflow:

  • setup: Applies migrations and runs seed
  • db:generate: Generates types with kysely-codegen
  • db:migrate: Creates migration diffs with Atlas
  • db:apply: Applies migrations with Atlas

This aligns with the PR objective to migrate from Prisma to Atlas + kysely-codegen.

Based on learnings, this represents a significant shift from the previous Prisma-based approach.


128-128: No action required. Version 0.19.0 is compatible with Kysely 0.28.2 (explicitly supported via fixed peer dependencies in that release) and is already the latest stable version available.


131-133: Both plugins are compatible with Prettier 3.7.4. prettier-plugin-organize-imports 4.3.0 supports Prettier 3 as documented, and prettier-plugin-tailwindcss 0.7.2 includes a fix for Prettier v3.7+ compatibility. No breaking changes identified.

app/routes/admin+/$organization.repositories.$repository.$pull/queries.server.ts (2)

4-20: LGTM! Type annotation updated correctly.

The parameter type change from DB.Repository['id'] to DB.Repositories['id'] correctly aligns with the pluralized DB type system.


22-32: LGTM! Function signature updated correctly.

The parameter type changes from DB.Repository['id'] to DB.Repositories['id'] and from DB.PullRequest['number'] to DB.PullRequests['number'] correctly align with the pluralized DB type system.

app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts (2)

3-9: LGTM!

Type signature correctly updated to DB.Repositories['id']. Query logic remains sound.


11-19: LGTM!

Type signature correctly updated to DB.Organizations['id']. The multi-line parameter formatting improves readability.

batch/bizlogic/export-spreadsheet.ts (2)

13-16: LGTM!

Type signatures correctly updated to pluralized forms (DB.PullRequests, DB.ExportSettings). The Selectable<> wrapper is appropriate for read-only data passed into the function.


81-90: LGTM!

Type signature for exportSetting correctly updated to Selectable<DB.ExportSettings>.

app/routes/admin+/$organization.settings/functions/queries.server.ts (4)

3-11: LGTM!

Type signature correctly updated to DB.Organizations['id'].


13-21: LGTM!

Consistent with the pluralized type migration pattern.


23-31: LGTM!

Type signature correctly updated.


33-41: LGTM!

The multi-line parameter formatting aligns with the pattern used in app/routes/admin+/$organization.repositories.$repository.settings/functions/queries.ts.

batch/provider/github/provider.ts (2)

10-12: LGTM!

Type signature correctly updated to Selectable<DB.Integrations>.


108-120: LGTM!

Type signatures correctly updated to pluralized forms (DB.OrganizationSettings, DB.Repositories[], DB.PullRequests[]).

Dockerfile (3)

44-45: LGTM!

Prisma generate step correctly removed since type generation is now handled by kysely-codegen.


61-71: LGTM!

Artifact copying correctly updated:

  • node_modules sourced from production-deps stage for smaller image
  • prisma directory replaced with db and atlas.hcl for Atlas-based migrations

7-13: Atlas CLI installation using the official script is correct.

The curl -sSf https://atlasgo.sh | sh approach uses Ariga's official installation script, which properly detects architecture and distribution. The rm -rf /var/lib/apt/lists/* cleanup is appropriately placed after package installation to minimize image size.

db/schema.sql (2)

1-14: LGTM!

Users table is well-structured with appropriate audit fields and constraints.


152-176: LGTM!

The pull_requests table correctly uses a composite primary key (repository_id, number) which aligns with the domain model where PR numbers are unique per repository.

app/services/type.ts (2)

1-11: LGTM!

This file is correctly marked as auto-generated by kysely-codegen. The Generated<T> utility type properly handles columns with default values.


168-182: LGTM!

The DB interface correctly maps camelCase table names to their corresponding pluralized interfaces, maintaining consistency with Kysely's table reference pattern (e.g., db.selectFrom('organizations')).

app/routes/admin+/$organization.settings/functions/mutations.server.ts (5)

10-19: LGTM!

Type signatures correctly updated. The Omit<..., 'createdAt'> properly prevents modification of the audit field.


21-36: LGTM!

Type signature correctly updated to DB.OrganizationSettings. The sql\CURRENT_TIMESTAMP`usage forupdatedAt` is appropriate for SQLite.


38-44: LGTM!

Type signatures correctly updated to pluralized forms.


46-61: LGTM!

Upsert pattern with onConflict is correctly implemented. Using nanoid() for ID generation when not provided is a good approach.


63-79: LGTM!

Consistent upsert pattern with proper conflict resolution and timestamp handling.

db/migrations/20251224122040_initial.sql (3)

170-181: Inconsistent datetime types in pull_requests table.

Several timestamp columns use text type instead of datetime:

  • first_committed_at, pull_request_created_at, first_reviewed_at, merged_at, released_at, updated_at

This differs from other tables (e.g., users, organizations) which use datetime. This inconsistency can cause sorting/comparison issues.

If these are intentionally stored as ISO strings from GitHub API responses, this may be acceptable. Otherwise, consider aligning with datetime for consistency.


1-200: Overall schema structure looks solid for the Prisma to Atlas migration.

The migration successfully establishes:

  • Proper multi-tenant isolation via organization_id FKs with CASCADE deletes
  • Consistent naming conventions
  • Appropriate indexing strategy for common query patterns

The issues noted above are refinements rather than blockers. Based on the retrieved learnings, note that CLAUDE.md references Prisma for schema definition—you may want to update that documentation to reflect the new Atlas workflow.


2-15: Consider adding a UNIQUE constraint on users.email or verify that better-auth enforces email uniqueness programmatically.

The email column lacks a unique constraint in the database schema. While the OAuth architecture supports multiple provider accounts per user, having no uniqueness enforcement on email—combined with the lack of visible application-level validation—is inconsistent with how other critical identifiers are handled (e.g., organizations.slug, sessions.token both have UNIQUE indexes). Either add a UNIQUE index on email or confirm that better-auth (v1.2.9) enforces this constraint at the library level.

- Update tech stack description
- Replace Prisma references with Atlas/kysely-codegen
- Document new db:* commands
- Update project structure (db/ instead of prisma/)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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