praxigraph 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praxigraph-1.0.0/.gitignore +19 -0
- praxigraph-1.0.0/CHANGELOG.md +23 -0
- praxigraph-1.0.0/LICENSE +21 -0
- praxigraph-1.0.0/PKG-INFO +182 -0
- praxigraph-1.0.0/README.md +150 -0
- praxigraph-1.0.0/docs/SPEC.md +73 -0
- praxigraph-1.0.0/examples/minimal/assets/logo.svg +5 -0
- praxigraph-1.0.0/examples/minimal/config.yaml +34 -0
- praxigraph-1.0.0/examples/minimal/documents/kickoff-protokoll.md +46 -0
- praxigraph-1.0.0/examples/minimal/documents/leistungsnachweis-august.md +28 -0
- praxigraph-1.0.0/examples/minimal/documents/statusbericht-august.md +40 -0
- praxigraph-1.0.0/pyproject.toml +61 -0
- praxigraph-1.0.0/src/praxigraph/__init__.py +3 -0
- praxigraph-1.0.0/src/praxigraph/builder.py +73 -0
- praxigraph-1.0.0/src/praxigraph/cli.py +60 -0
- praxigraph-1.0.0/src/praxigraph/config.py +162 -0
- praxigraph-1.0.0/src/praxigraph/document.py +91 -0
- praxigraph-1.0.0/src/praxigraph/pdf.py +113 -0
- praxigraph-1.0.0/src/praxigraph/render.py +191 -0
- praxigraph-1.0.0/src/praxigraph/themes/letter.css +297 -0
- praxigraph-1.0.0/tests/conftest.py +15 -0
- praxigraph-1.0.0/tests/test_builder.py +48 -0
- praxigraph-1.0.0/tests/test_cli.py +24 -0
- praxigraph-1.0.0/tests/test_config.py +68 -0
- praxigraph-1.0.0/tests/test_document.py +59 -0
- praxigraph-1.0.0/tests/test_render.py +87 -0
- praxigraph-1.0.0/uv.lock +250 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.venv/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
|
|
10
|
+
# Generated intermediate output when building the examples in the repo.
|
|
11
|
+
# The rendered example PDFs (examples/*/pdf/) ARE committed on purpose.
|
|
12
|
+
examples/*/.build/
|
|
13
|
+
|
|
14
|
+
# macOS
|
|
15
|
+
.DS_Store
|
|
16
|
+
|
|
17
|
+
# Local Claude instructions
|
|
18
|
+
CLAUDE.md
|
|
19
|
+
CLAUDE.local.md
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [1.0.0] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- First release: Markdown documents with YAML front matter rendered onto an
|
|
12
|
+
A4 letterhead (theme "letter") and exported to PDF via Chrome headless.
|
|
13
|
+
- Letterhead from `config.yaml`: logo (SVG inlined, PNG/JPEG embedded) in the
|
|
14
|
+
header and a multi-column footer (address, contact, tax IDs, bank details)
|
|
15
|
+
repeated on every page.
|
|
16
|
+
- Front matter fields: `type`, `title`, `date` (required), `number`,
|
|
17
|
+
`recipient`, `meta`, `signature`, `slug`, `lang`.
|
|
18
|
+
- Page numbers (`i / n`, bottom right) and PDF title/author metadata via pypdf.
|
|
19
|
+
- The footer's e-mail and website are clickable links in the PDF.
|
|
20
|
+
- CLI: `praxigraph build` (with `--doc`, `--html-only`, `--date`) and
|
|
21
|
+
`praxigraph validate`.
|
|
22
|
+
- Example under `examples/minimal/` with a fictional company; doubles as the
|
|
23
|
+
test fixture.
|
praxigraph-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Bortlik
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: praxigraph
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Markdown-driven business document generator on your own letterhead: reports, minutes and certificates as PDF via Chrome headless
|
|
5
|
+
Project-URL: Homepage, https://github.com/Supportlik/Praxigraph
|
|
6
|
+
Project-URL: Repository, https://github.com/Supportlik/Praxigraph
|
|
7
|
+
Project-URL: Issues, https://github.com/Supportlik/Praxigraph/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Supportlik/Praxigraph/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Specification, https://github.com/Supportlik/Praxigraph/blob/main/docs/SPEC.md
|
|
10
|
+
Author-email: Michael Bortlik <michael@bortlik.io>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: generator,letterhead,markdown,minutes,pdf,protocol,report
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Office/Business
|
|
25
|
+
Classifier: Topic :: Printing
|
|
26
|
+
Classifier: Topic :: Text Processing :: Markup :: HTML
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: markdown>=3.5
|
|
29
|
+
Requires-Dist: pypdf>=6.0
|
|
30
|
+
Requires-Dist: pyyaml>=6.0
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Praxigraph
|
|
34
|
+
|
|
35
|
+
[](https://github.com/Supportlik/Praxigraph/actions/workflows/ci.yml)
|
|
36
|
+
[](https://pypi.org/project/praxigraph/)
|
|
37
|
+
[](https://pypi.org/project/praxigraph/)
|
|
38
|
+
[](https://github.com/Supportlik/Praxigraph/blob/main/LICENSE)
|
|
39
|
+
|
|
40
|
+
**Praxigraph** (Greek *πρᾶξις* "act, transaction, proceeding" + *γράφειν* "to write": "the one that writes down your proceedings") is a Markdown-driven generator for business documents on your own letterhead: **meeting minutes, status reports, certificates, timesheets** — anything you issue on company paper that is not an invoice. It is the sibling project of [Ergograph](https://github.com/Supportlik/Ergograph), which does the same for CVs and dossiers.
|
|
41
|
+
|
|
42
|
+
The generator contains **no personal data**. Your letterhead (company name, address, contact, tax IDs, bank details, logo) lives in a `config.yaml` outside the repo; each document is one Markdown file with YAML front matter. The code only provides rendering, the theme and the PDF export.
|
|
43
|
+
|
|
44
|
+
## How it works
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
config.yaml + documents/*.md -> HTML (theme "letter") -> PDF (Chrome headless)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
1. `config.yaml` holds the letterhead and steers the build: header logo and the multi-column footer (address, contact, tax IDs, bank) are printed on **every** page.
|
|
51
|
+
2. One Markdown file per document. The front matter carries the document type, title, date, an optional number, recipient and extra info-box rows; the Markdown body becomes the content — headings, lists and tables included.
|
|
52
|
+
3. Chrome (headless) renders the HTML to A4 PDFs, which then get page numbers (`i / n`, bottom right) and title/author metadata stamped in.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
Requirements: Python ≥ 3.10 and Google Chrome or Chromium. Chrome is only needed
|
|
57
|
+
for the PDF step (`praxigraph build --html-only` works without it) and is not
|
|
58
|
+
installed by pip — Praxigraph looks for an existing installation (see `chrome:` below).
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# as an isolated tool (recommended)
|
|
62
|
+
uv tool install praxigraph
|
|
63
|
+
|
|
64
|
+
# or into the current environment
|
|
65
|
+
pip install praxigraph
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
All three dependencies (PyYAML, Markdown, pypdf) are pure Python.
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd examples/minimal/
|
|
74
|
+
praxigraph validate # check config + documents
|
|
75
|
+
praxigraph build # build everything (HTML + PDF)
|
|
76
|
+
praxigraph build --html-only # HTML only, no Chrome
|
|
77
|
+
praxigraph build --doc kickoff-protokoll
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The PDFs end up under `pdf/YYYY-MM-DD_<slug>.pdf` — the date comes from the
|
|
81
|
+
document's front matter, so rebuilding never shuffles your archive
|
|
82
|
+
(disable the prefix with `output.date_prefix: false`).
|
|
83
|
+
|
|
84
|
+
## Example output
|
|
85
|
+
|
|
86
|
+
The rendered example PDFs are committed under
|
|
87
|
+
[`examples/minimal/pdf/`](examples/minimal/pdf/): meeting minutes with a
|
|
88
|
+
recipient address, a status report, and a signed timesheet certificate — all
|
|
89
|
+
for a fictional company.
|
|
90
|
+
|
|
91
|
+
## The steering file `config.yaml`
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
letterhead:
|
|
95
|
+
name: Daniel Falkner # bold first line, also the PDF author
|
|
96
|
+
tagline: IT-Beratung & Systemintegration
|
|
97
|
+
street: Ahornweg 12
|
|
98
|
+
zip: "93049"
|
|
99
|
+
city: Regensburg
|
|
100
|
+
# country: Deutschland # optional, shown in the footer
|
|
101
|
+
logo: assets/logo.svg # optional; SVG is inlined, PNG/JPEG embedded
|
|
102
|
+
contact: # optional; each key is optional too
|
|
103
|
+
phone: +49 941 000000
|
|
104
|
+
email: mail@falkner-it.example
|
|
105
|
+
website: falkner-it.example
|
|
106
|
+
tax: # optional: vat_id, tax_number
|
|
107
|
+
vat_id: DE999999999
|
|
108
|
+
bank: # optional: name, iban, bic
|
|
109
|
+
name: Musterbank
|
|
110
|
+
iban: DE02 1203 0000 0000 2020 51
|
|
111
|
+
bic: BYLADEM1001
|
|
112
|
+
signature: # used by documents with `signature: true`
|
|
113
|
+
name: Daniel Falkner
|
|
114
|
+
place: Regensburg
|
|
115
|
+
|
|
116
|
+
theme: letter # bundled theme, or path to your own .css
|
|
117
|
+
# color: "#1a3c6e" # accent color (title, footer); default black
|
|
118
|
+
# lang: de # HTML language attribute, default de
|
|
119
|
+
# date_format: "%d.%m.%Y"
|
|
120
|
+
|
|
121
|
+
documents: documents # a directory with *.md, or an explicit list of files
|
|
122
|
+
|
|
123
|
+
labels: # optional overrides of the German defaults, e.g. for English paper
|
|
124
|
+
# date: Date
|
|
125
|
+
# vat_id: VAT ID
|
|
126
|
+
|
|
127
|
+
output:
|
|
128
|
+
html_dir: .build/html
|
|
129
|
+
pdf_dir: pdf
|
|
130
|
+
date_prefix: true # date-stamped file names; false = stable names
|
|
131
|
+
|
|
132
|
+
# chrome: /path/to/chrome # optional; otherwise auto-detected
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The letterhead footer renders up to four columns, and empty ones simply
|
|
136
|
+
disappear: address · contact · tax IDs · bank details.
|
|
137
|
+
|
|
138
|
+
## A document
|
|
139
|
+
|
|
140
|
+
````markdown
|
|
141
|
+
---
|
|
142
|
+
type: Protokoll # document type, printed above the title
|
|
143
|
+
title: Kickoff Website-Relaunch
|
|
144
|
+
date: 2026-08-14 # also the file-name prefix
|
|
145
|
+
number: P-2026-001 # optional, shown in the type line and info box
|
|
146
|
+
recipient: | # optional; adds a DIN-letter address block
|
|
147
|
+
Muster GmbH
|
|
148
|
+
Frau Erika Muster
|
|
149
|
+
Musterallee 8
|
|
150
|
+
93047 Regensburg
|
|
151
|
+
meta: # optional extra rows in the info box
|
|
152
|
+
- label: Projekt
|
|
153
|
+
value: Website-Relaunch
|
|
154
|
+
signature: true # optional signature block (place, date, line, name)
|
|
155
|
+
# slug: kickoff # optional, default: file name stem
|
|
156
|
+
# lang: de # optional, overrides config
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Teilnehmer
|
|
160
|
+
|
|
161
|
+
- Erika Muster (Muster GmbH)
|
|
162
|
+
...
|
|
163
|
+
````
|
|
164
|
+
|
|
165
|
+
The body is standard Markdown (Python-Markdown with the `tables`,
|
|
166
|
+
`fenced_code` and `sane_lists` extensions). Tables render in the letterhead
|
|
167
|
+
style: dark header row, thin rules. Front matter values are plain text and are
|
|
168
|
+
HTML-escaped; formatting belongs in the Markdown body.
|
|
169
|
+
|
|
170
|
+
## Development
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv run pytest # test suite, no Chrome and no network needed
|
|
174
|
+
cd examples/minimal && uv run praxigraph build
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Design decisions and requirements live in [`docs/SPEC.md`](docs/SPEC.md).
|
|
178
|
+
Version history: [`CHANGELOG.md`](CHANGELOG.md).
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Praxigraph
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Supportlik/Praxigraph/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/praxigraph/)
|
|
5
|
+
[](https://pypi.org/project/praxigraph/)
|
|
6
|
+
[](https://github.com/Supportlik/Praxigraph/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
**Praxigraph** (Greek *πρᾶξις* "act, transaction, proceeding" + *γράφειν* "to write": "the one that writes down your proceedings") is a Markdown-driven generator for business documents on your own letterhead: **meeting minutes, status reports, certificates, timesheets** — anything you issue on company paper that is not an invoice. It is the sibling project of [Ergograph](https://github.com/Supportlik/Ergograph), which does the same for CVs and dossiers.
|
|
9
|
+
|
|
10
|
+
The generator contains **no personal data**. Your letterhead (company name, address, contact, tax IDs, bank details, logo) lives in a `config.yaml` outside the repo; each document is one Markdown file with YAML front matter. The code only provides rendering, the theme and the PDF export.
|
|
11
|
+
|
|
12
|
+
## How it works
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
config.yaml + documents/*.md -> HTML (theme "letter") -> PDF (Chrome headless)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
1. `config.yaml` holds the letterhead and steers the build: header logo and the multi-column footer (address, contact, tax IDs, bank) are printed on **every** page.
|
|
19
|
+
2. One Markdown file per document. The front matter carries the document type, title, date, an optional number, recipient and extra info-box rows; the Markdown body becomes the content — headings, lists and tables included.
|
|
20
|
+
3. Chrome (headless) renders the HTML to A4 PDFs, which then get page numbers (`i / n`, bottom right) and title/author metadata stamped in.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
Requirements: Python ≥ 3.10 and Google Chrome or Chromium. Chrome is only needed
|
|
25
|
+
for the PDF step (`praxigraph build --html-only` works without it) and is not
|
|
26
|
+
installed by pip — Praxigraph looks for an existing installation (see `chrome:` below).
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# as an isolated tool (recommended)
|
|
30
|
+
uv tool install praxigraph
|
|
31
|
+
|
|
32
|
+
# or into the current environment
|
|
33
|
+
pip install praxigraph
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
All three dependencies (PyYAML, Markdown, pypdf) are pure Python.
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cd examples/minimal/
|
|
42
|
+
praxigraph validate # check config + documents
|
|
43
|
+
praxigraph build # build everything (HTML + PDF)
|
|
44
|
+
praxigraph build --html-only # HTML only, no Chrome
|
|
45
|
+
praxigraph build --doc kickoff-protokoll
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The PDFs end up under `pdf/YYYY-MM-DD_<slug>.pdf` — the date comes from the
|
|
49
|
+
document's front matter, so rebuilding never shuffles your archive
|
|
50
|
+
(disable the prefix with `output.date_prefix: false`).
|
|
51
|
+
|
|
52
|
+
## Example output
|
|
53
|
+
|
|
54
|
+
The rendered example PDFs are committed under
|
|
55
|
+
[`examples/minimal/pdf/`](examples/minimal/pdf/): meeting minutes with a
|
|
56
|
+
recipient address, a status report, and a signed timesheet certificate — all
|
|
57
|
+
for a fictional company.
|
|
58
|
+
|
|
59
|
+
## The steering file `config.yaml`
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
letterhead:
|
|
63
|
+
name: Daniel Falkner # bold first line, also the PDF author
|
|
64
|
+
tagline: IT-Beratung & Systemintegration
|
|
65
|
+
street: Ahornweg 12
|
|
66
|
+
zip: "93049"
|
|
67
|
+
city: Regensburg
|
|
68
|
+
# country: Deutschland # optional, shown in the footer
|
|
69
|
+
logo: assets/logo.svg # optional; SVG is inlined, PNG/JPEG embedded
|
|
70
|
+
contact: # optional; each key is optional too
|
|
71
|
+
phone: +49 941 000000
|
|
72
|
+
email: mail@falkner-it.example
|
|
73
|
+
website: falkner-it.example
|
|
74
|
+
tax: # optional: vat_id, tax_number
|
|
75
|
+
vat_id: DE999999999
|
|
76
|
+
bank: # optional: name, iban, bic
|
|
77
|
+
name: Musterbank
|
|
78
|
+
iban: DE02 1203 0000 0000 2020 51
|
|
79
|
+
bic: BYLADEM1001
|
|
80
|
+
signature: # used by documents with `signature: true`
|
|
81
|
+
name: Daniel Falkner
|
|
82
|
+
place: Regensburg
|
|
83
|
+
|
|
84
|
+
theme: letter # bundled theme, or path to your own .css
|
|
85
|
+
# color: "#1a3c6e" # accent color (title, footer); default black
|
|
86
|
+
# lang: de # HTML language attribute, default de
|
|
87
|
+
# date_format: "%d.%m.%Y"
|
|
88
|
+
|
|
89
|
+
documents: documents # a directory with *.md, or an explicit list of files
|
|
90
|
+
|
|
91
|
+
labels: # optional overrides of the German defaults, e.g. for English paper
|
|
92
|
+
# date: Date
|
|
93
|
+
# vat_id: VAT ID
|
|
94
|
+
|
|
95
|
+
output:
|
|
96
|
+
html_dir: .build/html
|
|
97
|
+
pdf_dir: pdf
|
|
98
|
+
date_prefix: true # date-stamped file names; false = stable names
|
|
99
|
+
|
|
100
|
+
# chrome: /path/to/chrome # optional; otherwise auto-detected
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The letterhead footer renders up to four columns, and empty ones simply
|
|
104
|
+
disappear: address · contact · tax IDs · bank details.
|
|
105
|
+
|
|
106
|
+
## A document
|
|
107
|
+
|
|
108
|
+
````markdown
|
|
109
|
+
---
|
|
110
|
+
type: Protokoll # document type, printed above the title
|
|
111
|
+
title: Kickoff Website-Relaunch
|
|
112
|
+
date: 2026-08-14 # also the file-name prefix
|
|
113
|
+
number: P-2026-001 # optional, shown in the type line and info box
|
|
114
|
+
recipient: | # optional; adds a DIN-letter address block
|
|
115
|
+
Muster GmbH
|
|
116
|
+
Frau Erika Muster
|
|
117
|
+
Musterallee 8
|
|
118
|
+
93047 Regensburg
|
|
119
|
+
meta: # optional extra rows in the info box
|
|
120
|
+
- label: Projekt
|
|
121
|
+
value: Website-Relaunch
|
|
122
|
+
signature: true # optional signature block (place, date, line, name)
|
|
123
|
+
# slug: kickoff # optional, default: file name stem
|
|
124
|
+
# lang: de # optional, overrides config
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Teilnehmer
|
|
128
|
+
|
|
129
|
+
- Erika Muster (Muster GmbH)
|
|
130
|
+
...
|
|
131
|
+
````
|
|
132
|
+
|
|
133
|
+
The body is standard Markdown (Python-Markdown with the `tables`,
|
|
134
|
+
`fenced_code` and `sane_lists` extensions). Tables render in the letterhead
|
|
135
|
+
style: dark header row, thin rules. Front matter values are plain text and are
|
|
136
|
+
HTML-escaped; formatting belongs in the Markdown body.
|
|
137
|
+
|
|
138
|
+
## Development
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
uv run pytest # test suite, no Chrome and no network needed
|
|
142
|
+
cd examples/minimal && uv run praxigraph build
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Design decisions and requirements live in [`docs/SPEC.md`](docs/SPEC.md).
|
|
146
|
+
Version history: [`CHANGELOG.md`](CHANGELOG.md).
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Praxigraph — Specification
|
|
2
|
+
|
|
3
|
+
Requirements are numbered R1…, design decisions D1…. Every substantive change
|
|
4
|
+
to formats or behavior updates this file.
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
|
|
8
|
+
Praxigraph renders business documents (meeting minutes, reports, certificates,
|
|
9
|
+
timesheets) from Markdown files onto a company letterhead and exports them as
|
|
10
|
+
A4 PDFs. It is the sibling of [Ergograph](https://github.com/Supportlik/Ergograph)
|
|
11
|
+
(CVs/dossiers) and follows the same philosophy: no personal data in the code,
|
|
12
|
+
everything steered from outside, Chrome headless for the PDF step, pypdf for
|
|
13
|
+
page numbers and metadata.
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
| # | Requirement | Implemented in |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| R1 | All letterhead data comes from `config.yaml`; the repo contains only a fictional example. | `config.py`, `examples/` |
|
|
20
|
+
| R2 | One document = one Markdown file with YAML front matter (`type`, `title`, `date` required). | `document.py` |
|
|
21
|
+
| R3 | The letterhead (logo header + company footer) is printed on **every** page. | theme `letter.css` (D2) |
|
|
22
|
+
| R4 | Page numbers `i / n` on every page, plus PDF title/author metadata. | `pdf.py` (D3) |
|
|
23
|
+
| R5 | An optional recipient renders as a letter address block with a small sender line above it. | `render.py` |
|
|
24
|
+
| R6 | An info box (number, date, free `meta` rows) sits top right on the first page. | `render.py` |
|
|
25
|
+
| R7 | `signature: true` appends a signature block (place, date, line, name, firm). | `render.py` |
|
|
26
|
+
| R8 | Labels default to German and are individually overridable (`labels:`). | `config.py` |
|
|
27
|
+
| R9 | Builds are reproducible: PDF names derive from the front matter date (`YYYY-MM-DD_<slug>.pdf`), or stable names with `date_prefix: false`. | `builder.py` |
|
|
28
|
+
| R10 | `praxigraph validate` checks config and all documents without Chrome. | `cli.py` |
|
|
29
|
+
| R11 | The test suite runs without Chrome and without network. | `tests/` |
|
|
30
|
+
| R12 | Front matter and config values are HTML-escaped; formatting belongs in the Markdown body. | `render.py` (D5) |
|
|
31
|
+
| R13 | The footer's e-mail and website are clickable PDF links (Chrome carries `<a href>` into link annotations), styled as plain text. | `render.py`, theme |
|
|
32
|
+
|
|
33
|
+
## Design decisions
|
|
34
|
+
|
|
35
|
+
- **D1 — Markdown, not YAML, for the body.** Ergograph's content is structured
|
|
36
|
+
data (lists of stations, skills), so YAML fits. Minutes and reports are
|
|
37
|
+
prose with headings and tables; Markdown is the natural format. Structured
|
|
38
|
+
metadata stays in the YAML front matter.
|
|
39
|
+
- **D2 — Letterhead via `position: fixed` + thead/tfoot spacers.** Chrome's
|
|
40
|
+
print engine supports neither CSS margin boxes nor `position: running`
|
|
41
|
+
(both Paged-Media features used by commercial renderers). It does repeat
|
|
42
|
+
`position: fixed` elements on every printed page, and a table's
|
|
43
|
+
thead/tfoot repeat too and reserve the vertical space. The page skeleton
|
|
44
|
+
therefore is one table with spacer rows; header and footer are fixed
|
|
45
|
+
elements. `@page` margin is 0; horizontal margins come from content padding.
|
|
46
|
+
- **D3 — Page numbers stamped with pypdf.** Chrome does not support
|
|
47
|
+
`counter(pages)`, so totals are unknowable in CSS. Like Ergograph, the
|
|
48
|
+
numbers are stamped post-hoc in Helvetica (a PDF base-14 font, no
|
|
49
|
+
embedding needed), bottom right just above the footer block.
|
|
50
|
+
- **D4 — The theme mirrors an invoice template.** The bundled theme "letter"
|
|
51
|
+
replicates the metrics of a sevdesk "black invoice" letterhead (Roboto
|
|
52
|
+
Condensed 9pt/11.5pt, content area 20/15 mm, ~46 mm header zone, ~30 mm
|
|
53
|
+
four-column 7pt footer, black table header rows), so documents and invoices
|
|
54
|
+
from the same company look like siblings. Custom themes: any `.css` path.
|
|
55
|
+
- **D5 — Scalar values are escaped, unlike Ergograph.** Ergograph treats
|
|
56
|
+
content values as trusted HTML fragments (D2 there). Praxigraph documents
|
|
57
|
+
have a real body channel for formatting — Markdown — so front matter and
|
|
58
|
+
config scalars are plain text and get escaped. This keeps `&` in company
|
|
59
|
+
names from breaking the page.
|
|
60
|
+
- **D6 — Webfont with graceful fallback.** The theme imports Roboto Condensed
|
|
61
|
+
from Google Fonts; offline builds fall back to Helvetica/Arial. Chrome's
|
|
62
|
+
`--virtual-time-budget` gives the font time to load.
|
|
63
|
+
- **D7 — No text-layer verification (yet).** Ergograph verifies ATS
|
|
64
|
+
readability because CVs are machine-parsed. Reports and minutes are read by
|
|
65
|
+
humans; the check adds little and is omitted in 0.1.0.
|
|
66
|
+
- **D8 — Fictional example doubles as the test fixture** (same as Ergograph):
|
|
67
|
+
format changes must update examples, tests and this spec together.
|
|
68
|
+
|
|
69
|
+
## File name scheme
|
|
70
|
+
|
|
71
|
+
`pdf/<date>_<slug>.pdf` with `<date>` = front matter date (ISO) or the
|
|
72
|
+
`--date` override; `<slug>` = front matter `slug` or the Markdown file's stem.
|
|
73
|
+
`output.date_prefix: false` drops the prefix (used by the committed examples).
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52" role="img" aria-label="Falkner IT logo">
|
|
2
|
+
<!-- Fictional example logo: a monogram "F" in a rounded square. -->
|
|
3
|
+
<rect x="3" y="3" width="46" height="46" rx="9" fill="none" stroke="#1a3c6e" stroke-width="3"/>
|
|
4
|
+
<path d="M18 38 V14 H36 M18 25 H31" fill="none" stroke="#1a3c6e" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Praxigraph steering file. Every value here belongs to a fictional company;
|
|
2
|
+
# it doubles as the test fixture for the test suite.
|
|
3
|
+
letterhead:
|
|
4
|
+
name: Daniel Falkner
|
|
5
|
+
tagline: IT-Beratung & Systemintegration
|
|
6
|
+
street: Ahornweg 12
|
|
7
|
+
zip: "93049"
|
|
8
|
+
city: Regensburg
|
|
9
|
+
logo: assets/logo.svg
|
|
10
|
+
contact:
|
|
11
|
+
phone: +49 941 000000
|
|
12
|
+
email: mail@falkner-it.example
|
|
13
|
+
website: falkner-it.example
|
|
14
|
+
tax:
|
|
15
|
+
vat_id: DE999999999
|
|
16
|
+
bank:
|
|
17
|
+
name: Musterbank
|
|
18
|
+
iban: DE02 1203 0000 0000 2020 51
|
|
19
|
+
bic: BYLADEM1001
|
|
20
|
+
signature:
|
|
21
|
+
name: Daniel Falkner
|
|
22
|
+
place: Regensburg
|
|
23
|
+
|
|
24
|
+
theme: letter
|
|
25
|
+
# color: "#1a3c6e" # optional accent color, default black
|
|
26
|
+
|
|
27
|
+
documents: documents # directory with the *.md documents
|
|
28
|
+
|
|
29
|
+
output:
|
|
30
|
+
html_dir: .build/html
|
|
31
|
+
pdf_dir: pdf
|
|
32
|
+
date_prefix: false # stable names so the committed example PDFs don't churn
|
|
33
|
+
|
|
34
|
+
# chrome: /path/to/chrome # optional; otherwise auto-detected
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Protokoll
|
|
3
|
+
title: Kickoff Website-Relaunch
|
|
4
|
+
date: 2026-08-14
|
|
5
|
+
number: P-2026-001
|
|
6
|
+
recipient: |
|
|
7
|
+
Muster GmbH
|
|
8
|
+
Frau Erika Muster
|
|
9
|
+
Musterallee 8
|
|
10
|
+
93047 Regensburg
|
|
11
|
+
meta:
|
|
12
|
+
- label: Projekt
|
|
13
|
+
value: Website-Relaunch muster.example
|
|
14
|
+
- label: Ort
|
|
15
|
+
value: Videokonferenz
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Teilnehmer
|
|
19
|
+
|
|
20
|
+
- Erika Muster (Muster GmbH, Auftraggeberin)
|
|
21
|
+
- Daniel Falkner (Falkner IT, Auftragnehmer)
|
|
22
|
+
|
|
23
|
+
## Besprochene Punkte
|
|
24
|
+
|
|
25
|
+
### Ausgangslage
|
|
26
|
+
|
|
27
|
+
Die bestehende Website läuft auf einer veralteten CMS-Version ohne
|
|
28
|
+
Sicherheitsupdates. Ziel ist ein Relaunch auf einer aktuellen Plattform bei
|
|
29
|
+
unverändertem Inhalt und Design.
|
|
30
|
+
|
|
31
|
+
### Vereinbarungen
|
|
32
|
+
|
|
33
|
+
| Nr. | Vereinbarung | Verantwortlich | Termin |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| 1 | Zugangsdaten zum Hosting bereitstellen | Muster GmbH | 21.08.2026 |
|
|
36
|
+
| 2 | Testumgebung mit Kopie der Live-Site aufsetzen | Falkner IT | 28.08.2026 |
|
|
37
|
+
| 3 | Angebot für den Relaunch vorlegen | Falkner IT | 04.09.2026 |
|
|
38
|
+
|
|
39
|
+
### Offene Punkte
|
|
40
|
+
|
|
41
|
+
- Klärung, ob der Newsletter-Dienst weiterbetrieben wird.
|
|
42
|
+
- Inventur der installierten Erweiterungen auf Kompatibilität.
|
|
43
|
+
|
|
44
|
+
## Nächster Termin
|
|
45
|
+
|
|
46
|
+
Freitag, 04.09.2026, 10:00 Uhr, Videokonferenz.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Leistungsnachweis
|
|
3
|
+
title: Leistungsnachweis August 2026
|
|
4
|
+
date: 2026-08-31
|
|
5
|
+
number: LN-2026-008
|
|
6
|
+
recipient: |
|
|
7
|
+
Muster GmbH
|
|
8
|
+
Musterallee 8
|
|
9
|
+
93047 Regensburg
|
|
10
|
+
meta:
|
|
11
|
+
- label: Projekt
|
|
12
|
+
value: Website-Relaunch muster.example
|
|
13
|
+
signature: true
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
Hiermit wird bescheinigt, dass im August 2026 die folgenden Leistungen
|
|
17
|
+
erbracht wurden:
|
|
18
|
+
|
|
19
|
+
| Datum | Tätigkeit | Stunden |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| 05.08.2026 | Testumgebung aufsetzen | 8,0 |
|
|
22
|
+
| 12.08.2026 | Erweiterungen prüfen | 6,0 |
|
|
23
|
+
| 19.08.2026 | Migrationspfad dokumentieren | 5,0 |
|
|
24
|
+
| 26.08.2026 | Abstimmung und Projektorganisation | 3,0 |
|
|
25
|
+
|
|
26
|
+
**Summe: 22,0 Stunden**
|
|
27
|
+
|
|
28
|
+
Die Leistungen wurden vertragsgemäß und vollständig erbracht.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Bericht
|
|
3
|
+
title: Statusbericht August 2026
|
|
4
|
+
date: 2026-08-31
|
|
5
|
+
number: B-2026-003
|
|
6
|
+
meta:
|
|
7
|
+
- label: Projekt
|
|
8
|
+
value: Website-Relaunch muster.example
|
|
9
|
+
- label: Zeitraum
|
|
10
|
+
value: 01.08. – 31.08.2026
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Zusammenfassung
|
|
14
|
+
|
|
15
|
+
Die Testumgebung steht und bildet die Live-Site vollständig ab. Die
|
|
16
|
+
Bestandsaufnahme der Erweiterungen ist abgeschlossen; zwei von elf
|
|
17
|
+
Erweiterungen sind nicht mit der Zielversion kompatibel und werden ersetzt.
|
|
18
|
+
|
|
19
|
+
## Erledigte Arbeiten
|
|
20
|
+
|
|
21
|
+
- Testumgebung mit Kopie der Live-Site aufgesetzt und verifiziert.
|
|
22
|
+
- Alle elf Erweiterungen auf Kompatibilität mit der Zielversion geprüft.
|
|
23
|
+
- Migrationspfad für die zwei inkompatiblen Erweiterungen dokumentiert.
|
|
24
|
+
|
|
25
|
+
## Kennzahlen
|
|
26
|
+
|
|
27
|
+
| Kennzahl | Plan | Ist |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| Aufwand im Berichtszeitraum | 24 h | 22 h |
|
|
30
|
+
| Fertigstellungsgrad | 40 % | 45 % |
|
|
31
|
+
|
|
32
|
+
## Risiken und offene Punkte
|
|
33
|
+
|
|
34
|
+
Der Newsletter-Dienst ist weiterhin ungeklärt; eine Entscheidung wird bis zum
|
|
35
|
+
nächsten Termin benötigt, da sie den Migrationsumfang beeinflusst.
|
|
36
|
+
|
|
37
|
+
## Ausblick September
|
|
38
|
+
|
|
39
|
+
Migration der Inhalte in die Testumgebung und erster Abnahmedurchlauf mit der
|
|
40
|
+
Auftraggeberin.
|