Skip to content

refactor(condo)DOMA-13068 use new file api in tickets and ticket comments#7449

Open
nomerdvadcatpyat wants to merge 4 commits intomainfrom
refactor/condo/DOMA-13068/use-new-file-api-in-tickets
Open

refactor(condo)DOMA-13068 use new file api in tickets and ticket comments#7449
nomerdvadcatpyat wants to merge 4 commits intomainfrom
refactor/condo/DOMA-13068/use-new-file-api-in-tickets

Conversation

@nomerdvadcatpyat
Copy link
Copy Markdown
Member

@nomerdvadcatpyat nomerdvadcatpyat commented Apr 10, 2026

Summary by CodeRabbit

  • New Features

    • Added file attachment capability for ticket comments.
    • Added file attachment capability for tickets.
    • Implemented client-side file upload functionality with improved authentication handling for ticket-related file operations.
  • Chores

    • Updated Helm and callcenter application submodule references.
    • Enhanced file service configuration to support flexible URL handling.

@nomerdvadcatpyat nomerdvadcatpyat added the ✋🙂 Review please Comments are resolved, take a look, please label Apr 10, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

Updates submodule references and introduces GraphQL mutations for creating ticket and comment files with client-side file upload integration. Generates corresponding Apollo hooks and types. Modifies file service URL configuration to derive baseUrl from FILE_SERVICE_URL.

Changes

Cohort / File(s) Summary
Submodule Updates
.helm, apps/callcenter
Updated subproject commit references to newer versions.
GraphQL Mutations
apps/condo/domains/ticket/queries/TicketCommentFile.graphql, apps/condo/domains/ticket/queries/TicketFile.graphql
Added createTicketCommentFile and createTicketFile mutations that accept file creation input and return created entity with associated file metadata.
Generated GraphQL Definitions
apps/condo/gql/index.ts, apps/condo/gql/operation.types.ts
Generated Apollo mutation documents, React hooks, and TypeScript types for both CreateTicketCommentFile and CreateTicketFile mutations.
Client-Side File Upload Hooks
apps/condo/domains/ticket/utils/clientSchema/TicketCommentFile.ts, apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts
Added custom useCreate hooks that handle file upload before mutation execution, transforming native File/UploadFile objects into signed file objects with signature, originalFilename, and mimetype.
File Service Configuration
packages/keystone/fields/CustomFile/Implementation.js, packages/keystone/fileAdapter/fileAdapter.js
Updated fileClientId derivation from JWT signature and modified URL construction to use FILE_SERVICE_URL with fallback to SERVER_URL.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client Application
    participant FileUpload as File Upload Service
    participant GraphQL as GraphQL API
    participant DB as Database
    
    Client->>Client: User provides File/UploadFile object
    Client->>Client: Check if file has signature
    alt File lacks signature
        Client->>FileUpload: POST upload with file + metadata<br/>(userId, orgId, fingerprint)
        FileUpload->>FileUpload: Process and store file
        FileUpload-->>Client: Return signature + file metadata
        Client->>Client: Transform to {signature, originalFilename, mimetype}
    else File already has signature
        Client->>Client: Use existing file object
    end
    Client->>GraphQL: Mutation with transformed file<br/>+ dv, sender, attrs, data
    GraphQL->>DB: Create TicketFile/TicketCommentFile record<br/>with file signature reference
    DB-->>GraphQL: Return created entity with id,<br/>ticket/ticketComment refs, file metadata
    GraphQL-->>Client: Return mutation result
    Client->>Client: Execute onComplete callback
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hops of joy through files so fine,
Signatures dance and uploads align,
Comments and tickets now carry their treasures,
GraphQL mutations bring coding pleasures!
With hooks and with schemas, we upload with grace,
Files find their home in this wonderful place! 🎉

🚥 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 primary change: refactoring ticket and ticket comment components to use a new file API, which is reflected throughout the changeset with new GraphQL mutations, client hooks, and file upload handling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ 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 refactor/condo/DOMA-13068/use-new-file-api-in-tickets

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

🧹 Nitpick comments (2)
apps/condo/domains/ticket/utils/clientSchema/TicketCommentFile.ts (1)

59-67: Consider handling undefined signature from upload result.

Same as TicketFile.ts - if the upload completes but doesn't return a signature, the code silently continues with the original file object.

♻️ Proposed improvement
 const signature = uploadResult.files?.[0]?.signature
-if (signature) {
-    fileField = {
-        signature,
-        originalFilename: maybeFile.name,
-        mimetype: maybeFile.type,
-    }
+if (!signature) {
+    throw new Error('Upload succeeded but no signature was returned')
 }
+fileField = {
+    signature,
+    originalFilename: maybeFile.name,
+    mimetype: maybeFile.type,
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/condo/domains/ticket/utils/clientSchema/TicketCommentFile.ts` around
lines 59 - 67, The uploadResult.files?.[0]?.signature can be undefined and
currently the code only sets fileField when signature exists; update the block
in TicketCommentFile.ts to handle a missing signature the same way as
TicketFile.ts does: check uploadResult and files[0].signature, and if signature
is missing, fall back to using the original file metadata (maybeFile.name,
maybeFile.type) or explicitly assign a safe fileField shape (and/or log the
missing signature) so downstream code doesn't silently rely on an undefined
signature; reference the variables uploadResult, signature, fileField and
maybeFile when making the change.
apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts (1)

59-67: Consider handling undefined signature from upload result.

If the upload request completes but uploadResult.files?.[0]?.signature is undefined, the code continues with the original File object which won't serialize correctly for the GraphQL mutation. Consider adding explicit error handling for this edge case.

♻️ Proposed improvement
 const signature = uploadResult.files?.[0]?.signature
-if (signature) {
-    fileField = {
-        signature,
-        originalFilename: maybeFile.name,
-        mimetype: maybeFile.type,
-    }
+if (!signature) {
+    throw new Error('Upload succeeded but no signature was returned')
 }
+fileField = {
+    signature,
+    originalFilename: maybeFile.name,
+    mimetype: maybeFile.type,
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts` around lines 59 -
67, The code currently assumes uploadResult.files?.[0]?.signature exists; update
the block that sets fileField (the code referencing uploadResult, signature,
fileField and maybeFile) to explicitly handle the undefined signature case: if
uploadResult.files?.[0]?.signature is undefined, either throw a descriptive
Error or return a rejected result (including uploadResult metadata) so the
GraphQL mutation never receives the raw File object; ensure the error path logs
or surfaces a clear message like "File upload succeeded but returned no
signature" and avoid falling back to the original maybeFile for serialization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts`:
- Line 30: The code in TicketFile.ts only extracts fileClientId from getConfig()
but must also extract condoDomain like TicketCommentFile.ts; update the
destructuring of getConfig() to include condoDomain (e.g., const {
publicRuntimeConfig: { fileClientId, condoDomain } = {} } = getConfig()) and
then pass condoDomain as the serverUrl argument to the upload call that uses
fileClientId (locate the upload invocation in TicketFile.ts and ensure
serverUrl: condoDomain is provided so files are uploaded to the correct server).
- Around line 48-57: The uploadFiles call in TicketFile.ts is missing the
serverUrl parameter, so uploads may target the wrong endpoint; update the call
to pass the same serverUrl used in TicketCommentFile (e.g., serverUrl variable
or config value) alongside files and meta so uploadFiles({ files: [maybeFile as
File], serverUrl, meta: buildMeta({ userId: user.id, fileClientId, modelNames:
['TicketFile'], fingerprint: sender.fingerprint, organizationId:
organization?.id }) }); ensure you reference the uploadFiles invocation and
buildMeta usage in TicketFile.ts and mirror how serverUrl is supplied in
TicketCommentFile.ts.

---

Nitpick comments:
In `@apps/condo/domains/ticket/utils/clientSchema/TicketCommentFile.ts`:
- Around line 59-67: The uploadResult.files?.[0]?.signature can be undefined and
currently the code only sets fileField when signature exists; update the block
in TicketCommentFile.ts to handle a missing signature the same way as
TicketFile.ts does: check uploadResult and files[0].signature, and if signature
is missing, fall back to using the original file metadata (maybeFile.name,
maybeFile.type) or explicitly assign a safe fileField shape (and/or log the
missing signature) so downstream code doesn't silently rely on an undefined
signature; reference the variables uploadResult, signature, fileField and
maybeFile when making the change.

In `@apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts`:
- Around line 59-67: The code currently assumes
uploadResult.files?.[0]?.signature exists; update the block that sets fileField
(the code referencing uploadResult, signature, fileField and maybeFile) to
explicitly handle the undefined signature case: if
uploadResult.files?.[0]?.signature is undefined, either throw a descriptive
Error or return a rejected result (including uploadResult metadata) so the
GraphQL mutation never receives the raw File object; ensure the error path logs
or surfaces a clear message like "File upload succeeded but returned no
signature" and avoid falling back to the original maybeFile for serialization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 50fa2133-a8a3-4597-baad-3cb17dd72615

📥 Commits

Reviewing files that changed from the base of the PR and between af4016f and 8cc2532.

📒 Files selected for processing (10)
  • .helm
  • apps/callcenter
  • apps/condo/domains/ticket/queries/TicketCommentFile.graphql
  • apps/condo/domains/ticket/queries/TicketFile.graphql
  • apps/condo/domains/ticket/utils/clientSchema/TicketCommentFile.ts
  • apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts
  • apps/condo/gql/index.ts
  • apps/condo/gql/operation.types.ts
  • packages/keystone/fields/CustomFile/Implementation.js
  • packages/keystone/fileAdapter/fileAdapter.js

useSoftDelete,
} = generateReactHooks<TicketFile, TicketFileCreateInput, TicketFileUpdateInput, QueryAllTicketFilesArgs>(TicketFileGQL)

const { publicRuntimeConfig: { fileClientId } = {} } = getConfig()
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.

⚠️ Potential issue | 🟠 Major

Missing condoDomain extraction - inconsistent with TicketCommentFile.ts.

This file only extracts fileClientId but TicketCommentFile.ts extracts both fileClientId and condoDomain. The condoDomain is used as serverUrl in the upload call to ensure files are uploaded to the correct server.

🐛 Proposed fix
-const { publicRuntimeConfig: { fileClientId } = {} } = getConfig()
+const { publicRuntimeConfig: { fileClientId, condoDomain } = {} } = getConfig()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { publicRuntimeConfig: { fileClientId } = {} } = getConfig()
const { publicRuntimeConfig: { fileClientId, condoDomain } = {} } = getConfig()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts` at line 30, The
code in TicketFile.ts only extracts fileClientId from getConfig() but must also
extract condoDomain like TicketCommentFile.ts; update the destructuring of
getConfig() to include condoDomain (e.g., const { publicRuntimeConfig: {
fileClientId, condoDomain } = {} } = getConfig()) and then pass condoDomain as
the serverUrl argument to the upload call that uses fileClientId (locate the
upload invocation in TicketFile.ts and ensure serverUrl: condoDomain is provided
so files are uploaded to the correct server).

Comment on lines +48 to +57
const uploadResult = await uploadFiles({
files: [maybeFile as File],
meta: buildMeta({
userId: user.id,
fileClientId,
modelNames: ['TicketFile'],
fingerprint: sender.fingerprint,
organizationId: organization?.id,
}),
})
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.

⚠️ Potential issue | 🟠 Major

Missing serverUrl parameter in upload call.

The uploadFiles call is missing the serverUrl parameter, which is present in TicketCommentFile.ts. Without this, uploads may go to an incorrect or default server endpoint.

🐛 Proposed fix
 const uploadResult = await uploadFiles({
+    serverUrl: condoDomain,
     files: [maybeFile as File],
     meta: buildMeta({
         userId: user.id,
         fileClientId,
         modelNames: ['TicketFile'],
         fingerprint: sender.fingerprint,
         organizationId: organization?.id,
     }),
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/condo/domains/ticket/utils/clientSchema/TicketFile.ts` around lines 48 -
57, The uploadFiles call in TicketFile.ts is missing the serverUrl parameter, so
uploads may target the wrong endpoint; update the call to pass the same
serverUrl used in TicketCommentFile (e.g., serverUrl variable or config value)
alongside files and meta so uploadFiles({ files: [maybeFile as File], serverUrl,
meta: buildMeta({ userId: user.id, fileClientId, modelNames: ['TicketFile'],
fingerprint: sender.fingerprint, organizationId: organization?.id }) }); ensure
you reference the uploadFiles invocation and buildMeta usage in TicketFile.ts
and mirror how serverUrl is supplied in TicketCommentFile.ts.

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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: 8cc25323b4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +48 to +49
const uploadResult = await uploadFiles({
files: [maybeFile as File],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use configured backend URL for ticket file upload

This new upload path calls uploadFiles without a serverUrl override, so the helper falls back to the browser origin. In deployments where the UI origin differs from the GraphQL/backend origin, ticket file uploads will be sent to the wrong host and fail (typically CORS/404) before createTicketFile runs. The previous GraphQL upload flow did not have this host-resolution issue for these environments.

Useful? React with 👍 / 👎.

useSoftDelete,
} = generateReactHooks<TicketCommentFile, TicketCommentFileCreateInput, TicketCommentFileUpdateInput, QueryAllTicketCommentFilesArgs>(TicketCommentFileGQL)

const { publicRuntimeConfig: { fileClientId, condoDomain } = {} } = getConfig()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace undefined runtime config key for comment uploads

The code reads condoDomain from publicRuntimeConfig, but this app exposes serverUrl (not condoDomain), so serverUrl: condoDomain is effectively undefined. That means comment uploads still resolve to window.location.origin, which breaks uploads whenever frontend and API are on different origins.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

@sitozzz sitozzz left a comment

Choose a reason for hiding this comment

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

looks good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✋🙂 Review please Comments are resolved, take a look, please

Development

Successfully merging this pull request may close these issues.

3 participants