Architecture Decision Records¶
ADRs document significant technical decisions, the context that forced them, and the trade-offs accepted. They are permanent — if a decision changes, a new ADR supersedes the old one. Nothing is deleted or rewritten.
Index¶
| # | Decision | Status |
|---|---|---|
| 001 | Load strategy terminology: full_refresh, incremental, historical, batch_replace |
Accepted |
| 002 | Intraday refresh patterns for dynamic tables | Accepted |
| 003 | Build-time DAG generation (YAML → Python) over runtime dag-factory | Accepted |
| 004 | Metadata columns: RECORD_KEY, RECORD_HASH, BATCH_ID, SOURCE_FILE, PIPELINE_RUN_ID, DATE_TO_WAREHOUSE |
Accepted |
| 005 | Three-tier stage configuration priority | Accepted |
| 006 | Bronze truncate + FORCE = TRUE for legacy pipelines |
Accepted |
| 007 | Skip logic inside task functions, not in DAG structure | Accepted |
| 008 | Gold layer: fct_, dim_, agg_, rpt_ |
Accepted |
| 009 | Naming conventions — tables, DAGs, S3 paths, columns | Accepted |
| 010 | Rosters in CORE_DB, glossaries in client DB |
Accepted |
| 011 | batch_replace for new pipelines, truncate_insert for legacy |
Accepted |
| 012 | Documentation structure: docs/ as single source of truth |
Accepted |
| 013 | Bronze all-VARCHAR + Silver owns type casting via TRY_TO_* |
Accepted |
| 014 | XOOS analytics data delivery: direct Snowflake + CloudFlare edge cache | Accepted |
| 015 | SANDBOX schema for ad-hoc / supplementary analyst datasets | Accepted |
| 016 | GitHub issue quality standards for XO Data Ops project (#15) | Accepted |
| 017 | Partner-managed Bronze: accepting external Snowflake loading (Rippit/MAESTRO_DB) | Accepted |
| 018 | Separate ELT and dbt DAGs via TriggerDagRunOperator to prevent Cosmos import timeouts |
Accepted |
| 019 | Gold layer standardization: naming, structure, KPI conventions, client/layer project layout | Accepted |
| 020 | Silver incremental strategy: merge + RECORD_HASH is canonical; append is legacy |
Accepted |
| 021 | Gold exploration layer (exp_): pilot/ad-hoc views, no SLA, promote to rpt_ when stable |
Accepted |
| 022 | WBP topic-level metric aggregates: fan-out grain, CSAT fuzzy join, QA URL parsing | Accepted |
| 023 | Config storage: env vars for credentials/static infra, Airflow Connections for host+auth, Airflow Variables for runtime tunables | Accepted |
| 024 | Bronze merge strategy for rolling-window state-snapshot sources (Gladly exports, mutable 30-day window) |
Accepted |
| 025 | Snowflake-to-Google Sheets sync: full_replace as default; row-count management via exp_ view rollups |
Accepted |
| 026 | Gold feed layer (feed_): production-grade external export views with conditional daily/weekly grain rollup |
Accepted |
| 027 | DAG config filename and pipeline_name convention: {client}-{source}-{type}-{grain} |
Accepted |
| 028 | dbt test policy: test once at the layer where data enters, drop Bronze source tests, not_null on TRY_TO_* structural columns, reclassify summary fct_ as agg_ |
Accepted |
| 029 | S3 lifecycle: stage/ transient (expire 14d), ingest/ archive (Glacier 90d, expire 2yr); failed/ quarantine on COPY failure |
Proposed |
| 030 | dbt DAG grain slot and GDrive source naming: triggered dbt DAGs drop {grain}; scheduled keep it; GDrive-intermediated sources use {source}-gdrive compound slot. Amends ADR 027 |
Accepted |
| 031 | WBP contact volume: use INBOX_WHEN_QUEUED as inbox dimension (not INBOX_WHEN_ENDED); won't match Gladly contact summary by design |
Accepted |
| — | Branching strategy | Accepted |
| — | Single account strategy | Accepted |
| — | Snowflake environments | Accepted |
| — | Naming conventions (legacy) | Superseded by 009 |
How to write a new ADR¶
- Open a Decision issue to work through options with the team
- Pick the next number and create
NNN-kebab-case-topic.mdin this directory - Use this structure:
# ADR NNN — Title
## Status
Accepted | Proposed | Superseded by ADR NNN
## Context
What situation or constraint forced this decision? What would happen if we did nothing?
## Decision
What did we decide to do?
## Consequences
What gets easier? What gets harder? What do we give up?
## Options Considered
What else did we evaluate and why did we reject it?
- Link the ADR from the Decision issue and close it
- Update this index table
ADRs are append-only. Never rewrite history — future readers need to understand why decisions made sense at the time they were made.