Skip to content

Conversation

@Siri-Ray
Copy link
Contributor

@Siri-Ray Siri-Ray commented Jan 15, 2026

  • Updated the hasFilledForm method to return user interests along with identity and hasFilledForm status.
  • Introduced extractInterestsFromAnswers method to parse interests from user answers.
  • Modified the HasFilledFormResponse type to include interests property.
  • Updated OpenAPI schema and generated types to reflect the new interests field.

Summary by CodeRabbit

  • New Features
    • Form completion status API responses now return a new interests field containing user interests information.
    • User interests are automatically extracted, parsed, and computed from all submitted form answers and responses.
    • User interests data is now tracked through the user properties system to persist user preferences across the application and sessions.

✏️ Tip: You can customize this high-level summary in your review settings.

- Updated the hasFilledForm method to return user interests along with identity and hasFilledForm status.
- Introduced extractInterestsFromAnswers method to parse interests from user answers.
- Modified the HasFilledFormResponse type to include interests property.
- Updated OpenAPI schema and generated types to reflect the new interests field.
@linear
Copy link

linear bot commented Jan 15, 2026

@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

The changes extend the hasFilledForm response payload to include an interests field. A new private method extracts interests from form answers in the service layer, the controller returns this field, frontend hooks consume it and update user properties, and type definitions are updated across multiple packages.

Changes

Cohort / File(s) Summary
Backend Form Module
apps/api/src/modules/form/form.controller.ts, apps/api/src/modules/form/form.service.ts
Added extractInterestsFromAnswers() helper to parse interests from form answers. Extended hasFilledForm() return type to include interests field and compute it alongside hasFilledForm and identity. Updated controller response payload to include the new field.
Frontend Hooks
packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
Integrated interests extraction from hasFilledForm() response and pass it as user_acquisition_source when updating user properties via updateUserProperties().
Type Definitions
packages/ai-workspace-common/src/requests/types.gen.ts, packages/request/src/requests/types.gen.ts, packages/openapi-schema/src/types.gen.ts
Added optional interests: string field to HasFilledFormResponse data object across all three type definition packages.
OpenAPI Schema
packages/openapi-schema/schema.yml, packages/openapi-schema/src/schemas.gen.ts
Added interests: string field to HasFilledFormResponseSchema and updated schema.yml accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • anthhub

Poem

🐰 A field of interests now flows through the forms,
From answers extracted to responses warm,
Types align as the changes cascade,
Through hooks and schemas, a path is made! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change—extending the hasFilledForm response to include user interests across multiple files and schemas.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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 and usage tips.

Copy link

@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 (5)
packages/openapi-schema/schema.yml (1)

10443-10462: Clarify interests type/shape (string vs string[]) and nullability to avoid schema drift.

Right now interests is type: string. If the service returns null (common when absent) or multiple interests, generated clients may break. Consider either:

  • Keep it as a string but explicitly define the format + allow null, or
  • Model it as an array of strings.
Option A: keep `string` (document format + allow null)
                 interests:
                   type: string
+                  nullable: true
-                  description: User interests
+                  description: User interests (comma-separated string)
Option B: change to `string[]`
                 interests:
-                  type: string
                   description: User interests
+                  type: array
+                  items:
+                    type: string
packages/ai-workspace-common/src/requests/types.gen.ts (1)

5744-5761: Fix type definition: interests can be null but the type doesn't reflect it.

The backend's hasFilledForm() method always returns interests ?? null (lines 115, 122 in form.service.ts), meaning the field can legitimately be null. However, the OpenAPI schema defines interests: type: string and the generated type is interests?: string;, neither of which allows null. The consumer code in use-get-user-settings.ts correctly expects string | null. Update the OpenAPI schema to make interests nullable (e.g., type: [string, "null"] or oneOf: [{ type: string }, { type: "null" }]) and regenerate, or ensure the backend never returns null for this field.

packages/request/src/requests/types.gen.ts (1)

5402-5420: Sync OpenAPI schema with actual service implementation for nullable handling.

The service implementation in form.service.ts (lines 115, 122) returns interests: interests ?? null, which means interests can be null. However, the OpenAPI schema defines interests as type: string without nullable: true, resulting in the generated type being interests?: string. This creates a type mismatch—TypeScript consumers will see string | undefined but the API returns null at runtime.

Fix by updating the OpenAPI schema to mark interests as nullable: true, then regenerate the client types.

apps/api/src/modules/form/form.service.ts (1)

97-124: hasFilledForm return type + payload nullability are inconsistent (and hasFilledForm defaulting to true is risky).
Right now the method promises identity/interests: string but returns null, and returning explicit null also conflicts with the OpenAPI shape (identity?: string, interests?: string). Also, preferences.hasFilledForm ?? true will treat missing preference as “filled”.

Proposed fix (align with OpenAPI optional fields + safer default)
   async hasFilledForm(
     uid: string,
-  ): Promise<{ hasFilledForm: boolean; identity: string; interests: string }> {
+  ): Promise<{ hasFilledForm: boolean; identity?: string; interests?: string }> {
     const user = await this.prisma.user.findUnique({
       where: { uid },
       select: { preferences: true },
     });

     const answers = await this.prisma.formSubmission.findFirst({
       where: { uid },
       select: { answers: true },
     });

     const identity = this.extractRoleFromAnswers(answers?.answers);
     const interests = this.extractInterestsFromAnswers(answers?.answers);

     if (!user?.preferences) {
-      return { hasFilledForm: false, identity: identity ?? null, interests: interests ?? null };
+      return {
+        hasFilledForm: false,
+        identity: identity ?? undefined,
+        interests: interests ?? undefined,
+      };
     }

-    const preferences = JSON.parse(user.preferences);
+    let preferences: any;
+    try {
+      preferences = JSON.parse(user.preferences);
+    } catch {
+      return {
+        hasFilledForm: false,
+        identity: identity ?? undefined,
+        interests: interests ?? undefined,
+      };
+    }
     return {
-      hasFilledForm: preferences.hasFilledForm ?? true,
-      identity: identity ?? null,
-      interests: interests ?? null,
+      hasFilledForm: preferences?.hasFilledForm ?? false,
+      identity: identity ?? undefined,
+      interests: interests ?? undefined,
     };
   }
packages/ai-workspace-common/src/hooks/use-get-user-settings.ts (1)

123-136: Fix incorrect response path access—accessing data?.data will always read undefined.

The API response structure for both hasBeenInvited() and hasFilledForm() is { success, data: { hasBeenInvited, hasFilledForm, identity, interests } }, not nested under an extra data layer. The code currently accesses:

  • invitationResp.data?.data → should be invitationResp.data?.hasBeenInvited
  • formResp.data?.data?.hasFilledForm → should be formResp.data?.hasFilledForm
  • formResp.data?.data?.identity → should be formResp.data?.identity
  • formResp.data?.data?.interests → should be formResp.data?.interests

This causes silent undefined reads that rely on the fallback defaults, masking potential data availability issues.

🤖 Fix all issues with AI agents
In `@apps/api/src/modules/form/form.controller.ts`:
- Around line 37-43: The controller is passing through result.interests which
can be null from formService.hasFilledForm(), violating the OpenAPI non-nullable
string for interests; update the hasFilledForm controller to coerce null to a
string (e.g., interests: result.interests ?? '') before calling
buildSuccessResponse, and ensure the returned payload shape in
HasFilledFormResponse matches the OpenAPI schema; adjust or add a minimal inline
conversion in the hasFilledForm method that uses the result from
formService.hasFilledForm(user.uid).

In `@apps/api/src/modules/form/form.service.ts`:
- Around line 28-41: The current extractInterestsFromAnswers function can
convert a null interest into the string "null" and ignores string or string[]
interest values; update extractInterestsFromAnswers to: parse answers as before,
then if parsed?.interests === null return null; if typeof parsed.interests ===
'string' return that string; if Array.isArray(parsed.interests) return
JSON.stringify(parsed.interests) (or join if you prefer a delimited string); if
typeof parsed.interests === 'object' return JSON.stringify(parsed.interests);
otherwise return null, keeping the existing try/catch behavior for invalid JSON.

In `@packages/ai-workspace-common/src/hooks/use-get-user-settings.ts`:
- Around line 151-157: The updateUserProperties call is sending potentially null
values and unbounded JSON (interests); change it to omit unset fields (use
undefined instead of null) and normalize interests to a small bounded string
before sending: only include user_plan when userTypeForUserProperties is
non-null, include user_identity only when identity exists, and transform
interests (the variable passed as user_acquisition_source) into a compact
representation (e.g., pick/top N, join into a short comma-separated string or
map to a single enum/tag and truncate to a safe length) so you never send large
JSON blobs to updateUserProperties in use-get-user-settings.ts.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a817e1 and 969b342.

📒 Files selected for processing (8)
  • apps/api/src/modules/form/form.controller.ts
  • apps/api/src/modules/form/form.service.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/schema.yml
  • packages/openapi-schema/src/schemas.gen.ts
  • packages/openapi-schema/src/types.gen.ts
  • packages/request/src/requests/types.gen.ts
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{js,ts,jsx,tsx}: Always use optional chaining (?.) when accessing object properties
Always use nullish coalescing (??) or default values for potentially undefined values
Always check array existence before using array methods
Always validate object properties before destructuring
Always use single quotes for string literals in JavaScript/TypeScript code

**/*.{js,ts,jsx,tsx}: Use semicolons at the end of statements
Include spaces around operators (e.g., a + b instead of a+b)
Always use curly braces for control statements
Place opening braces on the same line as their statement

**/*.{js,ts,jsx,tsx}: Group import statements in order: React/framework libraries, third-party libraries, internal modules, relative path imports, type imports, style imports
Sort imports alphabetically within each import group
Leave a blank line between import groups
Extract complex logic into custom hooks
Use functional updates for state (e.g., setCount(prev => prev + 1))
Split complex state into multiple state variables rather than single large objects
Use useReducer for complex state logic instead of multiple useState calls

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{js,ts,tsx,jsx,py,java,cpp,c,cs,rb,go,rs,php,swift,kt,scala,r,m,mm,sql}

📄 CodeRabbit inference engine (.cursor/rules/00-language-priority.mdc)

**/*.{js,ts,tsx,jsx,py,java,cpp,c,cs,rb,go,rs,php,swift,kt,scala,r,m,mm,sql}: All code comments MUST be written in English
All variable names, function names, class names, and other identifiers MUST use English words
Comments should be concise and explain 'why' rather than 'what'
Use proper grammar and punctuation in comments
Keep comments up-to-date when code changes
Document complex logic, edge cases, and important implementation details
Use clear, descriptive names that indicate purpose
Avoid abbreviations unless they are universally understood

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/00-language-priority.mdc)

Use JSDoc style comments for functions and classes in JavaScript/TypeScript

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/01-code-style.mdc)

**/*.{js,jsx,ts,tsx}: Use single quotes for string literals in TypeScript/JavaScript
Always use optional chaining (?.) when accessing object properties in TypeScript/JavaScript
Always use nullish coalescing (??) or default values for potentially undefined values in TypeScript/JavaScript
Always check array existence before using array methods in TypeScript/JavaScript
Validate object properties before destructuring in TypeScript/JavaScript
Use ES6+ features like arrow functions, destructuring, and spread operators in TypeScript/JavaScript
Avoid magic numbers and strings - use named constants in TypeScript/JavaScript
Use async/await instead of raw promises for asynchronous code in TypeScript/JavaScript

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/03-typescript-guidelines.mdc)

**/*.{ts,tsx}: Avoid using any type whenever possible - use unknown type instead with proper type guards
Always define explicit return types for functions, especially for public APIs
Prefer extending existing types over creating entirely new types
Use TypeScript utility types (Partial<T>, Pick<T, K>, Omit<T, K>, Readonly<T>, Record<K, T>) to derive new types
Use union types and intersection types to combine existing types
Always import types explicitly using the import type syntax
Group type imports separately from value imports
Minimize creating local type aliases for imported types

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{js,ts,jsx,tsx,css,json}

📄 CodeRabbit inference engine (.cursor/rules/04-code-formatting.mdc)

Maximum line length of 100 characters

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{js,ts,jsx,tsx,css,json,yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/04-code-formatting.mdc)

Use 2 spaces for indentation, no tabs

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/schema.yml
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{js,ts,jsx,tsx,css,json,yml,yaml,md}

📄 CodeRabbit inference engine (.cursor/rules/04-code-formatting.mdc)

No trailing whitespace at the end of lines

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/schema.yml
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{css,scss,sass,less,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/09-design-system.mdc)

**/*.{css,scss,sass,less,js,jsx,ts,tsx}: Primary color (#155EEF) should be used for main brand color in buttons, links, and accents
Error color (#F04438) should be used for error states and destructive actions
Success color (#12B76A) should be used for success states and confirmations
Warning color (#F79009) should be used for warnings and important notifications
Info color (#0BA5EC) should be used for informational elements

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/09-i18n-guidelines.mdc)

**/*.{tsx,ts}: Use the translation wrapper component and useTranslation hook in components
Ensure all user-facing text is translatable

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{tsx,ts,json}

📄 CodeRabbit inference engine (.cursor/rules/09-i18n-guidelines.mdc)

Support dynamic content with placeholders in translations

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{tsx,ts,jsx,js,vue,css,scss,less}

📄 CodeRabbit inference engine (.cursor/rules/11-ui-design-patterns.mdc)

**/*.{tsx,ts,jsx,js,vue,css,scss,less}: Use the primary blue (#155EEF) for main UI elements, CTAs, and active states
Use red (#F04438) only for errors, warnings, and destructive actions
Use green (#12B76A) for success states and confirmations
Use orange (#F79009) for warning states and important notifications
Use blue (#0BA5EC) for informational elements
Primary buttons should be solid with the primary color
Secondary buttons should have a border with transparent or light background
Danger buttons should use the error color
Use consistent padding, border radius, and hover states for all buttons
Follow fixed button sizes based on their importance and context
Use consistent border radius (rounded-lg) for all cards
Apply light shadows (shadow-sm) for card elevation
Maintain consistent padding inside cards (p-4 or p-6)
Use subtle borders for card separation
Ensure proper spacing between card elements
Apply consistent styling to all form inputs
Use clear visual indicators for focus, hover, and error states in form elements
Apply proper spacing between elements using 8px, 16px, 24px increments
Ensure proper alignment of elements (left, center, or right)
Use responsive layouts that work across different device sizes
Maintain a minimum contrast ratio of 4.5:1 for text

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{tsx,ts,jsx,js,vue}

📄 CodeRabbit inference engine (.cursor/rules/11-ui-design-patterns.mdc)

**/*.{tsx,ts,jsx,js,vue}: Include appropriate loading states for async actions in buttons
Group related form elements with appropriate spacing
Provide clear validation feedback for forms
Ensure proper labeling and accessibility for form elements
Ensure all interactive elements are keyboard accessible
Include appropriate ARIA attributes for complex components
Provide alternative text for images and icons
Support screen readers with semantic HTML elements

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/08-contributing-guidelines.mdc)

**/*.{ts,tsx,js,jsx}: Follow the TypeScript/JavaScript style guidelines
Ensure code is well-tested and documented

Files:

  • packages/request/src/requests/types.gen.ts
  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
  • packages/openapi-schema/src/types.gen.ts
  • apps/api/src/modules/form/form.controller.ts
  • packages/ai-workspace-common/src/requests/types.gen.ts
  • packages/openapi-schema/src/schemas.gen.ts
  • apps/api/src/modules/form/form.service.ts
apps/api/src/**/*.{controller,service}.ts

📄 CodeRabbit inference engine (.cursor/rules/06-api-structure.mdc)

Implement proper error handling in API modules

Files:

  • apps/api/src/modules/form/form.controller.ts
  • apps/api/src/modules/form/form.service.ts
apps/api/src/**/*.controller.ts

📄 CodeRabbit inference engine (.cursor/rules/06-api-structure.mdc)

Document APIs with OpenAPI specifications

Files:

  • apps/api/src/modules/form/form.controller.ts
🧠 Learnings (1)
📚 Learning: 2025-12-01T07:29:05.527Z
Learnt from: mrcfps
Repo: refly-ai/refly PR: 1678
File: packages/ai-workspace-common/src/hooks/use-logout.ts:60-65
Timestamp: 2025-12-01T07:29:05.527Z
Learning: In the Refly codebase (packages/ai-workspace-common/src/hooks/use-get-user-settings.ts), user preferences including 'refly-user-profile' and 'refly-local-settings' are stored on the server and fetched via the /user/settings API endpoint on every login. localStorage is used only as a cache for fast initial rendering, not as the source of truth. Therefore, clearing localStorage during logout is safe because preferences will be refetched from the server on next login.

Applied to files:

  • packages/ai-workspace-common/src/hooks/use-get-user-settings.ts
🧬 Code graph analysis (1)
apps/api/src/modules/form/form.controller.ts (1)
apps/api/src/utils/response.ts (1)
  • buildSuccessResponse (48-53)
🔇 Additional comments (2)
packages/openapi-schema/src/schemas.gen.ts (1)

7963-7993: Clarify interests semantics (nullable vs omitted vs multi-value) to match runtime responses.

Right now interests is an optional string (since it’s not in required). If the API ever returns null (or a list of interests), this schema will be inaccurate—consider updating the source OpenAPI (schema.yml) to either mark it nullable: true (and/or default to '') or model it as type: 'array' of strings, then regenerate.

packages/openapi-schema/src/types.gen.ts (1)

5757-5760: HasFilledFormResponse.data.interests?: string addition is consistent with the PR goal.
Since this file is auto-generated, just ensure schema.yml / generator inputs are the source of truth (avoid hand-editing generated output).

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 37 to +43
async hasFilledForm(@LoginedUser() user: User): Promise<HasFilledFormResponse> {
const result = await this.formService.hasFilledForm(user.uid);
return buildSuccessResponse({ hasFilledForm: result.hasFilledForm, identity: result.identity });
return buildSuccessResponse({
hasFilledForm: result.hasFilledForm,
identity: result.identity,
interests: result.interests,
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for relevant code in form service and schema
echo "=== Searching form.service.ts ==="
rg -n "hasFilledForm|interests" apps/api/src/modules/form/form.service.ts -A 5 -B 2

echo -e "\n=== Searching OpenAPI schema ==="
rg -n "HasFilledFormResponse|interests" packages/openapi-schema/schema.yml -A 3 -B 1

Repository: refly-ai/refly

Length of output: 2116


Prevent interests: null from leaking into the API response.

The FormService.hasFilledForm() method can return interests: null (see lines 115 and 122 where it returns interests: interests ?? null), but the OpenAPI schema defines interests as type: string (non-nullable). The controller passes this null value directly through, violating the API contract.

Proposed fix
  async hasFilledForm(`@LoginedUser`() user: User): Promise<HasFilledFormResponse> {
    const result = await this.formService.hasFilledForm(user.uid);
    return buildSuccessResponse({
      hasFilledForm: result.hasFilledForm,
      identity: result.identity,
-     interests: result.interests,
+     interests: result.interests ?? undefined,
    });
  }
🤖 Prompt for AI Agents
In `@apps/api/src/modules/form/form.controller.ts` around lines 37 - 43, The
controller is passing through result.interests which can be null from
formService.hasFilledForm(), violating the OpenAPI non-nullable string for
interests; update the hasFilledForm controller to coerce null to a string (e.g.,
interests: result.interests ?? '') before calling buildSuccessResponse, and
ensure the returned payload shape in HasFilledFormResponse matches the OpenAPI
schema; adjust or add a minimal inline conversion in the hasFilledForm method
that uses the result from formService.hasFilledForm(user.uid).

Comment on lines +28 to +41
private extractInterestsFromAnswers(answers: string): string | null {
if (!answers?.trim()) {
return null;
}

try {
const parsed = JSON.parse(answers) as { interests?: unknown } | null;
const interests =
typeof parsed?.interests === 'object' ? JSON.stringify(parsed.interests) : null;
return interests || null;
} catch {
return null;
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

extractInterestsFromAnswers currently turns null into the string "null" and ignores string interests.
Handle null explicitly and support string / string[] (likely for multi-select) so downstream telemetry doesn’t get noisy values.

Proposed fix
   private extractInterestsFromAnswers(answers: string): string | null {
     if (!answers?.trim()) {
       return null;
     }

     try {
       const parsed = JSON.parse(answers) as { interests?: unknown } | null;
-      const interests =
-        typeof parsed?.interests === 'object' ? JSON.stringify(parsed.interests) : null;
-      return interests || null;
+      const raw = parsed?.interests;
+      if (raw == null) {
+        return null;
+      }
+      if (typeof raw === 'string') {
+        return raw.trim() || null;
+      }
+      if (Array.isArray(raw) && raw.every((v) => typeof v === 'string')) {
+        return raw.map((v) => v.trim()).filter(Boolean).join(', ') || null;
+      }
+      return JSON.stringify(raw);
     } catch {
       return null;
     }
   }
🤖 Prompt for AI Agents
In `@apps/api/src/modules/form/form.service.ts` around lines 28 - 41, The current
extractInterestsFromAnswers function can convert a null interest into the string
"null" and ignores string or string[] interest values; update
extractInterestsFromAnswers to: parse answers as before, then if
parsed?.interests === null return null; if typeof parsed.interests === 'string'
return that string; if Array.isArray(parsed.interests) return
JSON.stringify(parsed.interests) (or join if you prefer a delimited string); if
typeof parsed.interests === 'object' return JSON.stringify(parsed.interests);
otherwise return null, keeping the existing try/catch behavior for invalid JSON.

Comment on lines 151 to 157
if (userTypeForUserProperties) {
updateUserProperties({ user_plan: userTypeForUserProperties, user_identity: identity });
updateUserProperties({
user_plan: userTypeForUserProperties,
user_identity: identity,
user_acquisition_source: interests,
});
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid sending null (and potentially large JSON) into telemetry user properties.
Prefer omitting unset fields (undefined) and consider normalizing interests to a small bounded string before sending as user_acquisition_source.

Proposed fix
     if (userTypeForUserProperties) {
       updateUserProperties({
         user_plan: userTypeForUserProperties,
-        user_identity: identity,
-        user_acquisition_source: interests,
+        user_identity: identity ?? undefined,
+        user_acquisition_source: interests ?? undefined,
       });
     }
🤖 Prompt for AI Agents
In `@packages/ai-workspace-common/src/hooks/use-get-user-settings.ts` around lines
151 - 157, The updateUserProperties call is sending potentially null values and
unbounded JSON (interests); change it to omit unset fields (use undefined
instead of null) and normalize interests to a small bounded string before
sending: only include user_plan when userTypeForUserProperties is non-null,
include user_identity only when identity exists, and transform interests (the
variable passed as user_acquisition_source) into a compact representation (e.g.,
pick/top N, join into a short comma-separated string or map to a single enum/tag
and truncate to a safe length) so you never send large JSON blobs to
updateUserProperties in use-get-user-settings.ts.

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