How-To: Common Team Questions
How do I add a new ERP integration?
Section titled βHow do I add a new ERP integration?β- Implement the TypeScript ERP service interface in
apps/webapp/src/services/erp/implementations/ - Register it in
ERPServiceFactory(apps/webapp/src/services/erp/erp-service-factory.tsandapps/ts-temporal-worker/src/services/erp-service-factory.ts) - Add a corresponding type-declaration stub in
apps/ts-temporal-worker/src/webapp-types/ - If the ERP needs Python-side sync (for the Dagster pipeline), add a source in
apps/dagster/erp_pipeline/sources/and register its orchestrator in PythonβsERPSourceFactory(apps/dagster/erp_pipeline/sources/erp_source_factory.py) - Add it to the
ERPTypeenum and registry (packages/integrations/src/registry/registry.ts)
Do not add ERP-specific branching anywhere outside the factory pattern.
How do I force a manual ERP sync?
Section titled βHow do I force a manual ERP sync?βUse the canonical admin endpoints (not the legacy Trigger.dev ones):
POST /api/erp/force-syncβ force a full ERP catalog syncPOST /api/erp/force-image-syncβ force image sync only
The legacy /api/trigger/force-erp-sync still works as a compat shim but
will be removed. Use the new endpoints.
How do I add a new feature flag?
Section titled βHow do I add a new feature flag?β- Create the flag in Flagsmith (staging first, then production) and add it to
infrastructure/flagsmith/configs/flags.json. Any change affecting ERP writes, extraction, validation, or email triage must follow the Feature Flag Policy for ERP Writes. - TypeScript (
webapp,ts-temporal-worker): Evaluate via@repo/feature-flags(getFeatureFlagon the server,useFeatureFlagin React). - Python (
apps/temporal-worker): Evaluate viapackages/feature-flags-py(from feature_flags_py import get_feature_flag). - Dagster (
apps/dagster): Inapps/dagster/erp_pipeline/config.py, add aget_<flag_name>()helper usingget_iceberg_catalog_enabled()orget_p21_custom_source_enabled()as a template (falls back to env vars for local dev). - Gate your code on these helpers rather than raw Flagsmith SDK calls.
How do I add a new API route?
Section titled βHow do I add a new API route?βExtend BaseAPIHandler in apps/webapp/src/lib/api/base-handler.ts.
- Use
requireAuthfor user-facing routes - Use
requireAdminfor admin-only routes - All routes automatically get rate limiting, bot blocking, and default-deny auth
How do I trigger a Temporal workflow from the webapp?
Section titled βHow do I trigger a Temporal workflow from the webapp?βUse the helpers in apps/webapp/src/lib/temporal.ts β donβt create new
Temporal client instances. For PDF extraction:
import { startPDFExtractionWorkflow } from '@/lib/temporal';const { workflowId } = await startPDFExtractionWorkflow(documentId, { ... });For ERP order submission, use the starters in
apps/webapp/src/temporal/starters/.
How do I run the Dagster pipeline locally?
Section titled βHow do I run the Dagster pipeline locally?βcd apps/dagsteruv run dagster devThe feature flag mediator (config.py) reads from env vars in local dev,
so set ICEBERG_CATALOG_ENABLED=true etc. to test flag-gated paths.
How do I add a column to the Iceberg schema?
Section titled βHow do I add a column to the Iceberg schema?β- Add to
FIELD_ORDERinapps/dagster/erp_pipeline/utils/schema_registry.pyfirst - Add to the transformer(s) that produce that column
- The canonical field order must be maintained β schema_registry.py is the single source of truth
Where do background jobs live?
Section titled βWhere do background jobs live?β- Temporal (apps/temporal-worker, apps/ts-temporal-worker): durable workflows (PDF extraction, ERP submission, billing, email routing)
- Dagster (apps/dagster): scheduled syncs, dbt runs, catalog jobs
- Do not use Trigger.dev β itβs retired
How do I debug a stuck Temporal workflow?
Section titled βHow do I debug a stuck Temporal workflow?βCheck the Temporal UI (ask David for the URL). Workflows that are stuck
in QUOTE_PENDING or processing usually mean an activity failed after
retries exhausted. Look at the workflow history for the specific error.
For PDF extraction specifically, the workflow ID is pdf-extraction-{documentId}.