Skip to content

Implement surrogate UUID keys on posts#190

Open
fennifith wants to merge 9 commits into
mainfrom
95/post-key-refactor
Open

Implement surrogate UUID keys on posts#190
fennifith wants to merge 9 commits into
mainfrom
95/post-key-refactor

Conversation

@fennifith

@fennifith fennifith commented Jul 11, 2026

Copy link
Copy Markdown
Member

Implements the schema changes described in #95

  • "Post groups" have no assigned ordering, so versionOrder is never set; by default, these would be ordered by creation date. A future issue should establish a frontmatter field to explicitly define the order.
  • Attachments are no longer removed from S3 once unreferenced - multiple branches can be referencing the same attachment, so it isn't practical to determine this in sync-post. A separate task will need to detect these & mark them for removal.
  • I've rewritten a couple tests using the faked db in test-utils/setup.ts, making them much more readable. It might be good to expand this and move it to test-fixtures to share it with packages/api.

Summary by CodeRabbit

  • New Features

    • Added support for retrieving content from specific branches, including the default main branch.
    • Improved handling of localized posts, drafts, collections, chapters, tags, authors, and attachments.
    • Added more reliable attachment reuse and metadata tracking during content synchronization.
    • Profile listings now accurately count and sort by published, indexable posts.
  • Bug Fixes

    • Corrected visibility and 404 handling for unpublished or missing content.
    • Improved synchronization cleanup and relationship handling for updated or deleted posts.

@fennifith fennifith linked an issue Jul 11, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@fennifith, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 10 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8cfb5812-0b18-4f7f-a6fe-074c0b81b984

📥 Commits

Reviewing files that changed from the base of the PR and between 8b32879 and 2645eae.

📒 Files selected for processing (10)
  • apps/api/src/routes/content/post.test.ts
  • apps/api/src/routes/content/post.ts
  • apps/api/src/routes/content/posts.test.ts
  • apps/api/src/routes/content/posts.ts
  • apps/api/src/routes/content/profiles.test.ts
  • apps/api/test-utils/setup.ts
  • apps/worker/src/tasks/grant-author-achievements/processor.ts
  • apps/worker/src/tasks/sync-post/processor.ts
  • apps/worker/test-utils/setup.ts
  • packages/db/src/relations.ts
📝 Walkthrough

Walkthrough

The change replaces slug-based post storage with UUID-based, locale-and-branch records, adds shared attachment storage, and updates API queries, worker synchronization, achievement metrics, relations, migrations, mocks, and tests.

Changes

Posts schema and persistence refactor

Layer / File(s) Summary
Posts schema and migrations
packages/db/src/schema/*, packages/db/src/relations.ts, packages/db/drizzle/*, packages/db/package.json
Posts and related tables now use UUID-based relationships, locale/branch uniqueness, shared attachment metadata, and updated migration snapshots.
Branch-aware content and profile queries
apps/api/src/routes/content/post.ts, apps/api/src/routes/content/post.test.ts, apps/api/src/routes/content/profiles.ts, apps/api/src/routes/content/profiles.test.ts, apps/api/test-utils/setup.ts
Post retrieval accepts branch, reads direct localized fields, filters unpublished chapters, and profile counts use published non-indexed posts rows.
Post and attachment synchronization
apps/worker/src/tasks/sync-post/processor.ts, apps/worker/src/tasks/sync-post/processor.test.ts, apps/worker/test-utils/setup.ts
Synchronization persists posts and relations per locale, reuses content-addressed attachments, uploads changed content, and tests returned post IDs and direct table writes.
Author achievement metrics
apps/worker/src/tasks/grant-author-achievements/processor.ts
Achievement metrics now query published English main-branch posts and identify co-authored posts through postId.

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

Sequence Diagram(s)

sequenceDiagram
  participant GitHub
  participant SyncPostProcessor
  participant S3
  participant Database
  GitHub->>SyncPostProcessor: provide post and attachment content
  SyncPostProcessor->>Database: load existing attachment keys
  SyncPostProcessor->>S3: upload changed attachments
  SyncPostProcessor->>Database: insert attachment metadata
  SyncPostProcessor->>Database: insert posts and receive post IDs
  SyncPostProcessor->>Database: insert author, tag, and attachment relations
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main schema change: switching posts to surrogate UUID keys.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 95/post-key-refactor

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

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/db/drizzle/20260711154730_confused_green_goblin/migration.sql (1)

47-53: 🚀 Performance & Scalability | 🔵 Trivial

Add indexes for FK columns not covered by composite PKs.

PostgreSQL does not automatically index FK columns. The composite PKs on post_authors(post_id, author_slug), post_tags(post_id, tag), and post_attachments(post_id, attachment_key) only index the leading post_id column. Queries that filter or join on the second column (e.g., post_authors.author_slug used in the profiles query, or post_tags.tag for tag-based lookups) will full-scan. Similarly, posts.collection_slug and posts.group_id have FKs but no index.

Consider adding:

  • CREATE INDEX on post_authors(author_slug) — used in profiles.ts join eq(postAuthors.authorSlug, profiles.slug)
  • CREATE INDEX on post_tags(tag) — for tag-based post lookups
  • CREATE INDEX on posts(collection_slug) — for collection chapter queries
  • CREATE INDEX on posts(group_id) — for group-based lookups
  • CREATE INDEX on posts(published_at) — for ordering/filtering published posts
🤖 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/20260711154730_confused_green_goblin/migration.sql`
around lines 47 - 53, Add indexes in the migration for the uncovered foreign-key
and query columns: post_authors.author_slug, post_tags.tag,
posts.collection_slug, posts.group_id, and posts.published_at. Use distinct,
descriptive index names and preserve the existing foreign-key constraints.
🤖 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/api/src/routes/content/post.test.ts`:
- Around line 244-245: Rename the second test around db.query.posts.findFirst
and the "spanish-only-post" URL to clearly identify its locale-specific
not-found behavior, while leaving the first 404 test name unchanged.

In `@apps/worker/src/tasks/grant-author-achievements/processor.ts`:
- Around line 12-21: Remove the unused drizzle-orm imports max and exists from
the import list at the top of processor.ts, leaving all referenced imports
unchanged.

In `@apps/worker/src/tasks/sync-post/processor.ts`:
- Around line 359-368: Update the delete operation in the post-processing
transaction to call tx.delete instead of db.delete, preserving the existing
posts table and where conditions so the deletion remains part of the transaction
and can be rolled back atomically.
- Around line 311-316: Update the attachments insert using the
db.insert(attachments) call to ignore conflicts on the attachmentKey primary
key, using onConflictDoNothing or the repository’s equivalent. Preserve the
existing values and ensure re-syncs do not fail when a retained attachment row
already exists.

---

Nitpick comments:
In `@packages/db/drizzle/20260711154730_confused_green_goblin/migration.sql`:
- Around line 47-53: Add indexes in the migration for the uncovered foreign-key
and query columns: post_authors.author_slug, post_tags.tag,
posts.collection_slug, posts.group_id, and posts.published_at. Use distinct,
descriptive index names and preserve the existing foreign-key constraints.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8924826-cf3b-45cf-830c-7a2b1b4ad0ff

📥 Commits

Reviewing files that changed from the base of the PR and between 48c152f and 8b32879.

📒 Files selected for processing (21)
  • apps/api/src/routes/content/post.test.ts
  • apps/api/src/routes/content/post.ts
  • apps/api/src/routes/content/profiles.test.ts
  • apps/api/src/routes/content/profiles.ts
  • apps/api/test-utils/setup.ts
  • apps/worker/src/tasks/grant-author-achievements/processor.ts
  • apps/worker/src/tasks/sync-post/processor.test.ts
  • apps/worker/src/tasks/sync-post/processor.ts
  • apps/worker/test-utils/setup.ts
  • packages/db/drizzle/20260711154425_odd_silver_centurion/migration.sql
  • packages/db/drizzle/20260711154425_odd_silver_centurion/snapshot.json
  • packages/db/drizzle/20260711154730_confused_green_goblin/migration.sql
  • packages/db/drizzle/20260711154730_confused_green_goblin/snapshot.json
  • packages/db/package.json
  • packages/db/src/relations.ts
  • packages/db/src/schema/attachments.ts
  • packages/db/src/schema/collections.ts
  • packages/db/src/schema/index.ts
  • packages/db/src/schema/post-attachments.ts
  • packages/db/src/schema/posts.ts
  • packages/db/src/schema/tags.ts
💤 Files with no reviewable changes (2)
  • packages/db/src/schema/tags.ts
  • packages/db/src/schema/post-attachments.ts

Comment thread apps/api/src/routes/content/post.test.ts Outdated
Comment thread apps/worker/src/tasks/grant-author-achievements/processor.ts Outdated
Comment thread apps/worker/src/tasks/sync-post/processor.ts Outdated
Comment thread apps/worker/src/tasks/sync-post/processor.ts
@fennifith fennifith force-pushed the 95/post-key-refactor branch from 633d28d to 2645eae Compare July 14, 2026 01:54
@fennifith fennifith enabled auto-merge July 14, 2026 01:54
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.

Support post revisions

1 participant