Typical architecture of an ELT pipeline with dbt and BigQuery
The pattern I usually use separates responsibilities into layers. In base (or staging) each source is loaded almost as is, with consistent names, corrected types and little else: it is the boundary between the outside world and yours. In core, business entities — customers, transactions, products — are modelled with rules, deduplication and well-defined keys. In marts, tables are built ready for each use: a dashboard, a predictive model, an export. Every layer has its tests and documentation, and dbt manages dependencies between models.
Data validation as part of the design
Tests are not a final add-on. From the first model I define uniqueness and not-null tests on keys, relationships between tables and business rules (for example, that an amount is not negative except for refunds). I add freshness checks to detect sources that have stopped arriving and, where possible, reconcile totals with the source system. Failures produce concrete alerts instead of silently wrong reports.
To run pipelines on a schedule I use Airflow when the project has enough dependencies to justify it; for simpler needs, simple scheduling is enough. In BigQuery, most of the saving comes from three decisions: querying only the columns you need, partitioning and clustering large tables according to how they are filtered, and avoiding full rebuilds when an incremental load is enough.
I have worked with SQL, dbt and BigQuery in a fintech analytics team (described at a high level for confidentiality) and I maintain a personal lab with more than 250,000 synthetic transactions that illustrates layer organisation, tests and orchestration. You will find it under projects.