Skip to content

Test payments scheduling#143

Open
jhechtf wants to merge 8 commits into
mainfrom
test-payments-scheduling
Open

Test payments scheduling#143
jhechtf wants to merge 8 commits into
mainfrom
test-payments-scheduling

Conversation

@jhechtf

@jhechtf jhechtf commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added a bill aggregator module that generates monthly payment records via a Supabase Edge Function, with automated job-run tracking.
    • Introduced new database structures for bills, payments, invitations, storage, and job execution history.
  • Documentation
    • Expanded the repo “Shape of the Repo” and added setup instructions for using the Supabase CLI for the new module.
  • Tests
    • Added unit coverage for monthly due-date calculation logic.
  • Chores
    • Updated CI workflow settings and improved dev/editor and formatting ignore rules.

@jhechtf jhechtf self-assigned this Jun 4, 2026
@vercel

vercel Bot commented Jun 4, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
bill-tracker-mono Ready Ready Preview, Comment Jul 24, 2026 8:13pm

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Introduces a bill aggregator system with PostgreSQL and Drizzle schemas, a Deno Supabase Edge Function for monthly payment generation, job-run tracking, date utilities, and supporting setup documentation.

Changes

Bill Aggregator System

Layer / File(s) Summary
Database schema and ORM mappings
packages/db/drizzle/..., packages/db/src/...
Adds billing, household, payment, membership, invitation, storage, and job-run schemas, relationships, migration metadata, indexes, and database exports.
Date calculation helper
apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.*
Adds and tests next-month ISO date calculation.
Payment generation edge function
apps/bill-aggregator/supabase/functions/generate-monthly-payments/index.ts
Processes bills in batches, upserts monthly payments, records job metrics and errors, and returns JSON status responses.
Project setup and documentation
apps/bill-aggregator/..., .vscode/settings.json, README.md, .gitignore, .prettierignore, .github/workflows/e2e.yml
Adds Deno and package configuration, editor and ignore settings, CI adjustment, and Supabase CLI deployment instructions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • sungmanito/mono#122: Both changes concern monthly payment generation and payments upserts keyed by bill and month.

Poem

🐰 Bills hop in batches, neat and bright,

Payments bloom for each new month’s light,
Schemas keep every record in tune,
Job runs report from dawn to moon,
The rabbit approves this tidy flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly refers to the payments scheduling work added in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test-payments-scheduling

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
.prettierignore (1)

4-5: ⚡ Quick win

Consider using recursive pattern for JSON files.

The pattern *.json only matches JSON files in the root directory, while **/supabase/** uses the recursive ** pattern. In this monorepo, you likely want to ignore JSON files at all levels (e.g., apps/bill-aggregator/package.json, apps/bill-aggregator/supabase/functions/deno.json).

If the intent is to skip formatting all JSON files throughout the repository, use **/*.json instead:

📝 Suggested pattern for consistency
-*.json
+**/*.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.prettierignore around lines 4 - 5, Update the .prettierignore JSON pattern
to be recursive so JSON files in subdirectories are ignored; replace the
root-only pattern "*.json" with the recursive "**/*.json" (keeping the existing
"**/supabase/**" entry) so files like apps/.../package.json and nested supabase
JSON files are covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/bill-aggregator/supabase/functions/deno.json`:
- Line 3: The dependency entry for "`@supabase/supabase-js`" currently uses a
floating major spec "https://esm.sh/@supabase/supabase-js@2" which yields
non-deterministic builds; update the value to a pinned exact release (for
example replace the URL with "https://esm.sh/@supabase/supabase-js@2.107.0" or
another specific 2.x.y release) in the deno.json dependency entry so that the
resolver always fetches the exact version.

In `@apps/bill-aggregator/supabase/functions/generate-monthly-payments/index.ts`:
- Around line 4-5: The parseInt calls for BATCH_SIZE and BATCH_DELAY_MS should
specify a radix to avoid octal parsing; update the two occurrences where
BATCH_SIZE and BATCH_DELAY_MS are defined (currently using
parseInt(Deno.env.get(...))) to call parseInt(..., 10) so both parseInt
invocations explicitly use radix 10.

In
`@apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.ts`:
- Around line 6-13: The function nextMonthDateFor mixes local and UTC getters
causing off-by-one-month near timezone boundaries; update it to use UTC getters
consistently by calling referenceDate.getUTCFullYear() and
referenceDate.getUTCMonth() (instead of getFullYear/getMonth) when constructing
next (and keep using next.getUTCFullYear()/getUTCMonth() and the existing
year/month/day formatting), so the month calculation uses a single timezone
basis for referenceDate, next, year, month and day.

In `@packages/db/drizzle/0000_tough_george_stacy.sql`:
- Around line 67-73: The storage.objects table defines id but lacks a PRIMARY
KEY; add a primary key constraint on the id column so that
payments.proof_image_id can validly reference storage.objects(id). Update the
CREATE TABLE "storage"."objects" statement to declare "id" uuid ... PRIMARY KEY
(or add an ALTER TABLE "storage"."objects" ADD PRIMARY KEY (id)) ensuring the id
column is unique and not null; verify the foreign key in payments.proof_image_id
continues to reference storage.objects(id) after the change.
- Around line 11-17: The table "auth"."identities" is missing a PRIMARY KEY;
update the schema for the auth.identities table to declare a primary key (either
single-column on "id" or a composite key on ("id","provider") depending on the
intended uniqueness); modify the CREATE TABLE for auth.identities to include
PRIMARY KEY(...) or add an ALTER TABLE "auth"."identities" ADD CONSTRAINT ...
PRIMARY KEY(...) statement referencing the "id" and/or "provider" columns so the
table enforces uniqueness.

---

Nitpick comments:
In @.prettierignore:
- Around line 4-5: Update the .prettierignore JSON pattern to be recursive so
JSON files in subdirectories are ignored; replace the root-only pattern "*.json"
with the recursive "**/*.json" (keeping the existing "**/supabase/**" entry) so
files like apps/.../package.json and nested supabase JSON files are covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9dc26046-2dc3-4d2c-aaea-1a0b714834d1

📥 Commits

Reviewing files that changed from the base of the PR and between 131f773 and 00c5499.

⛔ Files ignored due to path filters (2)
  • apps/bill-aggregator/supabase/functions/deno.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • .github/workflows/e2e.yml
  • .gitignore
  • .prettierignore
  • .vscode/settings.json
  • README.md
  • apps/bill-aggregator/package.json
  • apps/bill-aggregator/supabase/functions/deno.json
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/index.ts
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.test.ts
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.ts
  • packages/db/drizzle/0000_tough_george_stacy.sql
  • packages/db/drizzle/meta/0000_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/src/index.ts
  • packages/db/src/tables/index.ts
  • packages/db/src/tables/jobRuns.table.ts
💤 Files with no reviewable changes (1)
  • .github/workflows/e2e.yml

Comment thread apps/bill-aggregator/supabase/functions/deno.json Outdated
Comment thread apps/bill-aggregator/supabase/functions/generate-monthly-payments/index.ts Outdated
Comment on lines +11 to +17
CREATE TABLE "auth"."identities" (
"id" text NOT NULL,
"provider" text NOT NULL,
"user_id" uuid NOT NULL,
"email" text NOT NULL,
"updated_at" timestamp with time zone NOT NULL
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing PRIMARY KEY on auth.identities table.

The auth.identities table has no PRIMARY KEY constraint. Consider adding a primary key on id or a composite key on (id, provider) depending on the intended uniqueness semantics.

🐛 Proposed fix (single-column PK)
 CREATE TABLE "auth"."identities" (
-	"id" text NOT NULL,
+	"id" text PRIMARY KEY NOT NULL,
 	"provider" text NOT NULL,
 	"user_id" uuid NOT NULL,
 	"email" text NOT NULL,
 	"updated_at" timestamp with time zone NOT NULL
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/drizzle/0000_tough_george_stacy.sql` around lines 11 - 17, The
table "auth"."identities" is missing a PRIMARY KEY; update the schema for the
auth.identities table to declare a primary key (either single-column on "id" or
a composite key on ("id","provider") depending on the intended uniqueness);
modify the CREATE TABLE for auth.identities to include PRIMARY KEY(...) or add
an ALTER TABLE "auth"."identities" ADD CONSTRAINT ... PRIMARY KEY(...) statement
referencing the "id" and/or "provider" columns so the table enforces uniqueness.

Comment on lines +67 to +73
CREATE TABLE "storage"."objects" (
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"bucket_id" text NOT NULL,
"name" text NOT NULL,
"owner" uuid,
"path_tokens" text[]
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing PRIMARY KEY on storage.objects table.

The storage.objects table defines an id column but lacks a PRIMARY KEY constraint. Line 94 adds a foreign key from payments.proof_image_id referencing storage.objects(id), which requires the referenced column to have a PRIMARY KEY or UNIQUE constraint.

🐛 Proposed fix
 CREATE TABLE "storage"."objects" (
-	"id" uuid DEFAULT gen_random_uuid() NOT NULL,
+	"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
 	"bucket_id" text NOT NULL,
 	"name" text NOT NULL,
 	"owner" uuid,
 	"path_tokens" text[]
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/drizzle/0000_tough_george_stacy.sql` around lines 67 - 73, The
storage.objects table defines id but lacks a PRIMARY KEY; add a primary key
constraint on the id column so that payments.proof_image_id can validly
reference storage.objects(id). Update the CREATE TABLE "storage"."objects"
statement to declare "id" uuid ... PRIMARY KEY (or add an ALTER TABLE
"storage"."objects" ADD PRIMARY KEY (id)) ensuring the id column is unique and
not null; verify the foreign key in payments.proof_image_id continues to
reference storage.objects(id) after the change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/db/drizzle/schema.ts`:
- Line 1: Run the repository’s Prettier formatting command on
packages/db/drizzle/schema.ts (anchor, line 1) and
packages/db/drizzle/relations.ts (sibling, line 1), applying the formatter’s
generated style to both files without changing their behavior.
- Line 81: Change bills.amount in packages/db/drizzle/schema.ts at line 81 from
double precision to a numeric column using precision 12 and scale 2, with a
string zero default and not-null constraint, matching payments.amount’s numeric
strategy. Regenerate packages/db/drizzle/meta/0000_snapshot.json at lines
238-244 with Drizzle tooling and ensure the migration SQL reflects the corrected
bills.amount type.
- Around line 6-7: Wrap the PostgreSQL ID defaults in Drizzle SQL expressions
instead of invoking bare identifiers. Update the id fields in payments, invites,
bills, households, and jobRuns to use the existing default(sql`identifier()`)
pattern, ensuring schema evaluation does not reference undefined JavaScript
functions and generated defaults include the intended PostgreSQL expression.
- Line 18: Update the uniqueIndex definitions billId_month and the
users_to_households composite index to use operator classes matching each column
type: use text_ops for text columns, uuid_ops for userId, and date_ops only for
date columns. Preserve the existing index ordering and null handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f1004b08-85ea-4021-9a71-c8bf4c82681a

📥 Commits

Reviewing files that changed from the base of the PR and between 00c5499 and 4653a5f.

⛔ Files ignored due to path filters (2)
  • apps/bill-aggregator/supabase/functions/deno.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (18)
  • .github/workflows/e2e.yml
  • .gitignore
  • .prettierignore
  • .vscode/settings.json
  • README.md
  • apps/bill-aggregator/package.json
  • apps/bill-aggregator/supabase/functions/deno.json
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/index.ts
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.test.ts
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.ts
  • packages/db/drizzle/0000_tough_george_stacy.sql
  • packages/db/drizzle/meta/0000_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/drizzle/relations.ts
  • packages/db/drizzle/schema.ts
  • packages/db/src/index.ts
  • packages/db/src/tables/index.ts
  • packages/db/src/tables/jobRuns.table.ts
💤 Files with no reviewable changes (1)
  • .github/workflows/e2e.yml
🚧 Files skipped from review as they are similar to previous changes (12)
  • apps/bill-aggregator/package.json
  • packages/db/src/index.ts
  • apps/bill-aggregator/supabase/functions/deno.json
  • packages/db/src/tables/index.ts
  • packages/db/drizzle/meta/_journal.json
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.test.ts
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/next-month-date.ts
  • packages/db/src/tables/jobRuns.table.ts
  • .prettierignore
  • packages/db/drizzle/0000_tough_george_stacy.sql
  • .vscode/settings.json
  • apps/bill-aggregator/supabase/functions/generate-monthly-payments/index.ts

@@ -0,0 +1,136 @@
import { pgTable, uniqueIndex, index, foreignKey, text, timestamp, uuid, date, numeric, integer, doublePrecision } from "drizzle-orm/pg-core"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Prettier formatting failures in both generated files. CI reports the same formatting check failing across these two files; run the formatter to fix both in one pass.

  • packages/db/drizzle/schema.ts#L1-L1: run prettier . --write (or your repo's formatting script) to resolve the reported style issues.
  • packages/db/drizzle/relations.ts#L1-L1: same fix, same command.
🧰 Tools
🪛 GitHub Actions: Pr Checks / 1_formatter.txt

[warning] 1-1: Prettier reported formatting/code style issues in this file. Run 'prettier . --write' to fix.

🪛 GitHub Actions: Pr Checks / formatter

[warning] 1-1: Prettier check reported code style issues in this file.

📍 Affects 2 files
  • packages/db/drizzle/schema.ts#L1-L1 (this comment)
  • packages/db/drizzle/relations.ts#L1-L1
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/drizzle/schema.ts` at line 1, Run the repository’s Prettier
formatting command on packages/db/drizzle/schema.ts (anchor, line 1) and
packages/db/drizzle/relations.ts (sibling, line 1), applying the formatter’s
generated style to both files without changing their behavior.

Source: Pipeline failures

Comment on lines +6 to +7
export const payments = pgTable("payments", {
id: text().default(generate_ulid()).primaryKey().notNull(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm generate_ulid is undefined here and check if this file is actually imported anywhere.
rg -n 'generate_ulid' packages/db/drizzle/schema.ts packages/db/drizzle.config.ts
rg -n "from ['\"].*drizzle/schema['\"]" -g '!**/drizzle/**'

Repository: sungmanito/mono

Length of output: 623


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== schema.ts relevant lines =="
sed -n '1,150p' packages/db/drizzle/schema.ts | cat -n

echo
echo "== drizzle package config/typescript =="
ls -la packages/db | sed -n '1,80p'
cat -n packages/db/package.json | sed -n '1,220p' 2>/dev/null || true
cat -n packages/db/tsconfig.json 2>/dev/null | sed -n '1,220p' || true
if [ -f packages/db/drizzle.config.ts ]; then cat -n packages/db/drizzle.config.ts; fi

echo
echo "== schema imports/exports/usages =="
rg -n "packages/db/drizzle/schema|from ['\"]([^'\"]{0,}drizzle/schema[^'\"]{0,})['\"]|from ['\"]([^\']{0,}db" .

Repository: sungmanito/mono

Length of output: 8595


🏁 Script executed:

#!/bin/bash
set -euo pipe.fail

echo "== references to packages/db/drizzle/schema.ts or drizzle/schema =="
rg -n "packages/db/drizzle/schema|drizzle/schema" .
echo
echo "== all files importing packages/db =="
rg -n "from ['\"].*packages/db|import ['\"].*packages/db" .
echo
echo "== package metadata around db scripts =="
cat -n packages/db/package.json
echo
echo "== drizzle config schema paths =="
cat -n packages/db/drizzle.config.ts
echo
echo "== files in drizzle package =="
git ls-files packages/db | sed -n '1,160p'

Repository: sungmanito/mono

Length of output: 203


🏁 Script executed:

#!/bin/bash
set -eu

echo "== references to packages/db/drizzle/schema.ts or drizzle/schema =="
rg -n "packages/db/drizzle/schema|drizzle/schema" . || true
echo
echo "== all files importing packages/db =="
rg -n "from ['\"].*packages/db|import ['\"].*packages/db" . || true
echo
echo "== package metadata around db scripts =="
cat -n packages/db/package.json
echo
echo "== drizzle config schema paths =="
cat -n packages/db/drizzle.config.ts
echo
echo "== schema table definitions referenced in config =="
rg -n "table|Table|schema" packages/db/drizzle packages/db/src packages/db/drizzle.config.ts packages/db/package.json || true

Repository: sungmanito/mono

Length of output: 13996


🌐 Web query:

Drizzle pgColumn default value function template usage

💡 Result:

In Drizzle ORM, the way you handle default values depends on whether you need a database-level constant/SQL function or a runtime-generated value in your application code [1][2]. 1. Database-Level Defaults (.default) Use the.default method when you want the PostgreSQL database to manage the default value (e.g., during INSERT operations if the column is omitted) [1][3]. - Constant values: Simply pass the value (e.g.,.default(42)) [1][4]. - SQL Expressions: If you need a database function like now or gen_random_uuid, use the sql template tag (e.g.,.default(sqlnow())) [1][5]. Note: Values provided to.default are used by Drizzle Kit during migrations to generate the database schema [2][6]. 2. Runtime-Level Defaults ($defaultFn) If you need to generate a default value at runtime within your application—such as calling a JavaScript function (e.g., generating a cuid or UUID)—use the $defaultFn method [1][2]. - The function passed to $defaultFn is executed by Drizzle ORM at runtime when an INSERT query is performed [2][7]. - This value is not used by Drizzle Kit for schema generation, as it is strictly an ORM-level feature [2][7]. Example Usage: import { sql } from "drizzle-orm"; import { pgTable, integer, text, timestamp } from "drizzle-orm/pg-core"; import { createId } from "@paralleldrive/cuid2"; export const users = pgTable("users", { // Database-level default id: text("id").primaryKey.$defaultFn( => createId), status: text("status").default("active"), createdAt: timestamp("created_at").default(sqlnow()), // Runtime-level default counter: integer("counter").$defaultFn( => Math.floor(Math.random * 100)), }); Key Distinction: -.default: Use for database-enforced defaults (schema-level) [2][7]. - $defaultFn: Use for dynamic runtime defaults (application-level) [2][7]. - $default: This is an alias for $defaultFn [2][7].

Citations:


🌐 Web query:

site:drizzle.ohmi.me "pgTable" "pgColumn" ".default" sql function call

💡 Result:

In Drizzle ORM, you can use the sql template literal tag within the.default method to assign a SQL function call as a column's default value [1][2]. When defining a column in a pgTable, passing an sql tagged template literal allows you to execute arbitrary SQL expressions or functions on the database side [1][2]. Example implementation: import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core'; import { sql } from 'drizzle-orm'; export const users = pgTable('users', { id: serial('id').primaryKey, // Using a SQL function for an array default tags: text('tags').array.notNull.default(sql'{}'::text[]), // Using a SQL function for a timestamp createdAt: timestamp('created_at').notNull.default(sqlnow()), }); In this approach, the expression inside sql`` is sent directly to the database as part of the schema definition, enabling the use of database-native functions like now, ARRAY[], or custom expressions [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

echo "== local drizzle schema generator files =="
if command -v node >/dev/null 2>&1; then
  node --version || true
  echo "-- drizzle-orm package manifests from lockfiles if present --"
  fd -H 'package-lock.json|pnpm-lock.yaml|yarn.lock|bun.lockb|bun.lock' . | sed -n '1,80p' || true
  echo "-- installed drizzle-orm type files if available --"
  fd -H "column-builder" node_modules packages/db/node_modules . 2>/dev/null | sed -n '1,40p' || true
fi
echo
echo "== package lock snippets for drizzle versions =="
for f in package-lock.json pnpm-lock.yaml yarn.lock bun.lock packages/db/package-lock.json packages/db/pnpm-lock.yaml packages/db/yarn.lock packages/db/bun.lock; do
  [ -f "$f" ] && { echo "### $f"; rg -n '"drizzle-orm"|"drizzle-kit"|packages/drizzle' "$f" | sed -n '1,120p'; }
done

Repository: sungmanito/mono

Length of output: 405


Wrap the PostgreSQL ID defaults in sql.

generate_ulid() is a PostgreSQL function and is passed as a bare identifier in all generated ID columns, so Drizzle generates a syntax error like DEFAULT generate_ulid() instead of DEFAULT generate_ulid()::text. Also, if this runs against Drizzle 0.44.4 without TypeScript global augmentation, module evaluation will throw ReferenceError: generate_ulid is not defined and leave the schema never evaluated. Apply the same default(sql\identifier()`)pattern topayments.id, invites.id, bills.id, households.id, and jobRuns.id`.

Also applies to: 44-45, 74-75, 91-92, 128-129

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/drizzle/schema.ts` around lines 6 - 7, Wrap the PostgreSQL ID
defaults in Drizzle SQL expressions instead of invoking bare identifiers. Update
the id fields in payments, invites, bills, households, and jobRuns to use the
existing default(sql`identifier()`) pattern, ensuring schema evaluation does not
reference undefined JavaScript functions and generated defaults include the
intended PostgreSQL expression.

proofImageId: uuid("proof_image_id"),
amount: numeric({ precision: 12, scale: 6 }),
}, (table) => [
uniqueIndex("billId_month").using("btree", table.billId.asc().nullsLast().op("date_ops"), table.forMonthD.asc().nullsLast().op("date_ops")),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the relevant schema file and nearby index definitions.
if [ -f packages/db/drizzle/schema.ts ]; then
  echo "=== schema.ts outline ==="
  ast-grep outline packages/db/drizzle/schema.ts --view compact || true
  echo
  echo "=== relevant schema.ts lines ==="
  sed -n '1,140p' packages/db/drizzle/schema.ts | cat -n
else
  echo "packages/db/drizzle/schema.ts not found"
  fd -a 'schema\.ts$' . | sed -n '1,50p'
fi

echo
echo "=== usages of date_ops/text_ops/uuid_ops in schema ==="
rg -n '\.op\("(date_ops|text_ops|uuid_ops)"\)' packages/db/drizzle/schema.ts || true

echo
echo "=== column definitions for tables likely involved ==="
rg -n 'const .*Table =|billId|forMonthD|userId|householdId|user_id_household_id_index|billId_month' packages/db/drizzle/schema.ts || true

Repository: sungmanito/mono

Length of output: 9797


🏁 Script executed:

#!/bin/bash
set -euo pipefail

if [ -f packages/db/drizzle/schema.ts ]; then
  echo "=== schema.ts outline ==="
  ast-grep outline packages/db/drizzle/schema.ts --view compact || true
  echo
  echo "=== relevant schema.ts lines ==="
  sed -n '1,140p' packages/db/drizzle/schema.ts | cat -n
else
  echo "packages/db/drizzle/schema.ts not found"
  fd -a 'schema\.ts$' . | sed -n '1,50p'
fi

echo
echo "=== usages of date_ops/text_ops/uuid_ops in schema ==="
rg -n '\.op\("(date_ops|text_ops|uuid_ops)"\)' packages/db/drizzle/schema.ts || true

echo
echo "=== column definitions for tables likely involved ==="
rg -n 'const .*Table =|billId|forMonthD|userId|householdId|user_id_household_id_index|billId_month' packages/db/drizzle/schema.ts || true

Repository: sungmanito/mono

Length of output: 9797


🌐 Web query:

PostgreSQL btree index operator class mismatch text_ops date_ops uuid_ops CREATE INDEX mismatch operator class fails

💡 Result:

In PostgreSQL, the error stating that an operator class does not exist for an access method (or does not accept a specific data type) typically occurs due to one of three primary reasons: data type incompatibility, search path issues, or missing extensions [1][2][3][4]. 1. Data Type Incompatibility: An operator class defines how a specific data type is indexed by an access method (like btree or gin) [5][6]. If you attempt to use an operator class with a data type it does not support (e.g., trying to use timestamp_ops on a timestamptz column, or gin_trgm_ops on a tsvector column), PostgreSQL will raise a datatype mismatch or "does not accept data type" error [1][2]. You must use an operator class compatible with your specific data type [5]. 2. Search Path Issues: PostgreSQL looks for operator classes in your current search_path [7][4]. If the operator class exists but was created in a schema that is not in your current search_path, the database will report that it does not exist [8][4]. You can resolve this by either schema-qualifying the operator class (e.g., schema.opclass_name) or adding the containing schema to your search_path [4]. 3. Missing Extensions: Some operator classes are not built-in and require specific extensions to be installed (e.g., ginint_ops requires the intarray extension) [9][4]. Even if an extension is installed, ensure it is enabled in the current database [4]. To troubleshoot: - Verify compatibility: Check the system catalog to see which data types an operator class supports [1][10]. - Check the schema: If the operator class is in a non-standard schema, ensure your search_path is configured correctly or schema-qualify the class in your CREATE INDEX statement [7][4]. - Confirm extensions: Ensure that any required extensions are installed in the correct database and that the user has sufficient permissions [4]. You can query pg_opclass to see available operator classes and their associated types: SELECT opcname, opcintype::regtype FROM pg_opclass WHERE opcmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'); [1][10]

Citations:


Use matching operator classes for the indexed column types.

billId is text, so billId_month should use text_ops; date_ops only matches date. In users_to_households, userId is uuid and householdId is text, so the composite index has those operator classes swapped.

🐛 Proposed fix
-	uniqueIndex("billId_month").using("btree", table.billId.asc().nullsLast().op("date_ops"), table.forMonthD.asc().nullsLast().op("date_ops")),
+	uniqueIndex("billId_month").using("btree", table.billId.asc().nullsLast().op("text_ops"), table.forMonthD.asc().nullsLast().op("date_ops")),
-	uniqueIndex("user_id_household_id_index").using("btree", table.userId.asc().nullsLast().op("text_ops"), table.householdId.asc().nullsLast().op("uuid_ops")),
+	uniqueIndex("user_id_household_id_index").using("btree", table.userId.asc().nullsLast().op("uuid_ops"), table.householdId.asc().nullsLast().op("text_ops")),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/drizzle/schema.ts` at line 18, Update the uniqueIndex definitions
billId_month and the users_to_households composite index to use operator classes
matching each column type: use text_ops for text columns, uuid_ops for userId,
and date_ops only for date columns. Preserve the existing index ordering and
null handling.

householdId: text("household_id").notNull(),
notes: text(),
currency: text().default('USD').notNull(),
amount: doublePrecision().default(0).notNull(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

bills.amount stored as double precision, inconsistent with payments.amount (numeric(12,6)). Using floating-point for a monetary column risks rounding/precision errors that a numeric type avoids; payments already made the correct choice for the same kind of data. Since this is the initial migration, it's cheap to align now before any data or downstream consumers depend on the current type.

  • packages/db/drizzle/schema.ts#L81: change amount: doublePrecision().default(0).notNull() to a numeric column (e.g. numeric({ precision: 12, scale: 2 }).default('0').notNull()), matching payments.amount's type strategy.
  • packages/db/drizzle/meta/0000_snapshot.json#L238-L244: regenerate this snapshot (via drizzle-kit generate/pull) after the schema.ts fix so it reflects the corrected bills.amount type; the underlying migration SQL will also need the corresponding ALTER COLUMN/redefinition.
📍 Affects 2 files
  • packages/db/drizzle/schema.ts#L81-L81 (this comment)
  • packages/db/drizzle/meta/0000_snapshot.json#L238-L244
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/drizzle/schema.ts` at line 81, Change bills.amount in
packages/db/drizzle/schema.ts at line 81 from double precision to a numeric
column using precision 12 and scale 2, with a string zero default and not-null
constraint, matching payments.amount’s numeric strategy. Regenerate
packages/db/drizzle/meta/0000_snapshot.json at lines 238-244 with Drizzle
tooling and ensure the migration SQL reflects the corrected bills.amount type.

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