Executive Summary
As CONA scales to support 100+ e-commerce and payment integrations, we need a more maintainable architecture. This RFC proposes an Adapter Pattern that separates integration-specific transformation logic from shared workflow orchestration, reducing code duplication while preserving the unique business logic each integration requires. Key Goals:- Reduce time-to-implement new integrations from ~2 weeks to ~2-3 days
- Minimize code duplication across similar integration workflows
- Maintain flexibility for integrations with unique business logic (Shopify refunds, PayPal fees, Amazon settlements)
- Provide clear contracts for integration developers
- Enable easier testing and maintenance
- Establish a fixture-based approach for test data and schema discovery
- Forcing all integrations into a single generic workflow
- Removing integration-specific business logic
- Breaking existing integrations during migration
Problem Statement
Current Architecture
Each integration currently has its own complete Temporal workflow:Problems at Scale
| Problem | Impact |
|---|---|
| Code duplication | Same patterns (dedupe, number allocation, accounting) reimplemented per integration |
| Inconsistent patterns | Different approaches to error handling, progress tracking, continue-as-new |
| High onboarding cost | New integrations require understanding entire workflow structure |
| Maintenance burden | Bug fixes or improvements need replication across all workflows |
| Testing complexity | Each 1000+ line workflow needs comprehensive test coverage |
Integration Complexity Matrix
Each integration has unique requirements that cannot be abstracted away:| Integration | Unique Business Logic |
|---|---|
| Shopify Orders | Creates Sales Order + Invoice + Credit Note per order; Credit notes link back to invoices; Refunds update open amounts on original sales orders |
| Shopify Payments | Creates payment + fee documents; Links payments to orders via gateway transaction ID |
| PayPal | Creates 2 documents per transaction (payment + fee); Working Capital Loan detection; CSV and API dual-mode support |
| Amazon Orders | VAT Tax Report parsing; B2B customer detection; Multiple line item types (shipping, promo, gift wrap); NET vs GROSS price handling |
| Amazon Settlements | Settlement as virtual bank account; Multiple transaction types (Principal, Tax, Commission, FBA fees); Payout tracking; Reconciliation via Order ID |
Proposed Solution: Integration Adapter Pattern
Core Concept
An adapter is a translator that converts data from one format (Shopify, PayPal, Amazon) into a common format (CONA documents). It separates:- “What data to transform” → Integration Adapter (unique per integration)
- “How to process documents” → Generic Workflow Orchestrator (shared)
Adapter Interface
Example: Shopify Orders Adapter
Example: PayPal Payments Adapter
Generic Workflow Orchestrator
Directory Structure
Migration Strategy
Phase 1: Define Adapter Interface (Week 1)
- Create
packages/temporal-workflows/src/adapters/types.ts - Create adapter registry
- No changes to existing workflows
Phase 2: Extract PayPal Adapter (Week 2)
- Create
paypal-payments-adapter.ts - PayPal is simplest (no refund tracking, no document connections)
- Run both old workflow and new adapter-based workflow in parallel
- Compare outputs for parity
Phase 3: Extract Shopify Orders Adapter (Weeks 3-4)
- Create
shopify-orders-adapter.ts - Reuse existing helper functions (no rewrite needed)
- Handle unique Shopify logic (refunds, connections) in
postProcess - Validate with real Shopify data
Phase 4: Extract Amazon Orders Adapter (Week 5)
- Create
amazon-orders-adapter.ts - Amazon Settlements stays as custom workflow (too unique)
Phase 5: New Integrations Use Adapter Pattern (Ongoing)
- Etsy, WooCommerce, Stripe → implement adapter only
- Estimated: 2-3 days per integration
Phase 6: Deprecate Old Workflows (After Validation)
- Mark old workflows as deprecated
- Eventually remove after 3+ months of adapter stability
Trade-offs & Risks
Benefits
| Benefit | Impact |
|---|---|
| Faster new integrations | 2 weeks → 2-3 days |
| Code reduction | ~1500 lines/integration → ~300 lines |
| Single fix, all integrations | Bug in dedupe logic? Fix once |
| Clear contracts | New developers know exactly what to implement |
| Testable | Adapters are pure functions, easy to unit test |
Risks & Mitigations
| Risk | Mitigation |
|---|---|
| Generic workflow doesn’t fit edge case | Adapters can use custom workflows via registry |
| Migration introduces bugs | Run old/new in parallel, compare outputs |
| Team learning curve | Document pattern thoroughly, provide examples |
| Over-abstraction | Only add features to interface when 2+ integrations need them |
When NOT to Use an Adapter
Some integrations are too unique for the generic workflow:- Amazon Settlements - Settlement as virtual bank, complex payout tracking
- QuickBooks Sync - Two-way sync with conflict resolution
- Bank statement reconciliation - Fundamentally different flow
Success Metrics
| Metric | Current | Target |
|---|---|---|
| Lines of code per integration | ~1,500 | ~300 |
| Time to implement new integration | 2 weeks | 2-3 days |
| Shared code coverage | ~40% | ~80% |
| Unique code per integration | ~60% | ~20% |
Test Data & Schema Discovery Strategy
One of the hardest parts of building integrations is understanding incoming data schemas and obtaining realistic test data. This section defines our approach.The Core Challenge
Fixture Directory Structure
Approaches by Data Source Type
| Source Type | Test Data Approach | Tools |
|---|---|---|
| REST/GraphQL APIs | Sandbox accounts + Record & Replay | Shopify Partner stores, PayPal Sandbox |
| CSV/TSV Imports | Customer-provided samples (anonymized) | Manual export from platform |
| Report Downloads | Sandbox reports + sample files | Amazon Seller Central test reports |
Fixture Capture Script
Schema Contract Testing
Use Zod schemas to define the MINIMUM fields we expect from each API:Integration Testing Against Fixtures
Discovery Documentation
For each integration, create aDISCOVERY.md file:
Test Data Workflow
Data Anonymization Strategy
Always redact sensitive information in test fixtures before committing to git. This is critical for CONA since we handle financial and customer data.What to Redact vs. Preserve
| Data Type | Example Fields | Redaction Strategy |
|---|---|---|
| PII | Names, emails, phone numbers | Faker.js / deterministic hashing |
| Addresses | Street, city, postal code | Generic placeholders |
| Financial | Bank accounts, card numbers | Masked format (e.g., ****1234) |
| Credentials | API keys, tokens | Remove entirely or use [REDACTED] |
| Business IDs | Order IDs, customer IDs | Hash or sequential replacement |
| Structure | Field names, nesting, array sizes | ✅ KEEP - Safe to preserve |
| Types | Numbers stay numbers, dates dates | ✅ KEEP - Safe to preserve |
| Patterns | Currency codes, country codes | ✅ KEEP - Safe to preserve |
| Amounts | Order totals, line item prices | ✅ KEEP (or slightly randomize) |
| Dates | Order dates, timestamps | ✅ KEEP (maybe shift by fixed offset) |
Anonymization Utility
Capture Script with Auto-Anonymization
Fixture Storage Layers
| Layer | Action |
|---|---|
| Capture | Anonymize immediately on save |
| Storage | Only commit anonymized fixtures to git |
| CI | Add PII detection to prevent accidental commits |
| Local dev | Can use raw data locally (add to .gitignore) |
CI PII Detection Job
Quick Reference: Platform Sandbox Access
| Platform | Sandbox Type | How to Access |
|---|---|---|
| Shopify | Partner Development Store | partners.shopify.com → Create dev store |
| PayPal | Sandbox Accounts | developer.paypal.com → Sandbox accounts |
| Amazon | Draft App + Sandbox Mode | sellercentral.amazon.com → Developer portal |
| Stripe | Test Mode | Use sk_test_ API keys |
| WooCommerce | Local WordPress + WooCommerce | Docker or LocalWP |
| Etsy | Sandbox Environment | developers.etsy.com |
Decisions Made
1. Continue-as-New Handling
Decision: The generic workflow handles continue-as-new automatically using Temporal’s built-in suggestion. TheshouldContinueAsNew() utility checks workflowInfo().continueAsNewSuggested which Temporal sets when the workflow history is getting too large. This is adapter-agnostic and requires no configuration.
- No adapter configuration needed
- Temporal knows best when history is too large
- Consistent behavior across all integrations
- Test hook available for CI testing (
testContinueAsNew: true)
2. Adapter Packaging Strategy
Decision: Adapters are NOT separate npm packages. They live in the monorepo. All adapters will be co-located inpackages/core/src/integrations/adapters/:
- Simpler dependency management - No version mismatches between adapters
- Faster iteration - Change adapter + workflow in one PR
- Shared utilities - Adapters can easily share common transformation helpers
- Unified testing - Run all adapter tests in one CI job
- Build time is acceptable - With tree-shaking, unused adapters don’t bloat bundles
- If build times exceed 5+ minutes due to adapter count
- If external teams need to contribute adapters without monorepo access
- If adapters need independent release cycles
Open Questions
-
Where should fixtures live?
- Option A:
packages/core/src/integrations/adapters/{integration}/fixtures/(close to code) - Option B: Separate
packages/test-fixtures/package (shared across packages) - Option C: Top-level
fixtures/directory in monorepo root
- Option A:
-
How do we keep fixtures up-to-date when APIs change?
- Scheduled CI job to validate fixtures against live sandbox
- Contract tests that fail on schema drift
- Manual review during integration maintenance
References
- Adapter Pattern (Design Patterns)
- Temporal Workflow Patterns
- Existing CONA Workflows
- CONA Core Functions