> ## Documentation Index
> Fetch the complete documentation index at: https://docs.textql.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Module 1 · From Analysis to App

> Start from substance: an analysis with a result you believe. The app is that analysis, made explorable. (~25 min)

Start from substance: an analysis with a result you believe. The app is that analysis, made explorable.

```text Prompt theme={null}
Take the analysis in this thread [or: rebuild my analysis of [metric] by [dimension]] and turn it into a data app: the headline number up top, the trend chart, and the breakdown table — with the layout you'd recommend. Show me a preview before saving it.
```

<Check>
  **You'll see:** a generated app preview — real components on your governed numbers, not a mockup. Iterate conversationally ("move the table below the chart", "add a second metric card").
</Check>

<Note>
  **Migrating an existing HTML / Streamlit artifact?** — If you already have an HTML report or Streamlit-style artifact from an earlier thread, hand it to Ana: *"convert this into a data app, preserving the layout."* That's the fastest path from legacy one-off outputs to a governed, shareable app.
</Note>

<Warning>
  **Building on a large fact table? Start static-first** — If the analysis behind your app scans a multi-million-row fact table, the default build will re-query the warehouse on every filter click — and time out the first time a viewer touches it. Don't build naive and fix later: build **static-first from the start** (Module 6 has the why and the failure story). Use this variant of the build prompt:
</Warning>

```text Prompt theme={null}
Take the analysis in this thread and turn it into a STATIC-FIRST data app: pre-aggregate the metrics once at refresh into an in-memory snapshot (base cube + breakdown tables + supporting series) and run all filter/sort/tab/chart interaction in the browser against that snapshot — no warehouse query on routine filtering. De-duplicate every dimension before joining so filtered totals can't double-count. Apply filters instantly (no Apply button); show the snapshot timestamp and fall back to the last good snapshot on refresh failure. Use at most one bounded, debounced live query for un-cacheable distinct counts under a custom filter — never a fan-out of full scans. After building, reconcile the default view and one filtered slice to the dollar against a fresh warehouse query, and tell me which dimensions the breakdowns do and don't slice by. Show me a preview before saving.
```

### ✅ Checkpoint

* [ ] An app preview rendered from your real analysis
* [ ] You changed the layout conversationally at least once
