Skip to content

Self-hosted: live preview on unclaimed subdomains - #1440

Merged
feruzm merged 5 commits into
developfrom
feature/self-hosted-claim-preview
Aug 12, 2026
Merged

Self-hosted: live preview on unclaimed subdomains#1440
feruzm merged 5 commits into
developfrom
feature/self-hosted-claim-preview

Conversation

@feruzm

@feruzm feruzm commented Aug 11, 2026

Copy link
Copy Markdown
Member

Closes #1416.

Visiting an unclaimed subdomain served only a static claim CTA. Behind an explicit action the real app now boots as a live preview of the visitor's own Hive content:

  • The landing gains a "Preview this blog first" action, and ?preview=1 boots straight into preview for funnel deep links. Crawlers and casual hits keep the lightweight CTA.
  • The preview config is synthesized client-side for the host's name (blog or community derived from the hostname, default template, standard filters) and swapped into the config store; the template gate flips reactively and the normal route tree renders. Entirely in-memory and per-tab: nothing is provisioned, nothing persisted, reload without the param returns to the CTA.
  • Auth is disabled outright in the preview config, so login, likes, comments, tipping and the composer stay hidden: a preview is a brochure, not an instance.
  • A persistent banner states this is a preview of public Hive content, carries the claim deep link and an exit, and re-establishes the robots noindex that the claim landing removes on unmount, so unclaimed hosts stay out of the index while previewing.
  • The dead-route guard's registry covers the banner's claim link like the landing's.

Empty accounts show the app's existing designed empty states. Tests cover the config builder (blog and community shapes, auth off, the marker, the template flag being absent rather than false), the gate flip with DOM paint, strict param parsing and that a real tenant config never reads as a preview. SPA suite 884 tests, typecheck and production build green.

Summary by CodeRabbit

  • New Features
    • Added preview mode for unclaimed blog and community subdomains.
    • Added a direct entry point from the claim page to launch a preview.
    • Added a persistent preview banner with host details, localized messaging, claim actions, and an option to exit preview mode.
    • Preview mode disables authentication and prevents search engines from indexing preview content.
  • Tests
    • Added coverage for preview configuration, activation, navigation, and validation scenarios.

An unclaimed subdomain showed only a static claim CTA; nothing let the
visitor see their own Hive content as a blog before committing. Behind
an explicit action (the landing's preview button, or ?preview=1 from a
funnel link) the real app now boots against a config synthesized for
the host's name: blog or community derived from the hostname, default
template, auth disabled outright so every broadcast affordance stays
hidden. Entirely in-memory and per-tab; nothing is provisioned and a
reload without the param lands back on the CTA.

A persistent banner states that this is a preview of public Hive
content, carries the claim deep link and an exit, and re-establishes
the robots noindex the claim landing removes on unmount, so unclaimed
hosts stay out of the index while previewed. Crawlers and casual hits
keep getting the lightweight CTA.

Closes #1416
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (8)

Grey Divider


Remediation recommended

1. Preview title overwritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
Entering claim preview sets the document title via applyConfigDom, but when ClaimLanding unmounts
its existing effect cleanup restores the pre-landing title, clobbering the preview title. As a
result, the browser tab title can remain the template/previous title instead of the previewed
account/community name.
Code

apps/self-hosted/src/features/claim/claim-landing.tsx[R30-33]

+  useEffect(() => {
+    if (name && isClaimPreviewRequested(window.location.search)) {
+      enterClaimPreview(name, isCommunity);
+    }
Relevance

●●● Strong

Correctness bug: preview title likely clobbered by ClaimLanding cleanup; teams usually accept
deterministic UX fixes.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new effect calls enterClaimPreview, which applies the preview config (including its
meta.title) to the DOM. But ClaimLanding’s existing title-setting effect restores the previous title
on unmount, which occurs when the template gate flips, overwriting the preview title after it was
set.

apps/self-hosted/src/features/claim/claim-landing.tsx[27-48]
apps/self-hosted/src/features/claim/claim-preview.ts[50-56]
apps/self-hosted/src/features/claim/claim-preview.ts[86-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Entering claim preview triggers unmount of `ClaimLanding`, whose existing `useEffect` cleanup restores a previously-captured `document.title`. Because `enterClaimPreview()` already applied the preview config’s title via `applyConfigDom()`, the cleanup runs afterward and overwrites the preview title.
### Issue Context
`ClaimLanding` previously only needed to restore the title when leaving the landing for the real app, but the new in-place preview transition makes that cleanup ordering observable.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-landing.tsx[36-47]
- apps/self-hosted/src/features/claim/claim-landing.tsx[27-34]
- apps/self-hosted/src/features/claim/claim-preview.ts[86-90]
### Suggested fix
Update the ClaimLanding title effect cleanup so it does **not** restore a stale `prevTitle` when the landing unmounts.
Concrete options:
1) In the cleanup, re-apply the *current* config-derived title instead of `prevTitle` (e.g., call `applyConfigDom(InstanceConfigManager.getConfig(), { syncSystemTheme: true })` or set `document.title` from the current config).
2) Alternatively, remove the title restoration entirely and rely on config/route ownership of `document.title` once leaving the landing.
Add a small test (or extend existing claim-preview tests) to assert that after `enterClaimPreview`, the final `document.title` is the preview name, not the previous template title.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Preview likes/comments still render 🐞 Bug ≡ Correctness
Description
The synthesized claim-preview config explicitly enables likes and comments while disabling auth, so
like and comment UI still renders in preview even though the preview is intended to hide broadcast
affordances. This makes the preview less “brochure-like” and can expose disabled-but-visible
interaction controls.
Code

apps/self-hosted/src/features/claim/claim-preview.ts[R71-74]

+          likes: { enabled: true },
+          comments: { enabled: true },
+          post: { text2Speech: { enabled: false } },
+          auth: { enabled: false, methods: [] },
Relevance

●●● Strong

Matches PR intent (“brochure preview”): disable likes/comments in preview config; straightforward
correctness/UI fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preview config sets likes/comments enabled, and the blog UI reads those flags to decide whether
to render like/comment UI. In BlogPostFooter, the vote button is rendered when showLikes is true
(derived from the config likes flag), independent of whether auth is enabled.

apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[18-34]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`buildClaimPreviewConfig()` sets `features.likes.enabled` and `features.comments.enabled` to `true` while also setting `features.auth.enabled` to `false`. Several UI components render like/comment affordances based on the likes/comments feature flags (not strictly on auth), so these elements remain visible during claim preview.
### Issue Context
The claim preview is intended to be read-only and to hide broadcast affordances. Currently, likes/comment counts and the vote button can still render because the feature flags remain enabled.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[23-34]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]
### Suggested fix
In `buildClaimPreviewConfig`, set:
- `features.likes.enabled = false`
- `features.comments.enabled = false`
If you also want to remove other broadcast-ish UI (e.g., reblog), consider additionally gating those components on `useIsAuthEnabled()` or on `isClaimPreviewActive()` at render sites.
Update/extend the claim preview tests to assert that likes/comments are disabled (and, optionally, that key affordances are not rendered when `claimPreview` is active).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Preview likes/comments still render 🐞 Bug ≡ Correctness
Description
The synthesized claim-preview config explicitly enables likes and comments while disabling auth, so
like and comment UI still renders in preview even though the preview is intended to hide broadcast
affordances. This makes the preview less “brochure-like” and can expose disabled-but-visible
interaction controls.
Code

apps/self-hosted/src/features/claim/claim-preview.ts[R71-74]

+          likes: { enabled: true },
+          comments: { enabled: true },
+          post: { text2Speech: { enabled: false } },
+          auth: { enabled: false, methods: [] },
Relevance

●●● Strong

Matches PR intent (“brochure preview”): disable likes/comments in preview config; straightforward
correctness/UI fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preview config sets likes/comments enabled, and the blog UI reads those flags to decide whether
to render like/comment UI. In BlogPostFooter, the vote button is rendered when showLikes is true
(derived from the config likes flag), independent of whether auth is enabled.

apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[18-34]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`buildClaimPreviewConfig()` sets `features.likes.enabled` and `features.comments.enabled` to `true` while also setting `features.auth.enabled` to `false`. Several UI components render like/comment affordances based on the likes/comments feature flags (not strictly on auth), so these elements remain visible during claim preview.
### Issue Context
The claim preview is intended to be read-only and to hide broadcast affordances. Currently, likes/comment counts and the vote button can still render because the feature flags remain enabled.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[23-34]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]
### Suggested fix
In `buildClaimPreviewConfig`, set:
- `features.likes.enabled = false`
- `features.comments.enabled = false`
If you also want to remove other broadcast-ish UI (e.g., reblog), consider additionally gating those components on `useIsAuthEnabled()` or on `isClaimPreviewActive()` at render sites.
Update/extend the claim preview tests to assert that likes/comments are disabled (and, optionally, that key affordances are not rendered when `claimPreview` is active).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View review recommended (5)
4. Preview title overwritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
Entering claim preview sets the document title via applyConfigDom, but when ClaimLanding unmounts
its existing effect cleanup restores the pre-landing title, clobbering the preview title. As a
result, the browser tab title can remain the template/previous title instead of the previewed
account/community name.
Code

apps/self-hosted/src/features/claim/claim-landing.tsx[R30-33]

+  useEffect(() => {
+    if (name && isClaimPreviewRequested(window.location.search)) {
+      enterClaimPreview(name, isCommunity);
+    }
Relevance

●●● Strong

Correctness bug: preview title likely clobbered by ClaimLanding cleanup; teams usually accept
deterministic UX fixes.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new effect calls enterClaimPreview, which applies the preview config (including its
meta.title) to the DOM. But ClaimLanding’s existing title-setting effect restores the previous title
on unmount, which occurs when the template gate flips, overwriting the preview title after it was
set.

apps/self-hosted/src/features/claim/claim-landing.tsx[27-48]
apps/self-hosted/src/features/claim/claim-preview.ts[50-56]
apps/self-hosted/src/features/claim/claim-preview.ts[86-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Entering claim preview triggers unmount of `ClaimLanding`, whose existing `useEffect` cleanup restores a previously-captured `document.title`. Because `enterClaimPreview()` already applied the preview config’s title via `applyConfigDom()`, the cleanup runs afterward and overwrites the preview title.
### Issue Context
`ClaimLanding` previously only needed to restore the title when leaving the landing for the real app, but the new in-place preview transition makes that cleanup ordering observable.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-landing.tsx[36-47]
- apps/self-hosted/src/features/claim/claim-landing.tsx[27-34]
- apps/self-hosted/src/features/claim/claim-preview.ts[86-90]
### Suggested fix
Update the ClaimLanding title effect cleanup so it does **not** restore a stale `prevTitle` when the landing unmounts.
Concrete options:
1) In the cleanup, re-apply the *current* config-derived title instead of `prevTitle` (e.g., call `applyConfigDom(InstanceConfigManager.getConfig(), { syncSystemTheme: true })` or set `document.title` from the current config).
2) Alternatively, remove the title restoration entirely and rely on config/route ownership of `document.title` once leaving the landing.
Add a small test (or extend existing claim-preview tests) to assert that after `enterClaimPreview`, the final `document.title` is the preview name, not the previous template title.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Preview likes/comments still render 🐞 Bug ≡ Correctness
Description
The synthesized claim-preview config explicitly enables likes and comments while disabling auth, so
like and comment UI still renders in preview even though the preview is intended to hide broadcast
affordances. This makes the preview less “brochure-like” and can expose disabled-but-visible
interaction controls.
Code

apps/self-hosted/src/features/claim/claim-preview.ts[R71-74]

+          likes: { enabled: true },
+          comments: { enabled: true },
+          post: { text2Speech: { enabled: false } },
+          auth: { enabled: false, methods: [] },
Relevance

●●● Strong

Matches PR intent (“brochure preview”): disable likes/comments in preview config; straightforward
correctness/UI fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preview config sets likes/comments enabled, and the blog UI reads those flags to decide whether
to render like/comment UI. In BlogPostFooter, the vote button is rendered when showLikes is true
(derived from the config likes flag), independent of whether auth is enabled.

apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[18-34]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`buildClaimPreviewConfig()` sets `features.likes.enabled` and `features.comments.enabled` to `true` while also setting `features.auth.enabled` to `false`. Several UI components render like/comment affordances based on the likes/comments feature flags (not strictly on auth), so these elements remain visible during claim preview.
### Issue Context
The claim preview is intended to be read-only and to hide broadcast affordances. Currently, likes/comment counts and the vote button can still render because the feature flags remain enabled.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[23-34]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]
### Suggested fix
In `buildClaimPreviewConfig`, set:
- `features.likes.enabled = false`
- `features.comments.enabled = false`
If you also want to remove other broadcast-ish UI (e.g., reblog), consider additionally gating those components on `useIsAuthEnabled()` or on `isClaimPreviewActive()` at render sites.
Update/extend the claim preview tests to assert that likes/comments are disabled (and, optionally, that key affordances are not rendered when `claimPreview` is active).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Preview title overwritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
Entering claim preview sets the document title via applyConfigDom, but when ClaimLanding unmounts
its existing effect cleanup restores the pre-landing title, clobbering the preview title. As a
result, the browser tab title can remain the template/previous title instead of the previewed
account/community name.
Code

apps/self-hosted/src/features/claim/claim-landing.tsx[R30-33]

+  useEffect(() => {
+    if (name && isClaimPreviewRequested(window.location.search)) {
+      enterClaimPreview(name, isCommunity);
+    }
Relevance

●●● Strong

Correctness bug: preview title likely clobbered by ClaimLanding cleanup; teams usually accept
deterministic UX fixes.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new effect calls enterClaimPreview, which applies the preview config (including its
meta.title) to the DOM. But ClaimLanding’s existing title-setting effect restores the previous title
on unmount, which occurs when the template gate flips, overwriting the preview title after it was
set.

apps/self-hosted/src/features/claim/claim-landing.tsx[27-48]
apps/self-hosted/src/features/claim/claim-preview.ts[50-56]
apps/self-hosted/src/features/claim/claim-preview.ts[86-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Entering claim preview triggers unmount of `ClaimLanding`, whose existing `useEffect` cleanup restores a previously-captured `document.title`. Because `enterClaimPreview()` already applied the preview config’s title via `applyConfigDom()`, the cleanup runs afterward and overwrites the preview title.
### Issue Context
`ClaimLanding` previously only needed to restore the title when leaving the landing for the real app, but the new in-place preview transition makes that cleanup ordering observable.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-landing.tsx[36-47]
- apps/self-hosted/src/features/claim/claim-landing.tsx[27-34]
- apps/self-hosted/src/features/claim/claim-preview.ts[86-90]
### Suggested fix
Update the ClaimLanding title effect cleanup so it does **not** restore a stale `prevTitle` when the landing unmounts.
Concrete options:
1) In the cleanup, re-apply the *current* config-derived title instead of `prevTitle` (e.g., call `applyConfigDom(InstanceConfigManager.getConfig(), { syncSystemTheme: true })` or set `document.title` from the current config).
2) Alternatively, remove the title restoration entirely and rely on config/route ownership of `document.title` once leaving the landing.
Add a small test (or extend existing claim-preview tests) to assert that after `enterClaimPreview`, the final `document.title` is the preview name, not the previous template title.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Preview likes/comments still render 🐞 Bug ≡ Correctness
Description
The synthesized claim-preview config explicitly enables likes and comments while disabling auth, so
like and comment UI still renders in preview even though the preview is intended to hide broadcast
affordances. This makes the preview less “brochure-like” and can expose disabled-but-visible
interaction controls.
Code

apps/self-hosted/src/features/claim/claim-preview.ts[R71-74]

+          likes: { enabled: true },
+          comments: { enabled: true },
+          post: { text2Speech: { enabled: false } },
+          auth: { enabled: false, methods: [] },
Relevance

●●● Strong

Matches PR intent (“brochure preview”): disable likes/comments in preview config; straightforward
correctness/UI fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preview config sets likes/comments enabled, and the blog UI reads those flags to decide whether
to render like/comment UI. In BlogPostFooter, the vote button is rendered when showLikes is true
(derived from the config likes flag), independent of whether auth is enabled.

apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[18-34]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`buildClaimPreviewConfig()` sets `features.likes.enabled` and `features.comments.enabled` to `true` while also setting `features.auth.enabled` to `false`. Several UI components render like/comment affordances based on the likes/comments feature flags (not strictly on auth), so these elements remain visible during claim preview.
### Issue Context
The claim preview is intended to be read-only and to hide broadcast affordances. Currently, likes/comment counts and the vote button can still render because the feature flags remain enabled.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[23-34]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]
### Suggested fix
In `buildClaimPreviewConfig`, set:
- `features.likes.enabled = false`
- `features.comments.enabled = false`
If you also want to remove other broadcast-ish UI (e.g., reblog), consider additionally gating those components on `useIsAuthEnabled()` or on `isClaimPreviewActive()` at render sites.
Update/extend the claim preview tests to assert that likes/comments are disabled (and, optionally, that key affordances are not rendered when `claimPreview` is active).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Preview title overwritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
Entering claim preview sets the document title via applyConfigDom, but when ClaimLanding unmounts
its existing effect cleanup restores the pre-landing title, clobbering the preview title. As a
result, the browser tab title can remain the template/previous title instead of the previewed
account/community name.
Code

apps/self-hosted/src/features/claim/claim-landing.tsx[R30-33]

+  useEffect(() => {
+    if (name && isClaimPreviewRequested(window.location.search)) {
+      enterClaimPreview(name, isCommunity);
+    }
Relevance

●●● Strong

Correctness bug: preview title likely clobbered by ClaimLanding cleanup; teams usually accept
deterministic UX fixes.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new effect calls enterClaimPreview, which applies the preview config (including its
meta.title) to the DOM. But ClaimLanding’s existing title-setting effect restores the previous title
on unmount, which occurs when the template gate flips, overwriting the preview title after it was
set.

apps/self-hosted/src/features/claim/claim-landing.tsx[27-48]
apps/self-hosted/src/features/claim/claim-preview.ts[50-56]
apps/self-hosted/src/features/claim/claim-preview.ts[86-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Entering claim preview triggers unmount of `ClaimLanding`, whose existing `useEffect` cleanup restores a previously-captured `document.title`. Because `enterClaimPreview()` already applied the preview config’s title via `applyConfigDom()`, the cleanup runs afterward and overwrites the preview title.
### Issue Context
`ClaimLanding` previously only needed to restore the title when leaving the landing for the real app, but the new in-place preview transition makes that cleanup ordering observable.
### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-landing.tsx[36-47]
- apps/self-hosted/src/features/claim/claim-landing.tsx[27-34]
- apps/self-hosted/src/features/claim/claim-preview.ts[86-90]
### Suggested fix
Update the ClaimLanding title effect cleanup so it does **not** restore a stale `prevTitle` when the landing unmounts.
Concrete options:
1) In the cleanup, re-apply the *current* config-derived title instead of `prevTitle` (e.g., call `applyConfigDom(InstanceConfigManager.getConfig(), { syncSystemTheme: true })` or set `document.title` from the current config).
2) Alternatively, remove the title restoration entirely and rely on config/route ownership of `document.title` once leaving the landing.
Add a small test (or extend existing claim-preview tests) to assert that after `enterClaimPreview`, the final `document.title` is the preview name, not the previous template title.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

9. Claim preview test co-located 📜 Skill insight ⌂ Architecture
Description
The new test file is co-located under src/features/claim/ instead of the required
src/specs/features/claim/ mapping. This breaks the mandated test organization and can make test
discovery and ownership inconsistent.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[R1-3]

+// @vitest-environment jsdom
+import { beforeEach, describe, expect, it } from 'vitest';
+import { applyConfigDom, InstanceConfigManager } from '@/core';
Relevance

● Weak

Repo precedent rejected moving co-located tests into src/specs mapping; team likely won’t enforce
this rule.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires tests not be co-located with feature source and instead follow the
src/features//src/specs/features// mapping. The added file path
apps/self-hosted/src/features/claim/claim-preview.test.ts violates that placement requirement.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added test is placed under `apps/self-hosted/src/features/claim/`, but the compliance rule requires tests to live under the corresponding `apps/self-hosted/src/specs/features/claim/` directory.
## Issue Context
This PR adds `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Test file uses .test suffix 📜 Skill insight ⚙ Maintainability
Description
The new test file name uses .test.ts, but the compliance standard requires .spec.ts/.spec.tsx
naming. Inconsistent naming can prevent standardized tooling and conventions from applying
uniformly.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[1]

+// @vitest-environment jsdom
Relevance

● Weak

Repo precedent rejected renaming .test.ts to .spec.ts; team likely accepts .test suffix.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test files to follow the .spec.tsx or .spec.ts naming
convention. The newly added file name ends with .test.ts, which does not meet the required
pattern.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-3]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test file is named with a `.test.ts` suffix, but the compliance rule requires `.spec.ts` (or `.spec.tsx`) naming.
## Issue Context
This PR introduces `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Test file uses .test suffix 📜 Skill insight ⚙ Maintainability
Description
The new test file name uses .test.ts, but the compliance standard requires .spec.ts/.spec.tsx
naming. Inconsistent naming can prevent standardized tooling and conventions from applying
uniformly.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[1]

+// @vitest-environment jsdom
Relevance

● Weak

Repo precedent rejected renaming .test.ts to .spec.ts; team likely accepts .test suffix.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test files to follow the .spec.tsx or .spec.ts naming
convention. The newly added file name ends with .test.ts, which does not meet the required
pattern.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-3]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test file is named with a `.test.ts` suffix, but the compliance rule requires `.spec.ts` (or `.spec.tsx`) naming.
## Issue Context
This PR introduces `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View optional (5)
12. Claim preview test co-located 📜 Skill insight ⌂ Architecture
Description
The new test file is co-located under src/features/claim/ instead of the required
src/specs/features/claim/ mapping. This breaks the mandated test organization and can make test
discovery and ownership inconsistent.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[R1-3]

+// @vitest-environment jsdom
+import { beforeEach, describe, expect, it } from 'vitest';
+import { applyConfigDom, InstanceConfigManager } from '@/core';
Relevance

● Weak

Repo precedent rejected moving co-located tests into src/specs mapping; team likely won’t enforce
this rule.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires tests not be co-located with feature source and instead follow the
src/features//src/specs/features// mapping. The added file path
apps/self-hosted/src/features/claim/claim-preview.test.ts violates that placement requirement.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added test is placed under `apps/self-hosted/src/features/claim/`, but the compliance rule requires tests to live under the corresponding `apps/self-hosted/src/specs/features/claim/` directory.
## Issue Context
This PR adds `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. Test file uses .test suffix 📜 Skill insight ⚙ Maintainability
Description
The new test file name uses .test.ts, but the compliance standard requires .spec.ts/.spec.tsx
naming. Inconsistent naming can prevent standardized tooling and conventions from applying
uniformly.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[1]

+// @vitest-environment jsdom
Relevance

● Weak

Repo precedent rejected renaming .test.ts to .spec.ts; team likely accepts .test suffix.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test files to follow the .spec.tsx or .spec.ts naming
convention. The newly added file name ends with .test.ts, which does not meet the required
pattern.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-3]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test file is named with a `.test.ts` suffix, but the compliance rule requires `.spec.ts` (or `.spec.tsx`) naming.
## Issue Context
This PR introduces `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


14. Claim preview test co-located 📜 Skill insight ⌂ Architecture
Description
The new test file is co-located under src/features/claim/ instead of the required
src/specs/features/claim/ mapping. This breaks the mandated test organization and can make test
discovery and ownership inconsistent.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[R1-3]

+// @vitest-environment jsdom
+import { beforeEach, describe, expect, it } from 'vitest';
+import { applyConfigDom, InstanceConfigManager } from '@/core';
Relevance

● Weak

Repo precedent rejected moving co-located tests into src/specs mapping; team likely won’t enforce
this rule.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires tests not be co-located with feature source and instead follow the
src/features//src/specs/features// mapping. The added file path
apps/self-hosted/src/features/claim/claim-preview.test.ts violates that placement requirement.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added test is placed under `apps/self-hosted/src/features/claim/`, but the compliance rule requires tests to live under the corresponding `apps/self-hosted/src/specs/features/claim/` directory.
## Issue Context
This PR adds `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


15. Test file uses .test suffix 📜 Skill insight ⚙ Maintainability
Description
The new test file name uses .test.ts, but the compliance standard requires .spec.ts/.spec.tsx
naming. Inconsistent naming can prevent standardized tooling and conventions from applying
uniformly.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[1]

+// @vitest-environment jsdom
Relevance

● Weak

Repo precedent rejected renaming .test.ts to .spec.ts; team likely accepts .test suffix.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test files to follow the .spec.tsx or .spec.ts naming
convention. The newly added file name ends with .test.ts, which does not meet the required
pattern.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-3]
Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test file is named with a `.test.ts` suffix, but the compliance rule requires `.spec.ts` (or `.spec.tsx`) naming.
## Issue Context
This PR introduces `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


16. Claim preview test co-located 📜 Skill insight ⌂ Architecture
Description
The new test file is co-located under src/features/claim/ instead of the required
src/specs/features/claim/ mapping. This breaks the mandated test organization and can make test
discovery and ownership inconsistent.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[R1-3]

+// @vitest-environment jsdom
+import { beforeEach, describe, expect, it } from 'vitest';
+import { applyConfigDom, InstanceConfigManager } from '@/core';
Relevance

● Weak

Repo precedent rejected moving co-located tests into src/specs mapping; team likely won’t enforce
this rule.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires tests not be co-located with feature source and instead follow the
src/features//src/specs/features// mapping. The added file path
apps/self-hosted/src/features/claim/claim-preview.test.ts violates that placement requirement.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]
Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added test is placed under `apps/self-hosted/src/features/claim/`, but the compliance rule requires tests to live under the corresponding `apps/self-hosted/src/specs/features/claim/` directory.
## Issue Context
This PR adds `apps/self-hosted/src/features/claim/claim-preview.test.ts`.
## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 11, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Self-hosted: add live preview mode for unclaimed subdomains

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add an explicit “Preview this blog first” flow for unclaimed subdomains (or ?preview=1).
• Synthesize an in-memory, read-only instance config (auth disabled) and hot-swap it to boot the
 full app.
• Show a persistent preview banner with claim/exit actions and enforce robots noindex during
 preview.
Diagram

graph TD
  A["ClaimLanding"] --> B["claim-preview"] --> C["InstanceConfigManager"] --> D["RootComponent"]
  D --> E["ClaimPreviewBanner"] --> F{{"Ecency Hosting"}}
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Dedicated preview route + isolated config context
  • ➕ Avoids mutating the global InstanceConfigManager at runtime (less risk of side-effects).
  • ➕ Keeps template gating logic simpler (preview becomes an explicit route boundary).
  • ➖ Requires more routing/plumbing and potentially duplicating bootstrapping logic.
  • ➖ Harder to ensure the rest of the app consumes the preview context consistently.
2. Server-generated ephemeral preview config
  • ➕ Guarantees canonical/validated config shape from the backend (less client synthesis).
  • ➕ Could support richer preview features (e.g., controlled feature flags) consistently.
  • ➖ Adds infrastructure/state concerns (even if ephemeral) and complicates the 'nothing provisioned' promise.
  • ➖ Higher operational and security surface area for a feature intended to be lightweight.

Recommendation: The current client-side, in-memory config swap is a strong fit for the stated goals: explicit opt-in (protects SEO/crawlers), no persistence/provisioning, and a clean way to reuse the full route tree. Keep an eye on global-config side effects, but the explicit marker (claimPreview) + removal of the template gate key makes the behavior easy to reason about and test.

Files changed (7) +292 / -0

Enhancement (5) +200 / -0
i18n-strings.tsAdd claim-preview CTA and banner translation keys +12/-0

Add claim-preview CTA and banner translation keys

• Introduces new i18n keys for entering preview from the claim landing and for the persistent preview banner (blog/community text, claim, and exit labels).

apps/self-hosted/src/core/i18n-strings.ts

claim-landing.tsxAdd preview entry point and deep-link boot via '?preview=1' +19/-0

Add preview entry point and deep-link boot via '?preview=1'

• Adds a preview button to the unclaimed-host landing and a mount effect that enters preview automatically when the strict preview query param is present. Keeps the lightweight CTA as the default path for crawlers and casual visits.

apps/self-hosted/src/features/claim/claim-landing.tsx

claim-preview-banner.tsxIntroduce persistent preview banner and enforce noindex during preview +66/-0

Introduce persistent preview banner and enforce noindex during preview

• Adds a fixed bottom banner shown during claim preview with clear messaging, an exit action (removes param and forces reload), and a claim deep link. Re-adds a 'robots' noindex/nofollow meta tag for the preview lifecycle to prevent indexing unclaimed hosts.

apps/self-hosted/src/features/claim/claim-preview-banner.tsx

claim-preview.tsImplement claim preview config builder and activation helpers +97/-0

Implement claim preview config builder and activation helpers

• Defines the 'preview' boot param, strict parsing, and an in-memory synthesized InstanceConfig for blog/community derived from the host. Swaps the runtime config via InstanceConfigManager and applies DOM config; marks preview via 'claimPreview: true' while omitting 'template' to flip the root gate.

apps/self-hosted/src/features/claim/claim-preview.ts

__root.tsxRender claim preview banner when preview marker is active +6/-0

Render claim preview banner when preview marker is active

• Wires the new preview marker check into the root so the banner appears during preview alongside the normal route tree, while keeping the existing template gate behavior for the claim landing.

apps/self-hosted/src/routes/__root.tsx

Tests (2) +92 / -0
claim-preview.test.tsAdd unit tests for preview config synthesis and template gate flip +88/-0

Add unit tests for preview config synthesis and template gate flip

• Covers blog vs community preview config shapes, strict param parsing, auth disabled behavior, preview marker detection, and the critical behavior that 'template' must be absent (not false). Also asserts DOM attributes are repainted after entering preview.

apps/self-hosted/src/features/claim/claim-preview.test.ts

-internal-links.test.tsAllowlist preview banner claim link in internal-links guard +4/-0

Allowlist preview banner claim link in internal-links guard

• Registers the new absolute claim link constructed in the preview banner as an expected dynamic link to satisfy the dead-route/internal-links test suite.

apps/self-hosted/src/routes/-internal-links.test.ts

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

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

Next review available in: 34 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

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 Plus

Run ID: f0072b32-e094-4959-89ac-da2e1738cf04

📥 Commits

Reviewing files that changed from the base of the PR and between 52b7c05 and b4c276c.

📒 Files selected for processing (2)
  • apps/self-hosted/src/core/i18n-strings.ts
  • apps/self-hosted/src/features/claim/claim-landing.tsx
📝 Walkthrough

Walkthrough

The change adds live previews for unclaimed blog and community subdomains. It synthesizes an in-memory configuration, supports automatic or explicit preview entry, renders a persistent claim banner, preserves crawler metadata, and adds tests and translations.

Changes

Claim preview flow

Layer / File(s) Summary
Preview detection and configuration
apps/self-hosted/src/features/claim/claim-preview.ts, apps/self-hosted/src/features/claim/claim-preview.test.ts
The app detects preview=1, builds blog or community preview configurations, applies them in memory, and identifies active previews. Tests cover configuration, DOM state, parsing, and tenant guards.
Claim entry and preview banner
apps/self-hosted/src/features/claim/claim-landing.tsx, apps/self-hosted/src/features/claim/claim-preview-banner.tsx, apps/self-hosted/src/core/i18n-strings.ts
The claim page enters previews automatically or through a button. The banner shows localized messaging, claim and exit actions, and temporary robots metadata.
Root-route preview rendering
apps/self-hosted/src/routes/__root.tsx, apps/self-hosted/src/routes/-internal-links.test.ts
The root route detects active previews and renders the banner. The internal-link test allows the absolute claim destination.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Visitor
  participant ClaimLanding
  participant ClaimPreview
  participant InstanceConfigManager
  participant ClaimPreviewBanner
  Visitor->>ClaimLanding: Open unclaimed host with preview=1
  ClaimLanding->>ClaimPreview: Enter preview with host and target type
  ClaimPreview->>InstanceConfigManager: Apply synthesized preview configuration
  InstanceConfigManager-->>ClaimPreviewBanner: Expose active claim preview state
  ClaimPreviewBanner->>Visitor: Show preview, claim, and exit actions
Loading

Possibly related PRs

Poem

I hop through a preview, bright and clear,
With claim and exit buttons near.
Blog or community, the banners gleam,
A host becomes a living dream.
No crawler follows where I play—
Then I claim the name and bounce away! 🐇

🚥 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 clearly identifies the self-hosted live preview feature for unclaimed subdomains.
Linked Issues check ✅ Passed The changes implement preview entry, synthesized configuration, noindex protection, preview gating, tests, and a persistent claim banner required by issue [#1416].
Out of Scope Changes check ✅ Passed All modified files support claim-preview activation, configuration, UI, localization, routing, or related tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feature/self-hosted-claim-preview

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: 2

Caution

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

⚠️ Outside diff range comments (1)
apps/self-hosted/src/routes/__root.tsx (1)

81-104: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Announce preview entry to screen-reader users.

Line 104 mounts the banner only after preview mode starts. Add a LiveRegion that mounts during the initial render with message={null}. Update its message when isClaimPreview becomes true. Keep the banner controls outside the live region.

Based on learnings: In apps/self-hosted TSX files, use apps/self-hosted/src/features/shared/live-region.tsx for dynamic screen-reader announcements, keep it mounted from the initial render, and keep interactive controls outside 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 `@apps/self-hosted/src/routes/__root.tsx` around lines 81 - 104, Add a
LiveRegion alongside the preview layout that mounts on the initial render with
message={null}, then announces the preview state when isClaimPreview becomes
true. Use the shared LiveRegion from live-region.tsx, and keep
ClaimPreviewBanner and its interactive controls outside the live region.

Source: Learnings

🤖 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/self-hosted/src/core/i18n-strings.ts`:
- Line 387: Update the claim_preview_cta value used by ClaimLanding to use
target-neutral wording that applies equally to blog and community visitors,
removing the blog-specific “Preview this blog first” phrasing.

In `@apps/self-hosted/src/features/claim/claim-landing.tsx`:
- Around line 65-71: Guard the manual preview button around enterClaimPreview so
it cannot be activated when name is empty. Update the button in the claim
landing component to disable or hide it for an empty name, while preserving the
existing preview behavior when a valid name is present.

---

Outside diff comments:
In `@apps/self-hosted/src/routes/__root.tsx`:
- Around line 81-104: Add a LiveRegion alongside the preview layout that mounts
on the initial render with message={null}, then announces the preview state when
isClaimPreview becomes true. Use the shared LiveRegion from live-region.tsx, and
keep ClaimPreviewBanner and its interactive controls outside the live region.
🪄 Autofix

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 Plus

Run ID: 3e592129-acbf-4d65-ac29-e8e3ddd5e140

📥 Commits

Reviewing files that changed from the base of the PR and between 68bb4c4 and 52b7c05.

📒 Files selected for processing (7)
  • apps/self-hosted/src/core/i18n-strings.ts
  • apps/self-hosted/src/features/claim/claim-landing.tsx
  • apps/self-hosted/src/features/claim/claim-preview-banner.tsx
  • apps/self-hosted/src/features/claim/claim-preview.test.ts
  • apps/self-hosted/src/features/claim/claim-preview.ts
  • apps/self-hosted/src/routes/-internal-links.test.ts
  • apps/self-hosted/src/routes/__root.tsx

Comment thread apps/self-hosted/src/core/i18n-strings.ts Outdated
Comment thread apps/self-hosted/src/features/claim/claim-landing.tsx
@qodo-code-review

qodo-code-review Bot commented Aug 11, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (2)

Grey Divider


Remediation recommended

1. Preview likes/comments still render 🐞 Bug ≡ Correctness
Description
The synthesized claim-preview config explicitly enables likes and comments while disabling auth, so
like and comment UI still renders in preview even though the preview is intended to hide broadcast
affordances. This makes the preview less “brochure-like” and can expose disabled-but-visible
interaction controls.
Code

apps/self-hosted/src/features/claim/claim-preview.ts[R71-74]

+          likes: { enabled: true },
+          comments: { enabled: true },
+          post: { text2Speech: { enabled: false } },
+          auth: { enabled: false, methods: [] },
Relevance

●●● Strong

Matches PR intent (“brochure preview”): disable likes/comments in preview config; straightforward
correctness/UI fix.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preview config sets likes/comments enabled, and the blog UI reads those flags to decide whether
to render like/comment UI. In BlogPostFooter, the vote button is rendered when showLikes is true
(derived from the config likes flag), independent of whether auth is enabled.

apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[18-34]
apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`buildClaimPreviewConfig()` sets `features.likes.enabled` and `features.comments.enabled` to `true` while also setting `features.auth.enabled` to `false`. Several UI components render like/comment affordances based on the likes/comments feature flags (not strictly on auth), so these elements remain visible during claim preview.

### Issue Context
The claim preview is intended to be read-only and to hide broadcast affordances. Currently, likes/comment counts and the vote button can still render because the feature flags remain enabled.

### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.ts[67-75]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[23-34]
- apps/self-hosted/src/features/blog/components/blog-post-footer.tsx[60-75]

### Suggested fix
In `buildClaimPreviewConfig`, set:
- `features.likes.enabled = false`
- `features.comments.enabled = false`

If you also want to remove other broadcast-ish UI (e.g., reblog), consider additionally gating those components on `useIsAuthEnabled()` or on `isClaimPreviewActive()` at render sites.

Update/extend the claim preview tests to assert that likes/comments are disabled (and, optionally, that key affordances are not rendered when `claimPreview` is active).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Preview title overwritten ✓ Resolved 🐞 Bug ≡ Correctness
Description
Entering claim preview sets the document title via applyConfigDom, but when ClaimLanding unmounts
its existing effect cleanup restores the pre-landing title, clobbering the preview title. As a
result, the browser tab title can remain the template/previous title instead of the previewed
account/community name.
Code

apps/self-hosted/src/features/claim/claim-landing.tsx[R30-33]

+  useEffect(() => {
+    if (name && isClaimPreviewRequested(window.location.search)) {
+      enterClaimPreview(name, isCommunity);
+    }
Relevance

●●● Strong

Correctness bug: preview title likely clobbered by ClaimLanding cleanup; teams usually accept
deterministic UX fixes.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new effect calls enterClaimPreview, which applies the preview config (including its
meta.title) to the DOM. But ClaimLanding’s existing title-setting effect restores the previous title
on unmount, which occurs when the template gate flips, overwriting the preview title after it was
set.

apps/self-hosted/src/features/claim/claim-landing.tsx[27-48]
apps/self-hosted/src/features/claim/claim-preview.ts[50-56]
apps/self-hosted/src/features/claim/claim-preview.ts[86-90]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Entering claim preview triggers unmount of `ClaimLanding`, whose existing `useEffect` cleanup restores a previously-captured `document.title`. Because `enterClaimPreview()` already applied the preview config’s title via `applyConfigDom()`, the cleanup runs afterward and overwrites the preview title.

### Issue Context
`ClaimLanding` previously only needed to restore the title when leaving the landing for the real app, but the new in-place preview transition makes that cleanup ordering observable.

### Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-landing.tsx[36-47]
- apps/self-hosted/src/features/claim/claim-landing.tsx[27-34]
- apps/self-hosted/src/features/claim/claim-preview.ts[86-90]

### Suggested fix
Update the ClaimLanding title effect cleanup so it does **not** restore a stale `prevTitle` when the landing unmounts.

Concrete options:
1) In the cleanup, re-apply the *current* config-derived title instead of `prevTitle` (e.g., call `applyConfigDom(InstanceConfigManager.getConfig(), { syncSystemTheme: true })` or set `document.title` from the current config).
2) Alternatively, remove the title restoration entirely and rely on config/route ownership of `document.title` once leaving the landing.

Add a small test (or extend existing claim-preview tests) to assert that after `enterClaimPreview`, the final `document.title` is the preview name, not the previous template title.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Test file uses .test suffix 📜 Skill insight ⚙ Maintainability
Description
The new test file name uses .test.ts, but the compliance standard requires .spec.ts/.spec.tsx
naming. Inconsistent naming can prevent standardized tooling and conventions from applying
uniformly.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[1]

+// @vitest-environment jsdom
Relevance

● Weak

Repo precedent rejected renaming .test.ts to .spec.ts; team likely accepts .test suffix.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test files to follow the .spec.tsx or .spec.ts naming
convention. The newly added file name ends with .test.ts, which does not meet the required
pattern.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-3]
Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new test file is named with a `.test.ts` suffix, but the compliance rule requires `.spec.ts` (or `.spec.tsx`) naming.

## Issue Context
This PR introduces `apps/self-hosted/src/features/claim/claim-preview.test.ts`.

## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Claim preview test co-located 📜 Skill insight ⌂ Architecture
Description
The new test file is co-located under src/features/claim/ instead of the required
src/specs/features/claim/ mapping. This breaks the mandated test organization and can make test
discovery and ownership inconsistent.
Code

apps/self-hosted/src/features/claim/claim-preview.test.ts[R1-3]

+// @vitest-environment jsdom
+import { beforeEach, describe, expect, it } from 'vitest';
+import { applyConfigDom, InstanceConfigManager } from '@/core';
Relevance

● Weak

Repo precedent rejected moving co-located tests into src/specs mapping; team likely won’t enforce
this rule.

PR-#1437

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires tests not be co-located with feature source and instead follow the
src/features/<domain>/src/specs/features/<domain>/ mapping. The added file path
apps/self-hosted/src/features/claim/claim-preview.test.ts violates that placement requirement.

apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]
Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added test is placed under `apps/self-hosted/src/features/claim/`, but the compliance rule requires tests to live under the corresponding `apps/self-hosted/src/specs/features/claim/` directory.

## Issue Context
This PR adds `apps/self-hosted/src/features/claim/claim-preview.test.ts`.

## Fix Focus Areas
- apps/self-hosted/src/features/claim/claim-preview.test.ts[1-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 75 rules
✅ Skills: 6 invoked
  add-feature
  add-query
  add-sdk-mutation
  add-test
  code-review
  debug
✅ Web pages:
  +2 more
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 12/18, lines 292/200; both must reach the floor). Router rationale: This introduces multiple interacting preview paths—config synthesis, reactive root gating, URL/exit behavior, auth suppression, robots metadata, and claim navigation—across several files, creating a dense set of independent defects that benefits from redundant review.

Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/self-hosted/src/features/claim/claim-landing.tsx
Comment thread apps/self-hosted/src/features/claim/claim-preview.ts
feruzm added 3 commits August 11, 2026 22:22
Entering the live preview sets the preview title via applyConfigDom and
then unmounts the landing, whose cleanup restored the pre-landing title
over it. The cleanup now restores only when no claim preview took over.
The other review finding (likes and comments rendering in preview) is
by design: counts display read-only while every interactive control
gates on the disabled auth flag.
Review finding: on a ?preview=1 deep link the landing's title effect
ran after the preview had already painted its own title, sticking the
claim headline on the whole preview session. The effect now no-ops
when a claim preview is active; the banner owns noindex from there.
@feruzm
feruzm merged commit 7455e01 into develop Aug 12, 2026
8 of 9 checks passed
@feruzm
feruzm deleted the feature/self-hosted-claim-preview branch August 12, 2026 06:13
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.

Self-hosted: live preview on unclaimed subdomains

1 participant