Skip to content

Hosting: manage panel becomes a remote settings surface - #1457

Merged
feruzm merged 3 commits into
developfrom
feature/hosting-manage-remote-settings
Aug 12, 2026
Merged

Hosting: manage panel becomes a remote settings surface#1457
feruzm merged 3 commits into
developfrom
feature/hosting-manage-remote-settings

Conversation

@feruzm

@feruzm feruzm commented Aug 12, 2026

Copy link
Copy Markdown
Member

Closes #1423

What

Owners edit a hosted instance's title, description, theme and accent right from the manage panel on /hosting, no visit to the instance needed. Works while a tenant is still activating, since the PATCH persists for inactive tenants and publishes on activation.

How

  • Token in place (hosting-token.ts): every ecency.com login method holds a Hivesigner-compatible session token, so /v1/auth/hivesigner exchanges it for a hosting token as the universal rail; a Keychain posting-key challenge (/v1/auth/challenge + /v1/auth/verify) is the fallback. Tokens cache per account for their lifetime, so one authorization serves many edits.
  • Editor (tenant-settings.tsx): prefills from GET /v1/tenants/:username/config when the tenant is active (the endpoint answers 402 before activation, where fields start blank). Only fields that actually changed are sent through the flat-key PATCH and a blank field always means keep the current value. Mid-edit invalid accents block saving, same derivation as the signup.
  • Manage panel: an Edit settings toggle per tenant, offered for every status.
  • No server changes: the auth endpoints, the authorized PATCH /v1/tenants/:username and its owner check already exist, and CORS already admits ecency.com.

Tests

  • 3 hosting-token specs (exchange + cache, Keychain fallback, no-rail failure)
  • 3 editor specs (prefill + changed-fields-only payload, blind edit of an activating tenant, failed save surfaces)
  • Full suite green: 2631 web tests, typecheck clean

Summary by CodeRabbit

  • New Features
    • Added tenant settings for editing hosted-site titles, descriptions, themes, and accent colors.
    • Added per-tenant settings access in the hosting management panel.
    • Added secure authentication and token handling for loading and saving tenant configuration.
    • Settings now show localized save status, activation progress, and error messages.
  • Bug Fixes
    • Prevented loading data from overwriting edits already made by users.
    • Added validation to prevent invalid accent colors and unnecessary saves.

The manage panel edits a hosted instance's title, description, theme and
accent without a visit to the instance. Authorization is a hosting token
obtained in place: every ecency.com login method holds a
Hivesigner-compatible session token that /v1/auth/hivesigner exchanges,
with a Keychain posting-key challenge as the fallback rail, cached per
account for its lifetime. The editor prefills from the served config when
the tenant is active, sends only the fields that actually changed and a
blank field always keeps the current value. Works for a tenant that is
still activating too: the PATCH persists and publishes on activation.
@qodo-free-for-open-source-projects

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

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Prefill overwrites user edits ✓ Resolved 🐞 Bug ≡ Correctness
Description
TenantSettings applies the async tenantConfig() prefill unconditionally, so a late response can
overwrite user-typed values (or even a just-saved state) and lead to lost edits / incorrect
subsequent PATCH payloads.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[R56-60]

+  useEffect(() => {
+    if (tenant.subscriptionStatus !== "active") return;
+    let cancelled = false;
+    hostingApi
+      .tenantConfig(tenant.username)
Relevance

●●● Strong

Team previously accepted guards to prevent late async prefills overwriting user interaction state.

PR-#1022

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The prefill effect updates all form state when the fetch resolves, with no guard for whether the
user has already interacted; the only protection is an unmount-only cancelled flag. This matches a
previously accepted bug pattern where late async data overwrote user interaction state.

apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]
PR-#1022

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

## Issue description
`TenantSettings` triggers an async prefill (`hostingApi.tenantConfig`) and then unconditionally calls `setTitle/setDescription/setTheme/setAccent/setAccentInput` when it resolves. If the user starts editing before the request returns (or saves while it’s still in flight), the late response can clobber their edits and/or reset the "initial" baseline used to compute subsequent changes.
### Issue Context
This is a classic async-response race: the request is tied only to component mount and unmount (`cancelled`), not to whether the form is still pristine.
### How to fix
- Track a `dirtyRef` / `touchedRef` that flips to true on any user interaction (title/desc/theme/accent changes).
- Apply the prefill only if the form is still pristine (e.g., `if (dirtyRef.current) return;`).
- Optionally: use an `AbortController` or request-id approach to ensure only the latest request applies.
- Also consider preventing prefill from running (or applying) while `busy` is true.
### Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]

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


2. Prefill overwrites user edits ✓ Resolved 🐞 Bug ≡ Correctness
Description
TenantSettings applies the async tenantConfig() prefill unconditionally, so a late response can
overwrite user-typed values (or even a just-saved state) and lead to lost edits / incorrect
subsequent PATCH payloads.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[R56-60]

+  useEffect(() => {
+    if (tenant.subscriptionStatus !== "active") return;
+    let cancelled = false;
+    hostingApi
+      .tenantConfig(tenant.username)
Relevance

●●● Strong

Team previously accepted guards to prevent late async prefills overwriting user interaction state.

PR-#1022

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The prefill effect updates all form state when the fetch resolves, with no guard for whether the
user has already interacted; the only protection is an unmount-only cancelled flag. This matches a
previously accepted bug pattern where late async data overwrote user interaction state.

apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]
PR-#1022

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

## Issue description
`TenantSettings` triggers an async prefill (`hostingApi.tenantConfig`) and then unconditionally calls `setTitle/setDescription/setTheme/setAccent/setAccentInput` when it resolves. If the user starts editing before the request returns (or saves while it’s still in flight), the late response can clobber their edits and/or reset the "initial" baseline used to compute subsequent changes.
### Issue Context
This is a classic async-response race: the request is tied only to component mount and unmount (`cancelled`), not to whether the form is still pristine.
### How to fix
- Track a `dirtyRef` / `touchedRef` that flips to true on any user interaction (title/desc/theme/accent changes).
- Apply the prefill only if the form is still pristine (e.g., `if (dirtyRef.current) return;`).
- Optionally: use an `AbortController` or request-id approach to ensure only the latest request applies.
- Also consider preventing prefill from running (or applying) while `busy` is true.
### Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]

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


3. Prefill overwrites user edits ✓ Resolved 🐞 Bug ≡ Correctness
Description
TenantSettings applies the async tenantConfig() prefill unconditionally, so a late response can
overwrite user-typed values (or even a just-saved state) and lead to lost edits / incorrect
subsequent PATCH payloads.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[R56-60]

+  useEffect(() => {
+    if (tenant.subscriptionStatus !== "active") return;
+    let cancelled = false;
+    hostingApi
+      .tenantConfig(tenant.username)
Relevance

●●● Strong

Team previously accepted guards to prevent late async prefills overwriting user interaction state.

PR-#1022

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The prefill effect updates all form state when the fetch resolves, with no guard for whether the
user has already interacted; the only protection is an unmount-only cancelled flag. This matches a
previously accepted bug pattern where late async data overwrote user interaction state.

apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]
PR-#1022

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

## Issue description
`TenantSettings` triggers an async prefill (`hostingApi.tenantConfig`) and then unconditionally calls `setTitle/setDescription/setTheme/setAccent/setAccentInput` when it resolves. If the user starts editing before the request returns (or saves while it’s still in flight), the late response can clobber their edits and/or reset the "initial" baseline used to compute subsequent changes.
### Issue Context
This is a classic async-response race: the request is tied only to component mount and unmount (`cancelled`), not to whether the form is still pristine.
### How to fix
- Track a `dirtyRef` / `touchedRef` that flips to true on any user interaction (title/desc/theme/accent changes).
- Apply the prefill only if the form is still pristine (e.g., `if (dirtyRef.current) return;`).
- Optionally: use an `AbortController` or request-id approach to ensure only the latest request applies.
- Also consider preventing prefill from running (or applying) while `busy` is true.
### Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]

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



Remediation recommended

4. onChange uses any ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
TenantSettings uses (e: any) in input onChange handlers, introducing new any usage. This
weakens type safety and can hide runtime bugs in this new settings surface.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[136]

+        onChange={(e: any) => setTitle(e.target.value)}
Relevance

●● Moderate

Mixed precedent: some PRs accepted removing (e:any), others rejected the same change in similar
handlers.

PR-#1438
PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids introducing any in new/modified TypeScript code. The new
TenantSettings component uses (e: any) in onChange, which is an explicit any type.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/hosting-signup/tenant-settings.tsx[131-146]

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

## Issue description
`TenantSettings` introduces `any` in the `onChange` handlers (e.g., `(e: any)`), violating the requirement to avoid `any` in new TypeScript code.
## Issue Context
This is new UI logic for remotely editing tenant settings; keeping strong typing helps prevent subtle UI/input bugs.
## Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[131-147]

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


5. Feature files lack subdirs 📜 Skill insight ⌂ Architecture
Description
New hosting-manage settings code is added as top-level feature files instead of being organized
under the standard components/, api/, hooks/, and types/ subdirectories. This makes feature
boundaries harder to maintain as the feature grows.
Code

apps/web/src/features/hosting-signup/hosting-token.ts[R1-4]

+import { getLoginType, ensureValidToken } from "@/utils/user-token";
+import { signBuffer } from "@/utils/keychain";
+import { hostingApi, type HostingAuthResult } from "./hosting-api";
+
Relevance

●● Moderate

No close precedent found; directory structure is architectural and often left to author discretion.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668151 requires new feature code to use the standard feature directory structure
(with subdirectories like components/, api/, hooks/, types/). This PR adds new feature
modules directly at the feature root (hosting-token.ts, tenant-settings.tsx).

apps/web/src/features/hosting-signup/hosting-token.ts[1-4]
apps/web/src/features/hosting-signup/tenant-settings.tsx[1-8]
Skill: add-feature: Skill: add-feature: Skill: add-feature: Skill: add-feature: Skill: add-feature: Skill: add-feature: Skill: add-feature: Skill: add-feature

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

## Issue description
New feature modules were added directly under `apps/web/src/features/hosting-signup/` rather than following the standard feature folder structure.
## Issue Context
The checklist requires feature code to be organized into the standard subdirectories to keep feature growth manageable.
## Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-token.ts[1-66]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[1-194]

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


6. Misleading inactive save message ✓ Resolved 🐞 Bug ◔ Observability
Description
After a successful save, the UI always shows “Changes reach your site within a minute”, but the
hosting API returns a different message when published=false (inactive subscription) indicating
changes only go live on activation; the UI ignores published/message and misinforms owners editing
inactive tenants.
Code

apps/web/src/features/i18n/locales/en-US.json[R101-103]

+    "settings-save": "Save settings",
+    "settings-saved": "Saved. Changes reach your site within a minute.",
+    "settings-failed": "Could not save. Please try again.",
Relevance

●● Moderate

No strong precedent for using API-provided success messages over fixed i18n copy; UX/observability
is subjective.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The UI hardcodes a universal success message, but the hosting API’s PATCH handler explicitly returns
a different message when published is false: “Configuration saved. It goes live once the
subscription is active.” This mismatch is user-visible specifically in the new “edit while inactive”
flow introduced by this PR.

apps/web/src/features/hosting-signup/tenant-settings.tsx[180-191]
apps/web/src/features/i18n/locales/en-US.json[94-103]
apps/self-hosted/hosting/api/src/routes/tenants.ts[699-717]

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 editor shows a single success message (`hosting.settings-saved`: “Saved. Changes reach your site within a minute.”) regardless of tenant state. However, the hosting API’s PATCH response differentiates between `published=true` vs `published=false`, and explicitly returns a different message when the config is only stored (not live yet).
### Issue Context
This PR intentionally allows editing inactive tenants (persist now, publish on activation). The UI should reflect that reality or owners will think the change is immediately visible.
### How to fix
- Change `hostingApi.updateTenant` return type to include `published?: boolean` and `message?: string` (and optionally `discarded/reset` for future-proofing).
- In `TenantSettings.save()`, capture the response and:
- Prefer displaying `response.message` when present, OR
- Choose localized copy based on `response.published` (or `tenant.subscriptionStatus`).
- Add/adjust i18n strings for “saved but not live yet” vs “published soon”.
### Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-api.ts[174-178]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[110-120]
- apps/web/src/features/i18n/locales/en-US.json[95-103]

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


View medium (6)
7. Feature files lack subdirs ✗ Dismissed 📜 Skill insight ⌂ Architecture
Description
New hosting-manage settings code is added as top-level feature files instead of being organized
under the standard components/, api/, hooks/, and types/ subdirectories. This makes feature
boundaries harder to maintain as the feature grows.
Code

apps/web/src/features/hosting-signup/hosting-token.ts[R1-4]

+import { getLoginType, ensureValidToken } from "@/utils/user-token";
+import { signBuffer } from "@/utils/keychain";
+import { hostingApi, type HostingAuthResult } from "./hosting-api";
+
Relevance

●● Moderate

No close precedent found; directory structure is architectural and often left to author discretion.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668151 requires new feature code to use the standard feature directory structure
(with subdirectories like components/, api/, hooks/, types/). This PR adds new feature
modules directly at the feature root (hosting-token.ts, tenant-settings.tsx).

apps/web/src/features/hosting-signup/hosting-token.ts[1-4]
apps/web/src/features/hosting-signup/tenant-settings.tsx[1-8]
Skill: add-feature: Skill: add-feature: Skill: add-feature: Skill: add-feature

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

## Issue description
New feature modules were added directly under `apps/web/src/features/hosting-signup/` rather than following the standard feature folder structure.
## Issue Context
The checklist requires feature code to be organized into the standard subdirectories to keep feature growth manageable.
## Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-token.ts[1-66]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[1-194]

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


8. Misleading inactive save message ✓ Resolved 🐞 Bug ◔ Observability
Description
After a successful save, the UI always shows “Changes reach your site within a minute”, but the
hosting API returns a different message when published=false (inactive subscription) indicating
changes only go live on activation; the UI ignores published/message and misinforms owners editing
inactive tenants.
Code

apps/web/src/features/i18n/locales/en-US.json[R101-103]

+    "settings-save": "Save settings",
+    "settings-saved": "Saved. Changes reach your site within a minute.",
+    "settings-failed": "Could not save. Please try again.",
Relevance

●● Moderate

No strong precedent for using API-provided success messages over fixed i18n copy; UX/observability
is subjective.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The UI hardcodes a universal success message, but the hosting API’s PATCH handler explicitly returns
a different message when published is false: “Configuration saved. It goes live once the
subscription is active.” This mismatch is user-visible specifically in the new “edit while inactive”
flow introduced by this PR.

apps/web/src/features/hosting-signup/tenant-settings.tsx[180-191]
apps/web/src/features/i18n/locales/en-US.json[94-103]
apps/self-hosted/hosting/api/src/routes/tenants.ts[699-717]

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 editor shows a single success message (`hosting.settings-saved`: “Saved. Changes reach your site within a minute.”) regardless of tenant state. However, the hosting API’s PATCH response differentiates between `published=true` vs `published=false`, and explicitly returns a different message when the config is only stored (not live yet).
### Issue Context
This PR intentionally allows editing inactive tenants (persist now, publish on activation). The UI should reflect that reality or owners will think the change is immediately visible.
### How to fix
- Change `hostingApi.updateTenant` return type to include `published?: boolean` and `message?: string` (and optionally `discarded/reset` for future-proofing).
- In `TenantSettings.save()`, capture the response and:
- Prefer displaying `response.message` when present, OR
- Choose localized copy based on `response.published` (or `tenant.subscriptionStatus`).
- Add/adjust i18n strings for “saved but not live yet” vs “published soon”.
### Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-api.ts[174-178]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[110-120]
- apps/web/src/features/i18n/locales/en-US.json[95-103]

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


9. onChange uses any ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
TenantSettings uses (e: any) in input onChange handlers, introducing new any usage. This
weakens type safety and can hide runtime bugs in this new settings surface.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[136]

+        onChange={(e: any) => setTitle(e.target.value)}
Relevance

●● Moderate

Mixed precedent: some PRs accepted removing (e:any), others rejected the same change in similar
handlers.

PR-#1438
PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids introducing any in new/modified TypeScript code. The new
TenantSettings component uses (e: any) in onChange, which is an explicit any type.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/hosting-signup/tenant-settings.tsx[131-146]

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

## Issue description
`TenantSettings` introduces `any` in the `onChange` handlers (e.g., `(e: any)`), violating the requirement to avoid `any` in new TypeScript code.
## Issue Context
This is new UI logic for remotely editing tenant settings; keeping strong typing helps prevent subtle UI/input bugs.
## Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[131-147]

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


10. Feature files lack subdirs ✗ Dismissed 📜 Skill insight ⌂ Architecture
Description
New hosting-manage settings code is added as top-level feature files instead of being organized
under the standard components/, api/, hooks/, and types/ subdirectories. This makes feature
boundaries harder to maintain as the feature grows.
Code

apps/web/src/features/hosting-signup/hosting-token.ts[R1-4]

+import { getLoginType, ensureValidToken } from "@/utils/user-token";
+import { signBuffer } from "@/utils/keychain";
+import { hostingApi, type HostingAuthResult } from "./hosting-api";
+
Relevance

●● Moderate

No close precedent found; directory structure is architectural and often left to author discretion.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668151 requires new feature code to use the standard feature directory structure
(with subdirectories like components/, api/, hooks/, types/). This PR adds new feature
modules directly at the feature root (hosting-token.ts, tenant-settings.tsx).

apps/web/src/features/hosting-signup/hosting-token.ts[1-4]
apps/web/src/features/hosting-signup/tenant-settings.tsx[1-8]
Skill: add-feature: Skill: add-feature

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

## Issue description
New feature modules were added directly under `apps/web/src/features/hosting-signup/` rather than following the standard feature folder structure.
## Issue Context
The checklist requires feature code to be organized into the standard subdirectories to keep feature growth manageable.
## Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-token.ts[1-66]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[1-194]

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


11. Misleading inactive save message ✓ Resolved 🐞 Bug ◔ Observability
Description
After a successful save, the UI always shows “Changes reach your site within a minute”, but the
hosting API returns a different message when published=false (inactive subscription) indicating
changes only go live on activation; the UI ignores published/message and misinforms owners editing
inactive tenants.
Code

apps/web/src/features/i18n/locales/en-US.json[R101-103]

+    "settings-save": "Save settings",
+    "settings-saved": "Saved. Changes reach your site within a minute.",
+    "settings-failed": "Could not save. Please try again.",
Relevance

●● Moderate

No strong precedent for using API-provided success messages over fixed i18n copy; UX/observability
is subjective.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The UI hardcodes a universal success message, but the hosting API’s PATCH handler explicitly returns
a different message when published is false: “Configuration saved. It goes live once the
subscription is active.” This mismatch is user-visible specifically in the new “edit while inactive”
flow introduced by this PR.

apps/web/src/features/hosting-signup/tenant-settings.tsx[180-191]
apps/web/src/features/i18n/locales/en-US.json[94-103]
apps/self-hosted/hosting/api/src/routes/tenants.ts[699-717]

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 editor shows a single success message (`hosting.settings-saved`: “Saved. Changes reach your site within a minute.”) regardless of tenant state. However, the hosting API’s PATCH response differentiates between `published=true` vs `published=false`, and explicitly returns a different message when the config is only stored (not live yet).
### Issue Context
This PR intentionally allows editing inactive tenants (persist now, publish on activation). The UI should reflect that reality or owners will think the change is immediately visible.
### How to fix
- Change `hostingApi.updateTenant` return type to include `published?: boolean` and `message?: string` (and optionally `discarded/reset` for future-proofing).
- In `TenantSettings.save()`, capture the response and:
- Prefer displaying `response.message` when present, OR
- Choose localized copy based on `response.published` (or `tenant.subscriptionStatus`).
- Add/adjust i18n strings for “saved but not live yet” vs “published soon”.
### Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-api.ts[174-178]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[110-120]
- apps/web/src/features/i18n/locales/en-US.json[95-103]

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


12. onChange uses any ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
TenantSettings uses (e: any) in input onChange handlers, introducing new any usage. This
weakens type safety and can hide runtime bugs in this new settings surface.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[136]

+        onChange={(e: any) => setTitle(e.target.value)}
Relevance

●● Moderate

Mixed precedent: some PRs accepted removing (e:any), others rejected the same change in similar
handlers.

PR-#1438
PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids introducing any in new/modified TypeScript code. The new
TenantSettings component uses (e: any) in onChange, which is an explicit any type.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/hosting-signup/tenant-settings.tsx[131-146]

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

## Issue description
`TenantSettings` introduces `any` in the `onChange` handlers (e.g., `(e: any)`), violating the requirement to avoid `any` in new TypeScript code.
## Issue Context
This is new UI logic for remotely editing tenant settings; keeping strong typing helps prevent subtle UI/input bugs.
## Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[131-147]

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



Informational

13. vi.importActual in specs 📘 Rule violation ⚙ Maintainability
Description
New specs use vi.importActual(...), introducing explicit any into test code. This reduces
type-checking effectiveness and can mask incorrect mock shapes.
Code

apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[27]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
Relevance

● Weak

Close rejection precedent: team previously rejected removing vi.importActual / test any
usage.

PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in new/modified TypeScript files. Both newly
added spec files explicitly use any via vi.importActual(...).

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-28]
apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-18]

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 Vitest specs call `vi.importActual<any>(...)`, introducing explicit `any` types.
## Issue Context
These tests are part of the new hosting token/auth rail coverage; typing the `importActual` result avoids drifting mocks and improves refactor safety.
## Fix Focus Areas
- apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-36]
- apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-26]

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


14. vi.importActual in specs 📘 Rule violation ⚙ Maintainability
Description
New specs use vi.importActual(...), introducing explicit any into test code. This reduces
type-checking effectiveness and can mask incorrect mock shapes.
Code

apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[27]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
Relevance

● Weak

Close rejection precedent: team previously rejected removing vi.importActual / test any
usage.

PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in new/modified TypeScript files. Both newly
added spec files explicitly use any via vi.importActual(...).

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-28]
apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-18]

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 Vitest specs call `vi.importActual<any>(...)`, introducing explicit `any` types.
## Issue Context
These tests are part of the new hosting token/auth rail coverage; typing the `importActual` result avoids drifting mocks and improves refactor safety.
## Fix Focus Areas
- apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-36]
- apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-26]

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


15. vi.importActual in specs 📘 Rule violation ⚙ Maintainability
Description
New specs use vi.importActual(...), introducing explicit any into test code. This reduces
type-checking effectiveness and can mask incorrect mock shapes.
Code

apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[27]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
Relevance

● Weak

Close rejection precedent: team previously rejected removing vi.importActual / test any
usage.

PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in new/modified TypeScript files. Both newly
added spec files explicitly use any via vi.importActual(...).

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-28]
apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-18]

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 Vitest specs call `vi.importActual<any>(...)`, introducing explicit `any` types.
## Issue Context
These tests are part of the new hosting token/auth rail coverage; typing the `importActual` result avoids drifting mocks and improves refactor safety.
## Fix Focus Areas
- apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-36]
- apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-26]

ⓘ 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

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The hosting manage panel now edits tenant title, description, theme, and accent settings. It retrieves stored configuration, obtains cached authenticated hosting tokens, submits changed values, and reports publication status. Tests cover authentication, prefilling, editing, persistence, loading races, and failures.

Changes

Remote tenant settings

Layer / File(s) Summary
Hosting API contracts and operations
apps/web/src/features/hosting-signup/hosting-api.ts
The hosting API now retrieves tenant configuration, supports Hivesigner and Keychain authentication, and updates tenant configuration with authenticated PATCH requests.
Hosting token acquisition
apps/web/src/features/hosting-signup/hosting-token.ts, apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts
Hosting tokens are cached per account. Session-token exchange runs first, with Keychain challenge signing as fallback. Tests cover caching, fallback, and errors.
Tenant settings editor and persistence
apps/web/src/features/hosting-signup/tenant-settings.tsx, apps/web/src/features/i18n/locales/en-US.json, apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx
TenantSettings loads active tenant values, preserves edits during loading, validates accent colors, sends changed fields, and displays localized save states and errors.
Manage panel integration
apps/web/src/features/hosting-signup/hosting-manage.tsx
Each tenant now has an inline settings control. The open settings panel resets when the active account changes.

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

Sequence Diagram(s)

sequenceDiagram
  participant Owner
  participant TenantSettings
  participant obtainHostingToken
  participant hostingApi
  Owner->>TenantSettings: Edit tenant settings
  TenantSettings->>hostingApi: Retrieve stored configuration
  hostingApi-->>TenantSettings: Return configuration
  TenantSettings->>obtainHostingToken: Request owner token
  obtainHostingToken-->>TenantSettings: Return hosting token
  TenantSettings->>hostingApi: PATCH changed settings
  hostingApi-->>TenantSettings: Return publication status
  TenantSettings-->>Owner: Display save status
Loading

Possibly related PRs

Poem

A rabbit edits themes with care,
While tokens hop through hosting air.
Title, accent, dark or light,
PATCHes make the settings right.
If publishing waits, the status says so. 🐇

🚥 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 summarizes the main change: the hosting manage panel now provides remote settings management.
Linked Issues check ✅ Passed The changes satisfy issue #1423 by adding remote tenant editing, token authorization, inactive-tenant support, and related tests.
Out of Scope Changes check ✅ Passed All code and localization changes support the linked issue’s remote hosting settings and authorization objectives.
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/hosting-manage-remote-settings

Warning

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

🔧 ESLint

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

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

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

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

Copy link
Copy Markdown

PR Summary by Qodo

Hosting: edit tenant settings from /hosting manage panel

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add an inline tenant settings editor to the /hosting manage panel (all tenant statuses).
• Obtain and cache a hosting API token in-place (session-token exchange, Keychain fallback).
• Extend hosting API client for config prefill + authorized PATCH; add coverage and strings.
Diagram

graph TD
  M["HostingManage panel"] --> S["TenantSettings editor"]
  S -->|"prefill"| A["hostingApi client"] -->|"GET /v1/tenants/:u/config"| H{{"Hosting API"}}
  S -->|"save"| T("hosting-token") -->|"auth rails"| A -->|"PATCH /v1/tenants/:u"| H
  subgraph Legend
    direction LR
    _ui["UI component"] ~~~ _util("Utility") ~~~ _ext{{"External service"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Persist hosting token in storage (localStorage/cookie)
  • ➕ Survives reloads; fewer auth round-trips across sessions
  • ➕ Can improve UX for repeated edits across page loads
  • ➖ Bearer token persistence increases exposure window if XSS occurs
  • ➖ More careful invalidation/rotation logic required
2. Mint hosting token via an ecency backend proxy endpoint
  • ➕ Keeps hosting token off the browser; tighter security boundary
  • ➕ Centralizes auth logic and rate-limiting in one place
  • ➖ Requires server changes and deployment coordination
  • ➖ Adds backend dependency/latency; contradicts 'no server changes' goal
3. Keychain-only challenge flow (no session-token exchange)
  • ➕ Single consistent auth rail; fewer assumptions about session token availability
  • ➖ Worse UX for non-Keychain logins
  • ➖ More interactive; harder to batch multiple edits without caching anyway

Recommendation: Current approach is a good tradeoff: it delivers remote settings without server work by reusing existing Hosting API auth rails, and avoids long-lived token persistence by caching only in module memory with expiry slack. Consider storage persistence only if users frequently reload /hosting mid-session and re-auth becomes a pain point.

Files changed (7) +561 / -1

Enhancement (4) +335 / -1
hosting-api.tsAdd tenant config/auth endpoints and authorized PATCH helper +55/-1

Add tenant config/auth endpoints and authorized PATCH helper

• Introduces a generic PATCH helper that attaches a Bearer token. Adds client methods for fetching stored tenant config, exchanging session tokens for a hosting token (plus Keychain challenge/verify), and updating tenant config via flat-key PATCH, along with new result/config types.

apps/web/src/features/hosting-signup/hosting-api.ts

hosting-manage.tsxExpose per-tenant settings editor toggle in manage panel +20/-0

Expose per-tenant settings editor toggle in manage panel

• Adds local state to toggle a settings surface per tenant and renders the new TenantSettings component inline. Resets the editor state when switching active accounts to avoid cross-account leakage.

apps/web/src/features/hosting-signup/hosting-manage.tsx

hosting-token.tsImplement in-place hosting token acquisition with caching and fallback +66/-0

Implement in-place hosting token acquisition with caching and fallback

• Adds obtainHostingToken() that first attempts session-token exchange (refreshed via ensureValidToken) and falls back to a Keychain posting-key challenge/verify flow. Caches tokens per username with expiry slack and provides a test seam to reset cache.

apps/web/src/features/hosting-signup/hosting-token.ts

tenant-settings.tsxAdd remote tenant settings editor (prefill + changed-fields-only save) +194/-0

Add remote tenant settings editor (prefill + changed-fields-only save)

• Implements an inline editor for title, description, theme, and accent with optional prefill from the stored config for active tenants. Builds a PATCH payload containing only changed non-blank fields, blocks save on invalid accent input, and surfaces save errors/success to the user.

apps/web/src/features/hosting-signup/tenant-settings.tsx

Tests (2) +216 / -0
hosting-token.spec.tsTest hosting token exchange, caching, and Keychain fallback rails +95/-0

Test hosting token exchange, caching, and Keychain fallback rails

• Adds Vitest coverage ensuring session-token exchange is cached per account, Keychain challenge flow is used when exchange is unavailable, and exchange errors surface when no fallback rail exists.

apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts

tenant-settings.spec.tsxTest settings editor prefill, diffed payload, and error surfacing +121/-0

Test settings editor prefill, diffed payload, and error surfacing

• Adds React Testing Library specs verifying active-tenant prefill and changed-fields-only PATCH payloads, blind editing for inactive tenants (no prefill), and proper display of save failures without false success messaging.

apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx

Other (1) +10 / -0
en-US.jsonAdd i18n strings for manage-panel settings editor +10/-0

Add i18n strings for manage-panel settings editor

• Adds English strings for the new manage-panel settings UI (toggle text, hints, theme labels, save/success/failure messages).

apps/web/src/features/i18n/locales/en-US.json

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 865ced502f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +74 to +75
initialRef.current = next;
setTitle(next.title);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve edits made before prefill completes

For an active tenant on a slow config request, the form is editable immediately, so a user can begin typing before tenantConfig() resolves; these unconditional state updates then replace every in-progress edit with the fetched values. Disable editing until prefill finishes or apply each fetched value only while its field remains untouched.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed and fixed in 2101219: fetched values now seed only fields the owner has not started editing (functional setState, prev wins) and a prefill landing after a save began is dropped entirely, so neither race can discard edits or overwrite the post-save baseline. The change diff still compares against the fetched snapshot. A spec pins the typing-during-prefill case.

"theme-light": "Light",
"theme-dark": "Dark",
"settings-save": "Save settings",
"settings-saved": "Saved. Changes reach your site within a minute.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Report inactive saves as unpublished

When settings are saved for an inactive, expired, or suspended tenant, the PATCH only persists the configuration and does not publish it until the tenant becomes active, but this unconditional success message promises that the changes reach the site within a minute. Use the tenant status or the PATCH response's published field to show an activation-dependent message for these saves.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed and fixed in 2101219: saves for a tenant that is not active show a status-dependent message saying the changes publish when the site activates, instead of promising a live site. Spec asserts the pending message on the inactive path.

@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Prefill overwrites user edits ✓ Resolved 🐞 Bug ≡ Correctness
Description
TenantSettings applies the async tenantConfig() prefill unconditionally, so a late response can
overwrite user-typed values (or even a just-saved state) and lead to lost edits / incorrect
subsequent PATCH payloads.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[R56-60]

+  useEffect(() => {
+    if (tenant.subscriptionStatus !== "active") return;
+    let cancelled = false;
+    hostingApi
+      .tenantConfig(tenant.username)
Relevance

●●● Strong

Team previously accepted guards to prevent late async prefills overwriting user interaction state.

PR-#1022

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The prefill effect updates all form state when the fetch resolves, with no guard for whether the
user has already interacted; the only protection is an unmount-only cancelled flag. This matches a
previously accepted bug pattern where late async data overwrote user interaction state.

apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]
PR-#1022

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

### Issue description
`TenantSettings` triggers an async prefill (`hostingApi.tenantConfig`) and then unconditionally calls `setTitle/setDescription/setTheme/setAccent/setAccentInput` when it resolves. If the user starts editing before the request returns (or saves while it’s still in flight), the late response can clobber their edits and/or reset the "initial" baseline used to compute subsequent changes.

### Issue Context
This is a classic async-response race: the request is tied only to component mount and unmount (`cancelled`), not to whether the form is still pristine.

### How to fix
- Track a `dirtyRef` / `touchedRef` that flips to true on any user interaction (title/desc/theme/accent changes).
- Apply the prefill only if the form is still pristine (e.g., `if (dirtyRef.current) return;`).
- Optionally: use an `AbortController` or request-id approach to ensure only the latest request applies.
- Also consider preventing prefill from running (or applying) while `busy` is true.

### Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[56-80]

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



Remediation recommended

2. Feature files lack subdirs ✗ Dismissed 📜 Skill insight ⌂ Architecture
Description
New hosting-manage settings code is added as top-level feature files instead of being organized
under the standard components/, api/, hooks/, and types/ subdirectories. This makes feature
boundaries harder to maintain as the feature grows.
Code

apps/web/src/features/hosting-signup/hosting-token.ts[R1-4]

+import { getLoginType, ensureValidToken } from "@/utils/user-token";
+import { signBuffer } from "@/utils/keychain";
+import { hostingApi, type HostingAuthResult } from "./hosting-api";
+
Relevance

●● Moderate

No close precedent found; directory structure is architectural and often left to author discretion.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668151 requires new feature code to use the standard feature directory structure
(with subdirectories like components/, api/, hooks/, types/). This PR adds new feature
modules directly at the feature root (hosting-token.ts, tenant-settings.tsx).

apps/web/src/features/hosting-signup/hosting-token.ts[1-4]
apps/web/src/features/hosting-signup/tenant-settings.tsx[1-8]
Skill: add-feature

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

## Issue description
New feature modules were added directly under `apps/web/src/features/hosting-signup/` rather than following the standard feature folder structure.

## Issue Context
The checklist requires feature code to be organized into the standard subdirectories to keep feature growth manageable.

## Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-token.ts[1-66]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[1-194]

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


3. Misleading inactive save message ✓ Resolved 🐞 Bug ◔ Observability
Description
After a successful save, the UI always shows “Changes reach your site within a minute”, but the
hosting API returns a different message when published=false (inactive subscription) indicating
changes only go live on activation; the UI ignores published/message and misinforms owners editing
inactive tenants.
Code

apps/web/src/features/i18n/locales/en-US.json[R101-103]

+    "settings-save": "Save settings",
+    "settings-saved": "Saved. Changes reach your site within a minute.",
+    "settings-failed": "Could not save. Please try again.",
Relevance

●● Moderate

No strong precedent for using API-provided success messages over fixed i18n copy; UX/observability
is subjective.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The UI hardcodes a universal success message, but the hosting API’s PATCH handler explicitly returns
a different message when published is false: “Configuration saved. It goes live once the
subscription is active.” This mismatch is user-visible specifically in the new “edit while inactive”
flow introduced by this PR.

apps/web/src/features/hosting-signup/tenant-settings.tsx[180-191]
apps/web/src/features/i18n/locales/en-US.json[94-103]
apps/self-hosted/hosting/api/src/routes/tenants.ts[699-717]

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 editor shows a single success message (`hosting.settings-saved`: “Saved. Changes reach your site within a minute.”) regardless of tenant state. However, the hosting API’s PATCH response differentiates between `published=true` vs `published=false`, and explicitly returns a different message when the config is only stored (not live yet).

### Issue Context
This PR intentionally allows editing inactive tenants (persist now, publish on activation). The UI should reflect that reality or owners will think the change is immediately visible.

### How to fix
- Change `hostingApi.updateTenant` return type to include `published?: boolean` and `message?: string` (and optionally `discarded/reset` for future-proofing).
- In `TenantSettings.save()`, capture the response and:
 - Prefer displaying `response.message` when present, OR
 - Choose localized copy based on `response.published` (or `tenant.subscriptionStatus`).
- Add/adjust i18n strings for “saved but not live yet” vs “published soon”.

### Fix Focus Areas
- apps/web/src/features/hosting-signup/hosting-api.ts[174-178]
- apps/web/src/features/hosting-signup/tenant-settings.tsx[110-120]
- apps/web/src/features/i18n/locales/en-US.json[95-103]

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


4. onChange uses any ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
TenantSettings uses (e: any) in input onChange handlers, introducing new any usage. This
weakens type safety and can hide runtime bugs in this new settings surface.
Code

apps/web/src/features/hosting-signup/tenant-settings.tsx[136]

+        onChange={(e: any) => setTitle(e.target.value)}
Relevance

●● Moderate

Mixed precedent: some PRs accepted removing (e:any), others rejected the same change in similar
handlers.

PR-#1438
PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids introducing any in new/modified TypeScript code. The new
TenantSettings component uses (e: any) in onChange, which is an explicit any type.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/hosting-signup/tenant-settings.tsx[131-146]

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

## Issue description
`TenantSettings` introduces `any` in the `onChange` handlers (e.g., `(e: any)`), violating the requirement to avoid `any` in new TypeScript code.

## Issue Context
This is new UI logic for remotely editing tenant settings; keeping strong typing helps prevent subtle UI/input bugs.

## Fix Focus Areas
- apps/web/src/features/hosting-signup/tenant-settings.tsx[131-147]

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



Informational

5. vi.importActual<any> in specs 📘 Rule violation ⚙ Maintainability
Description
New specs use vi.importActual<any>(...), introducing explicit any into test code. This reduces
type-checking effectiveness and can mask incorrect mock shapes.
Code

apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[27]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
Relevance

● Weak

Close rejection precedent: team previously rejected removing vi.importActual<any> / test any
usage.

PR-#1456

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in new/modified TypeScript files. Both newly
added spec files explicitly use any via vi.importActual<any>(...).

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-28]
apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-18]

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 Vitest specs call `vi.importActual<any>(...)`, introducing explicit `any` types.

## Issue Context
These tests are part of the new hosting token/auth rail coverage; typing the `importActual` result avoids drifting mocks and improves refactor safety.

## Fix Focus Areas
- apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts[26-36]
- apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx[16-26]

ⓘ 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
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 11/18, lines 562/200; both must reach the floor). Router rationale: This is a security-sensitive remote settings flow with token exchange and Keychain fallback, plus substantial new editor/API logic across several independent paths where multiple subtle defects could be missed in one pass.

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/web/src/features/hosting-signup/tenant-settings.tsx Outdated
Comment thread apps/web/src/features/hosting-signup/hosting-token.ts
Comment thread apps/web/src/features/hosting-signup/tenant-settings.tsx
Comment thread apps/web/src/features/i18n/locales/en-US.json
feruzm added 2 commits August 12, 2026 16:52
Fetched values now seed only fields the owner has not started editing and
a prefill landing after a save is dropped entirely, so neither race can
discard edits or re-flag saved fields. Saves for a tenant that is not yet
active say the changes publish on activation instead of promising a live
site, and the new input handlers carry real event types.
… status

The PATCH answers with an authoritative published flag; the manage list's
subscription status can go stale between fetching the panel and saving, so
the success copy now keys on the response, falling back to the status only
for an older API that omits the flag.
@feruzm
feruzm merged commit bc1c343 into develop Aug 12, 2026
7 of 8 checks passed
@feruzm
feruzm deleted the feature/hosting-manage-remote-settings branch August 12, 2026 17:01

@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

🤖 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/web/src/features/hosting-signup/hosting-token.ts`:
- Around line 59-65: Update the authentication helper around the signature and
session-token failure paths to throw stable, non-user-facing error codes instead
of the literal messages “Signature refused” and “No session token available”. In
TenantSettings, detect those codes and resolve the displayed messages through
i18next using entries added to en-US.json, while preserving existing
exchange-error handling.

In `@apps/web/src/features/hosting-signup/tenant-settings.tsx`:
- Around line 145-161: Associate the title and description labels with their
corresponding FormControl inputs by adding stable, unique id values and matching
htmlFor attributes. Update the relevant specs to locate both fields by role and
accessible name, using the label text rather than implementation-specific
selectors.
🪄 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: 2fc9a2a2-13cd-42a6-ba4c-9cff8a934c01

📥 Commits

Reviewing files that changed from the base of the PR and between 5dde702 and 343120e.

📒 Files selected for processing (7)
  • apps/web/src/features/hosting-signup/hosting-api.ts
  • apps/web/src/features/hosting-signup/hosting-manage.tsx
  • apps/web/src/features/hosting-signup/hosting-token.ts
  • apps/web/src/features/hosting-signup/tenant-settings.tsx
  • apps/web/src/features/i18n/locales/en-US.json
  • apps/web/src/specs/features/hosting-signup/hosting-token.spec.ts
  • apps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx

Comment on lines +59 to +65
if (!signed.success || !signed.result) {
throw new Error(signed.message || "Signature refused");
}
return remember(await hostingApi.authVerify(username, signed.result, challenge));
}

throw exchangeError ?? new Error("No session token available");

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localize fallback authentication errors.

TenantSettings renders these error messages to the owner. "Signature refused" and "No session token available" bypass en-US.json and i18next.

Return stable error codes from this helper. Map those codes to localized messages in the UI.

As per coding guidelines, “All new user-facing strings must be added to en-US.json and accessed through i18next.”

🤖 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/web/src/features/hosting-signup/hosting-token.ts` around lines 59 - 65,
Update the authentication helper around the signature and session-token failure
paths to throw stable, non-user-facing error codes instead of the literal
messages “Signature refused” and “No session token available”. In
TenantSettings, detect those codes and resolve the displayed messages through
i18next using entries added to en-US.json, while preserving existing
exchange-error handling.

Source: Coding guidelines

Comment on lines +145 to +161
<label className="text-sm font-semibold">{i18next.t("hosting.blog-title-label")}</label>
<FormControl
type="text"
value={title}
maxLength={100}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setTitle(e.target.value)}
placeholder={i18next.t("hosting.settings-keep")}
/>

<label className="text-sm font-semibold">{i18next.t("hosting.blog-desc-label")}</label>
<FormControl
type="text"
value={description}
maxLength={500}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setDescription(e.target.value)}
placeholder={i18next.t("hosting.settings-keep")}
/>

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Associate each text input with its label.

Line 145 and Line 154 render standalone <label> elements. The FormControl elements have no matching id. Screen readers cannot determine whether each input edits the title or description.

Add stable id values to both inputs and matching htmlFor values to both labels. Update the specs to select these fields by role and accessible name.

🤖 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/web/src/features/hosting-signup/tenant-settings.tsx` around lines 145 -
161, Associate the title and description labels with their corresponding
FormControl inputs by adding stable, unique id values and matching htmlFor
attributes. Update the relevant specs to locate both fields by role and
accessible name, using the label text rather than implementation-specific
selectors.

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.

Hosting: make the manage panel a remote settings surface

1 participant