not bad
This commit is contained in:
1 parent
1ea3de74f2
commit
9db080faea
8 files changed
+2064
-55
No files matched your search
@@ -0,0 +1,133 @@
|
||||
# AGENTS.md
|
||||
|
||||
Guidance for agents working in this repository (Brandize · BI Dashboard).
|
||||
|
||||
## What this project is
|
||||
|
||||
A **flat, server-free browser dashboard** for the Brandize BI webhook. It renders
|
||||
gross revenue (Brutto inkl. USt) per departure country plus a VAT summary, with KPI
|
||||
cards, bar charts and detail tables. There is **no build step, no framework, no
|
||||
package manager** — just static files opened directly in a browser.
|
||||
|
||||
Supporting tools: a bash dev-server launcher (`start`) and a Python CLI (`send`) that
|
||||
uploads CSV rows to an n8n webhook. SQL scripts (`sql/`) define the upstream queries
|
||||
that feed the webhook (Odoo 17 / PostgreSQL).
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Purpose |
|
||||
| --- | --- |
|
||||
| `index.html` | Dashboard markup: sidebar nav, shared filter bar, one `<main class="view">` per report, auth overlay |
|
||||
| `styles.css` | All styling (CSS custom properties in `:root`, BEM-ish class names) |
|
||||
| `app.js` | Everything: data loading, parsing, rendering, CSV export, auth, navigation |
|
||||
| `README.md` | User-facing docs (German/English mixed). Update it when behavior changes |
|
||||
| `start` | Bash: installs `live-server` if missing and serves the folder on :8080 |
|
||||
| `send` | Python CLI: batches CSV rows to the `.../webhook/VAT` n8n webhook |
|
||||
| `sql/*.sql` | Upstream Odoo/PostgreSQL queries (see below) |
|
||||
| `data/` | Git-ignored. Empty in the repo; holds local CSV payloads for `send` |
|
||||
|
||||
## Running / validating
|
||||
|
||||
There is **no test suite and no linter**. Validation is manual:
|
||||
|
||||
- Open `index.html` directly (double-click) — the intended primary usage, works over `file://`.
|
||||
- Or run `./start` and browse `http://localhost:8080` for live reload.
|
||||
- `./send data/<file>.csv` requires Python 3 + `requests` and network access to the webhook.
|
||||
|
||||
Because `fetch` hits a remote webhook protected by HTTP Basic Auth, you generally
|
||||
**cannot fully exercise the UI without valid credentials and network access**. Don't
|
||||
claim validation passed unless you actually loaded the page and saw it work; otherwise
|
||||
state clearly what you could not run.
|
||||
|
||||
## Architecture notes (`app.js`)
|
||||
|
||||
Single file, loaded as a plain `<script>` (not a module), `"use strict"` at the top.
|
||||
No bundler — keep everything in global scope as the file already does.
|
||||
|
||||
- **Config constants** at the top: `API_URL`, `MONTHS` (German abbreviations), `PALETTE`.
|
||||
- **`els`** — a single object caching all `getElementById`/`querySelector` lookups.
|
||||
Add new DOM handles here rather than querying inline.
|
||||
- **State**: `currentView`, `lastData` (`{ abgangsland, vat }`), `auth`.
|
||||
- **Sections** are delimited by `/* ---------- Name ---------- */` banners: Auth,
|
||||
Period selector, Formatting, Data, Rendering (per report), CSV export, Navigation, Init.
|
||||
- **Views**: the `VIEWS` map defines title/subtitle per view id. `showView(name)`
|
||||
toggles `.hidden` on the `<main class="view">` elements and re-renders. A new report
|
||||
needs: markup section in `index.html`, an entry in `VIEWS`, a render function, and a
|
||||
`viewEls()` branch.
|
||||
- **Data flow**: `load()` → `POST API_URL` with `{ query, month }` → `extractArray(payload, key)`
|
||||
→ `normalizeAbgangsland` / `normalizeVat` → `renderActiveView()`. `load()` queries
|
||||
**only** the active dashboard's dataset; it is triggered from `showView()` (when a
|
||||
dashboard is displayed) and from the refresh/period controls — never prefetched.
|
||||
|
||||
### Webhook / data contract
|
||||
|
||||
- The webhook is called with **POST** and a JSON body `{ "query": <key>, "month": "YYYY-MMM" }`
|
||||
(quarter dashboards send `{ "query": <key>, "quarter": "YYYY-QN" }` instead).
|
||||
`query` selects the dataset. The datasets are large, so **exactly one dataset is
|
||||
requested per call**, for the dashboard currently shown (no prefetching).
|
||||
- Query keys: `"Summe je Abgangsland"` (Umsatz je Abgangsland), `"VAT Summary"`,
|
||||
`"ODOO Rechnungen pro Monat"`, `"Alle Rechnungen pro Monat"` and `"Quartal Schweiz"`.
|
||||
Each view's `query` lives in the `VIEWS` map, which maps the active dashboard to its
|
||||
`normalize` function; `quarter: true` marks the dashboards that use a quarter period.
|
||||
- `extractArray` accepts the dataset either as a bare array or wrapped under the
|
||||
query key (case-insensitive). If the shape changes upstream, adjust the normalizers.
|
||||
- The webhook returns **German-formatted strings**, e.g. `"90.717,93 €"` and
|
||||
`"1.234"`. Parsing (`parseEuro`, `parseQuantity`) strips symbols and swaps
|
||||
`.`/`,` — do **not** use `parseFloat` directly on the raw values.
|
||||
- `month` uses `YYYY-MMM` (e.g. `2026-SEP`), matching `%(month)s` in `sql/*.sql`;
|
||||
`quarter` uses `YYYY-QN` (e.g. `2026-Q3`), matching `%(quarter)s` in `sql/Quartal_Schweiz.sql`.
|
||||
|
||||
### Auth
|
||||
|
||||
HTTP Basic. The first request goes out without credentials; a `401` triggers the
|
||||
login overlay. Credentials live in `sessionStorage` (best-effort — unavailable on
|
||||
`file://`, where they stay in memory only) and are sent as `Authorization: Basic ...`.
|
||||
|
||||
## SQL scripts (`sql/`)
|
||||
|
||||
Odoo 17 / PostgreSQL against table `brandize_datacenter_amazon_vat_transaction`.
|
||||
Each file has a header block documenting the model, parameters and invocation.
|
||||
|
||||
- Parameter is named `%(month)s` for psycopg2; in `psql` use `:'month'` instead
|
||||
(documented in the headers — respect this distinction).
|
||||
- Money is formatted **in SQL** to German notation via
|
||||
`translate(to_char(...), ',.', '.,') || ' €'` so the frontend receives display-ready
|
||||
strings. Keep formatting consistent if you add columns.
|
||||
- `Delete_Activity_Period.sql` is destructive — note the "ACHTUNG" warning and the
|
||||
transaction-bracket guidance. Be cautious editing it.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Language**: UI text is **German**, code identifiers and comments are English
|
||||
(comments occasionally German). Keep new user-facing strings German.
|
||||
- **Number/date formatting**: always `de-DE` via `toLocaleString` in JS and German
|
||||
`to_char` formatting in SQL. Dates as `YYYY-MMM` with the `MONTHS` abbreviations.
|
||||
- **JS style**: `"use strict"`, double quotes, semicolons, 2-space indent, `const`/`let`
|
||||
(no `var`), named `function` declarations, `camelCase`. Nullish-safe (`??`, optional
|
||||
guards). DOM built imperatively with `document.createElement` (charts are hand-rolled
|
||||
bars/lists, no chart library).
|
||||
- **CSS**: use the existing `:root` custom properties for colors/spacing/radius; reuse
|
||||
existing class patterns rather than inventing new naming.
|
||||
- **CSV export**: semicolon-delimited, UTF-8 **with BOM** (for Excel umlauts), CRLF line
|
||||
endings, includes a `Gesamt` total row, filename `*_YYYY-MMM.csv`. Follow this pattern
|
||||
for any new exportable view.
|
||||
- Keep changes minimal and consistent with the existing file structure — this is a small,
|
||||
intentionally dependency-free static app. Prefer no new dependencies.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `data/` is git-ignored; never commit contents from it. `send` expects CSVs with a
|
||||
header row (`csv.DictReader`) and posts JSON arrays in batches of 50.
|
||||
- The `send` script targets a **different** webhook (`/webhook/VAT`) than the dashboard
|
||||
(`/webhook/bi-dashboard`). Don't conflate them.
|
||||
- `fetch` from `file://` sends `Origin: null`; the webhook reflects origins to allow CORS.
|
||||
Changing how requests are made can break the "just open the file" workflow.
|
||||
- README documents behavior (navigation, auth, CSV, filter). If you change any of these,
|
||||
update `README.md` in the same change.
|
||||
- The invoice dashboards (*ODOO Rechnungen pro Monat*, *Alle Rechnungen pro Monat*
|
||||
and *Quartal Schweiz*) are pivot experiments: they load jQuery, jQuery UI and
|
||||
PivotTable.js from CDNs (so they need internet), reuse `normalizeRechnungen`, and
|
||||
render via `renderRechnungenPivot` (no detail table). Layouts come from
|
||||
`PIVOT_PRESETS` (keyed per view; the Vorlage dropdown) / the pivotUI panel; the
|
||||
renderer is fixed to *Table*. The pivot container is recreated on each render so
|
||||
a preset actually applies.
|
||||
Reference in new issue
Block a user