Skip to content

EFIAL-458-config/dependencies and EFIAL-459-partner-sync#76

Open
rtavernaea wants to merge 35 commits into
developmentfrom
EDFIAL-458
Open

EFIAL-458-config/dependencies and EFIAL-459-partner-sync#76
rtavernaea wants to merge 35 commits into
developmentfrom
EDFIAL-458

Conversation

@rtavernaea

@rtavernaea rtavernaea commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

This PR addresses EDFIAL-458 and EDFIAL-459.

EDFIAL-458:

  • Add config for UM & Tx sync
    • Texas specific secret & TX_SYNC_CRON
      • I think both syncs could potentially end up using the same SYNC_CRON value but kept them separate for now
  • PartnerSyncCoordinator handles scheduling and kicking off each sync based on what config values are available.
    • Right now it goes through all of the possible handlers each time the app starts up. Alternatively it could check the db first for only sync handlers that are currently implemented. This might be more efficient but would mean we have to add an initial partner to register the sync method.

EDFIAL-459:

Both syncs share the same pg-boss connection

  • user_management_sync
    • Mirrors exsiting connection and transactions from Podium sync
    • No children/metatenancy for now
    • Partners not sync-managed (i.e., sync_managed: null) are left alone by the sync
  • tx_sync
    • Empty for now. Need to land on the best approach for this between options laid out in EDFIAL-460

@rtavernaea rtavernaea changed the title Edfial 458 EFIAL-458-config/dependencies and EFIAL-459-partner-sync Jun 18, 2026
@rtavernaea rtavernaea marked this pull request as ready for review June 25, 2026 17:49
@rtavernaea rtavernaea requested a review from edandylytics June 25, 2026 18:03

@edandylytics edandylytics left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Still taking it in and need to try it out. Overall, it's looking pretty good -- just a few early thoughts in the comments.

One scope update; let's hold off on including any of the TX config or other components until we're building that piece. The enum value is fine, but it's hard to tell whether the rest is correct until we're actually building the TX sync

const partnerIdsToDelete: string[] = [];
const partnerIdsToUndelete: string[] = [];

if (partnersResult.status === 'success') {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should stop early if the partner request fails. Continuing to sync tenants is probably fine, but I find it difficult to reason about its correctness.

}

for (const partner of existingPartners) {
if (!!partner.managedBy && !partner.deletedOn && !apiPartnerCodes.has(partner.id)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Where do we check that the partner we're deleting is managed by this specific sync? E.g. TX doesn't delete UM partners and vice verse?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oh right, I wasn't thinking of that but I guess we need it because there is a tx partner in UM?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yep -- TX being in the UM results is a clearer case than the one I mentioned. Here's how I think about it: It's Runway's job to determine which partners each sync manages. Runway shouldn't trust external systems to say which partners it can update. That means we need to ensure that it's Runway's internal state (partner.magagedBy) that scopes the sync, not what the external systems report.

return;
}

const tenantMap: Map<string, GetTenantDto> = tenantsByPartner.get(partnerId) ?? new Map();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can this be Tenant instead of GetTenantDto? Looks like it holds tenants from Prisma, not tenant DTOs. They're mostly the same shape today, but we could update the DTO in a way that'd break this

@snyk-io-us

snyk-io-us Bot commented Jun 26, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@edandylytics edandylytics left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A couple more comments.

const url = this.get('UM_URL');
const auth0Domain = this.get('UM_AUTH0_DOMAIN');
const clientId = this.get('UM_CLIENT_ID');
const clientSecret = this.get('UM_CLIENT_SECRET');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Deployed environments will need to look up credentials in an AWS secret. You can check out other methods on this service for how to use a secret and fall back to env vars if a secret doesn't exist. postgresPoolConfig is a good example.

}

for (const partner of existingPartners) {
if (!!partner.managedBy && !partner.deletedOn && !apiPartnerCodes.has(partner.id)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yep -- TX being in the UM results is a clearer case than the one I mentioned. Here's how I think about it: It's Runway's job to determine which partners each sync manages. Runway shouldn't trust external systems to say which partners it can update. That means we need to ensure that it's Runway's internal state (partner.magagedBy) that scopes the sync, not what the external systems report.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should probably refactor away from this coordinator class. It looks like it does two things:

  1. Initialize PgBoss and manage its lifecycle
  2. Start up the sync

For PgBoss, I expect we'll be using that in other places in the app soon and it'd be helpful to have that as it's own injectable component that can be shared.

Once you remove the PgBoss initialization, do we need a coordinator? It seems each sync service could start itself in its own OnModuleInit. Then we don't need the getSyncConfig wrapper either.

Let me know if I'm missing something there, though.

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