Skip to content

Conversation

@BOHEUS
Copy link
Contributor

@BOHEUS BOHEUS commented Nov 9, 2025

  • update dependencies in mailchimp, stripe and last email interaction apps
  • fix logic in mailchimp integration, now it's triggered by update of People records and allows for update Mailchimp records
  • fix logic in stripe integration, now properly reads data from webhook
  • update READMEs to make it more understandable to non-technical users

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This PR updates three Hacktoberfest apps with dependency updates, logic fixes, and enhanced functionality for the Twenty CRM integration ecosystem.

Key Changes:

  • Updated twenty-sdk and axios dependencies across all three apps
  • Last Email Interaction: Refactored to extract helper functions, removed unnecessary delays, and fixed event property access from properties.receivedAt to properties.after.receivedAt
  • Mailchimp Synchronizer: Added update functionality (triggered by person.updated), introduced proper type definitions, and added UPDATE_PERSON environment variable to control update behavior
  • Stripe Synchronizer: Extended to handle both company and person entities, extracted types to separate file, improved webhook data reading from stripe.data.object structure, and added field creation for person objects
  • Updated READMEs across all apps for better clarity

Critical Issues Found:

  • API response structure bugs in last-email-interaction and stripe-synchronizer that will cause runtime failures
  • Inverted comparison logic in mailchimp-synchronizer causing updates when records are identical
  • Incorrect parameter passing in recursive pagination call
  • Wrong variable assignment preventing company ID propagation

Confidence Score: 1/5

  • This PR contains multiple critical logical errors that will cause runtime failures and prevent the apps from functioning correctly
  • The PR introduces 4 critical logic bugs that will cause runtime errors: incorrect API response path access, inverted comparison logic, wrong recursive parameter, and incorrect variable assignment. These bugs will prevent the apps from working as intended. While the overall architecture improvements and refactoring are good, the logical errors need to be fixed before merge.
  • All three main serverless function files require immediate attention: packages/twenty-apps/hacktoberfest-2025/last-email-interaction/serverlessFunctions/test/src/index.ts, packages/twenty-apps/hacktoberfest-2025/mailchimp-synchronizer/serverlessFunctions/mailchimp/src/index.ts, and packages/twenty-apps/hacktoberfest-2025/stripe-synchronizer/serverlessFunctions/stripe/src/index.ts

Important Files Changed

File Analysis

Filename Score Overview
packages/twenty-apps/hacktoberfest-2025/last-email-interaction/serverlessFunctions/test/src/index.ts 2/5 Refactored to extract helper functions and fix event property access, but contains critical API response structure bug
packages/twenty-apps/hacktoberfest-2025/mailchimp-synchronizer/serverlessFunctions/mailchimp/src/index.ts 1/5 Added update functionality and proper type definitions, but contains inverted comparison logic and incorrect cursor parameter in recursive call
packages/twenty-apps/hacktoberfest-2025/stripe-synchronizer/serverlessFunctions/stripe/src/index.ts 1/5 Added person entity handling and improved type safety, but contains incorrect status code check and wrong variable assignment
packages/twenty-apps/hacktoberfest-2025/stripe-synchronizer/serverlessFunctions/stripe/src/types.ts 4/5 New file extracting type definitions for better organization, though uses enum contrary to style guidelines

Sequence Diagram

sequenceDiagram
    participant User
    participant TwentyDB as Twenty Database
    participant LastEmailApp as Last Email Interaction App
    participant MailchimpApp as Mailchimp Synchronizer
    participant StripeApp as Stripe Synchronizer
    participant Mailchimp as Mailchimp API
    participant Stripe as Stripe API

    Note over TwentyDB,MailchimpApp: Message Interaction Flow
    User->>TwentyDB: Create/Update Message
    TwentyDB->>LastEmailApp: Trigger message.created/updated event
    LastEmailApp->>TwentyDB: Check if custom fields exist
    alt Fields don't exist
        LastEmailApp->>TwentyDB: Create lastInteraction and interactionStatus fields
    end
    LastEmailApp->>TwentyDB: Get message details with participants
    LastEmailApp->>TwentyDB: Fetch related people IDs
    LastEmailApp->>TwentyDB: Fetch related company IDs for each person
    LastEmailApp->>TwentyDB: Update people records with interaction data
    LastEmailApp->>TwentyDB: Update company records with interaction data

    Note over TwentyDB,Mailchimp: Person to Mailchimp Sync Flow
    User->>TwentyDB: Update Person Record
    TwentyDB->>MailchimpApp: Trigger person.updated event
    MailchimpApp->>TwentyDB: Fetch company data (if required)
    MailchimpApp->>Mailchimp: Check if person exists in Mailchimp
    alt Person exists in Mailchimp
        MailchimpApp->>MailchimpApp: Compare records
        alt Records differ and UPDATE_PERSON=true
            MailchimpApp->>Mailchimp: Update person in Mailchimp
        end
    else Person doesn't exist
        MailchimpApp->>Mailchimp: Add new person to Mailchimp
    end

    Note over Stripe,TwentyDB: Stripe Subscription Sync Flow
    Stripe->>StripeApp: Webhook: subscription.created/updated
    StripeApp->>Stripe: Get customer data
    StripeApp->>TwentyDB: Check if custom fields exist
    alt Fields don't exist
        StripeApp->>TwentyDB: Create seats and subStatus fields
    end
    StripeApp->>TwentyDB: Check if company exists by business name
    alt Company doesn't exist
        StripeApp->>TwentyDB: Create company with subscription data
    else Company exists
        StripeApp->>TwentyDB: Update company with subscription data
    end
    StripeApp->>TwentyDB: Check if person exists by email
    alt Person doesn't exist
        StripeApp->>TwentyDB: Create person linked to company
    else Person exists
        StripeApp->>TwentyDB: Update person with subscription data
    end
Loading

14 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@martmull martmull left a comment

Choose a reason for hiding this comment

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

Nice changes thank you, some comments but not blocking

Comment on lines +3 to +37
type stripeItem = {
quantity: number;
};

type stripeItemsData = {
data: stripeItem[];
};

type stripeEventObject = {
customer: string;
items: stripeItemsData;
status: stripeStatus;
quantity: number | null;
};

type stripeEventData = {
object: stripeEventObject;
};

export type stripeEvent = {
data: stripeEventData;
type: string;
};

export type stripeCustomer = {
businessName?: string;
name: string | null;
email: string | null;
};

export type twentyObject = {
id: string;
nameSingular: string;
fields: Record<string, any>[];
}; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

you can probably export that from stripe sdk

## Todo
- add validation of signature key from Stripe to ensure that incoming request is valid
- add validation of signature key from Stripe to ensure that incoming request is valid
(possible once request headers are exposed to serverless functions)
Copy link
Contributor

Choose a reason for hiding this comment

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

duly noted ^^

Comment on lines +230 to +250
const checkIfStripePersonExistsInTwenty = async (email: string | null) => {
const options = {
method: 'GET',
headers: {
Authorization: `Bearer ${TWENTY_API_KEY}`,
'Content-Type': 'application/json',
},
url: `${TWENTY_API_URL}/people?filter=emails.primaryEmail%5Beq%5D%3A%22${email}%22`, // mail is unique by default so there can be only 1 person with given mail
};
try {
const response = await axios.request(options);
return response.status === 200 &&
response.data.data.people[0].id !== undefined
? (response.data.data.people[0].id as string)
: '';
} catch (error) {
if (axios.isAxiosError(error)) {
throw error;
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

would be easier to use the Stripe node sdk I guess -> https://github.com/stripe/stripe-node

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Stripe library will be used once headers are exposed to validate the webhook signature, I try to keep apps minimalistic as much as it's possible

@martmull martmull merged commit ae2d399 into twentyhq:main Nov 10, 2025
40 checks passed
@github-actions
Copy link
Contributor

Thanks @BOHEUS for your contribution!
This marks your 38th PR on the repo. You're top 2% of all our contributors 🎉
See contributor page - Share on LinkedIn - Share on Twitter

Contributions

NotYen pushed a commit to NotYen/twenty-ym that referenced this pull request Nov 10, 2025
- update dependencies in mailchimp, stripe and last email interaction
apps
- fix logic in mailchimp integration, now it's triggered by update of
People records and allows for update Mailchimp records
- fix logic in stripe integration, now properly reads data from webhook
- update READMEs to make it more understandable to non-technical users
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