Skip to content

feature/adding ticket creation in Zendesk integration#557

Merged
lukasz-hycom merged 61 commits intomainfrom
feature/adding-createTicket-form
Jan 29, 2026
Merged

feature/adding ticket creation in Zendesk integration#557
lukasz-hycom merged 61 commits intomainfrom
feature/adding-createTicket-form

Conversation

@lukasz-hycom
Copy link
Copy Markdown
Contributor

@lukasz-hycom lukasz-hycom commented Jan 21, 2026

What does this PR do?

  • added ticket creation in Zendesk integration
  • supported file upload
  • handling new submit destination in Survey.js module

Key Changes

  • Added ticket creation via Survey.js forms: Forms with submitDestination: ['tickets'] submit data to the ticket service and create tickets in Zendesk, including file attachments.

Summary by CodeRabbit

  • New Features

    • Zendesk ticket creation via POST /tickets (attachments & custom fields)
    • Surveys can be submitted directly as support tickets
  • Enhancements

    • Ticket list/details show Ticket ID, case type (topic), status, last-updated and mapped custom fields
    • Ticket type made optional; improved consent and attachment handling
    • Field mapping configurable via environment-driven mappings
  • Documentation

    • Expanded Zendesk setup, usage, and field-mapping guides; updated SurveyJS docs

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

@vercel
Copy link
Copy Markdown

vercel Bot commented Jan 21, 2026

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

1 Skipped Deployment
Project Deployment Review Updated (UTC)
o2s-docs Skipped Skipped Jan 28, 2026 6:09pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 21, 2026

Walkthrough

Adds end-to-end Zendesk ticket creation (attachments, custom-field mapping), SurveyJS → tickets submission path, makes ticket.type optional across models/UI, updates CMS mappers/mocks to Zendesk fields, expands Zendesk env config, and enforces changeset checks in CI.

Changes

Cohort / File(s) Summary
Zendesk service & mappers
packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.service.ts, packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.mapper.ts, packages/integrations/zendesk/src/modules/tickets/zendesk-field.mapper.ts
Implements full createTicket flow (HttpService-based), user resolution, parallel attachment uploads, env-driven custom-field mapping, topic derivation, expanded error handling, and new helper exports.
SurveyJS integration
packages/modules/surveyjs/src/.../surveyjs.service.ts, .../surveyjs.mapper.ts, .../surveyjs.controller.ts, .../surveyjs.module.ts, packages/modules/surveyjs/src/sdk/surveyjs.ts
Adds mapSurveyToTicket, wires Tickets.Service into module/service, adds submitToTickets path for 'tickets' destination, and updates SDK/controller/module to route survey submissions to tickets.
Framework ticket API & models
packages/framework/src/modules/tickets/tickets.request.ts, packages/framework/src/modules/tickets/tickets.model.ts
Extends PostTicketBody with type, attachments, fields; makes Ticket.type optional; adjusts GetTicketListQuery types.
Blocks: list/recent/details changes
packages/blocks/ticket-list/..., packages/blocks/ticket-recent/..., packages/blocks/ticket-details/...
Makes ticket.type optional in models and mappers; updates UI to conditionally render type and ticketId, adjusts property mapping to use fieldMapping translations.
CMS mappers & mocks
packages/integrations/contentful-cms/.../cms.ticket-details.mapper.ts, packages/integrations/mocked/.../cms.ticket-details.mapper.ts, packages/integrations/mocked/.../tickets.mocks.ts, packages/integrations/mocked/.../cms.ticket-list.mapper.ts
Replaces topic/type with expanded Zendesk custom-field set across locales; updates mocks and generators to remove type and restrict topics to CONTACT_US/REQUEST_DEVICE_MAINTENANCE/COMPLAINT.
FieldMapping typing & labels
packages/framework/src/modules/cms/models/blocks/ticket-details.model.ts, packages/framework/src/modules/cms/models/blocks/ticket-list.model.ts, packages/integrations/strapi-cms/src/.../cms.fieldMapping.mapper.ts
Expands fieldMapping types to allow nested per-field mappings; adds optional ticketId label fields in models and mappers.
Product & Recommended blocks (server)
packages/blocks/product-details/src/frontend/ProductDetails.server.tsx, packages/blocks/recommended-products/src/frontend/RecommendedProducts.server.tsx
Refactors data fetching to assign data inside try and render after try/catch (single return path); returns null on fetch error.
Env/config & package changes
apps/api-harmonization/package.json, apps/api-harmonization/turbo.json, packages/integrations/zendesk/turbo.json
Adds @types/multer and expands turbo env arrays with many ZENDESK_*_FIELD_ID and form ID variables.
CI/CD: changeset enforcement
.github/actions/changed-packages/action.yaml, .github/workflows/pull-request.yaml, .github/CI_CD_README.md
Adds requires_changeset output and detection step, new check-changeset job validating .changeset files when core packages change, and updates docs/workflow wiring.
Docs & changelog
apps/docs/docs/integrations/tickets/zendesk/*, apps/docs/docs/integrations/forms/surveyjs/*, apps/docs/docs/main-components/.../core-model-tickets.md, .changeset/*
Adds docs for ticket creation API, field mappings, env setup, SurveyJS ticket usage, updates core model docs, and includes a changeset for the release.
Minor server/client & tests
packages/blocks/.../RecommendedProducts.server.tsx, packages/blocks/.../ProductDetails.server.tsx, packages/blocks/ticket-list/src/api-harmonization/ticket-list.mapper.spec.ts
Refactors server fetch return paths; updates tests to tolerate undefined ticket.type.

Sequence Diagram

sequenceDiagram
    actor User
    participant SurveyUI as SurveyJS Form
    participant API as SurveyJS Controller
    participant Mapper as mapSurveyToTicket
    participant Service as SurveyJS Service
    participant TicketsSvc as Zendesk TicketService
    participant Zendesk as Zendesk API

    User->>SurveyUI: submit survey
    SurveyUI->>API: POST /surveys/submit
    API->>Mapper: mapSurveyToTicket(payload)
    Mapper-->>API: PostTicketBody
    API->>Service: submitSurvey(body, auth)
    Service->>Service: validate & route to 'tickets'
    Service->>TicketsSvc: createTicket(mappedData, auth)
    TicketsSvc->>TicketsSvc: find or create requester
    TicketsSvc->>Zendesk: upload attachments (parallel)
    TicketsSvc->>Zendesk: create ticket with custom fields
    Zendesk-->>TicketsSvc: ticket created
    TicketsSvc-->>Service: success
    Service-->>API: success response
    API-->>User: 200 OK
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • marcinkrasowski

Poem

🐰 I hop through code with tiny feet,

Surveys become tickets—neat!
Fields mapped by env and art,
Attachments fly and play their part.
Optional type, a lighter heart. 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning PR description is incomplete and lacks key required sections from the template including Related Tickets and How to test. Add missing sections: provide a related ticket/issue reference, explain detailed setup instructions and step-by-step testing procedures, and describe any side effects from the extensive changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding ticket creation functionality to the Zendesk integration, which is the primary objective of this PR.

✏️ 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
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: 9

Caution

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

⚠️ Outside diff range comments (1)
packages/modules/surveyjs/src/api-harmonization/surveyjs.module.ts (1)

6-32: Fix missing @Optional() on Tickets.Service injection.

Line 28 of surveyjs.service.ts injects Tickets.Service as a required dependency without @Optional(), but the provider is only registered when config.integrations.tickets?.service exists (lines 19–24 of surveyjs.module.ts). When the tickets integration is disabled, Nest will fail during bootstrap because it cannot resolve this required dependency. Add @Optional() to the ticketsService parameter or provide a fallback implementation.

🤖 Fix all issues with AI agents
In `@packages/framework/src/modules/tickets/tickets.request.ts`:
- Around line 9-21: TicketAttachmentInput currently exposes content as a Node
Buffer which breaks browser SDK JSON serialization; change
TicketAttachmentInput.content to a base64 string (e.g., content: string) and
update any code that constructs PostTicketBody so attachments provide
base64-encoded content, or alternatively implement a serializer/SDK interceptor
in sdk.ts that converts Buffer → base64 before calling createTicket/ofetch; also
audit and update all createTicket call sites to always supply topic on
PostTicketBody to avoid 4xx validation errors, and if you must keep Buffer in
server-only APIs, document the need for a Buffer polyfill (e.g., npm buffer) for
browser consumers.

In
`@packages/integrations/contentful-cms/src/modules/cms/mappers/cms.page.mapper.ts`:
- Around line 224-229: getAllPages and getAlternativePages are missing the new
create-ticket page constants even though mapMockPage now maps '/create-ticket'
variants; update both functions to include PAGE_CREATE_TICKET_EN,
PAGE_CREATE_TICKET_DE, and PAGE_CREATE_TICKET_PL in their returned lists (and
any locale-alternative mapping arrays) so the create-ticket routes appear in
page listings and locale switching logic referenced by mapMockPage.

In `@packages/integrations/mocked/src/modules/cms/mappers/cms.page.mapper.ts`:
- Around line 245-250: getAllPages and getAlternativePages are missing the
create-ticket page constants even though mapPage handles '/create-ticket'
(PAGE_CREATE_TICKET_EN, PAGE_CREATE_TICKET_DE, PAGE_CREATE_TICKET_PL); update
both functions to include these three constants in their returned lists so
listing and locale switching work for the create-ticket routes, ensuring you add
PAGE_CREATE_TICKET_EN/DE/PL to the same arrays/enum usages where other page
constants are listed.

In `@packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.service.ts`:
- Around line 407-416: The upload URL is duplicating /api/v2 because
this.baseUrl already contains the API suffix; update the uploadAttachment method
to build the uploadUrl without re-adding /api/v2 (use this.baseUrl +
'/uploads?filename=...' or otherwise normalize/remove trailing/leading slashes)
so the final URL is .../api/v2/uploads only once; ensure
encodeURIComponent(filename) is still used and preserve the existing
Authorization and Content-Type headers in uploadAttachment.
- Around line 255-289: The current enrichment pipeline (fetchTicketComments ->
fetchUser -> mapTicketToModel) can throw in the catchError and cause the whole
operation to fail after the ticket is created; change it to be best‑effort by
catching enrichment errors and returning the created ticket instead of
rethrowing: inside the observable chain around
fetchTicketComments/firstValueFrom(fetchUser)/mapTicketToModel and in the
catchError block, replace the throwError with code that logs the enrichment
error (or records it) and returns of(mapTicketToModel(createdTicket, comments)
or simply of(createdTicket) as a safe fallback; also ensure individual author
fetch failures are tolerated (filter undefined authors already exists) so the
overall flow always emits the createdTicket model even when enrichment fails.
- Around line 376-394: The current findZendeskUserByEmail silently swallows
API/network errors by returning of(undefined) in the catchError, which must
instead propagate real failures while still returning undefined for "no user
found" cases; update the catchError after the map to rethrow the original error
(use throwError(() => err) or equivalent) so searchUsers errors bubble up, and
keep the existing map logic that returns undefined when users array has no exact
match—refer to the findZendeskUserByEmail function and its catchError/map around
the searchUsers call.

In `@packages/modules/surveyjs/src/api-harmonization/surveyjs.service.ts`:
- Around line 181-188: The code currently builds ticketData
(Tickets.Request.PostTicketBody) by defaulting required fields title,
description, and topic to empty strings from surveyData which can create
invalid/low-quality tickets; update the logic around the ticket creation (where
ticketData is constructed) to validate that surveyData.title,
surveyData.description, and surveyData.topic are present and non-empty before
constructing/posting the ticket (e.g., return or throw a validation error if any
required field is missing), remove the empty-string fallbacks, and ensure any
callers of the function handling survey submissions (the code that uses
ticketData) properly handle the validation error so tickets are only created
when required fields are provided.

In `@packages/modules/surveyjs/src/frontend/Survey.tsx`:
- Around line 110-172: handleSubmit closes over the initial state.model (null)
so file field detection using state.model fails; fix by making handleSubmit
accept the current survey model as an explicit parameter (e.g.,
handleSubmit(data, model)) and use that model instead of reading state.model
inside handleSubmit (referencing state.model, handleSubmit, startTransition);
then update the completion/callback that invokes handleSubmit (the survey
onComplete/submit handler) to pass the up-to-date state.model into handleSubmit
so fileFieldNames detection uses the live model and multipart submission is used
when files exist.

In `@packages/modules/surveyjs/src/sdk/surveyjs.ts`:
- Around line 32-99: The multipart branch of submitSurvey serializes every field
with String(value), which corrupts arrays/objects; update submitSurvey (handling
inside the 'surveyPayload' branch and the else branch where Object.entries are
appended) to detect non-primitive values (e.g., Array.isArray(value) || (typeof
value === 'object' && value !== null)) and use JSON.stringify(value) for those,
while leaving strings, numbers and booleans appended as-is; keep file appends
for 'attachments' unchanged and keep headers logic and sdk.makeRequest usage
intact; also ensure this matches how mapSurveyJsRequest expects JSON-stringified
fields on the backend.
🧹 Nitpick comments (1)
packages/modules/surveyjs/src/api-harmonization/surveyjs.service.ts (1)

92-105: Multipart submissions to non-ticket destinations will fail.

If a multipart submission is made to a survey that doesn't have 'tickets' in submitDestination, the code falls through to line 103 which checks for 'surveyPayload' in payload. This check will fail for multipart form data, throwing a BadRequestException.

Consider adding explicit handling or a clearer error message for this case:

Suggested improvement
                // For multipart submissions with files going to tickets - handle directly
                if (isMultipartSubmission && survey.submitDestination.includes('tickets')) {
                    return this.handleMultipartTicketSubmission(
                        payload as Record<string, string>,
                        files,
                        authorization,
                    );
                }

+               // Multipart submissions are only supported for ticket destinations
+               if (isMultipartSubmission) {
+                   throw new BadRequestException('File uploads are only supported for ticket submissions');
+               }
+
                // For JSON submissions - validate payload format
                if (!('surveyPayload' in payload)) {
                    throw new BadRequestException('Invalid payload format for JSON submission');
                }

Comment thread packages/framework/src/modules/tickets/tickets.request.ts Outdated
Comment thread packages/integrations/contentful-cms/src/modules/cms/mappers/cms.page.mapper.ts Outdated
Comment thread packages/integrations/mocked/src/modules/cms/mappers/cms.page.mapper.ts Outdated
Comment thread packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.service.ts Outdated
Comment thread packages/modules/surveyjs/src/api-harmonization/surveyjs.service.ts Outdated
Comment thread packages/modules/surveyjs/src/frontend/Survey.tsx Outdated
Comment thread packages/modules/surveyjs/src/sdk/surveyjs.ts Outdated
@lukasz-hycom lukasz-hycom self-assigned this Jan 21, 2026
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 21, 2026 11:30 Inactive
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 21, 2026 11:53 Inactive
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 21, 2026 11:59 Inactive
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 21, 2026 12:03 Inactive
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 21, 2026 12:12 Inactive
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 28, 2026 16:15 Inactive
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

🤖 Fix all issues with AI agents
In
`@packages/integrations/contentful-cms/src/modules/cms/mappers/blocks/cms.ticket-details.mapper.ts`:
- Around line 35-77: Add localized mappings for the preferredContactMethod enum
wherever other field mappings exist (same blocks that contain inquiryType,
productCategory, maintenanceType) so raw Zendesk enum keys won't be shown to
users; update the preferredContactMethod entries in each language block's
mapping object (the same object that contains
inquiryType/productCategory/maintenanceType) and in the fieldMapping that
references properties.preferredContactMethod, providing human-readable localized
strings for each enum value (e.g., email/phone/whatsapp/other or your project's
enum keys) across all language sections mentioned.

In
`@packages/integrations/mocked/src/modules/cms/mappers/blocks/cms.ticket-details.mapper.ts`:
- Around line 35-77: The mapper cms.ticket-details.mapper.ts is missing
localized field mappings for the preferredContactMethod property, so the UI will
show raw enum values; update the fieldMapping (or add a new mapping object
alongside inquiryType/productCategory/etc.) to include localized labels for each
possible preferredContactMethod value (e.g., PHONE, EMAIL, SMS or whatever enum
keys exist) for the locale in this file, using the same pattern as
status/inquiryType/productCategory, or if preferredContactMethod is free-text,
add a comment on the preferredContactMethod entry in properties to indicate it's
free-text and leave out fieldMapping.

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

🤖 Fix all issues with AI agents
In `@packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.mapper.ts`:
- Around line 51-62: The code builds consentFieldIds and contactFormId using
Number(...) but only filters null, so NaN values slip through; update the
construction of consentFieldIds to convert env vars and filter out non-finite
numbers (e.g., use Number(...) and .filter((id): id is number =>
Number.isFinite(id))) and change contactFormId to produce undefined for invalid
or NaN values (e.g., const contactFormId =
Number(process.env.ZENDESK_CONTACT_FORM_ID); const contactFormIdValid =
Number.isFinite(contactFormId) ? contactFormId : undefined) and then use
contactFormIdValid in isContactUsForm (ticket.ticket_form_id ===
contactFormIdValid) so bogus env strings no longer cause mismatches.

@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 28, 2026 17:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – o2s-docs January 28, 2026 18:09 Inactive
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

🤖 Fix all issues with AI agents
In `@apps/docs/docs/integrations/forms/surveyjs/features.md`:
- Around line 158-165: Update the earlier "Form Submission" section to mention
ticket destinations alongside the SurveyJS backend: reference the
submitDestination configuration and note that submitDestination can include
'tickets' to route submissions into the framework's Tickets service (e.g.,
Zendesk), and list required fields description (string) and ticketFormId
(number) for ticket submissions so the two sections align with the SurveyJS
module's ticket-support behavior.

In
`@apps/docs/docs/main-components/harmonization-app/normalized-data-model/core-model-tickets.md`:
- Around line 119-125: Update the parameter table in core-model-tickets.md to
call out integration-specific required fields: keep 'description' and 'type'
marked optional in the core model but add a clear note (adjacent to the table or
as a footnote) stating that certain integrations (e.g., Zendesk, SurveyJS)
require these fields; reference the exact parameter names 'description' and
'type' and, optionally, list affected integrations to prevent confusion for
implementers.
🧹 Nitpick comments (2)
apps/docs/docs/integrations/tickets/zendesk/features.md (1)

186-228: Clarify user-facing error semantics.
Consider describing the failure as HTTP 400 rather than the framework exception class name to keep the docs API-centric.

💡 Suggested wording tweak
- **Important**: If the `type` doesn't match any configured form ID, the ticket creation will fail with a `BadRequestException`. This ensures that all tickets are properly categorized.
+ **Important**: If the `type` doesn't match any configured form ID, ticket creation fails with HTTP 400 (bad request). This ensures that all tickets are properly categorized.
apps/docs/docs/integrations/tickets/zendesk/usage.md (1)

152-207: Clarify request vs. response type semantics.
The request uses a numeric form ID, but the example response shows a normalized string type. Add a short note to avoid confusion.

📝 Suggested addition
 **Example Response:**
+
+> Note: The response `type` is the normalized ticket type, not the numeric form ID provided in the request.
 
 ```json
 {

Comment thread apps/docs/docs/integrations/forms/surveyjs/features.md
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: 1

🤖 Fix all issues with AI agents
In @.changeset/cuddly-teams-flash.md:
- Line 15: The changeset summary sentence is incomplete; update the final clause
in .changeset/cuddly-teams-flash.md to finish the thought and be specific about
which CMS mapper mocks were changed (e.g., "Updated mapper mocks in cms:
[name-of-cms]-mapper and [other-cms]-mapper" or similar), ensuring the sentence
reads as a complete, grammatically correct release note and lists the exact
mapper names updated.

Comment thread .changeset/cuddly-teams-flash.md
@lukasz-hycom lukasz-hycom changed the title feature/adding create-ticket form feature/adding ticket creation in Zendesk integration Jan 29, 2026
@lukasz-hycom lukasz-hycom merged commit 1a5a22d into main Jan 29, 2026
10 checks passed
@lukasz-hycom lukasz-hycom deleted the feature/adding-createTicket-form branch January 29, 2026 09:55
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