Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@steven-tey
Copy link
Collaborator

@steven-tey steven-tey commented Sep 2, 2025

Summary by CodeRabbit

  • New Features

    • Added Deep View configuration for domains (Advanced Options). Deep View is validated, saved with the domain, and treated as a Pro feature (Free users prompted to upgrade). Deep View data is persisted and backfilled for existing domains.
  • Style

    • Revamped Add/Edit Domain form: toggleable advanced options, JSON helpers/textarea for Deep View, Enter-to-submit, and a sticky bottom action bar.
    • Modal header is now sticky for improved scrolling usability.
  • Tests

    • Domain tests updated to include Deep View in responses.
  • Messaging

    • Pro-features list updated (Asset Links capitalization; Deep View added).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Warning

Rate limit exceeded

@steven-tey has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 47 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 51405d7 and 774ee50.

📒 Files selected for processing (1)
  • apps/web/ui/domains/add-edit-domain-form.tsx (11 hunks)

Walkthrough

Adds a nullable JSON deepviewData field across DB, schemas, APIs, UI, deeplink validation, tests, and a backfill script; wires deepviewData through create/patch flows with pro-plan gating and converts multiple JSON-null write sites to use Prisma.DbNull/AnyNull.

Changes

Cohort / File(s) Summary
Domain API: create/patch
apps/web/app/api/domains/route.ts, apps/web/app/api/domains/[domain]/route.ts
Add deepviewData to request schemas/parsing, include it in create/patch payloads (JSON.parse or Prisma.DbNull when null), update pro-feature gating/message to include “Deep View” and capitalize “Asset Links”.
Zod schemas & deep-link validation
apps/web/lib/zod/schemas/domains.ts, apps/web/lib/zod/schemas/deep-links.ts
Add createDomainBodySchemaExtended with deepviewData: z.string().nullish() and introduce deepViewDataSchema (nullable object with ios/android).
Domain typing & transform
apps/web/lib/types.ts, apps/web/lib/api/domains/transform-domain.ts
Add deepviewData?: string to DomainProps; extend DomainSchema parse and serialize deepviewData as JSON string or null.
Deeplink page
apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[key]/page.tsx
Load and validate shortDomain.deepviewData with deepViewDataSchema; require it (in addition to AASA) for redirect/preview flow.
UI: Domain form & modal
apps/web/ui/domains/add-edit-domain-form.tsx, apps/web/ui/modals/add-edit-domain-modal.tsx
Add Deep View advanced option (JSON textarea + paste formatting), wire deepviewData into form defaults/submission, add enter-submit and sticky action bar, remove className prop from AddEditDomainForm, make modal header sticky.
Database & migration
packages/prisma/schema/domain.prisma, apps/web/scripts/migrations/backfill-deepview.ts
Add deepviewData Json? @default("{}") to Domain model and new script to backfill null deepviewData to {} for existing rows.
Prisma null-handling changes
apps/web/app/(ee)/api/bounties/[bountyId]/route.ts, apps/web/lib/actions/partners/create-reward.ts, apps/web/lib/actions/partners/update-program.ts, apps/web/lib/actions/partners/update-reward.ts, apps/web/lib/api/links/bulk-create-links.ts, apps/web/lib/api/links/bulk-update-links.ts, apps/web/lib/api/links/create-link.ts, apps/web/lib/api/links/update-link.ts, apps/web/app/sitemap.ts
Replace uses/checks of Prisma.JsonNull (or not: Prisma.JsonNull) with Prisma.DbNull or Prisma.AnyNull so provided null persists as DB NULL or filters exclude both JSON/DB nulls.
Data fetching gating
apps/web/lib/swr/use-payouts-count.ts, apps/web/ui/layout/sidebar/app-sidebar-nav.tsx
Add enabled option to usePayoutsCount and gate the sidebar fetch based on area + program id.
Tests
apps/web/tests/domains/index.test.ts
Update expected domain fixture to include deepviewData: "{}".

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant API as Domains API
  participant Auth as Plan Checker
  participant DB as Prisma/DB

  Client->>API: POST/PATCH /domains { deepviewData, ... }
  API->>Auth: Check plan & pro-feature fields (incl. deepviewData)
  alt Free plan with pro fields
    Auth-->>API: Block
    API-->>Client: 403 + pro-features message (includes "Deep View")
  else Allowed
    API->>API: parse assetLinks / appleAppSiteAssociation / deepviewData
    API->>DB: Create/Update Domain (persist deepviewData or Prisma.DbNull)
    DB-->>API: OK
    API-->>Client: 200 with domain payload
  end
Loading
sequenceDiagram
  autonumber
  participant Page as Deeplink Page
  participant Fetch as Load shortDomain
  participant Validate as deepViewDataSchema
  participant Router as Redirect Logic

  Page->>Fetch: Get domain data (AASA, deepviewData)
  Fetch-->>Page: shortDomain
  Page->>Validate: Parse shortDomain.deepviewData
  alt Missing/invalid deepviewData or AASA
    Page-->>Router: Prevent redirect / show fallback
  else Valid
    Page-->>Router: Proceed with deeplink redirect
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • devkiran

Poem

I nibble bytes and tidy schemes,
Deep View nested in JSON dreams.
Domains now whisper mobile cues,
Pro gates guard those richer views.
Hop, commit — the rabbit cheers. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch deepview

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link
Contributor

vercel bot commented Sep 2, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Sep 2, 2025 4:31am

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (2)
apps/web/scripts/migrations/backfill-deepview.ts (1)

1-26: Simplify and harden backfill script

  • Replace the two-step findMany + updateMany with a single updateMany({ where: { deepviewData: { equals: Prisma.AnyNull } }, data: { deepviewData: {} } })
  • Wrap in try/finally and call await prisma.$disconnect() to close the client and prevent hanging
 import { prisma } from "@dub/prisma";
 import { Prisma } from "@prisma/client";
 import "dotenv-flow/config";
 
 async function main() {
-  const domains = await prisma.domain.findMany({
-    where: {
-      deepviewData: {
-        equals: Prisma.AnyNull,
-      },
-    },
-    take: 1000,
-  });
-
-  const deepviewData = await prisma.domain.updateMany({
-    where: {
-      id: { in: domains.map((domain) => domain.id) },
-    },
-    data: { deepviewData: {} },
-  });
-
-  console.log(deepviewData);
+  try {
+    const res = await prisma.domain.updateMany({
+      where: { deepviewData: { equals: Prisma.AnyNull } },
+      data: { deepviewData: {} },
+    });
+    console.log(res);
+  } finally {
+    await prisma.$disconnect();
+  }
 }
 
 main();
apps/web/ui/domains/add-edit-domain-form.tsx (1)

147-156: Ensure Advanced settings auto-expand when only Deep View is present.

When props.deepviewData exists (but neither AASA nor assetLinks), the Advanced section stays collapsed.

Apply:

 useEffect(() => {
-  if (props?.appleAppSiteAssociation || props?.assetLinks) {
+  if (
+    props?.appleAppSiteAssociation ||
+    props?.assetLinks ||
+    props?.deepviewData
+  ) {
     setShowAdvancedOptions(true);
     setShowOptionStates((prev) => ({
       ...prev,
       appleAppSiteAssociation: !!props?.appleAppSiteAssociation?.trim(),
       assetLinks: !!props?.assetLinks?.trim(),
     }));
   }
 
-  if (props?.deepviewData) {
+  if (props?.deepviewData) {
     setShowOptionStates((prev) => ({
       ...prev,
       deepviewData: !!props?.deepviewData?.trim(),
     }));
   }
 }, [props]);

Also applies to: 157-162

🧹 Nitpick comments (11)
apps/web/lib/types.ts (1)

247-247: Align DomainProps.deepviewData type with API/DB usage

Upstream schemas use .nullish() and the DB stores JSON. To avoid TS/runtime mismatches when null is returned, make this string | null (still serialized JSON on the client).

-  deepviewData?: string;
+  deepviewData?: string | null;
packages/prisma/schema/domain.prisma (1)

14-15: Default {} on optional JSON can conflict with caller expectations

New rows won’t be null, while older rows are backfilled. If callers (e.g., UI/schema) expect “missing” to be falsy, consider either removing the default or ensuring all reads use a safe validator instead of .parse(). At minimum, document this semantic difference from appleAppSiteAssociation/assetLinks.

apps/web/lib/api/domains/transform-domain.ts (1)

19-21: Avoid returning "{}" for unset Deep View config

If deepviewData defaults to {}, this will serialize to "{}" and look “configured” to clients. Align with assetLinks/appleAppSiteAssociation by treating empty objects as null.

Apply:

-    deepviewData: domain.deepviewData
-      ? JSON.stringify(domain.deepviewData)
-      : null,
+    deepviewData:
+      domain.deepviewData &&
+      typeof domain.deepviewData === "object" &&
+      Object.keys(domain.deepviewData as Record<string, unknown>).length > 0
+        ? JSON.stringify(domain.deepviewData)
+        : null,

Confirm whether the intended default is “unset” (null) vs “empty config” ({}). If the latter, keep as-is and ensure downstream UI handles "{}" gracefully.

apps/web/lib/zod/schemas/deep-links.ts (1)

3-8: Tighten schema: replace z.any() with safer types

z.any() defeats validation. Prefer permissive-but-safe shapes or unknown with passthrough.

Apply:

 export const deepViewDataSchema = z
   .object({
-    ios: z.any(),
-    android: z.any(),
+    // If exact shapes are not finalized, accept arbitrary key/values safely.
+    ios: z.record(z.string(), z.unknown()).optional(),
+    android: z.record(z.string(), z.unknown()).optional(),
   })
   .nullish();

Optionally, refine to require at least one platform:

.refine((v) => !v || v.ios || v.android, { message: "Provide iOS or Android config" })

Does the deep link page parse JSON and validate with this schema after JSON.parse? If not, add parsing before validation to avoid validating raw strings.

apps/web/ui/modals/add-edit-domain-modal.tsx (2)

33-35: Restore semantic heading inside sticky header

Use an h2 for accessibility while preserving the sticky container.

Apply:

-      <div className="sticky top-0 z-10 border-b border-neutral-200 bg-white px-4 py-4 text-lg font-medium sm:px-6">
-        {props ? "Update" : "Add"} Domain
-      </div>
+      <div className="sticky top-0 z-10 border-b border-neutral-200 bg-white px-4 py-4 sm:px-6">
+        <h2 className="text-lg font-medium">
+          {props ? "Update" : "Add"} Domain
+        </h2>
+      </div>

36-44: Ensure modal body remains scrollable on small viewports

Removing the previous overflow-auto container can trap content beyond viewport height. Add vertical scrolling to the body wrapper.

Apply:

-      <div className="bg-neutral-50">
+      <div className="bg-neutral-50 overflow-y-auto">
         <AddEditDomainForm

Manually test on a 320×568 viewport with long forms to confirm the sticky header + body scroll behave correctly.

apps/web/app/api/domains/route.ts (1)

100-101: Consider bounding deepviewData size at schema level

To prevent oversized payloads, enforce a reasonable byte/length limit in createDomainBodySchema (via parseJsonSchema or z.string().max(N)) before parsing.

Confirm whether parseJsonSchema already enforces size; if not, add a max (e.g., 50KB) and mirror in updateDomainBodySchema.

apps/web/lib/zod/schemas/domains.ts (1)

75-78: Optional: align null handling and examples.

Consider .nullable().default(null) for consistency with assetLinks/appleAppSiteAssociation, and add an OpenAPI example clarifying this is a JSON string in responses (while API accepts JSON object on input).

apps/web/ui/domains/add-edit-domain-form.tsx (3)

165-177: No-op effect due to double-spread; simplify initialization.

{ ...prev, x:false, ...prev } restores prior values, making the effect inert.

Apply:

 useEffect(() => {
-  setShowOptionStates((prev) => ({
-    ...prev,
-    appleAppSiteAssociation: false,
-    assetLinks: false,
-    logo: false,
-    expiredUrl: false,
-    notFoundUrl: false,
-    placeholder: false,
-    deepviewData: false,
-    ...prev,
-  }));
+  setShowOptionStates((prev) => ({
+    appleAppSiteAssociation: prev.appleAppSiteAssociation ?? false,
+    assetLinks: prev.assetLinks ?? false,
+    logo: prev.logo ?? false,
+    expiredUrl: prev.expiredUrl ?? false,
+    notFoundUrl: prev.notFoundUrl ?? false,
+    placeholder: prev.placeholder ?? false,
+    deepviewData: prev.deepviewData ?? false,
+  }));
 }, []);

219-221: Enter-to-submit can hijack newlines in JSON textareas—gate on Cmd/Ctrl+Enter.

Prevent accidental submits while editing JSON.

Apply:

-const { handleKeyDown } = useEnterSubmit(formRef);
+const { handleKeyDown } = useEnterSubmit(formRef);

And for the textarea:

-  onKeyDown={handleKeyDown}
+  onKeyDown={(e) => {
+    if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
+      handleKeyDown(e);
+    }
+  }}

Also applies to: 553-554


288-296: Wire label to input for a11y.

label htmlFor="domain" doesn't target the input (no id). Add an id.

Apply:

-<label htmlFor="domain" className="flex items-center gap-x-2">
+<label htmlFor="domain" className="flex items-center gap-x-2">
   ...
-  <input
+  <input
+    id="domain"
     {...register("slug", {
       onChange: (e) => {
         setDomainStatus("idle");
         debouncedValidateDomain(e.target.value);
       },
     })}

Also applies to: 331-341

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b804622 and 93d9830.

📒 Files selected for processing (12)
  • apps/web/app/api/domains/[domain]/route.ts (3 hunks)
  • apps/web/app/api/domains/route.ts (3 hunks)
  • apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[key]/page.tsx (3 hunks)
  • apps/web/lib/api/domains/transform-domain.ts (1 hunks)
  • apps/web/lib/types.ts (1 hunks)
  • apps/web/lib/zod/schemas/deep-links.ts (1 hunks)
  • apps/web/lib/zod/schemas/domains.ts (4 hunks)
  • apps/web/lib/zod/schemas/utils.ts (2 hunks)
  • apps/web/scripts/migrations/backfill-deepview.ts (1 hunks)
  • apps/web/ui/domains/add-edit-domain-form.tsx (9 hunks)
  • apps/web/ui/modals/add-edit-domain-modal.tsx (1 hunks)
  • packages/prisma/schema/domain.prisma (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
apps/web/scripts/migrations/backfill-deepview.ts (1)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[key]/page.tsx (1)
apps/web/lib/zod/schemas/deep-links.ts (1)
  • deepViewDataSchema (3-8)
apps/web/lib/zod/schemas/domains.ts (1)
apps/web/lib/zod/schemas/utils.ts (1)
  • parseJsonSchema (37-50)
apps/web/ui/domains/add-edit-domain-form.tsx (2)
packages/ui/src/tooltip.tsx (2)
  • InfoTooltip (193-199)
  • SimpleTooltipContent (130-158)
packages/ui/src/shimmer-dots.tsx (1)
  • ShimmerDots (52-188)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Vade Review
  • GitHub Check: build
🔇 Additional comments (10)
apps/web/lib/zod/schemas/utils.ts (1)

3-3: Import OK

ZodIssueCode is fine to keep if we add a validator using superRefine (see next comment).

apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[key]/page.tsx (3)

1-1: Import OK


33-34: Selecting deepviewData is correct


44-49: Use safeParse instead of parse and confirm schema strictness

  • Replace deepViewDataSchema.parse(...) with deepViewDataSchema.safeParse(...).success to avoid runtime errors when link.shortDomain.deepviewData is {} or invalid.
-  const deepViewData = deepViewDataSchema.parse(link.shortDomain.deepviewData);
-  // if the link domain doesn't have an AASA file configured (or deepviewData is null)
-  if (!link.shortDomain.appleAppSiteAssociation || !deepViewData) {
+  const hasDeepViewData = deepViewDataSchema.safeParse(
+    link.shortDomain.deepviewData,
+  ).success;
+  // if the link domain doesn't have an AASA file configured (or deepviewData is missing/invalid)
+  if (!link.shortDomain.appleAppSiteAssociation || !hasDeepViewData) {
     redirect(link.ios ?? link.url);
   }
  • deepViewDataSchema currently requires both ios and android. Should we relax the schema (e.g., make keys optional or partial) or change the runtime check to allow either platform?
apps/web/app/api/domains/[domain]/route.ts (1)

69-93: Pro-feature gating additions look correct

Including Deep View in free-plan gating and message composition reads well and matches the new field.

apps/web/app/api/domains/route.ts (1)

186-188: Create path correctly persists deepviewData

Conditional spread with JSON.parse only when provided is correct and avoids unintended defaults.

apps/web/lib/zod/schemas/domains.ts (2)

60-60: LGTM: domain logo field addition.

Shape and nullability align with usage on the UI.


8-8: Imports look good.

parseUrlSchemaAllowEmpty and parseJsonSchema usage is appropriate after the fix above.

apps/web/ui/domains/add-edit-domain-form.tsx (2)

141-144: LGTM: default deepviewData wiring.

Pre-populating with pretty-printed JSON mirrors existing behavior for AASA/assetLinks.


240-242: LGTM: deepviewData submission path.

Sanitization mirrors existing fields; empty strings are omitted.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
apps/web/tests/domains/index.test.ts (1)

32-32: Make JSON assertion resilient

In apps/web/tests/domains/index.test.ts:32, avoid brittle string equality for JSON serialization:

-  deepviewData: "{}",
+  deepviewData: expect.stringMatching(/^\{\}$/),

Optional: the codebase currently uses both deepviewData and deepViewData variants—consider unifying casing for consistency.

apps/web/ui/layout/sidebar/app-sidebar-nav.tsx (1)

462-478: Deduplicate the enabled condition into a single const.

You repeat the same Boolean for three hooks; hoisting reduces drift risk and improves readability.

   const { payoutsCount: pendingPayoutsCount } = usePayoutsCount<
     number | undefined
   >({
     eligibility: "eligible",
     status: "pending",
-    enabled: Boolean(currentArea === "program" && defaultProgramId),
+    enabled: programEnabled,
   });

-  const applicationsCount = useProgramApplicationsCount({
-    enabled: Boolean(currentArea === "program" && defaultProgramId),
-  });
+  const applicationsCount = useProgramApplicationsCount({
+    enabled: programEnabled,
+  });

   const { submissionsCount } = useBountySubmissionsCount<
     SubmissionsCountByStatus[]
   >({
-    enabled: Boolean(currentArea === "program" && defaultProgramId),
+    enabled: programEnabled,
   });

And define once:

   }, [slug, pathname]);
 
+  const programEnabled = currentArea === "program" && Boolean(defaultProgramId);
apps/web/lib/swr/use-payouts-count.ts (1)

10-13: Avoid leaking enabled into the query and fix loading when disabled.

  • enabled currently lives in opts which is spread into getQueryString; depending on its behavior, this can add ?enabled=true to the URL. Strip it out explicitly.
  • When disabled, loading should be false to avoid spinner flicker.
-export default function usePayoutsCount<T>(
-  opts: z.input<typeof payoutsCountQuerySchema> & { enabled?: boolean } = {
-    enabled: true,
-  },
-) {
+type UsePayoutsCountOpts = z.input<typeof payoutsCountQuerySchema> & {
+  enabled?: boolean;
+};
+
+export default function usePayoutsCount<T>(
+  opts: UsePayoutsCountOpts = { enabled: true },
+) {
   const { id: workspaceId, defaultProgramId } = useWorkspace();
   const { getQueryString } = useRouterStuff();
 
-  const { data: payoutsCount, error } = useSWR<PayoutsCount[]>(
+  const { enabled = true, ...query } = opts || {};
+
+  const { data: payoutsCount, error } = useSWR<PayoutsCount[]>(
     workspaceId &&
       defaultProgramId &&
-      opts.enabled &&
+      enabled &&
       `/api/programs/${defaultProgramId}/payouts/count${getQueryString(
-        {
-          ...opts,
-          workspaceId,
-        },
-        {
-          include: ["status", "partnerId"],
-        },
+        { ...query, workspaceId },
+        { include: ["status", "partnerId"] },
       )}`,
     fetcher,
   );
 
   return {
     payoutsCount: payoutsCount as T,
     error,
-    loading: payoutsCount === undefined && !error,
+    loading: enabled ? payoutsCount === undefined && !error : false,
   };
 }

Also applies to: 20-21, 33-37

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 93d9830 and 06ce625.

📒 Files selected for processing (5)
  • apps/web/app/api/domains/[domain]/route.ts (3 hunks)
  • apps/web/lib/swr/use-payouts-count.ts (1 hunks)
  • apps/web/lib/zod/schemas/domains.ts (3 hunks)
  • apps/web/tests/domains/index.test.ts (1 hunks)
  • apps/web/ui/layout/sidebar/app-sidebar-nav.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/app/api/domains/[domain]/route.ts
  • apps/web/lib/zod/schemas/domains.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/web/lib/swr/use-payouts-count.ts (3)
apps/web/lib/zod/schemas/payouts.ts (1)
  • payoutsCountQuerySchema (38-51)
apps/web/lib/swr/use-workspace.ts (1)
  • useWorkspace (6-45)
apps/web/lib/types.ts (1)
  • PayoutsCount (445-449)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Vade Review
  • GitHub Check: build
🔇 Additional comments (2)
apps/web/ui/layout/sidebar/app-sidebar-nav.tsx (1)

462-468: Gating payouts fetch behind program context — solid.

This prevents unnecessary requests (and potential 404s) when not in Program or without a defaultProgramId. Matches the pattern used for applications and bounty submissions.

apps/web/lib/swr/use-payouts-count.ts (1)

20-21: Enabled-gated SWR key — good addition.

Using opts.enabled to short-circuit the key is the right approach to stop the fetch cleanly.

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (2)
apps/web/lib/api/links/update-link.ts (1)

207-210: Schedule A/B completion based on persisted values, not input.

If the client omits testVariants, this check skips scheduling even when variants already exist. Use the updated response to reflect DB state.

-      changedTestCompletedAt &&
-        testVariants &&
-        testCompletedAt &&
-        scheduleABTestCompletion(response),
+      changedTestCompletedAt &&
+        response.testVariants &&
+        response.testCompletedAt &&
+        scheduleABTestCompletion(response),
apps/web/ui/domains/add-edit-domain-form.tsx (1)

222-243: Preflight-validate JSON fields client-side to avoid 500s.

Validate appleAppSiteAssociation/assetLinks/deepviewData before sending; show inline errors if invalid.

Apply:

   const onSubmit = async (formData: FormData) => {
     try {
+      // Client-side JSON validation for advanced fields
+      const jsonFields = [
+        "appleAppSiteAssociation",
+        "assetLinks",
+        "deepviewData",
+      ] as const;
+      const invalid: string[] = [];
+      for (const f of jsonFields) {
+        const v = formData[f];
+        if (typeof v === "string" && v.trim()) {
+          try {
+            JSON.parse(v);
+          } catch {
+            invalid.push(f);
+            setError(f as any, { type: "validate", message: "Invalid JSON" });
+          }
+        }
+      }
+      if (invalid.length) {
+        toast.error(`Fix invalid JSON in: ${invalid.join(", ")}`);
+        return;
+      }
+
       const res = await fetch(endpoint.url, {
         method: endpoint.method,
         headers: {
           "Content-Type": "application/json",
         },
         body: JSON.stringify({
♻️ Duplicate comments (2)
apps/web/lib/zod/schemas/domains.ts (1)

166-168: Validate deepviewData is JSON (or accept parsed object).

Right now any string passes; add JSON validation to prevent bad payloads, or parse into an object.

Apply:

-export const createDomainBodySchemaExtended = createDomainBodySchema.extend({
-  deepviewData: z.string().nullish(),
-});
+export const createDomainBodySchemaExtended = createDomainBodySchema.extend({
+  deepviewData: z
+    .string()
+    .nullish()
+    .refine(
+      (s) => {
+        if (!s) return true;
+        try {
+          JSON.parse(s);
+          return true;
+        } catch {
+          return false;
+        }
+      },
+      { message: "deepviewData must be valid JSON." },
+    ),
+});

Alternative: accept object post-preprocess

+// Alternative:
+// deepviewData: z.preprocess((v) => (typeof v === "string" ? JSON.parse(v) : v), z.record(z.any()).nullish()),
apps/web/app/api/domains/[domain]/route.ts (1)

149-160: Nice: conditional spreads avoid clobbering omitted fields.

Only updating keys when present prevents accidental nulling on PATCH. Matches prior feedback.

🧹 Nitpick comments (9)
apps/web/app/(ee)/api/bounties/[bountyId]/route.ts (1)

173-181: Double-check re-notification behavior when startsAt moves.

If a previous notify job exists, publishing another without cancel/dedupe may double-notify. Confirm QStash dedupe strategy or include an idempotency key.

apps/web/lib/api/links/create-link.ts (1)

70-73: Switch to DbNull on create is fine; align bulk-create/read paths.

Ensure all writers use the same defaulting (DbNull) for geo/testVariants, and that readers don’t rely on JSON-null semantics.

apps/web/lib/api/links/bulk-create-links.ts (1)

74-76: Use DbNull for geo to match create-link semantics.

Make createMany explicit instead of relying on omitted fields/defaults.

Apply:

-        expiresAt: link.expiresAt ? new Date(link.expiresAt) : null,
-        geo: link.geo || undefined,
-        testVariants: link.testVariants || Prisma.DbNull,
+        expiresAt: link.expiresAt ? new Date(link.expiresAt) : null,
+        geo: link.geo || Prisma.DbNull,
+        testVariants: link.testVariants || Prisma.DbNull,
apps/web/lib/actions/partners/update-program.ts (1)

87-89: Clear publishedAt and revalidate when landerData is cleared.

When landerData is explicitly null, also clear landerPublishedAt. Revalidation should run on both set and clear.

Apply:

-        landerData: landerData === null ? Prisma.DbNull : landerData,
-        landerPublishedAt: landerData ? new Date() : undefined,
+        landerData: landerData === null ? Prisma.DbNull : landerData,
+        landerPublishedAt:
+          landerData === null ? null : landerData ? new Date() : undefined,

And below:

-        ...(name !== program.name ||
-        logoUrl ||
-        wordmarkUrl ||
-        brandColor !== program.brandColor ||
-        landerData
+        ...(name !== program.name ||
+        logoUrl ||
+        wordmarkUrl ||
+        brandColor !== program.brandColor ||
+        landerData !== undefined
           ? [
apps/web/lib/actions/partners/create-reward.ts (2)

55-56: Use nullish coalescing to avoid accidental DbNull.

|| treats some valid (albeit unlikely) falsy JSON values as empty. Prefer ?? so only null/undefined fall back.

-          modifiers: modifiers || Prisma.DbNull,
+          modifiers: modifiers ?? Prisma.DbNull,

27-31: Gate advanced logic on presence, not generic truthiness.

If the client sends an empty object/array, if (modifiers && …) may block unnecessarily. Consider an explicit “has rules” check or at least modifiers != null.

-    if (modifiers && !canUseAdvancedRewardLogic) {
+    if (modifiers != null && !canUseAdvancedRewardLogic) {
apps/web/app/api/domains/[domain]/route.ts (1)

21-24: Validate deepviewData at the schema boundary (optional).

Consider parsing/validating deepviewData as JSON in the Zod extension so bad inputs fail fast with a 400 instead of surfacing later during update.

Example:

-const updateDomainBodySchemaExtended = updateDomainBodySchema.extend({
-  deepviewData: z.string().nullish(),
-  autoRenew: z.boolean().nullish(),
-});
+const updateDomainBodySchemaExtended = updateDomainBodySchema.extend({
+  deepviewData: z
+    .string()
+    .nullish()
+    .refine((v) => v == null || isValidJson(v), "deepviewData must be valid JSON"),
+  autoRenew: z.boolean().nullish(),
+});
+
+function isValidJson(s?: string | null) {
+  if (!s) return true;
+  try {
+    JSON.parse(s);
+    return true;
+  } catch {
+    return false;
+  }
+}
apps/web/ui/domains/add-edit-domain-form.tsx (2)

123-131: Expose setError from useForm for client-side JSON validation.

You’ll need setError to surface field errors before submit.

Apply:

-  const {
+  const {
     register,
     control,
     handleSubmit,
     watch,
     setValue,
+    setError,
     formState: { isSubmitting, isDirty },
   } = useForm<FormData>({

657-662: Consistency: “Asset Links” (plural) to match API messaging.

UI shows “Asset Link” but server toasts/gating say “Asset Links”. Consider plural for consistency.

Apply:

-    title: "Asset Link",
+    title: "Asset Links",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 06ce625 and 44585d8.

📒 Files selected for processing (14)
  • apps/web/app/(ee)/api/bounties/[bountyId]/route.ts (1 hunks)
  • apps/web/app/api/domains/[domain]/route.ts (5 hunks)
  • apps/web/app/api/domains/route.ts (3 hunks)
  • apps/web/app/sitemap.ts (1 hunks)
  • apps/web/lib/actions/partners/create-reward.ts (1 hunks)
  • apps/web/lib/actions/partners/update-program.ts (1 hunks)
  • apps/web/lib/actions/partners/update-reward.ts (1 hunks)
  • apps/web/lib/api/domains/transform-domain.ts (1 hunks)
  • apps/web/lib/api/links/bulk-create-links.ts (1 hunks)
  • apps/web/lib/api/links/bulk-update-links.ts (1 hunks)
  • apps/web/lib/api/links/create-link.ts (1 hunks)
  • apps/web/lib/api/links/update-link.ts (1 hunks)
  • apps/web/lib/zod/schemas/domains.ts (2 hunks)
  • apps/web/ui/domains/add-edit-domain-form.tsx (11 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/lib/api/domains/transform-domain.ts
  • apps/web/app/api/domains/route.ts
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-07-30T15:29:54.131Z
Learnt from: TWilson023
PR: dubinc/dub#2673
File: apps/web/ui/partners/rewards/rewards-logic.tsx:268-275
Timestamp: 2025-07-30T15:29:54.131Z
Learning: In apps/web/ui/partners/rewards/rewards-logic.tsx, when setting the entity field in a reward condition, dependent fields (attribute, operator, value) should be reset rather than preserved because different entities (customer vs sale) have different available attributes. Maintaining existing fields when the entity changes would create invalid state combinations and confusing UX.

Applied to files:

  • apps/web/lib/actions/partners/create-reward.ts
  • apps/web/lib/actions/partners/update-reward.ts
📚 Learning: 2025-06-06T07:59:03.120Z
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.

Applied to files:

  • apps/web/lib/api/links/create-link.ts
  • apps/web/lib/api/links/bulk-update-links.ts
  • apps/web/lib/api/links/bulk-create-links.ts
📚 Learning: 2025-08-26T14:32:33.851Z
Learnt from: TWilson023
PR: dubinc/dub#2736
File: apps/web/lib/actions/partners/create-bounty-submission.ts:105-112
Timestamp: 2025-08-26T14:32:33.851Z
Learning: Non-performance bounties are required to have submissionRequirements. In create-bounty-submission.ts, it's appropriate to let the parsing fail if submissionRequirements is null for non-performance bounties, as this indicates a data integrity issue that should be caught.

Applied to files:

  • apps/web/app/(ee)/api/bounties/[bountyId]/route.ts
📚 Learning: 2025-08-26T14:20:23.943Z
Learnt from: TWilson023
PR: dubinc/dub#2736
File: apps/web/app/api/workspaces/[idOrSlug]/notification-preferences/route.ts:13-14
Timestamp: 2025-08-26T14:20:23.943Z
Learning: The updateNotificationPreference action in apps/web/lib/actions/update-notification-preference.ts already handles all notification preference types dynamically, including newBountySubmitted, through its schema validation using the notificationTypes enum and Prisma's dynamic field update pattern.

Applied to files:

  • apps/web/app/(ee)/api/bounties/[bountyId]/route.ts
  • apps/web/lib/actions/partners/update-reward.ts
📚 Learning: 2025-08-14T05:17:51.825Z
Learnt from: devkiran
PR: dubinc/dub#2735
File: apps/web/lib/actions/partners/delete-reward.ts:33-41
Timestamp: 2025-08-14T05:17:51.825Z
Learning: In the partner groups system, a rewardId can only belong to one group, establishing a one-to-one relationship between rewards and groups. This means using Prisma's `update` method (rather than `updateMany`) is appropriate when updating groups by rewardId.

Applied to files:

  • apps/web/app/(ee)/api/bounties/[bountyId]/route.ts
  • apps/web/lib/actions/partners/update-reward.ts
🧬 Code graph analysis (7)
apps/web/lib/api/links/update-link.ts (1)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/lib/actions/partners/create-reward.ts (1)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/lib/api/links/create-link.ts (1)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/app/sitemap.ts (1)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/app/(ee)/api/bounties/[bountyId]/route.ts (1)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/app/api/domains/[domain]/route.ts (2)
apps/web/lib/zod/schemas/domains.ts (1)
  • updateDomainBodySchema (170-170)
packages/prisma/client.ts (1)
  • Prisma (20-20)
apps/web/ui/domains/add-edit-domain-form.tsx (1)
apps/web/lib/zod/schemas/domains.ts (1)
  • createDomainBodySchemaExtended (166-168)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Vade Review
🔇 Additional comments (9)
apps/web/lib/zod/schemas/domains.ts (1)

60-60: LGTM: DomainSchema.logo surfaced on read shape.

apps/web/lib/actions/partners/update-reward.ts (1)

43-44: LGTM: precise null semantics for JSON field.

modifiers === null ? Prisma.DbNull : modifiers correctly distinguishes null (clear) from undefined (no-op) and aligns with Prisma’s JSON null types.

apps/web/app/sitemap.ts (1)

20-21: LGTM: broadened null filter is correct.

Switching to not: Prisma.AnyNull correctly excludes both DB NULL and JSON NULL for landerData, matching upstream writes that may use DbNull.

apps/web/lib/api/links/bulk-update-links.ts (1)

57-59: LGTM: safe null handling for JSON fields.

Using === null ? Prisma.DbNull : value preserves existing data when fields are omitted and only clears on explicit null. Matches Prisma best practices and is consistent with update semantics.

apps/web/app/api/domains/[domain]/route.ts (1)

71-96: Confirm intended behavior: free users can clear Pro fields.

With the current gating, empty strings (falsy) won’t trigger the Pro check, allowing free users to clear Asset Links/AASA/Deep View but not set them. If that’s intended, all good; if not, tighten the condition to check key presence rather than truthiness.

apps/web/ui/domains/add-edit-domain-form.tsx (4)

546-583: Good UX: JSON paste formatting with fallback.

Nice touch to auto-format JSON while preserving raw text on parse failure.


219-221: Enter-to-submit wiring looks solid.

Form ref + useEnterSubmit applied to textareas; consider also applying to the domain input if desired.


141-144: Prepopulate Deep View editor with formatted JSON.

Formatting default deepviewData improves readability. LGTM.


5-5: No stale className props found in AddEditDomainForm usage. Verified that call sites in the onboarding form and modal only pass props and onSuccess, matching the updated schema.

Comment on lines 109 to 113
...(bounty.type === "submission" &&
submissionRequirements !== undefined && {
submissionRequirements: submissionRequirements ?? Prisma.JsonNull,
submissionRequirements: submissionRequirements ?? Prisma.DbNull,
}),
...(updatedPartnerGroups && {
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Do not allow null submissionRequirements for submission bounties.

Allowing submissionRequirements to be set to DbNull on submission-type bounties breaks the invariant that non-performance/submission bounties must have requirements (per past learnings). Guard against nulls before the update.

Apply:

@@
-    const data = await prisma.$transaction(async (tx) => {
+    // Enforce invariant: submission bounties require submissionRequirements
+    if (bounty.type === "submission" && submissionRequirements === null) {
+      throw new DubApiError({
+        message: "submissionRequirements is required for submission bounties.",
+        code: "bad_request",
+      });
+    }
+
+    const data = await prisma.$transaction(async (tx) => {
@@
-          ...(bounty.type === "submission" &&
-            submissionRequirements !== undefined && {
-              submissionRequirements: submissionRequirements ?? Prisma.DbNull,
-            }),
+          ...(bounty.type === "submission" &&
+            submissionRequirements !== undefined && {
+              // for submission bounties, only accept defined (non-null) values
+              submissionRequirements,
+            }),
+          ...(
+            bounty.type !== "submission" &&
+            submissionRequirements !== undefined && {
+              submissionRequirements: submissionRequirements ?? Prisma.DbNull,
+            }
+          ),

Verification (ensures no other code assumes JSON-null for this field):


🏁 Script executed:

#!/bin/bash
# Find legacy JsonNull usage or is-null checks on submissionRequirements
rg -nP --type=ts '(submissionRequirements[^:\n]*:\s*Prisma\.JsonNull)|(\bJsonNull\b.*submissionRequirements)|(\bsubmissionRequirements\b[^}]*\bnot:\s*Prisma\.JsonNull)'

Length of output: 170


🏁 Script executed:

#!/bin/bash
set -e

# Search all TypeScript files for any usage of submissionRequirements
rg -n --type=ts "submissionRequirements" -C3

# Check for explicit null comparisons (=== null or == null)
rg -nP --type=ts "submissionRequirements\s*===?\s*null"

# Check for nullish coalescing usage (??)
rg -nP --type=ts "submissionRequirements\s*\?\?"

Length of output: 14208


Enforce non-null submissionRequirements on submission bounties
In apps/web/app/(ee)/api/bounties/[bountyId]/route.ts, before the transaction throw a DubApiError if bounty.type is "submission" and submissionRequirements is null, and remove the Prisma.DbNull fallback so that only defined arrays are persisted.

🤖 Prompt for AI Agents
In apps/web/app/(ee)/api/bounties/[bountyId]/route.ts around lines 109 to 113,
enforce that submission bounties have non-null submissionRequirements and stop
persisting Prisma.DbNull; before the DB transaction, add a guard that if
bounty.type === "submission" and submissionRequirements == null then throw a
DubApiError with an appropriate message, and change the update payload so the
submissionRequirements property is only spread when submissionRequirements is
not undefined (remove the Prisma.DbNull fallback) so only defined arrays are
persisted.

Comment on lines +7 to +9
where: {
deepviewData: {
equals: Prisma.AnyNull,
Copy link
Contributor

Choose a reason for hiding this comment

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

The migration script uses an incorrect Prisma query condition that will likely return no results, preventing the backfill operation from working.

View Details
📝 Patch Details
diff --git a/apps/web/scripts/migrations/backfill-deepview.ts b/apps/web/scripts/migrations/backfill-deepview.ts
index 09ea20e5e..e08312ba8 100644
--- a/apps/web/scripts/migrations/backfill-deepview.ts
+++ b/apps/web/scripts/migrations/backfill-deepview.ts
@@ -1,13 +1,10 @@
 import { prisma } from "@dub/prisma";
-import { Prisma } from "@prisma/client";
 import "dotenv-flow/config";
 
 async function main() {
   const domains = await prisma.domain.findMany({
     where: {
-      deepviewData: {
-        equals: Prisma.AnyNull,
-      },
+      deepviewData: null,
     },
     take: 1000,
   });

Analysis

The migration script uses equals: Prisma.AnyNull to find domains where deepviewData is null, but this is incorrect Prisma syntax. Prisma.AnyNull is used for setting values to null in updates, not for querying null values.

The correct query condition should be:

where: {
  deepviewData: null,
},

Or if you want to find domains where deepviewData is either null or the JSON value is null:

where: {
  OR: [
    { deepviewData: null },
    { deepviewData: Prisma.JsonNull },
  ],
},

The current code will likely return no results, making the migration ineffective.

Comment on lines -538 to -544
].includes(id)
) {
e.preventDefault();
const pastedText =
e.clipboardData.getData("text");

try {
Copy link
Contributor

Choose a reason for hiding this comment

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

Developer explicitly marked this Deep View initialization as a "hacky frontend workaround" indicating incomplete implementation.

View Details
📝 Patch Details
diff --git a/apps/web/ui/domains/add-edit-domain-form.tsx b/apps/web/ui/domains/add-edit-domain-form.tsx
index 8b9501d09..0c07a646f 100644
--- a/apps/web/ui/domains/add-edit-domain-form.tsx
+++ b/apps/web/ui/domains/add-edit-domain-form.tsx
@@ -534,15 +534,7 @@ export function AddEditDomainForm({
                                   ...prev,
                                   [id]: checked,
                                 }));
-                                if (checked) {
-                                  // hacky frontend workaround since we don't have a way
-                                  // to customize the actual appearance of the deepview page yet
-                                  if (id === "deepviewData") {
-                                    setValue("deepviewData", "{}", {
-                                      shouldDirty: true,
-                                    });
-                                  }
-                                } else {
+                                if (!checked) {
                                   setValue(id, "", {
                                     shouldDirty: true,
                                   });
@@ -552,7 +544,7 @@ export function AddEditDomainForm({
                             />
                           </div>
 
-                          {showOptionStates[id] && id !== "deepviewData" && (
+                          {showOptionStates[id] && (
                             <div className="rounded-md border border-neutral-200 bg-white">
                               <textarea
                                 {...register(id)}
@@ -565,6 +557,7 @@ export function AddEditDomainForm({
                                     [
                                       "appleAppSiteAssociation",
                                       "assetLinks",
+                                      "deepviewData",
                                     ].includes(id)
                                   ) {
                                     e.preventDefault();

Analysis

The comment on lines 538-539 states this is a "hacky frontend workaround since we don't have a way to customize the actual appearance of the deepview page yet." This indicates the Deep View feature is not fully implemented and is using a temporary solution.

When developers explicitly mark code with comments like "hacky frontend workaround," it typically signals that the implementation needs proper completion before release. The current approach of simply setting deepviewData to "{}" when enabled suggests the feature may not be fully functional, and the developer is acknowledging this is temporary code that should be improved.

This type of explicit developer intent comment should be addressed before merging, as it indicates known technical debt or incomplete functionality.

@steven-tey steven-tey merged commit ce4c6be into main Sep 2, 2025
8 of 9 checks passed
@steven-tey steven-tey deleted the deepview branch September 2, 2025 04:34
@coderabbitai coderabbitai bot mentioned this pull request Sep 22, 2025
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.

2 participants