# Back Office — Report Builder (UI prototype)

> Fully interactive frontend prototype — mock data in memory, no API, no persistence.
> Goal: validate the report-builder UX before building the real thing.

## Embedded in the production chrome

`variants/a-builder.html` is **generated**: the real client-panel `<head>` + dark sidebar DOM are
spliced from the production snapshot (`../report/variants/a-report.html`) and the builder UI
(`_template.html` at the page root) is inserted as the main section. It loads the production CSS
bundle + Clopos (GoogleSans) fonts from `../report/variants/assets/`, so the frame is 1:1 the real
panel; the sidebar shows an active "Report Builder" item under Statistikalar. All builder classes
are prefixed `rb-` to avoid collisions with `rs-`/`tw-`/mantine.

**To change the builder UI:** edit `_template.html`, then re-run
`python3 .build/build.py` (from this page's folder) — it re-splices the prod head+sidebar
around the template. Never hand-edit `variants/a-builder.html` directly.

## Mock data

Seeded PRNG (stable across reloads):

- **Sales** — 420 rows over the last 90 days: date · venue (Port Baku / 28 Mall / Ganjlik Plaza) ·
  waiter (8) · terminal (per venue) · payment (Cash/Card/Online) · total (10–200 ₼) ·
  discount (~28% of checks, 5–20%) · guest count (1–8).
- **Products** — 460 rows: date · venue · category (6) · product (30, real Subway-like menu with
  prices) · qty · gross · net · cost (30–42% of gross).

## Layout — three zones

1. **Left — Fields** (264px): dataset segmented switcher, search, Dimensions/Metrics sections.
   Click toggles a field; drag onto the preview card also adds it. Added fields show a check.
2. **Center — Live preview**: instant re-render on every config change. Sticky header,
   sortable column headers (click to sort), totals footer (sticky), row/group count in the
   header, "showing first 100" note. Empty states: no fields ("Add fields to start building" +
   "load an example" link) and no matching rows.
3. **Right — Configuration** (316px): Columns (chips; metric chips have inline Sum/Avg/Min/Max/Count
   dropdown; dims dimmed while grouping hides them) · Filters (field → operator per type → value
   input: select / multi-select / text / number / between) · Group by (toggle chips from added
   dimensions) · Sort (field + direction) · Date range (Today / Yesterday / Last 7 days /
   This month / Custom + summary line).

## Aggregation engine (client-side, real)

filter (date range + filters) → group by (multi-dim) → aggregate each metric by its own agg →
sort → render. Totals row aggregates over **all** filtered raw rows. When grouping is active the
table shows group-by dims + metrics only (standard analytics semantics); non-grouped dimension
chips dim with a tooltip.

Smart default: adding the first dimension while metrics exist auto-enables grouping by it.

## Save flow (mocked)

- Save report → modal: name + "Share with team" toggle (Enter saves, Esc closes).
- My Reports: list with dataset badge, shared icon, created date; hover actions
  Open / Rename / Duplicate / Delete. Open restores the full builder state.
- Two seeded example reports so the list isn't empty on first visit.
- State lives in JS memory only (reload resets — by design).

## Out of scope

Charts, export, real API, auth, routing beyond builder ↔ my reports, i18n (English-only UI).
