quicksight-gen 3.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. quicksight_gen-3.2.1/LICENSE +24 -0
  2. quicksight_gen-3.2.1/PKG-INFO +381 -0
  3. quicksight_gen-3.2.1/README.md +336 -0
  4. quicksight_gen-3.2.1/pyproject.toml +85 -0
  5. quicksight_gen-3.2.1/setup.cfg +4 -0
  6. quicksight_gen-3.2.1/src/quicksight_gen/__init__.py +3 -0
  7. quicksight_gen-3.2.1/src/quicksight_gen/__main__.py +6 -0
  8. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/__init__.py +1 -0
  9. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/analysis.py +1101 -0
  10. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/constants.py +37 -0
  11. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/datasets.py +871 -0
  12. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/demo_data.py +1771 -0
  13. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/etl_examples.py +289 -0
  14. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/filters.py +716 -0
  15. quicksight_gen-3.2.1/src/quicksight_gen/account_recon/visuals.py +2657 -0
  16. quicksight_gen-3.2.1/src/quicksight_gen/cli.py +529 -0
  17. quicksight_gen-3.2.1/src/quicksight_gen/common/__init__.py +1 -0
  18. quicksight_gen-3.2.1/src/quicksight_gen/common/aging.py +80 -0
  19. quicksight_gen-3.2.1/src/quicksight_gen/common/cleanup.py +225 -0
  20. quicksight_gen-3.2.1/src/quicksight_gen/common/clickability.py +67 -0
  21. quicksight_gen-3.2.1/src/quicksight_gen/common/config.py +153 -0
  22. quicksight_gen-3.2.1/src/quicksight_gen/common/dataset_contract.py +105 -0
  23. quicksight_gen-3.2.1/src/quicksight_gen/common/deploy.py +291 -0
  24. quicksight_gen-3.2.1/src/quicksight_gen/common/models.py +964 -0
  25. quicksight_gen-3.2.1/src/quicksight_gen/common/rich_text.py +79 -0
  26. quicksight_gen-3.2.1/src/quicksight_gen/common/theme.py +349 -0
  27. quicksight_gen-3.2.1/src/quicksight_gen/demo/__init__.py +15 -0
  28. quicksight_gen-3.2.1/src/quicksight_gen/demo/schema.sql +890 -0
  29. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/__init__.py +1 -0
  30. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/analysis.py +834 -0
  31. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/constants.py +39 -0
  32. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/datasets.py +718 -0
  33. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/demo_data.py +1017 -0
  34. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/etl_examples.py +347 -0
  35. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/filters.py +704 -0
  36. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/recon_filters.py +207 -0
  37. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/recon_visuals.py +480 -0
  38. quicksight_gen-3.2.1/src/quicksight_gen/payment_recon/visuals.py +1074 -0
  39. quicksight_gen-3.2.1/src/quicksight_gen.egg-info/PKG-INFO +381 -0
  40. quicksight_gen-3.2.1/src/quicksight_gen.egg-info/SOURCES.txt +52 -0
  41. quicksight_gen-3.2.1/src/quicksight_gen.egg-info/dependency_links.txt +1 -0
  42. quicksight_gen-3.2.1/src/quicksight_gen.egg-info/entry_points.txt +2 -0
  43. quicksight_gen-3.2.1/src/quicksight_gen.egg-info/requires.txt +23 -0
  44. quicksight_gen-3.2.1/src/quicksight_gen.egg-info/top_level.txt +1 -0
  45. quicksight_gen-3.2.1/tests/test_account_recon.py +3110 -0
  46. quicksight_gen-3.2.1/tests/test_dataset_contract.py +126 -0
  47. quicksight_gen-3.2.1/tests/test_demo_data.py +615 -0
  48. quicksight_gen-3.2.1/tests/test_demo_etl_examples.py +258 -0
  49. quicksight_gen-3.2.1/tests/test_demo_sql.py +191 -0
  50. quicksight_gen-3.2.1/tests/test_etl_examples.py +378 -0
  51. quicksight_gen-3.2.1/tests/test_generate.py +422 -0
  52. quicksight_gen-3.2.1/tests/test_models.py +664 -0
  53. quicksight_gen-3.2.1/tests/test_recon.py +195 -0
  54. quicksight_gen-3.2.1/tests/test_theme_presets.py +131 -0
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
@@ -0,0 +1,381 @@
1
+ Metadata-Version: 2.4
2
+ Name: quicksight-gen
3
+ Version: 3.2.1
4
+ Summary: Programmatic AWS QuickSight analysis generator for financial reporting
5
+ License-Expression: Unlicense
6
+ Project-URL: Homepage, https://chotchki.github.io/Quicksight-Generator/
7
+ Project-URL: Documentation, https://chotchki.github.io/Quicksight-Generator/
8
+ Project-URL: Source, https://github.com/chotchki/Quicksight-Generator
9
+ Project-URL: Issues, https://github.com/chotchki/Quicksight-Generator/issues
10
+ Project-URL: Changelog, https://github.com/chotchki/Quicksight-Generator/blob/main/RELEASE_NOTES.md
11
+ Keywords: quicksight,aws,dashboards,reconciliation,analytics,finance
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Office/Business :: Financial :: Accounting
21
+ Classifier: Topic :: Software Development :: Code Generators
22
+ Requires-Python: >=3.11
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: click>=8.1
26
+ Requires-Dist: pyyaml>=6.0
27
+ Provides-Extra: demo
28
+ Requires-Dist: psycopg2-binary>=2.9; extra == "demo"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
32
+ Requires-Dist: boto3-stubs[quicksight]>=1.34; extra == "dev"
33
+ Requires-Dist: psycopg2-binary>=2.9; extra == "dev"
34
+ Requires-Dist: build>=1.0; extra == "dev"
35
+ Requires-Dist: twine>=5.0; extra == "dev"
36
+ Provides-Extra: docs
37
+ Requires-Dist: mkdocs>=1.6; extra == "docs"
38
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
39
+ Provides-Extra: e2e
40
+ Requires-Dist: pytest>=7.0; extra == "e2e"
41
+ Requires-Dist: pytest-xdist>=3.5; extra == "e2e"
42
+ Requires-Dist: boto3>=1.34; extra == "e2e"
43
+ Requires-Dist: playwright>=1.40; extra == "e2e"
44
+ Dynamic: license-file
45
+
46
+ # QuickSight Analysis Generator
47
+
48
+ [![CI](https://github.com/chotchki/Quicksight-Generator/actions/workflows/ci.yml/badge.svg)](https://github.com/chotchki/Quicksight-Generator/actions/workflows/ci.yml)
49
+ [![Coverage](https://raw.githubusercontent.com/chotchki/Quicksight-Generator/badges/coverage-badge.svg)](https://github.com/chotchki/Quicksight-Generator/actions/workflows/ci.yml)
50
+ [![PyPI](https://img.shields.io/pypi/v/quicksight-gen.svg)](https://pypi.org/project/quicksight-gen/)
51
+
52
+ Python tool that programmatically generates AWS QuickSight JSON definitions (theme, datasets, analyses, dashboards) and deploys them via boto3. It currently ships two independent QuickSight apps:
53
+
54
+ - **Payment Reconciliation** — sales → settlements → payments → external-system matching for a merchant bank.
55
+ - **Account Reconciliation** — stored daily balances, transfers, and postings for a double-entry ledger.
56
+
57
+ Both apps share one theme, one AWS account, one datasource, and the same CLI surface (`quicksight-gen generate|deploy|demo|cleanup`). Change the Python (or ask Claude), re-run `deploy --generate`, get a new dashboard.
58
+
59
+ ## Demo Docs
60
+
61
+ The demo ships with three task-shaped handbooks, one per persona team at Sasquatch National Bank. Deployed to GitHub Pages at **[chotchki.github.io/Quicksight-Generator](https://chotchki.github.io/Quicksight-Generator/)**.
62
+
63
+ - **[GL Reconciliation Handbook](https://chotchki.github.io/Quicksight-Generator/handbook/ar/)** — how the Accounting Operations team works the AR Exceptions sheet. Morning rollups + per-check drill-downs for 17 exception classes.
64
+ - **[Payment Reconciliation Handbook](https://chotchki.github.io/Quicksight-Generator/handbook/pr/)** — how the Merchant Support team answers "where's my money?" calls. 7 walkthroughs organized by operator question.
65
+ - **[Data Integration Handbook](https://chotchki.github.io/Quicksight-Generator/handbook/etl/)** — how the Data Integration Team maps an upstream system into `transactions` + `daily_balances`, validates the load, and extends the metadata contract. 5 foundational / extension / debug walkthroughs.
66
+
67
+ Source lives in `docs/`; rebuild locally with `mkdocs serve`.
68
+
69
+ ## Why this exists
70
+
71
+ The customer for these reports doesn't know exactly what they want yet. Rather than click through the QuickSight console and lose the work when requirements change, everything is generated from code and deployed idempotently (delete-then-create). Iteration is one command.
72
+
73
+ ## The two apps
74
+
75
+ ### Payment Reconciliation — 6 tabs
76
+
77
+ | Tab | What it shows |
78
+ |---|---|
79
+ | Getting Started | Landing page — heading + per-sheet highlights; demo scenario block when seeded. |
80
+ | Sales Overview | KPIs + by-merchant / by-location bar charts + detail table. |
81
+ | Settlements | KPIs + bar by merchant type + detail table. Click a row to drill into Sales. |
82
+ | Payments | KPIs + pie by status + detail table. Click a row to drill into Settlements. Right-click `external_transaction_id` to drill into Payment Reconciliation. |
83
+ | Exceptions & Alerts | Unsettled sales, returned payments, sale↔settlement and settlement↔payment mismatches, and unmatched external transactions. Compact half-width tables. |
84
+ | Payment Reconciliation | KPIs + match-status bar + dual mutually-filterable tables (external transactions ↔ internal payments). Click a row in either to filter the other. |
85
+
86
+ ### Account Reconciliation — 5 tabs
87
+
88
+ | Tab | What it shows |
89
+ |---|---|
90
+ | Getting Started | Landing page — heading + per-sheet highlights; demo scenario block when seeded. |
91
+ | Balances | Ledger and sub-ledger account balance tables. Click an account to drill into its transactions. |
92
+ | Transfers | One row per `transfer_id` with net-zero flags. Click to drill into transactions. |
93
+ | Transactions | Raw ledger (one row per leg, with an `origin` tag for filtering), filtered by date / type / posting-level / origin / Show-Only-Failed. |
94
+ | Exceptions | Cross-check rollups at the top (expected-zero EOD, two-sided post mismatch, balance-drift timelines), then per-check details: ledger / sub-ledger drift, non-zero transfers, limit breaches, overdrafts, and seven Cash Management Suite checks (ZBA sweep, ACH origination non-zero EOD, missing Fed confirmations, force-posted card without internal catch-up, GL-vs-Fed Master drift, stuck-in-suspense, reversed-but-not-credited). Aging bars on every check. |
95
+
96
+ ### Shared conventions
97
+
98
+ - **Clickable cells look clickable.** Accent-colored text = left-click drill; accent text on a pale tint background = right-click menu drill.
99
+ - Every sheet has a plain-language description; every visual has a subtitle. Coverage is asserted in unit + API e2e tests.
100
+ - All resources tagged `ManagedBy: quicksight-gen`; extra tags via `extra_tags` in config.
101
+
102
+ ## Quick start
103
+
104
+ ### Prerequisites
105
+
106
+ - Python 3.11+
107
+ - An AWS account with QuickSight Enterprise enabled
108
+ - Either a pre-existing QuickSight datasource ARN **or** a PostgreSQL **17+** database URL for demo mode (the schema uses SQL/JSON path syntax)
109
+
110
+ ### Install from PyPI
111
+
112
+ For consumers — using a pre-existing QuickSight datasource ARN:
113
+
114
+ ```bash
115
+ pip install quicksight-gen
116
+ ```
117
+
118
+ For demo mode (Postgres 17+, requires `psycopg2-binary`):
119
+
120
+ ```bash
121
+ pip install "quicksight-gen[demo]"
122
+ ```
123
+
124
+ ### Setup from source
125
+
126
+ For development on this repo:
127
+
128
+ ```bash
129
+ python3 -m venv .venv
130
+ source .venv/bin/activate
131
+ pip install -e ".[dev]"
132
+ ```
133
+
134
+ ### Configure
135
+
136
+ ```bash
137
+ cp config.example.yaml config.yaml
138
+ ```
139
+
140
+ Edit `config.yaml`:
141
+
142
+ ```yaml
143
+ aws_account_id: "123456789012"
144
+ aws_region: "us-east-2"
145
+
146
+ # Pre-existing QuickSight datasource ARN.
147
+ # Not required when demo_database_url is set (auto-derived).
148
+ datasource_arn: "arn:aws:quicksight:us-east-2:123456789012:datasource/your-datasource-id"
149
+
150
+ # Optional: prefix for all generated resource IDs (default: qs-gen)
151
+ resource_prefix: "qs-gen"
152
+
153
+ # Optional: which theme preset to use. One of: default, sasquatch-bank, sasquatch-bank-ar
154
+ theme_preset: "default"
155
+
156
+ # Optional: IAM principals granted permissions on generated resources.
157
+ # Accepts a single string or a list; one ResourcePermission is emitted per entry.
158
+ principal_arns:
159
+ - "arn:aws:quicksight:us-east-1:123456789012:user/default/admin"
160
+
161
+ # Optional: default value for any "late" / "days outstanding" filter (default: 30)
162
+ late_default_days: 30
163
+
164
+ # Optional: additional tags on every generated resource
165
+ extra_tags:
166
+ Environment: production
167
+ Team: finance
168
+
169
+ # Optional: PostgreSQL URL for demo apply
170
+ # demo_database_url: "postgresql://user:pass@localhost:5432/quicksight_demo"
171
+ ```
172
+
173
+ All values can also be set via `QS_GEN_`-prefixed environment variables (e.g. `QS_GEN_AWS_ACCOUNT_ID`). Env vars override YAML.
174
+
175
+ ### Generate and deploy
176
+
177
+ ```bash
178
+ # Generate both apps' JSON
179
+ quicksight-gen generate --all -c config.yaml -o out/
180
+
181
+ # Deploy everything (delete-then-create, idempotent)
182
+ quicksight-gen deploy --all -c config.yaml -o out/
183
+
184
+ # Or combine: regenerate + deploy in one shot (typical iteration loop)
185
+ quicksight-gen deploy --all --generate -c config.yaml -o out/
186
+
187
+ # Deploy a single app
188
+ quicksight-gen generate payment-recon -c config.yaml -o out/
189
+ quicksight-gen deploy payment-recon -c config.yaml -o out/
190
+ ```
191
+
192
+ `deploy` polls async resources (analyses, dashboards) until they reach a terminal state. Resources with the `ManagedBy: quicksight-gen` tag that aren't in the current output aren't touched — clean those up explicitly:
193
+
194
+ ```bash
195
+ quicksight-gen cleanup --dry-run # list stale tagged resources
196
+ quicksight-gen cleanup --yes # delete them without prompting
197
+ ```
198
+
199
+ ### What you get
200
+
201
+ ```
202
+ out/
203
+ theme.json
204
+ payment-recon-analysis.json
205
+ payment-recon-dashboard.json
206
+ account-recon-analysis.json
207
+ account-recon-dashboard.json
208
+ datasource.json # demo apply only
209
+ datasets/
210
+ qs-gen-merchants-dataset.json # 11 PR datasets
211
+ qs-gen-sales-dataset.json
212
+ qs-gen-settlements-dataset.json
213
+ qs-gen-payments-dataset.json
214
+ qs-gen-settlement-exceptions-dataset.json
215
+ qs-gen-payment-returns-dataset.json
216
+ qs-gen-sale-settlement-mismatch-dataset.json
217
+ qs-gen-settlement-payment-mismatch-dataset.json
218
+ qs-gen-unmatched-external-txns-dataset.json
219
+ qs-gen-external-transactions-dataset.json
220
+ qs-gen-payment-recon-dataset.json
221
+ qs-gen-ar-ledger-accounts-dataset.json # 21 AR datasets
222
+ qs-gen-ar-subledger-accounts-dataset.json
223
+ qs-gen-ar-transactions-dataset.json
224
+ qs-gen-ar-ledger-balance-drift-dataset.json
225
+ qs-gen-ar-subledger-balance-drift-dataset.json
226
+ qs-gen-ar-transfer-summary-dataset.json
227
+ qs-gen-ar-non-zero-transfers-dataset.json
228
+ qs-gen-ar-limit-breach-dataset.json
229
+ qs-gen-ar-overdraft-dataset.json
230
+ qs-gen-ar-sweep-target-nonzero-dataset.json
231
+ qs-gen-ar-concentration-master-sweep-drift-dataset.json
232
+ qs-gen-ar-ach-orig-settlement-nonzero-dataset.json
233
+ qs-gen-ar-ach-sweep-no-fed-confirmation-dataset.json
234
+ qs-gen-ar-fed-card-no-internal-catchup-dataset.json
235
+ qs-gen-ar-gl-vs-fed-master-drift-dataset.json
236
+ qs-gen-ar-internal-transfer-stuck-dataset.json
237
+ qs-gen-ar-internal-transfer-suspense-nonzero-dataset.json
238
+ qs-gen-ar-internal-reversal-uncredited-dataset.json
239
+ qs-gen-ar-expected-zero-eod-rollup-dataset.json
240
+ qs-gen-ar-two-sided-post-mismatch-rollup-dataset.json
241
+ qs-gen-ar-balance-drift-timelines-rollup-dataset.json
242
+ ```
243
+
244
+ ## Demo mode
245
+
246
+ A deterministic demo generator seeds both apps end-to-end so you can see them work without wiring up real data.
247
+
248
+ ```bash
249
+ # Emit SQL only (no DB connection needed) — schema ships in the wheel,
250
+ # `demo schema` writes a copy out for inspection or hand-loading.
251
+ quicksight-gen demo schema --all -o /tmp/schema.sql
252
+ quicksight-gen demo seed --all -o /tmp/seed.sql
253
+
254
+ # Apply schema + seed to PostgreSQL, then generate QuickSight JSON
255
+ # Requires: demo_database_url in config.yaml and `pip install -e ".[demo]"`
256
+ quicksight-gen demo apply --all -c config.yaml -o out/
257
+ ```
258
+
259
+ `demo apply` creates tables + views, inserts the sample data, writes a `datasource.json` derived from the database URL, and generates all QuickSight JSON. Both apps feed two shared base tables — `transactions` (every money-movement leg) and `daily_balances` (per-account end-of-day snapshots) — plus AR-only dimension tables (`ar_ledger_accounts`, `ar_subledger_accounts`, `ar_ledger_transfer_limits`). The `account_type` and `transfer_type` columns discriminate which app a row belongs to. See [`docs/Schema_v3.md`](docs/Schema_v3.md) for the full feed contract, canonical type values, metadata key catalog, and ETL examples for piping production data into the same shape.
260
+
261
+ **PostgreSQL 17+ is required** for `demo apply`: the schema uses SQL/JSON path syntax (`JSON_VALUE`, `JSON_QUERY`, `JSON_EXISTS`) for the `metadata TEXT` columns, and the portable subset forbids the Postgres-only `->>` / `->` / `@>` / `?` operators and JSONB.
262
+
263
+ Datasets are all Direct Query (no SPICE), so seed changes show up immediately after a fresh `demo apply` — no refresh step needed.
264
+
265
+ ### Demo scenarios
266
+
267
+ - **Payment Recon — Sasquatch National Bank (merchant settlement).** Six fictional Seattle coffee shops (Bigfoot Brews, Sasquatch Sips, Yeti Espresso, Skookum Coffee Co., Cryptid Coffee Cart, Wildman's Roastery). Sales flow into settlements and payments; planted unsettled sales, returned payments, amount mismatches, and orphan external transactions populate every exception table.
268
+ - **Account Recon — Sasquatch National Bank (treasury / GL).** Same bank from the treasury side, after SNB absorbed Farmers Exchange Bank's commercial book. Eight internal GL control accounts (Cash & Due From FRB, ACH Origination Settlement, Card Acquiring Settlement, Wire Settlement Suspense, Internal Transfer Suspense, Cash Concentration Master, Internal Suspense / Reconciliation, Customer Deposits — DDA Control) plus per-customer DDAs for three coffee retailers (Bigfoot Brews, Sasquatch Sips, Yeti Espresso) and four commercial customers (Cascade Timber Mill, Pinecrest Vineyards, Big Meadow Dairy, Harvest Moon Bakery). The Cash Management Suite drives four telling-transfer flows — ZBA / Cash Concentration sweeps, daily ACH origination sweeps to the FRB Master Account, external force-posted card settlements, and on-us internal transfers through Internal Transfer Suspense. Each flow plants both success cycles and characteristic failures so every Exceptions check (including the cross-check rollups) surfaces distinct rows.
269
+
270
+ ## Theming
271
+
272
+ | Preset | Palette | Analysis name prefix |
273
+ |---|---|---|
274
+ | `default` | Navy / blue / grey | — |
275
+ | `sasquatch-bank` | Forest green + bark brown + bank gold | `Demo — ` |
276
+ | `sasquatch-bank-ar` | Valley green + harvest gold + earth | `Demo — ` |
277
+
278
+ Set `theme_preset:` in `config.yaml` (or pass `--theme-preset` to `generate` / `deploy --generate`). Add a new preset by declaring a `ThemePreset` in `src/quicksight_gen/common/theme.py` and registering it in `PRESETS`.
279
+
280
+ Rich-text on the Getting Started sheets (headings, bullets, hyperlinks) uses the preset's accent color, resolved to hex at generate time.
281
+
282
+ ## Project structure
283
+
284
+ ```
285
+ src/quicksight_gen/
286
+ __main__.py # python -m quicksight_gen entry point
287
+ cli.py # Click CLI — generate / deploy / cleanup / demo
288
+ common/
289
+ config.py # Config dataclass + YAML/env loader
290
+ models.py # Dataclasses mapping to QuickSight API JSON
291
+ theme.py # Theme presets (default, sasquatch-bank, sasquatch-bank-ar)
292
+ deploy.py # Python deploy (delete-then-create, async waiters)
293
+ cleanup.py # Tag-based cleanup of stale resources
294
+ clickability.py # Conditional-format helpers (plain + menu-link accent styles)
295
+ rich_text.py # XML helpers for SheetTextBox.Content (heading/bullets/…)
296
+ payment_recon/
297
+ analysis.py # 6 sheets, drill-downs, filter groups, dashboard
298
+ visuals.py # Sales / Settlements / Payments / Exceptions visuals
299
+ recon_visuals.py# Payment Reconciliation side-by-side tables + KPIs
300
+ filters.py # Pipeline-tab filter groups + controls
301
+ recon_filters.py# Payment Reconciliation filters
302
+ datasets.py # 11 custom-SQL datasets
303
+ demo_data.py # Sasquatch Bank demo data generator
304
+ constants.py # Sheet + dataset identifier constants
305
+ account_recon/
306
+ analysis.py # 5 sheets, drill-downs, filter groups, dashboard
307
+ visuals.py # Balances / Transfers / Transactions / Exceptions visuals
308
+ filters.py # Per-tab filters + Show-Only-X toggles
309
+ datasets.py # 21 custom-SQL datasets
310
+ demo_data.py # Sasquatch National Bank — CMS treasury demo data generator
311
+ constants.py # Sheet + dataset identifier constants
312
+ demo/
313
+ schema.sql # Full PostgreSQL DDL — shared `transactions` + `daily_balances` base layer + AR dimension tables; emitted by `demo schema`
314
+ docs/
315
+ Schema_v3.md # Data Integration Team feed contract: column specs, metadata keys, ETL examples
316
+ tests/
317
+ test_models.py, test_generate.py, test_recon.py, test_account_recon.py,
318
+ test_theme_presets.py, test_demo_data.py, test_demo_sql.py
319
+ e2e/ # Two-layer e2e (API + browser); skipped unless QS_GEN_E2E=1
320
+ run_e2e.sh # One-shot: generate + deploy + e2e
321
+ config.example.yaml
322
+ ```
323
+
324
+ ## Tests
325
+
326
+ ```bash
327
+ pytest # unit + integration (fast, no AWS)
328
+ ./run_e2e.sh # regenerate + deploy both apps + e2e (pytest-xdist -n 4)
329
+ ./run_e2e.sh --parallel 8 # override worker count (1 = serial; stable ceiling ~8)
330
+ ./run_e2e.sh --skip-deploy api # only API e2e
331
+ ./run_e2e.sh --skip-deploy browser # only browser e2e
332
+ ```
333
+
334
+ Coverage:
335
+
336
+ - **Unit / integration (344 tests)**: models, tags, config, CLI, demo determinism + FK integrity + scenario coverage, theme preset registry, dataset builders, visual builders, filter groups, cross-reference validation (dataset ARNs, filter bindings, visual ID uniqueness, sheet scoping), explanation coverage, schema + seed SQL structure.
337
+ - **E2E (101 tests)**: two layers gated by `QS_GEN_E2E=1`.
338
+ - *API layer (boto3)* — resource existence, status, dashboard structure, dataset import health.
339
+ - *Browser layer (Playwright WebKit, headless)* — dashboard loads via pre-authenticated embed URL, sheet tabs, per-sheet visual counts, drill-downs, mutual-filter reconciliation tables, date-range filter narrowing, Show-Only-X toggles.
340
+
341
+ E2E tunables (env vars): `QS_E2E_PAGE_TIMEOUT`, `QS_E2E_VISUAL_TIMEOUT`, `QS_E2E_USER_ARN`, `QS_E2E_IDENTITY_REGION`. Failure screenshots land in `tests/e2e/screenshots/<app>/` (gitignored).
342
+
343
+ ## Known limitations
344
+
345
+ ### Drill-down parameters stack across tab-switches
346
+
347
+ QuickSight has no API to clear a parameter on tab-switch. When a drill-down sets a parameter on its destination sheet (e.g. clicking a `settlement_id` on Settlements navigates to Sales and sets `pSettlementId`), the parameter stays set even after the user tabs away and back — the destination sheet stays filtered to that one value.
348
+
349
+ **Workaround:** refresh the dashboard tab in the browser to clear all parameter filters.
350
+
351
+ Captured as an `xfail(strict=False)` characterization test in `tests/e2e/test_filter_stacking.py` so the behavior is documented and would surface if AWS ever fixes it.
352
+
353
+ ## Customising
354
+
355
+ ### Change the SQL
356
+
357
+ Edit the dataset builders in `<app>/datasets.py`. Each dataset has a `sql` string and a `DatasetContract` (column name + type list) — unit tests assert the SQL projection matches the contract, so the contract is the safety net when rewriting.
358
+
359
+ The dataset SQL reads from two shared base tables (`transactions`, `daily_balances`) plus the AR-only dimension tables. To wire your production data in, ETL into the same shape: see [`docs/Schema_v3.md`](docs/Schema_v3.md) for column specifications, the canonical `account_type` / `transfer_type` values, the JSON metadata key catalog, and end-to-end ETL examples.
360
+
361
+ ### Add a visual or tab
362
+
363
+ 1. Add the builder function in `<app>/visuals.py`.
364
+ 2. Wire it into the sheet layout in `<app>/analysis.py`.
365
+ 3. Add a subtitle (coverage tests enforce this).
366
+ 4. Run `pytest`.
367
+
368
+ ### Add a filter
369
+
370
+ 1. Add the `FilterGroup` builder in `<app>/filters.py` (or `recon_filters.py` for PR).
371
+ 2. Add a matching `FilterControl`.
372
+ 3. Register it on the relevant sheet's `FilterControls` in `analysis.py`.
373
+ 4. `pytest` will flag any broken `SourceFilterId` references.
374
+
375
+ ### Add a theme preset
376
+
377
+ Declare a `ThemePreset` in `common/theme.py` and add it to the `PRESETS` dict. Set `analysis_name_prefix="Demo"` if it should tag analyses with a demo prefix.
378
+
379
+ ### Ask Claude
380
+
381
+ The codebase is intentionally easy to mutate. Ask Claude to add visuals, reshape the layout, adjust filters, update SQL for your schema, or add conditional formatting — it'll edit the Python and re-run tests.