From 39de507020402a13efa3df0f0449ba9716301548 Mon Sep 17 00:00:00 2001 From: Omer H Date: Thu, 30 Jul 2026 16:19:43 +0300 Subject: [PATCH 01/16] intial commit with plan --- .gitignore | 2 +- package-lock.json | 40 +--- temp-context/content-file-schema.md | 162 +++++++++++++++ temp-context/getting-started.md | 28 +++ temp-context/hebrew-example.md | 45 ++++ temp-context/overview.md | 31 +++ temp-context/reports/q1-metrics.md | 31 +++ temp-context/reports/tipat-chalav.md | 87 ++++++++ temp-context/subject-dashboards-plan.md | 266 ++++++++++++++++++++++++ 9 files changed, 654 insertions(+), 38 deletions(-) create mode 100644 temp-context/content-file-schema.md create mode 100644 temp-context/getting-started.md create mode 100644 temp-context/hebrew-example.md create mode 100644 temp-context/overview.md create mode 100644 temp-context/reports/q1-metrics.md create mode 100644 temp-context/reports/tipat-chalav.md create mode 100644 temp-context/subject-dashboards-plan.md diff --git a/.gitignore b/.gitignore index 32972e0..0d09546 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,4 @@ testem.log # System files .DS_Store Thumbs.db -.env \ No newline at end of file +.env diff --git a/package-lock.json b/package-lock.json index ba83d1f..5c348fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -284,7 +284,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.1.1.tgz", "integrity": "sha512-MWZKQSFBr7iEfLH4tSpsjjC/Afq8Udp4v6kv4YGRcXuJKn8cL6KZ+8nPFkZACYPNrB/5jrWN27HGjWWlO2Z2Hg==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -412,7 +411,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.1.1.tgz", "integrity": "sha512-2ZbnV8lM81ekLjRMRufRho7N8adz+Yjwj+3y5RB7+GW8fX5f9mm740ifyieBCXPLtiWb8ZK1i9gime6y64BEBQ==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -428,7 +426,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-19.1.1.tgz", "integrity": "sha512-bXPiJKQYjH6kSBnlVHx8aLzYY7YhWw1cidthWwqNaXyZ4YYILom1lN3C7nJYOVDX8W64QCMimHqf8iD4guByxA==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -449,7 +446,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.1.1.tgz", "integrity": "sha512-mk+CIV98WtZPfk4R0cdo7Jx8bZZewCO5K0dcG7/AMck+e2dDl2pjtXz1wYJi8NpUUAtcrr9HWlvxQ2L8IJMIag==", "dev": true, - "peer": true, "dependencies": { "@babel/core": "7.26.0", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -477,7 +473,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.1.1.tgz", "integrity": "sha512-uEDnomaIh7yUPx6hHWMFcWrUMOwishkkPToSFMltVLfRrfmAQL+WMpOGtR6qiFG6PIppsADIxXPRWVzfnYOYZg==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -511,7 +506,6 @@ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-19.1.1.tgz", "integrity": "sha512-MHrCE8bxNEp2BkSoLeuGJE0PMBF+Xu3zV52VpUaCrMQRHvHpq4ie+qosinQSDX72DKUUJUZuv0unApFCvhr2HA==", "dev": true, - "peer": true, "dependencies": { "@babel/core": "7.26.0", "@types/babel__core": "7.20.5", @@ -535,7 +529,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.1.1.tgz", "integrity": "sha512-L33rk7j3FepDqHo29iqp7ucL1tBjGQed+e22ei9bCsj7CG0GNi5w8id3nyNImhwN26wtg++4cu4la+XxKWIkXg==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -574,7 +567,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-19.1.1.tgz", "integrity": "sha512-hUlQDSwQQ5w4AWMN5hWNzk6WXdcUmX5A/HNk8dzn/vtUl/1pmXWiZuF21NN80iAcWPVIv3fTH1QzHvoAKC18zg==", - "peer": true, "dependencies": { "tslib": "^2.3.0", "xhr2": "^0.2.0" @@ -594,7 +586,6 @@ "version": "19.1.1", "resolved": "https://registry.npmjs.org/@angular/router/-/router-19.1.1.tgz", "integrity": "sha512-DbgluW4P0AfZ01kaoSJK+4eKrYnBvP5yGVSx+rhZhXOPpoVx76IOn691cdwC9CQuDIG9RqQWZL5TLfS959K0cA==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -612,7 +603,6 @@ "version": "19.1.2", "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-19.1.2.tgz", "integrity": "sha512-MMQyEGDcsgXKCuwGWwb8NkpzFSCINMU4y0ABmJVEZ58/3ni3NnwTnflCVFfuWefjzgyOBLZw1gOjQF2iwLH/Ng==", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -668,7 +658,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.0", @@ -2728,7 +2717,6 @@ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.2.1.tgz", "integrity": "sha512-v2JSGri6/HXSfoGIwuKEn8sNCQK6nsB2BNpy2lSX6QH9bsECrMv93QHnj5+f+1ZWpF/VNioIV2B/PDox8EvGuQ==", "dev": true, - "peer": true, "dependencies": { "@inquirer/checkbox": "^4.0.4", "@inquirer/confirm": "^5.1.1", @@ -4806,7 +4794,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.14.tgz", "integrity": "sha512-w6qdYetNL5KRBiSClK/KWai+2IMEJuAj+EujKCumalFOwXtvOXaEan9AuwcRID2IcOIAWSIfR495hBtgKlx2zg==", "dev": true, - "peer": true, "dependencies": { "undici-types": "~6.19.2" } @@ -5160,7 +5147,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -5609,7 +5595,6 @@ "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-3.0.3.tgz", "integrity": "sha512-91hoBHKk1C4pGeD+oE9Ld222k2GNQEAsI5AElqR8iLLWNrmZR2LPP8B0h8dpld9u7kro5IEUB3pUb0DJ3n1cRQ==", "dev": true, - "peer": true, "dependencies": { "browser-sync-client": "^3.0.3", "browser-sync-ui": "^3.0.3", @@ -5755,7 +5740,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -6592,7 +6576,6 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "peer": true, "dependencies": { "internmap": "1 - 2" }, @@ -6664,7 +6647,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "peer": true, "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -6680,7 +6662,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "peer": true, "engines": { "node": ">=12" } @@ -8765,8 +8746,7 @@ "version": "4.6.1", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/jest-worker": { "version": "27.5.1", @@ -8802,7 +8782,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -8899,7 +8878,6 @@ "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, - "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -8989,7 +8967,6 @@ "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", "dev": true, - "peer": true, "dependencies": { "jasmine-core": "^4.1.0" }, @@ -9310,7 +9287,6 @@ "resolved": "https://registry.npmjs.org/less/-/less-4.2.1.tgz", "integrity": "sha512-CasaJidTIhWmjcqv0Uj5vccMI7pJgfD9lMkKtlnTHAdJdYK/7l8pM9tumLyJ0zhbD4KJLo/YvTj+xznQd5NBhg==", "dev": true, - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -11240,7 +11216,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", @@ -11877,7 +11852,6 @@ "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -13115,7 +13089,6 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "dev": true, - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -13247,8 +13220,7 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "peer": true + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/tuf-js": { "version": "3.0.1", @@ -13299,7 +13271,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -13536,7 +13507,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz", "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==", "dev": true, - "peer": true, "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.4.49", @@ -13655,7 +13625,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -13731,7 +13700,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.0.tgz", "integrity": "sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==", "dev": true, - "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -13955,7 +13923,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14279,8 +14246,7 @@ "node_modules/zone.js": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.0.tgz", - "integrity": "sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==", - "peer": true + "integrity": "sha512-9oxn0IIjbCZkJ67L+LkhYWRyAy7axphb3VgE2MBDlOqnmHMPWGYMxJxBYFueFq/JGY2GMwS0rU+UCLunEmy5UA==" } } } diff --git a/temp-context/content-file-schema.md b/temp-context/content-file-schema.md new file mode 100644 index 0000000..0166600 --- /dev/null +++ b/temp-context/content-file-schema.md @@ -0,0 +1,162 @@ +# Content File Schema + +Defines the exact shape a generated dashboard file (`content/**/*.md`) must have. +This is the contract between the generator (`main_agent/`, driven by the BudgetKey +MCP tools) and the viewer (`server/` + React app), per `prd.md`. A file that +doesn't match this schema either fails to parse (skipped from the sidebar) or +renders with missing/incorrect metadata. + +## 1. Frontmatter (metadata) + +Every file starts with a YAML frontmatter block, exactly the fields below — no +more, no fewer. The server parses this into `DashboardMeta`; unknown extra +fields are ignored, missing required fields make the file fail to parse. + +```yaml +--- +title: תקציב טיפות חלב בישראל +created: 2026-07-30 +updated: 2026-07-30 +model: claude-sonnet-5 +path: reports/tipat-chalav +--- +``` + +| Field | Type | Required | Meaning | +| --------- | ------ | -------- | ---------------------------------------------------------------- | +| `title` | string | yes | Display name shown in the sidebar and detail header. | +| `created` | date | yes | `YYYY-MM-DD`. When the dashboard was first generated. | +| `updated` | date | yes | `YYYY-MM-DD`. When it was last refreshed. Sidebar sorts on this. | +| `model` | string | yes | Model that produced the file, e.g. `claude-sonnet-5`. | +| `path` | string | yes | Free-form source/category tag shown in the header. Independent of the file's slug — does not need to match the folder it's saved in. | + +Rules: + +- Dates may be quoted (`"2026-07-30"`) or bare YAML dates — the server + normalizes both to `YYYY-MM-DD` strings. Prefer quoting to avoid YAML + parsing it as a `Date` object with unexpected timezone shifting. +- `title` may be Hebrew or English; the body may mix both (see + `hebrew-example.md` / `tipat-chalav.md` for precedent). +- `updated` must be `>= created`. +- The file's path under `content/` (minus `.md`) is the slug (URL identity). + `path` is separate, human-facing metadata — do not conflate the two. + +## 2. Body content + +After the frontmatter, the body is GFM Markdown. Three things are expected of +every non-trivial dashboard: graphs, cross-links, and sourced/reliability +information. + +### 2.1 Graphs + +Use fenced ` ```mermaid ` blocks for any data with a natural visual shape — +distributions, trends over time, or process flow. Rendered client-side as SVG; +diagram source must be valid Mermaid syntax (no HTML injection — the viewer +renders with `securityLevel: 'strict'`, so `click`/script bindings are +stripped). + +Guidance on which diagram type to reach for: + +| Data shape | Mermaid diagram | +| ---------------------------------------- | ------------------ | +| Share of a total across categories | `pie` | +| Trend across time (multiple series) | `xychart-beta` or a Markdown table (Mermaid has no native multi-series line chart — prefer a table for exact figures, a chart only for the shape of the trend) | +| Process / pipeline / data flow | `flowchart` | +| Sequence of events between actors | `sequenceDiagram` | + +Every chart's numbers must also appear in an adjacent Markdown table when +precision matters (see `q1-metrics.md`, `tipat-chalav.md`) — the diagram +communicates shape, the table carries the exact values and is what a reader +can actually check against the source. + +### 2.2 Links to other pages + +Cross-link related dashboards using relative Markdown links, resolved against +the **current file's directory**: + +```markdown +See the [product overview](../overview.md). +[Q1 metrics](./reports/q1-metrics.md) +``` + +Rules: + +- Relative links to another `.md` file under `content/` are resolved + client-side and navigate without a full page reload. Always link to the + `.md` file itself (not a slug URL) — the app resolves the relative path the + same way the filesystem would. +- External links (`http://`, `https://`, `mailto:`) are left as normal links + and open in a new tab. Use these for citing source records (see 2.3). + Never rewrite an external URL into a relative path. + - Do not fabricate URLs. Only link to sources actually returned by the MCP + tools (`DatasetInfo` / `DatasetFullTextSearch` / `DatasetDBQuery`) during + generation. +- Don't link outside `content/` or use absolute filesystem paths — the server + rejects any resolved path escaping `content/` (404), and such a link would + never navigate correctly client-side anyway. +- Prefer linking back to a natural "parent" page (e.g. an overview or index + dashboard) at the end of the body, so a reader can always navigate back up. + +### 2.3 Information reliability + +Because every figure in a dashboard originates from a live MCP query against +real budget data, the body must let a reader trace a number back to its +source and judge how solid it is. Every dashboard that presents figures (not +pure narrative) must include: + +1. **A closing `## Sources` section** (or `## מקורות` for Hebrew dashboards) + listing the concrete records the figures came from, as external links — + typically `item_url` values returned by `DatasetDBQuery`, or dataset/program + identifiers (e.g. a `program_key`). Do not summarize without attaching at + least one traceable source link per major claim. + +2. **Actual vs. projected data marked inline.** Budget data mixes originally + planned, revised, and executed amounts, and the most recent year is often + incomplete. Mark incomplete/not-yet-executed figures explicitly rather than + presenting them as final — e.g. a table cell of `טרם בוצע` / "not yet + executed" or "pending" instead of a number, or a footnote flagging an + estimate. + +3. **A stated coverage window.** Call out the year/date range the data spans + (e.g. "מכסים את השנים 2016–2026") so a reader knows what's in scope and + what predates or postdates the report. + +4. **Caveats on anomalies called out, not silently presented.** If a number + looks like an outlier (a large deviation, revised budget far exceeding the + original, etc.), name it and offer the most likely explanation available + from the data — don't just print the table and move on. + +Narrative-only sections (e.g. a "Notes" section giving color on a chart) don't +individually need citations if the section immediately above already sourced +the underlying figures. + +## 3. Minimal template + +```markdown +--- +title: +created: +updated: +model: +path: +--- + +## + + + +## + +| ... | + +​```mermaid +pie title ... +​``` + +## Sources + +- []() + +Back to the [](.md). +``` + diff --git a/temp-context/getting-started.md b/temp-context/getting-started.md new file mode 100644 index 0000000..679bc49 --- /dev/null +++ b/temp-context/getting-started.md @@ -0,0 +1,28 @@ +--- +title: Getting Started +created: 2026-07-10 +updated: 2026-07-20 +model: claude-sonnet-5 +path: docs/getting-started +--- + +## How this works + +1. A script connects to an MCP server and fetches data from the web +2. The script asks a model to summarize the findings +3. The model's output is written to a `.md` file under `content/`, with + frontmatter metadata and any diagrams as Mermaid code blocks +4. This viewer reads `content/` and renders each file as a dashboard + +## Frontmatter fields + +| Field | Meaning | +| ------- | --------------------------------- | +| title | Display name in the sidebar | +| created | When the dashboard was first generated | +| updated | When it was last refreshed | +| model | Which model produced it | +| path | Free-form source/category tag | + +Head back to the [product overview](./overview.md) to see a real example, or check +the [Hebrew example](./hebrew-example.md) to see right-to-left (RTL) content rendered. diff --git a/temp-context/hebrew-example.md b/temp-context/hebrew-example.md new file mode 100644 index 0000000..9a7f150 --- /dev/null +++ b/temp-context/hebrew-example.md @@ -0,0 +1,45 @@ +--- +title: סקירת מכירות רבעונית +created: 2026-07-25 +updated: 2026-07-30 +model: claude-opus-5 +path: reports/hebrew-example +--- + +## סיכום + +להלן סיכום של נתוני המכירות לרבעון האחרון, שנאסף מתוך כלי ה-MCP ומקורות מידע +באינטרנט. הדוגמה הזו נועדה להדגים תמיכה בתוכן בעברית (RTL) בתוך הדשבורדים. + +## מגמות עיקריות + +- העלייה בתנועה האורגנית נמשכת גם ברבעון הזה +- מספר הלקוחות החדשים גדל ב-15% לעומת הרבעון הקודם +- זמן התגובה של צוות התמיכה השתפר משמעותית + +## הכנסות לפי ערוץ + +| ערוץ | הכנסות | שינוי | +| -------- | -------- | ----- | +| אורגני | ₪120,000 | +12% | +| ישיר | ₪45,000 | -3% | +| הפניות | ₪30,000 | +8% | + +## תרשים זרימה + +```mermaid +flowchart LR + A[איסוף נתונים] --> B[ניתוח עם מודל] + C[כתיבת דוח] --> D[הצגה בדשבורד] + A --> B --> C --> D +``` + +## קטע קוד + +בלוקים של קוד תמיד נשארים משמאל-לימין, גם בתוך טקסט בעברית: + +```bash +npm run dev +``` + +חזרה ל[סקירת המוצר](./overview.md). diff --git a/temp-context/overview.md b/temp-context/overview.md new file mode 100644 index 0000000..75fea28 --- /dev/null +++ b/temp-context/overview.md @@ -0,0 +1,31 @@ +--- +title: Product Overview +created: 2026-07-18 +updated: 2026-07-29 +model: claude-opus-5 +path: research/product-overview +--- + +## Summary + +A snapshot of where the product stands this quarter, pulled from web research and +internal signals via MCP tools. + +```mermaid +flowchart LR + A[Fetch web data] --> B[MCP tool calls] + B --> C[Summarize with Claude] + C --> D[Write dashboard.md] + D --> E[Render in viewer] +``` + +## Highlights + +- Traffic is trending up across all major channels +- Two competitor launches worth tracking closely +- Support ticket volume is flat month-over-month + +See the [Q1 metrics report](./reports/q1-metrics.md) for the full numbers, or check +the [getting started guide](./getting-started.md) for how this pipeline works. + +External reference: [Vite docs](https://vite.dev/) diff --git a/temp-context/reports/q1-metrics.md b/temp-context/reports/q1-metrics.md new file mode 100644 index 0000000..2e5ec64 --- /dev/null +++ b/temp-context/reports/q1-metrics.md @@ -0,0 +1,31 @@ +--- +title: Q1 Metrics Report +created: 2026-07-15 +updated: 2026-07-30 +model: claude-opus-5 +path: reports/2026-q1 +--- + +## Traffic by channel + +| Channel | Sessions | Change | +| -------- | -------- | ------ | +| Organic | 42,100 | +12% | +| Referral | 8,300 | +4% | +| Direct | 15,750 | -2% | +| Social | 6,900 | +21% | + +```mermaid +pie title Sessions by channel + "Organic" : 42100 + "Referral" : 8300 + "Direct" : 15750 + "Social" : 6900 +``` + +## Notes + +Social growth is driven by the two launch posts from early July. Direct traffic +dipped slightly, likely seasonal. + +Back to the [product overview](../overview.md). diff --git a/temp-context/reports/tipat-chalav.md b/temp-context/reports/tipat-chalav.md new file mode 100644 index 0000000..daf74e4 --- /dev/null +++ b/temp-context/reports/tipat-chalav.md @@ -0,0 +1,87 @@ +--- +title: תקציב טיפות חלב בישראל +created: 2026-07-30 +updated: 2026-07-30 +model: claude-sonnet-5 +path: reports/tipat-chalav +--- + +## סיכום + +דוח זה סוקר את התקציב והביצוע של שירותי "טיפת חלב" (בריאות המשפחה) בישראל, +המתוקצבים תחת סעיף `24.16.03.62` במשרד הבריאות. הנתונים נשלפו בזמן אמת דרך +כלי ה-MCP של [מפתח התקציב](https://next.obudget.org/) ומכסים את השנים +2016–2026. + +## מגמת התקציב לאורך השנים + +| שנה | תקציב מקורי | תקציב מתוקן | ביצוע בפועל | +| ---- | ----------- | ----------- | ------------ | +| 2016 | ₪36.7M | ₪45.1M | ₪43.6M | +| 2017 | ₪37.0M | ₪45.1M | ₪43.9M | +| 2018 | ₪37.7M | ₪47.7M | ₪44.3M | +| 2019 | ₪38.5M | ₪48.7M | ₪46.5M | +| 2020 | — | ₪50.7M | ₪48.8M | +| 2021 | ₪48.2M | ₪46.8M | ₪45.4M | +| 2022 | ₪44.2M | ₪49.5M | ₪46.3M | +| 2023 | ₪47.2M | ₪53.0M | ₪50.5M | +| 2024 | ₪60.2M | ₪68.8M | ₪60.3M | +| 2025 | ₪67.4M | ₪93.4M | ₪64.5M | +| 2026 | ₪70.1M | ₪70.1M | טרם בוצע | + +התקציב המתוקן חורג באופן עקבי מהתקציב המקורי כמעט בכל שנה, מגמה שהתחדדה +במיוחד ב-2024–2025 (חריגה של יותר מ-15% ב-2024 ומעל 38% ב-2025), כנראה +כתוצאה מהעלייה בביקוש לשירותי בריאות המשפחה ומהרחבת פעילות התחנות. + +## התפלגות ביצוע לפי רשות מקומית / ספק + +התרשים הבא מציג את החלוקה בין הרשויות המקומיות והספקים המרכזיים שביצעו את +התקציב תחת סעיף זה (2016–2026): + +```mermaid +pie title ביצוע תקציבי לפי ספק (₪, מצטבר) + "עירית ירושלים" : 206126052 + "עירית תל-אביב-יפו" : 97088314 + "עירית פתח תקוה" : 11335861 + "עירית רמת גן" : 4811408 + "עירית בני ברק" : 2977121 + "אחרים" : 2709408 +``` + +## עשרת המבצעים הגדולים + +| רשות / ספק | ביצוע מצטבר | מס' התקשרויות | +| --------------------- | ----------- | -------------- | +| עירית ירושלים | ₪206.1M | 13 | +| עירית תל-אביב-יפו | ₪97.1M | 12 | +| עירית פתח תקוה | ₪11.3M | 9 | +| עירית רמת גן | ₪4.8M | 12 | +| עירית בני ברק | ₪3.0M | 12 | +| שירותי בריאות כללית | ₪2.2M | 6 | +| עירית בת-ים | ₪0.24M | 2 | +| עיריית נתניה | ₪0.20M | 1 | +| עירית ראשון לציון | ₪0.17M | 1 | +| עירית רחובות | ₪0.13M | 1 | + +עיריית ירושלים ועיריית תל-אביב-יפו מפעילות בעצמן חלק ניכר משירותי טיפות +החלב בתחומן (מודל "70:30" בו משרד הבריאות משתתף ב-70% מהעלות), בעוד שברוב +הרשויות האחרות השירות ניתן ישירות על ידי קופות החולים. + +## תוכנית התמיכה הייעודית + +מעבר להתקשרויות הרכש, קיימת גם תוכנית תמיכה תקציבית ייעודית ("טיפות חלב", +`program_key: 0024160162_טיפותחלב`) של משרד הבריאות הפעילה מאז 2010: + +- **סה"כ אושר** (2010–2026): ₪40,851,797 +- **סה"כ שולם בפועל**: ₪15,795,477 + +הפער בין הסכום שאושר לסכום ששולם בפועל עשוי להצביע על תמיכות רב-שנתיות +שטרם מוצו במלואן, או על שינויים בזכאות הרשויות/העמותות המבקשות. + +## מקורות + +- [סעיף התקציב 24.16.03.62 לשנת 2026](https://next.obudget.org/i/4ffd002f054b) +- [תוכנית התמיכה בטיפות חלב](https://next.obudget.org/i/3e0c6c78d139) +- [התקשרות עירית ירושלים 2023](https://next.obudget.org/i/f93404381692) + +חזרה ל[סקירת המוצר](../overview.md). diff --git a/temp-context/subject-dashboards-plan.md b/temp-context/subject-dashboards-plan.md new file mode 100644 index 0000000..999b375 --- /dev/null +++ b/temp-context/subject-dashboards-plan.md @@ -0,0 +1,266 @@ +# Subject Dashboards — Implementation Plan + +Persistent plan for the "subject-dashboards" feature. Each numbered step below is +meant to be done in its own session by someone unfamiliar with this thread — read +the "Decisions" section first, then do exactly one step, then run its +Verification before starting the next. Check off steps as you complete them +(edit this file) so the next session knows where things stand. + +## Context + +- Repo: Angular 19 app with SSR (`projects/budgetkey/src/server.ts`, Express + + `CommonEngine`), `prerender: true` in `angular.json`. +- Existing precedent to copy the pattern from: `projects/budgetkey/src/app/about/about-page/` + fetches a raw `.md` file via `HttpClient` (`responseType: 'text'`), converts it + with `Showdown`, and renders via `[innerHtml]` + `DomSanitizer.bypassSecurityTrustHtml`. + Reuse that pattern's shape; don't touch the `about` module itself. +- There is an unrelated existing module also called `dashboards` + (`projects/budgetkey/src/app/dashboards/`, route `/dashboards`) — a config-driven + visualization feature. Not related to this work; don't confuse the two. +- Content schema/examples for this feature are in `temp-context/` (this repo, untracked): + `overview.md`, `hebrew-example.md`, `getting-started.md`, `reports/q1-metrics.md`, + `reports/tipat-chalav.md`, and `content-file-schema.md` (the schema doc itself — + not a content sample, has no frontmatter). Note: `content-file-schema.md` and + `getting-started.md` describe a *different* reference implementation (mentions + a `server/` + React app, `main_agent/`) — that's just where the schema was + authored, not this repo's stack. Ignore its tech-stack mentions; only the + frontmatter/body **schema rules** in `content-file-schema.md` apply here. + +## Decisions (already made — don't re-litigate) + +1. **Content delivery**: content is baked into the Angular build as static assets, + same as the `about` module. The cronjob/pipeline commits `.md` files into + `projects/budgetkey/src/assets/subject-dashboards/`, and a normal rebuild+redeploy + picks up changes. No server-side directory reads, no Docker volume, no new + Express routes. +2. **Content index**: generated at build time by a small script in this repo (not + by the content pipeline). It walks `assets/subject-dashboards/`, reads each + file's frontmatter, and writes `assets/subject-dashboards/index.json`. The app + only ever fetches that one JSON file — it never lists a directory at runtime. +3. **Home page UX**: `/subject-dashboards` renders a **nested list mirroring the + directory structure** (folders as grouping labels, files as links using their + `title`) — not a flat list, not a search box. +4. **Naming**: plural throughout — route `/subject-dashboards`, module + `SubjectDashboardsModule`, folder `subject-dashboards`, asset dir + `assets/subject-dashboards/`. +5. **Detail routing**: `/subject-dashboards/` where `` is the file's + path under `assets/subject-dashboards/` minus `.md`, and can be multiple + segments deep (e.g. `/subject-dashboards/reports/tipat-chalav`). Needs a + wildcard (`**`) route, not a single `:param`. +6. **Prerendering**: don't fight Angular's static `prerender` enumeration for this + feature. Confirm in step 9 whether the lazy module's wildcard route breaks + `ng build`'s prerender step; if it does, exclude these routes from prerender + and let the existing SSR path (`server.ts` / `CommonEngine`) render them + per-request — that already works for any route and doesn't need new code. +7. **Security**: unlike `about` page content (hand-authored by the dev team), this + content is LLM/automation-generated on a schedule. Sanitize the Showdown output + with DOMPurify before `bypassSecurityTrustHtml` (new dependency) — defense in + depth, since `about` page's existing "trust it raw" approach isn't appropriate + for automation-generated content. + +## Directory/file layout this plan produces + +``` +projects/budgetkey/src/assets/subject-dashboards/ + overview.md + getting-started.md + hebrew-example.md + reports/ + q1-metrics.md + tipat-chalav.md + index.json <- generated, gitignored, not hand-edited + +projects/budgetkey/scripts/ + generate-subject-dashboards-index.js <- Node script, run before `ng build` + +projects/budgetkey/src/app/subject-dashboards/ + subject-dashboards.module.ts + subject-dashboards-routing.module.ts + subject-dashboards-home/ + subject-dashboards-home.component.{ts,html,less} + subject-dashboard-page/ + subject-dashboard-page.component.{ts,html,less} +``` + +--- + +## Step 1 — Fixtures + asset directory scaffolding + +- Create `projects/budgetkey/src/assets/subject-dashboards/`. +- Copy these files from `temp-context/` into it, preserving relative paths: + `overview.md`, `getting-started.md`, `hebrew-example.md`, + `reports/q1-metrics.md`, `reports/tipat-chalav.md`. + (Do **not** copy `content-file-schema.md` — it's schema documentation, not a + dashboard file; it has no frontmatter and would fail to parse.) +- Add `projects/budgetkey/src/assets/subject-dashboards/index.json` to `.gitignore` + (it's a generated build artifact, step 2 produces it). + +**Verification**: the 5 files exist under the new path with identical content to +`temp-context/`. `git status` shows the new files as untracked (or staged, per +your workflow) and `index.json` is ignored once step 2 generates it. + +## Step 2 — Build-time index generator + +- Write `projects/budgetkey/scripts/generate-subject-dashboards-index.js` + (plain Node/CommonJS — `package.json` has no `"type": "module"`, so this + matches the rest of the repo's tooling scripts). +- It should: + - Recursively walk `projects/budgetkey/src/assets/subject-dashboards/**/*.md`. + - For each file, extract the frontmatter block (`---\n...\n---`) with a small + regex-based parser — the schema only has 5 flat scalar fields + (`title`, `created`, `updated`, `model`, `path`), so a full YAML parser is + unnecessary. Normalize `created`/`updated` to `YYYY-MM-DD` strings (strip + surrounding quotes if present). + - Compute `slug` = the file's path relative to `assets/subject-dashboards/`, + with `.md` stripped and backslashes normalized to `/` (matters on Windows). + - Skip any file that fails to parse required frontmatter fields (log a + warning to stdout, don't crash the build). + - Write a JSON array of `{ slug, title, created, updated, model, path }` to + `assets/subject-dashboards/index.json`. +- Wire it into the build: add an npm script + `"generate:subject-dashboards-index": "node projects/budgetkey/scripts/generate-subject-dashboards-index.js"`, + and prefix it onto `build`, `build-dev`, and `watch` in `package.json` + (e.g. `"build": "npm run generate:subject-dashboards-index && ng build"`). + +**Verification**: run +`node projects/budgetkey/scripts/generate-subject-dashboards-index.js` manually. +Inspect the generated `index.json`: 5 entries, slugs are +`overview`, `getting-started`, `hebrew-example`, `reports/q1-metrics`, +`reports/tipat-chalav`, Hebrew `title` values are intact UTF-8 (not mangled/escaped +oddly), `updated >= created` for all entries. + +## Step 3 — Angular module + routing scaffolding + +- Generate `SubjectDashboardsModule` under + `projects/budgetkey/src/app/subject-dashboards/`, lazy-loaded, following the + exact pattern of `about.module.ts` / `about-routing.module.ts` (imports + `CommonModule`, `CommonComponentsModule`; provides `provideHttpClient(withInterceptorsFromDi())` + if it does its own HTTP calls, matching `about.module.ts`). +- Add to `app-routing.module.ts`: + `{ path: 'subject-dashboards', loadChildren: () => import('./subject-dashboards/subject-dashboards.module').then(m => m.SubjectDashboardsModule) }`. +- Internal routes in `subject-dashboards-routing.module.ts`: + - `{ path: '', component: SubjectDashboardsHomeComponent }` + - `{ path: '**', component: SubjectDashboardPageComponent }` +- Both components can be empty placeholders for this step (just render a string). + +**Verification**: `ng serve`, navigate to `/subject-dashboards` (renders home +placeholder) and `/subject-dashboards/reports/tipat-chalav` (renders detail +placeholder, does **not** 404). Confirm `/dashboards` (the other, unrelated +existing feature) still works unchanged. + +## Step 4 — Home page: nested tree from index.json + +- `SubjectDashboardsHomeComponent` fetches `assets/subject-dashboards/index.json` + via `HttpClient` (same `ps.BASE + '/assets/...'` pattern as `about-page.component.ts` + uses via `PlatformService`). +- Build a nested tree in the component from the flat `{slug, title, ...}[]` list, + splitting each `slug` on `/`: intermediate segments become folder nodes + (label = the raw segment name), the last segment is a leaf node (label = + `title`, links to `/subject-dashboards/`). +- Render the tree as nested `