Skip to content

[feat] Add completedAt column to resource_completion#2684

Open
Will-Howard wants to merge 1 commit into
masterfrom
wh-2679-resource-completedat-schema-2026-06
Open

[feat] Add completedAt column to resource_completion#2684
Will-Howard wants to merge 1 commit into
masterfrom
wh-2679-resource-completedat-schema-2026-06

Conversation

@Will-Howard

Copy link
Copy Markdown
Collaborator

Description

For parity with exercise responses, and to allow shipping resource_completed events to PostHog, I'm migrating the isCompleted field to completedAt

Issue

#2679

Developer checklist

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

A completedAt text column is added to resourceCompletionPgTable in libraries/db/src/schema.ts, extending the inferred ResourceCompletion model type. In ResourceListItem.tsx, the optimistic cache update for saveResourceCompletion now populates completedAt with the current ISO timestamp when inserting a new completion record. Test utility mock factories are updated to reflect the new shape: createMockResourceCompletion gains completedAt: null, and createMockCourseRegistration gains rejectedAt: null and withdrawnAt: null.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and specifically describes the main change: adding a completedAt column to the resource_completion table.
Description check ✅ Passed The description includes required sections with clear motivation, issue reference, and developer checklist, though some non-critical sections lack detail.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

✨ 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 wh-2679-resource-completedat-schema-2026-06

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.

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a completedAt column to resource_completion (as text(), matching the type used for exerciseResponsePgTable.completedAt) to enable parity with exercise responses and support PostHog event shipping. The schema, test utility, and optimistic UI update are all updated consistently.

  • completedAt: text() is added to resourceCompletionPgTable in schema.ts, keeping isCompleted: boolean() in place as a co-existing field.
  • The optimistic update in ResourceListItem.tsx sets completedAt: new Date().toISOString(), but the server-side saveResourceCompletion mutation in resources.ts was not updated and never writes completedAt to the database — meaning the column will remain null for all records.

Confidence Score: 4/5

Safe to merge once the server mutation is updated to write completedAt; the column will otherwise always be null in production.

The schema column, test utility, and optimistic UI update are all correctly added, but the saveResourceCompletion mutation in resources.ts — the only place that persists resource completion records — never sets completedAt. Every insert and update omits the field, so the column will be null for all rows even after the migration ships.

apps/website/src/server/routers/resources.ts — the mutation's INSERT and UPDATE paths both need completedAt populated.

Important Files Changed

Filename Overview
libraries/db/src/schema.ts Adds completedAt: text() column to resourceCompletionPgTable, consistent with the text() type used for createdAt and exerciseResponsePgTable.completedAt.
apps/website/src/components/courses/ResourceListItem.tsx Adds completedAt to the optimistic update object, but the server mutation (saveResourceCompletion) never persists it, so the field reverts to null after the query refetch.
apps/website/src/tests/testUtils.ts Adds completedAt: null to createMockResourceCompletion and fills in two missing CourseRegistration fields (rejectedAt, withdrawnAt); straightforward test utility update.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as ResourceListItem
    participant Cache as React Query Cache
    participant Server as resources.saveResourceCompletion
    participant DB as PostgreSQL

    UI->>Cache: "Optimistic update (completedAt = now)"
    UI->>Server: "mutation({ isCompleted, feedback, ... })"
    Server->>DB: INSERT/UPDATE (isCompleted, feedback, ...) — completedAt NOT set
    DB-->>Server: "row (completedAt = null)"
    Server-->>UI: "response (completedAt = null)"
    UI->>Cache: Invalidate + refetch
    Cache-->>UI: "completedAt = null (optimistic value lost)"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as ResourceListItem
    participant Cache as React Query Cache
    participant Server as resources.saveResourceCompletion
    participant DB as PostgreSQL

    UI->>Cache: "Optimistic update (completedAt = now)"
    UI->>Server: "mutation({ isCompleted, feedback, ... })"
    Server->>DB: INSERT/UPDATE (isCompleted, feedback, ...) — completedAt NOT set
    DB-->>Server: "row (completedAt = null)"
    Server-->>UI: "response (completedAt = null)"
    UI->>Cache: Invalidate + refetch
    Cache-->>UI: "completedAt = null (optimistic value lost)"
Loading

Reviews (2): Last reviewed commit: "[feat] Add completedAt column to resourc..." | Re-trigger Greptile

// Points at courseBuilderUserTable (the Course-builder-base sync of User)
createdByUserId: text().array(),
createdAt: text(),
completedAt: 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.

P2 Type mismatch with exerciseResponsePgTable.completedAt

The PR description cites parity with exercise responses, but exerciseResponsePgTable.completedAt is declared as text() (line 153), while this new column uses timestamp({ mode: 'string', withTimezone: true }). When Drizzle reads a TIMESTAMPTZ column with mode: 'string', PostgreSQL returns the value in its own format ("2026-01-01 10:00:00+00") rather than the ISO 8601 format that new Date().toISOString() produces ("2026-01-01T10:00:00.000Z"). Future code that inserts ISO strings or treats both completedAt fields interchangeably (e.g. PostHog event shipping) may encounter subtle format differences.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

👍 I did go back to the basic text() type for this reason

@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Want your agent to iterate on Greptile's feedback? Try greploops.

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

🤖 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 `@libraries/db/src/schema.ts`:
- Line 1520: The addition of the completedAt column to the schema in
libraries/db/src/schema.ts must be split into separate PRs to follow the
required rollout contract for schema changes. Remove all changes related to
consumer code usage (the updates in
apps/website/src/components/courses/ResourceListItem.tsx and
apps/website/src/__tests__/testUtils.ts), keeping only the schema column
addition at line 1520. After this PR is merged, create a second PR that adds the
consumer code changes to use the newly available completedAt column.
🪄 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: 4af999d4-c840-47b3-938e-63bcc497c93a

📥 Commits

Reviewing files that changed from the base of the PR and between e3a9179 and c9e396f.

📒 Files selected for processing (3)
  • apps/website/src/__tests__/testUtils.ts
  • apps/website/src/components/courses/ResourceListItem.tsx
  • libraries/db/src/schema.ts

// Points at courseBuilderUserTable (the Course-builder-base sync of User)
createdByUserId: text().array(),
createdAt: text(),
completedAt: 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 | 🟠 Major | 🏗️ Heavy lift

Split this column addition from consumer usage into staged PRs.

Line 1520 adds completedAt, but this PR also updates consumer code in apps/website/src/components/courses/ResourceListItem.tsx and apps/website/src/__tests__/testUtils.ts. That breaks the required rollout contract for schema changes and creates deployment-order risk.

As per coding guidelines: “Adding a column requires 2 PRs: (1) add column in libraries/db/src/schema.ts and merge, (2) then PR the code that uses it.”

🤖 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 `@libraries/db/src/schema.ts` at line 1520, The addition of the completedAt
column to the schema in libraries/db/src/schema.ts must be split into separate
PRs to follow the required rollout contract for schema changes. Remove all
changes related to consumer code usage (the updates in
apps/website/src/components/courses/ResourceListItem.tsx and
apps/website/src/__tests__/testUtils.ts), keeping only the schema column
addition at line 1520. After this PR is merged, create a second PR that adds the
consumer code changes to use the newly available completedAt column.

Source: Coding guidelines

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