Skip to content

Changed gift-links service to split CQRS queries and commands#28977

Draft
rob-ghost wants to merge 1 commit into
mainfrom
refactor/gift-links-cqrs
Draft

Changed gift-links service to split CQRS queries and commands#28977
rob-ghost wants to merge 1 commit into
mainfrom
refactor/gift-links-cqrs

Conversation

@rob-ghost

Copy link
Copy Markdown
Contributor

The gift-links service had grown into a single GiftLinksService class that mixed read and write responsibilities, so anything that only needed to resolve a token (such as the frontend entry controller) still pulled in the full surface of mutation and action-logging logic. That coupling made the read path harder to reason about and harder to reuse in isolation.

This change reshapes the service into a CQRS layout. Reads now live in GiftLinkQueries and writes in GiftLinkCommands, so the two paths no longer share a class or each other's dependencies. Action recording and the database row codec were pulled out into their own actions.ts and codec.ts modules, and the database concerns file was renamed from database.ts to schema.ts to better reflect its contents. The entry routing controller now resolves gift-link tokens through the query path directly, keeping that read seam free of command and action dependencies.

The old service.ts and its integration test were removed in favour of the split modules, with new focused unit tests covering the extracted actions. This is an internal refactor with no behavioural or user-facing change.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 50df0e5f-d329-4729-93d6-2c747752ab13

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/gift-links-cqrs

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.

@nx-cloud

nx-cloud Bot commented Jun 29, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit cf704c4

Command Status Duration Result
nx run ghost:test:ci:integration ✅ Succeeded 2m 33s View ↗
nx run ghost:test:integration ✅ Succeeded 2m 23s View ↗
nx run ghost:test:legacy ✅ Succeeded 2m 55s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 15s View ↗
nx run-many --target=build --projects=tag:publi... ✅ Succeeded 1s View ↗
nx run-many -t lint -p ghost ✅ Succeeded 37s View ↗
nx run-many -t test:unit -p ghost ✅ Succeeded 29s View ↗
nx run @tryghost/admin:build ✅ Succeeded 6s View ↗
Additional runs (2) ✅ Succeeded ... View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-06-29 23:03:52 UTC

@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 `@ghost/core/core/server/services/gift-links/commands.ts`:
- Around line 19-26: The `GiftLinksCommands.ensure()` flow is not atomic: it
checks `post.giftLinks` before the write path, while `mint()` merges on
`post_id`, so concurrent calls can mint different tokens and return one that is
later overwritten. Move the “no gift link exists” check into the transaction
used by `mint()`/the ensure path, and use an insert-or-lock strategy so only one
call can create the association. Make `ensure()` return the live association
created or observed in that transaction, and call `recordAction({context, verb:
'add', subject: postId})` only when this invocation actually created the link.
🪄 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: c8a01828-04e2-4700-9f03-55892801828d

📥 Commits

Reviewing files that changed from the base of the PR and between 03bed4a and f4a20bc.

📒 Files selected for processing (19)
  • ghost/core/core/frontend/services/proxy.js
  • ghost/core/core/frontend/services/routing/controllers/entry/gift-links.ts
  • ghost/core/core/server/api/endpoints/gift-links.ts
  • ghost/core/core/server/api/endpoints/utils/serializers/output/gift-links.ts
  • ghost/core/core/server/services/gift-links/actions.ts
  • ghost/core/core/server/services/gift-links/codec.ts
  • ghost/core/core/server/services/gift-links/commands.ts
  • ghost/core/core/server/services/gift-links/index.ts
  • ghost/core/core/server/services/gift-links/models.ts
  • ghost/core/core/server/services/gift-links/queries.ts
  • ghost/core/core/server/services/gift-links/schema.ts
  • ghost/core/core/server/services/gift-links/serializers.ts
  • ghost/core/core/server/services/gift-links/service.ts
  • ghost/core/test/e2e-api/admin/gift-links.test.ts
  • ghost/core/test/e2e-frontend/gift-links-toast-override.test.ts
  • ghost/core/test/e2e-frontend/gift-links.test.ts
  • ghost/core/test/integration/services/gift-links.test.ts
  • ghost/core/test/unit/server/services/gift-links/actions.test.ts
  • ghost/core/test/unit/server/services/gift-links/gift-link-token.test.ts
💤 Files with no reviewable changes (4)
  • ghost/core/test/integration/services/gift-links.test.ts
  • ghost/core/core/server/services/gift-links/serializers.ts
  • ghost/core/core/server/services/gift-links/schema.ts
  • ghost/core/core/server/services/gift-links/service.ts

Comment thread ghost/core/core/server/services/gift-links/commands.ts
Separated the gift-links read path (GiftLinkQueries) from the write path
(GiftLinkCommands) so reads and mutations no longer share one class, and
extracted action recording and the row codec into their own modules. The
entry controller now resolves tokens through queries directly, keeping the
read seam free of command/action dependencies.
@rob-ghost rob-ghost force-pushed the refactor/gift-links-cqrs branch from f4a20bc to cf704c4 Compare June 29, 2026 22:53
@rob-ghost rob-ghost self-assigned this Jun 29, 2026
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