first commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
TZ=Europe/Berlin
|
||||
REPORT_RENDERER_PORT=8080
|
||||
GOTENBERG_URL=http://gotenberg:3000
|
||||
RENDER_TIMEOUT_SECONDS=60
|
||||
MAX_PAYLOAD_BYTES=2097152
|
||||
@@ -0,0 +1,7 @@
|
||||
.env
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.pytest_cache/
|
||||
output/*.pdf
|
||||
output/*.html
|
||||
!output/.gitkeep
|
||||
@@ -0,0 +1,17 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
@@ -0,0 +1,92 @@
|
||||
.env.example
|
||||
.gitignore
|
||||
LICENSE
|
||||
Makefile
|
||||
QUICKSTART.md
|
||||
README.md
|
||||
docker-compose.yml
|
||||
docs/CUSTOMIZATION.md
|
||||
docs/DATA_MODEL.md
|
||||
docs/PRODUCTION_CHECKLIST.md
|
||||
examples/curl-render.sh
|
||||
examples/render-all-themes.sh
|
||||
examples/sample-claude-input.json
|
||||
examples/sample-claude-output.json
|
||||
examples/sample-report.json
|
||||
n8n/README.md
|
||||
n8n/code-build-claude-request.js
|
||||
n8n/code-build-render-payload.js
|
||||
n8n/code-extract-claude-output.js
|
||||
n8n/code-normalize-month.js
|
||||
n8n/postgres-example-queries.sql
|
||||
n8n/postgres-schema.sql
|
||||
n8n/workflow-template.json
|
||||
output/.gitkeep
|
||||
output/sample-report-classic.html
|
||||
output/sample-report-classic.pdf
|
||||
output/sample-report-modern.html
|
||||
output/sample-report-modern.pdf
|
||||
output/theme-catalog/alpine-sage.html
|
||||
output/theme-catalog/classic.html
|
||||
output/theme-catalog/editorial-ink.html
|
||||
output/theme-catalog/editorial-ivory.html
|
||||
output/theme-catalog/editorial-rose.html
|
||||
output/theme-catalog/executive-blue.html
|
||||
output/theme-catalog/executive-burgundy.html
|
||||
output/theme-catalog/executive-charcoal.html
|
||||
output/theme-catalog/forest-lodge.html
|
||||
output/theme-catalog/ledger-blue.html
|
||||
output/theme-catalog/ledger-green.html
|
||||
output/theme-catalog/ledger-sepia.html
|
||||
output/theme-catalog/magazine-citrus.html
|
||||
output/theme-catalog/magazine-cobalt.html
|
||||
output/theme-catalog/magazine-plum.html
|
||||
output/theme-catalog/midnight-gold.html
|
||||
output/theme-catalog/modern.html
|
||||
output/theme-catalog/nordic-light.html
|
||||
output/theme-catalog/nordic-night.html
|
||||
output/theme-catalog/ocean-breeze.html
|
||||
output/theme-catalog/poster-mono.html
|
||||
output/theme-catalog/poster-red.html
|
||||
output/theme-catalog/poster-yellow.html
|
||||
output/theme-catalog/soft-lavender.html
|
||||
output/theme-catalog/split-teal.html
|
||||
output/theme-catalog/split-terracotta.html
|
||||
output/theme-catalog/split-violet.html
|
||||
output/theme-catalog/sunset-coral.html
|
||||
output/theme-catalog/theme-gallery.html
|
||||
output/theme-catalog/theme-gallery.pdf
|
||||
prompts/anthropic-request-template.json
|
||||
prompts/system-prompt.txt
|
||||
prompts/user-prompt-template.txt
|
||||
pytest.ini
|
||||
renderer/Dockerfile
|
||||
renderer/app/__init__.py
|
||||
renderer/app/formatting.py
|
||||
renderer/app/main.py
|
||||
renderer/app/renderer.py
|
||||
renderer/app/schemas/claude-output-anthropic.schema.json
|
||||
renderer/app/schemas/claude-output.schema.json
|
||||
renderer/app/schemas/report-payload.schema.json
|
||||
renderer/app/templates/_shared/footer.html.j2
|
||||
renderer/app/templates/_shared/macros.html.j2
|
||||
renderer/app/templates/classic/footer.html.j2
|
||||
renderer/app/templates/classic/report.html.j2
|
||||
renderer/app/templates/dashboard/report.html.j2
|
||||
renderer/app/templates/editorial/report.html.j2
|
||||
renderer/app/templates/ledger/report.html.j2
|
||||
renderer/app/templates/magazine/report.html.j2
|
||||
renderer/app/templates/minimal/report.html.j2
|
||||
renderer/app/templates/modern/footer.html.j2
|
||||
renderer/app/templates/modern/report.html.j2
|
||||
renderer/app/templates/poster/report.html.j2
|
||||
renderer/app/templates/sidebar/report.html.j2
|
||||
renderer/app/templates/split/report.html.j2
|
||||
renderer/app/theme_catalog.py
|
||||
renderer/app/validation.py
|
||||
renderer/requirements.txt
|
||||
scripts/render-local.py
|
||||
scripts/render-theme-gallery.py
|
||||
tests/conftest.py
|
||||
tests/test_render.py
|
||||
tests/test_validation.py
|
||||
@@ -0,0 +1,27 @@
|
||||
.PHONY: up down logs test sample preview zip
|
||||
|
||||
up:
|
||||
docker compose up -d --build
|
||||
|
||||
down:
|
||||
docker compose down
|
||||
|
||||
logs:
|
||||
docker compose logs -f report-renderer gotenberg
|
||||
|
||||
test:
|
||||
python -m pytest -q
|
||||
|
||||
sample:
|
||||
mkdir -p output
|
||||
curl -sS -X POST http://localhost:8080/render \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-binary @examples/sample-report.json \
|
||||
-o output/sample-report.pdf
|
||||
|
||||
preview:
|
||||
mkdir -p output
|
||||
curl -sS -X POST http://localhost:8080/preview/html \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-binary @examples/sample-report.json \
|
||||
-o output/sample-report.html
|
||||
@@ -0,0 +1,52 @@
|
||||
# Schnellstart in 10 Schritten
|
||||
|
||||
1. Ordner auf deinen Docker-Host kopieren.
|
||||
2. `.env.example` nach `.env` kopieren.
|
||||
3. `docker compose up -d --build` starten.
|
||||
4. `http://HOST:8080/health` pruefen.
|
||||
5. `examples/sample-report.json` anpassen.
|
||||
6. Mit `/preview/html` zuerst das HTML kontrollieren.
|
||||
7. Mit `/render` das PDF erzeugen.
|
||||
8. `n8n/workflow-template.json` in n8n importieren.
|
||||
9. Anthropic-API-Key in n8n als Credential oder Secret hinterlegen.
|
||||
10. Beispiel-Set-Node durch deine PostgreSQL-Abfragen ersetzen.
|
||||
|
||||
## Minimaler Render-Aufruf
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
-X POST http://localhost:8080/render \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-binary @examples/sample-report.json \
|
||||
-o output/report.pdf
|
||||
```
|
||||
|
||||
## Dienste
|
||||
|
||||
- Report Renderer: `http://localhost:8080`
|
||||
- Gotenberg: standardmaessig nur im internen Docker-Netz erreichbar
|
||||
|
||||
## API-Routen
|
||||
|
||||
- `GET /health`
|
||||
- `GET /themes`
|
||||
- `POST /validate`
|
||||
- `POST /preview/html`
|
||||
- `POST /render`
|
||||
|
||||
|
||||
## Designs ansehen
|
||||
|
||||
Alle IDs abfragen:
|
||||
|
||||
```bash
|
||||
curl -s http://localhost:8080/themes | python3 -m json.tool
|
||||
```
|
||||
|
||||
Im Beispiel-Payload `design.theme` ändern oder alle Designs rendern:
|
||||
|
||||
```bash
|
||||
bash examples/render-all-themes.sh
|
||||
```
|
||||
|
||||
Der mitgelieferte visuelle Katalog liegt unter `output/theme-catalog/theme-gallery.pdf`.
|
||||
@@ -0,0 +1,124 @@
|
||||
# Monthly Report Kit
|
||||
|
||||
Ein reproduzierbares Starterpaket fuer monatliche Kundenreports mit:
|
||||
|
||||
- Claude Structured Outputs fuer valide, schemakonforme Inhalte
|
||||
- fester HTML/CSS-Vorlage statt KI-generiertem Layout
|
||||
- 28 austauschbaren Designs in 10 Layoutfamilien
|
||||
- Python/FastAPI-Render-Service
|
||||
- Gotenberg fuer die PDF-Erzeugung mit Chromium
|
||||
- JSON-Schema-Validierung vor jedem Rendern
|
||||
- n8n-Bausteinen und einem importierbaren Beispielworkflow
|
||||
- Beispielreport, Prompt-Vorlagen und PostgreSQL-Grundstruktur
|
||||
|
||||
## Architektur
|
||||
|
||||
```text
|
||||
PostgreSQL / andere Datenquelle
|
||||
|
|
||||
v
|
||||
n8n normalisiert Monatsdaten
|
||||
|
|
||||
v
|
||||
Claude Messages API + output_config.format
|
||||
|
|
||||
v
|
||||
validiertes Claude-JSON
|
||||
|
|
||||
v
|
||||
Report-Payload aus Kunde + Kennzahlen + Claude-Inhalt
|
||||
|
|
||||
v
|
||||
report-renderer -> HTML/Jinja2 -> Gotenberg -> PDF
|
||||
```
|
||||
|
||||
Claude entscheidet nur, **was** im Report steht. Das Template entscheidet, **wie** es aussieht.
|
||||
|
||||
## Schnellstart
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
docker compose up -d --build
|
||||
curl http://localhost:8080/health
|
||||
```
|
||||
|
||||
Beispielreport erzeugen:
|
||||
|
||||
```bash
|
||||
curl \
|
||||
--request POST http://localhost:8080/render \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data @examples/sample-report.json \
|
||||
--output output/monatsreport-beispiel.pdf
|
||||
```
|
||||
|
||||
HTML-Vorschau im Browser:
|
||||
|
||||
```bash
|
||||
curl \
|
||||
--request POST http://localhost:8080/preview/html \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data @examples/sample-report.json \
|
||||
--output output/preview.html
|
||||
```
|
||||
|
||||
## Wichtigste Dateien
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `renderer/app/theme_catalog.py` | Katalog aller 28 Designs und Farbpaletten |
|
||||
| `renderer/app/templates/` | 10 wiederverwendbare Layoutfamilien |
|
||||
| `scripts/render-theme-gallery.py` | erzeugt Vorschauen und einen PDF-Designkatalog |
|
||||
| `renderer/app/schemas/claude-output-anthropic.schema.json` | API-kompatibles Structured-Output-Schema |
|
||||
| `renderer/app/schemas/claude-output.schema.json` | strenge Nachvalidierung mit Textlaengen und Grenzen |
|
||||
| `renderer/app/schemas/report-payload.schema.json` | kompletter Render-Payload |
|
||||
| `prompts/system-prompt.txt` | feste Claude-Rolle und Regeln |
|
||||
| `prompts/user-prompt-template.txt` | dynamischer Auftrag je Kunde/Monat |
|
||||
| `n8n/workflow-template.json` | importierbarer Workflow-Startpunkt |
|
||||
| `n8n/postgres-schema.sql` | Tabellen fuer Konfiguration und Reportlaeufe |
|
||||
|
||||
## Design auswählen
|
||||
|
||||
Alle verfügbaren Designs liefert der Renderer über `GET /themes`. Im Payload genügt die Theme-ID:
|
||||
|
||||
```json
|
||||
{
|
||||
"design": {
|
||||
"theme": "executive-blue",
|
||||
"palette_mode": "theme"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`palette_mode: "theme"` verwendet die fest definierte Farbwelt des Designs. Mit `palette_mode: "custom"` bleiben Layout und Typografie erhalten, während die im Payload gelieferten Kundenfarben verwendet werden. Die flexiblen Varianten `modern` und `classic` verwenden standardmäßig Kundenfarben.
|
||||
|
||||
### Enthaltene Layoutfamilien
|
||||
|
||||
| Familie | Charakter | Designs |
|
||||
|---|---|---|
|
||||
| Modern | Karten, Verlaufskopf, weich | `modern`, `soft-lavender`, `midnight-gold` |
|
||||
| Classic | Serifenschrift, feine Linien | `classic` |
|
||||
| Minimal | viel Weißraum, ruhige Flächen | `nordic-light`, `nordic-night`, `alpine-sage` |
|
||||
| Dashboard | Management-orientierte KPI-Flächen | `executive-blue`, `executive-charcoal`, `executive-burgundy` |
|
||||
| Sidebar | markante Seitenleiste | `ocean-breeze`, `forest-lodge`, `sunset-coral` |
|
||||
| Editorial | magazinartige Serifengestaltung | `editorial-ivory`, `editorial-ink`, `editorial-rose` |
|
||||
| Magazine | große Typografie, asymmetrische Module | `magazine-cobalt`, `magazine-citrus`, `magazine-plum` |
|
||||
| Ledger | dicht, tabellarisch, zahlenorientiert | `ledger-green`, `ledger-blue`, `ledger-sepia` |
|
||||
| Split | geteilte Titel- und Inhaltsflächen | `split-teal`, `split-violet`, `split-terracotta` |
|
||||
| Poster | plakativ, sehr große Kennzahlen | `poster-red`, `poster-yellow`, `poster-mono` |
|
||||
|
||||
Den vollständigen visuellen Katalog findest du nach dem Entpacken unter `output/theme-catalog/theme-gallery.pdf`. Neu erzeugen kannst du ihn mit:
|
||||
|
||||
```bash
|
||||
python scripts/render-theme-gallery.py
|
||||
```
|
||||
|
||||
## Produktionshinweise
|
||||
|
||||
- API-Key niemals in Workflows exportieren oder im Repository speichern.
|
||||
- `report_version`, `prompt_version` und `template_version` je Report sichern.
|
||||
- Vor dem Versand immer Payload- und PDF-Pruefungen ausfuehren.
|
||||
- Wiederholungen ueber einen eindeutigen Schluessel aus `customer_id + period` verhindern.
|
||||
- Externe Bild-URLs vermeiden. Logos als Base64 Data URI uebergeben.
|
||||
|
||||
Weitere Hinweise stehen unter `docs/`.
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
3772de64cc98a7a239dd0ac1b671f5727c436eb97fdb6c04e4a026ac7c927d5e .env.example
|
||||
cddeca481da53748d012f440fb4cc6346d79a4a435b088790df22a8fbeb5d14e .gitignore
|
||||
ec4ab498897ee0d12aa7f8e354f3a7d4fd1baaf9db18dbf99927ffb78bed08ed LICENSE
|
||||
734d0a6525a8303825860336d7199dd3a1f0c64ca6eef6f5216028b9c1de410d Makefile
|
||||
f89b8af8904b9c2db9d798faa666e3dd680c1b1bb07dedde707a2db802780c15 QUICKSTART.md
|
||||
8a173a2995256f0a31633d5bb7a389701b7ce7c0ed8f4b6bc75bb8ea77f33cec README.md
|
||||
0234c23e00d70cd029f88c3d720326ec3fe0d14d4b857e36bb191836cece95d5 docker-compose.yml
|
||||
339d856cdafc72a681fc14f5b21c525852ed7f9157e70464a21978328a8754a0 docs/CUSTOMIZATION.md
|
||||
86bb53e3a4c40bf29feb11af0d4e160365b323010bdb846f473838afb66c5a4d docs/DATA_MODEL.md
|
||||
9de8e978680517af375577c166af6fee0698a9e86ce0e37cd877dc2b91971b59 docs/PRODUCTION_CHECKLIST.md
|
||||
901e0b2ffe44168bcdca34b2f37d257eafd183b50b66ab0fec38698a87014142 examples/curl-render.sh
|
||||
ca7b0ddae3f0456def13ae40183ecf97e1d718e6fb80382ae2d8995e8260e00e examples/render-all-themes.sh
|
||||
a188ee2512e5acc5015495e10701b412fb673dfb37885b580a4b2ece983f915f examples/sample-claude-input.json
|
||||
c5db2c90552fc7499225c96a19f415cadeb40501c7834842c6e24ac8448467bd examples/sample-claude-output.json
|
||||
9d83b926c4eab21bd7a9468bbde907a4a7075aa0a9f088fec3b587e4b76037c1 examples/sample-report.json
|
||||
114c245d8200036e65e6e40530b747c643a09ce328e719b6713a0405ea75083f n8n/README.md
|
||||
d95757c0b89bbb9257833f552f6fa28e5a69998421ce2ddfbf5eea1bdcf4b70a n8n/code-build-claude-request.js
|
||||
19a764449c5040ac6cd1beee28a6a79073ea33063134b846a59a5bae23c44643 n8n/code-build-render-payload.js
|
||||
2181b163b2a38bc280099a45fce6ade4729376f299e7b5b29ffbe62697471a7f n8n/code-extract-claude-output.js
|
||||
e5a3dbef59ddb1b926a1fd282c3cf0f763d54429ed7f5f3265cb560544d663a4 n8n/code-normalize-month.js
|
||||
c5f095a90926e7909d28623c8e2ae1e4dd2a755597b8f258de46e6040669168e n8n/postgres-example-queries.sql
|
||||
1a69a0f745ea8b6b0f4aeaf841bfe30efd215dfab4d428dbf94451402a5ff54d n8n/postgres-schema.sql
|
||||
80a655e305f2a9e6f33b73f7e1b6c468498727237260a49612b51ab137f1a2dc n8n/workflow-template.json
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 output/.gitkeep
|
||||
67e0aa47dbab19484bd9668105f0c4452ec28295a23ca320b25f1e7067bb92b1 output/sample-report-classic.html
|
||||
eda43c23832bd4ad9f0b8b6657235a13dd7fe3ccff6d25b8b62efd486ada1cdb output/sample-report-classic.pdf
|
||||
3b51d683b8b13ba657d71067cb6b3ab5ba007aca4baa4d200bc654dc2e5da9af output/sample-report-modern.html
|
||||
a4515612d9c153d77b423d6247501be2ecab64777b76ebb28ca9744b9ddfea06 output/sample-report-modern.pdf
|
||||
182b07aa4da2759c1be79e82e72acefc068c89b1cdd4a79acec319ee76695a23 output/theme-catalog/alpine-sage.html
|
||||
67e0aa47dbab19484bd9668105f0c4452ec28295a23ca320b25f1e7067bb92b1 output/theme-catalog/classic.html
|
||||
cd65005a85bbe343a94773f8d97c6f12c75a313d7ea418858e3d4c892ecc744e output/theme-catalog/editorial-ink.html
|
||||
e9e5e90889cf6b8075b3653d5cfc8632f17004ade3e4a3ec6dda2c0223ebb940 output/theme-catalog/editorial-ivory.html
|
||||
9f6657791c563288c6a3e2bb0a154cbd356db0a9a33512343738956ae931272e output/theme-catalog/editorial-rose.html
|
||||
9085f9d73c9afac53e336c424cde1f0fe8b1d7b062864db56eb9e45b5cdbdc46 output/theme-catalog/executive-blue.html
|
||||
97227d9ed5d70ab9a24fe274e6718db808029cc12c5ffc09b451d8211a3c3031 output/theme-catalog/executive-burgundy.html
|
||||
64607b1569dc17840cf8fc10a4eccd6409eb084193e46beb8556fbb8bc77fddc output/theme-catalog/executive-charcoal.html
|
||||
2106baf980e86f5bdd0a520a073df40d35428a215e4efcc7f3f472adcdfa8594 output/theme-catalog/forest-lodge.html
|
||||
3732f81d77b1cc80dba468f2cbda94779a613630ae74d84c65efcba7ec742c7c output/theme-catalog/ledger-blue.html
|
||||
78783ddbc17c0e9866b25b6b93fa9010c488610115f4fa1a794108a7fb56e040 output/theme-catalog/ledger-green.html
|
||||
514e8cf3e981ae304262866edae11cb69628ca870ba6ec7736969c9ca6f2ebe9 output/theme-catalog/ledger-sepia.html
|
||||
f2b4413e8743a8e36fc5721df8fd3bad8cd4f500ecf60714d346086e34e2cde2 output/theme-catalog/magazine-citrus.html
|
||||
889db73c6c649bb114fdd29055abc5e0a8fb30fe66e98fefb9608e4d25bdd823 output/theme-catalog/magazine-cobalt.html
|
||||
2b7911ed20750b1939f96cc030243d95dd8ade9841c4cca3e059524f6e3b7d20 output/theme-catalog/magazine-plum.html
|
||||
786f9f8ad6e27a27ab7ad0579d4ff5bd37900a653c53519f1aa5c7d9e7de83e6 output/theme-catalog/midnight-gold.html
|
||||
3b51d683b8b13ba657d71067cb6b3ab5ba007aca4baa4d200bc654dc2e5da9af output/theme-catalog/modern.html
|
||||
c12b3922f8f96afd221c1e9049fd5eaa7fcca6fdf608221630fe0deed6cfa07f output/theme-catalog/nordic-light.html
|
||||
7ae6c3eae738abb26f7272e4171ef23dc3ded84e12938a2d35e1b9a5437a70b1 output/theme-catalog/nordic-night.html
|
||||
52e63e72d056acbbb93f9c9954ffdf9406e18966955f9b3c76c54ef257e14995 output/theme-catalog/ocean-breeze.html
|
||||
b0ccf9b7e7d492ce27a002b3da5b0aa7f6b056102997375e4492b54af4ba1f73 output/theme-catalog/poster-mono.html
|
||||
11a3b7ebfc570371b0d2d59e065b0083630bfd5b180a679f045d22fc427fe47b output/theme-catalog/poster-red.html
|
||||
d456da8ab54fc6b6e4c10d3fb5d10d964db40c819d2f3bb53816a1198315e0dc output/theme-catalog/poster-yellow.html
|
||||
fe926c94c73f51b1aabf03bafef7a04acda08c6291ac19a70cfe5897ffb2fac8 output/theme-catalog/soft-lavender.html
|
||||
b96d8a0c74e8f41e19085620366448bd4492ae49bd950268585a76f2a4a8846c output/theme-catalog/split-teal.html
|
||||
c6dc77a1de12a41cf9540d8906debaf4512cc431c2797eacf524b1df15400924 output/theme-catalog/split-terracotta.html
|
||||
2472963115164b2ae2c7fb38278e691065db845a95db8ad94be183aef66ae612 output/theme-catalog/split-violet.html
|
||||
7aba082062da87bd78d08d8d984ee7ca755fe32917654e72d937ad4e9678a960 output/theme-catalog/sunset-coral.html
|
||||
08d242bed264e0f31e1ab31ed79a37fb8a6bd18b91b63e79e05af175e97d4608 output/theme-catalog/theme-gallery.html
|
||||
f39bb252bd52865c4551691a929d0cdf10d00eddd6a7f3ae0378f8bf2a8c5b55 output/theme-catalog/theme-gallery.pdf
|
||||
23134c1e9992b5eb7c877b1c157d53ab0e36ac9c8ddcb2821b083f992b3dda39 prompts/anthropic-request-template.json
|
||||
cd385809063a0badc73a37d7f87dc436886999785f8707c41bd57bd886fddc91 prompts/system-prompt.txt
|
||||
0c6faf43172f0fa137d9c361dacceae4c5b972aef8623dcc14ea849bb1ccfb9b prompts/user-prompt-template.txt
|
||||
c809c969ec7e11b9ff37784e9c6fcc0b7c5148d168e18b05aed797e03fbd6ead pytest.ini
|
||||
6622f5ec0bc98804a17760ae13be6c9a9d1532eb36b69f72de01c749b565d454 renderer/Dockerfile
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 renderer/app/__init__.py
|
||||
f46c52197e900e03b4a0b86d3b421534aa0387421c571ba743e3f0e041c2a0aa renderer/app/formatting.py
|
||||
d515a0b7f4ea1976ba09903100409a3596f5f39e90aa496b4b7f2250a919d53f renderer/app/main.py
|
||||
f18636cfa6ee4c5e509608cf047194eafb289b6798913595e4b43f3db7506178 renderer/app/renderer.py
|
||||
8b7af092bdc0088832bd8f0e2fca15c10cb7c058ad4ad9d736ab7cbd677f97d6 renderer/app/schemas/claude-output-anthropic.schema.json
|
||||
75b1bc32ae1e6d334279b385cf99712bf33cc78366e59c8f7013a39d11e334fc renderer/app/schemas/claude-output.schema.json
|
||||
b1d9da86c2b0723f8c3bc3f03ffe89da15a099b1411b4e0a6c49a1e4be52b40a renderer/app/schemas/report-payload.schema.json
|
||||
632d0dc09ca2bd9b98ac98aaf4540c14cd7c41c7cbad63358a56139303fce6e0 renderer/app/templates/_shared/footer.html.j2
|
||||
cff8e11e83cca48fe3a6fc59cf0d72be2349c3d7c1ad5b168cb1826d8975594c renderer/app/templates/_shared/macros.html.j2
|
||||
4c085ecc7a6418eb6d7fd673242dce76a65076b65c428baf6b1fff191354dd5a renderer/app/templates/classic/footer.html.j2
|
||||
140c3d2810b67d62729a57cc03aa45d651236f93d6e124c9caaca7267157a62b renderer/app/templates/classic/report.html.j2
|
||||
1690c913f1b92e45d40093338478ecff2b63e4a3efb92cf2e9e8da2af74c687e renderer/app/templates/dashboard/report.html.j2
|
||||
e43f73535b336a52da00f2e6c11699c4f304a819f0f738629cef65b23b6af8b0 renderer/app/templates/editorial/report.html.j2
|
||||
9f2827abc07b4888d2ffe9d5bb20062a242fcfcc0e50b183cb88bdd8532cbeb5 renderer/app/templates/ledger/report.html.j2
|
||||
b3acd510ba16424bb32baa2e08b1ac9de95d84ac912e39913e19348d02d81e13 renderer/app/templates/magazine/report.html.j2
|
||||
a89095e83da21a3c3f5db08d2abce769fcb6dbdb4f0bc89ae55e5aff0c740b86 renderer/app/templates/minimal/report.html.j2
|
||||
a63847d53e571ddb28fd5cf3593e0913e6273ad6c9a6d50c550f045e1fb38942 renderer/app/templates/modern/footer.html.j2
|
||||
cbb71a402abbd4ad4bcd95bfdfde6688a68d88c05168d6da51abbe72335e8446 renderer/app/templates/modern/report.html.j2
|
||||
dd1d096c8c34ac741d3d645ec2bc23c698c208376c61036bcaa2c9235dda7173 renderer/app/templates/poster/report.html.j2
|
||||
75a16ed98c86ba108e64d528c5292432c96101d4d466e27706c0ee4be216108e renderer/app/templates/sidebar/report.html.j2
|
||||
63c48859557e147be9ed8b929370d49de8d7c192d0d2ad0361075353e819b68a renderer/app/templates/split/report.html.j2
|
||||
30fbfcaf3973531384b8d0ed8df1b8868987a1be1d42d297953bf172db3d6e6d renderer/app/theme_catalog.py
|
||||
1c8d516e13a21c16a306b35dedbc26929012f7afe03a8cb28899da09960b2d26 renderer/app/validation.py
|
||||
35137cd8aeecd002116d489d98d0dc505909ec5d999d237387a094bd3e7f72f9 renderer/requirements.txt
|
||||
e9ba2837656241375edd0f1027efe34c874d401efe87f3840a0a95e42a326ad0 scripts/render-local.py
|
||||
0991e6bfdd450d1ce376b1cbf17170ba8c35342ac9bf320b30e858f0e45be49c scripts/render-theme-gallery.py
|
||||
23b58558bad1c0c26a9095cb788f1b17bc8ba048c6db5fc9b24fa80b7097aa9b tests/conftest.py
|
||||
811ecd465756c60292e65450434c6003ded577572315eee7f7809525ec253a49 tests/test_render.py
|
||||
391a85063ce5ccafc11b23c24262292d05115c540d046a2dc177592233026852 tests/test_validation.py
|
||||
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
report-renderer:
|
||||
build:
|
||||
context: ./renderer
|
||||
container_name: monthly-report-renderer
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TZ: ${TZ:-Europe/Berlin}
|
||||
GOTENBERG_URL: ${GOTENBERG_URL:-http://gotenberg:3000}
|
||||
RENDER_TIMEOUT_SECONDS: ${RENDER_TIMEOUT_SECONDS:-60}
|
||||
MAX_PAYLOAD_BYTES: ${MAX_PAYLOAD_BYTES:-2097152}
|
||||
ports:
|
||||
- "${REPORT_RENDERER_PORT:-8080}:8080"
|
||||
depends_on:
|
||||
gotenberg:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- report-net
|
||||
|
||||
gotenberg:
|
||||
image: gotenberg/gotenberg:8
|
||||
container_name: monthly-report-gotenberg
|
||||
restart: unless-stopped
|
||||
command:
|
||||
- gotenberg
|
||||
- --chromium-disable-javascript=true
|
||||
- --api-timeout=90s
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "--fail", "http://localhost:3000/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- report-net
|
||||
|
||||
networks:
|
||||
report-net:
|
||||
name: monthly-report-net
|
||||
@@ -0,0 +1,2 @@
|
||||
[pytest]
|
||||
testpaths = tests
|
||||
Reference in New Issue
Block a user