flo-pm 0.1.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.
- flo_pm-0.1.0/.gitignore +6 -0
- flo_pm-0.1.0/PKG-INFO +173 -0
- flo_pm-0.1.0/README.md +162 -0
- flo_pm-0.1.0/examples/kettle/.context/README.md +184 -0
- flo_pm-0.1.0/examples/kettle/.context/TEMPLATE.md +45 -0
- flo_pm-0.1.0/examples/kettle/.context/favicon.svg +14 -0
- flo_pm-0.1.0/examples/kettle/.context/loyalty.md +37 -0
- flo_pm-0.1.0/examples/kettle/.context/menu.md +42 -0
- flo_pm-0.1.0/examples/kettle/.context/ordering.md +70 -0
- flo_pm-0.1.0/examples/kettle/.context/payments.md +58 -0
- flo_pm-0.1.0/examples/kettle/.context/pos/README.md +35 -0
- flo_pm-0.1.0/examples/kettle/.context/pos/opening-hours.md +32 -0
- flo_pm-0.1.0/examples/kettle/.context/pos/till-sync.md +38 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-01-menu-data-model.md +28 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-02-basket-and-checkout.md +28 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-03-pickup-slot-picker.md +28 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-04-shop-opening-hours.md +27 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-05-card-payments.md +32 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-06-refunds-on-cancel.md +29 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-07-order-confirmation-messages.md +23 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-08-orders-to-shop-tills.md +31 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-09-allergen-labels.md +28 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-10-deploy-pipeline.md +24 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-11-monitoring-and-alerts.md +27 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-12-loyalty-points.md +27 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-13-customer-accounts.md +24 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-14-checkout-screen-reader-pass.md +23 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-15-courier-delivery.md +21 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-16-gift-cards.md +25 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-17-daily-sales-export.md +21 -0
- flo_pm-0.1.0/examples/kettle/.issues/KET-18-price-list-sign-off.md +23 -0
- flo_pm-0.1.0/examples/kettle/.issues/NEXT-ID +1 -0
- flo_pm-0.1.0/examples/kettle/.issues/README.md +204 -0
- flo_pm-0.1.0/examples/kettle/.issues/TEMPLATE.md +37 -0
- flo_pm-0.1.0/examples/kettle/.issues/favicon.svg +12 -0
- flo_pm-0.1.0/examples/kettle/flo-theme.css +64 -0
- flo_pm-0.1.0/examples/kettle/flo.toml +358 -0
- flo_pm-0.1.0/pyproject.toml +36 -0
- flo_pm-0.1.0/src/flo/__init__.py +3 -0
- flo_pm-0.1.0/src/flo/backlog.py +4954 -0
- flo_pm-0.1.0/src/flo/burnup.py +2318 -0
- flo_pm-0.1.0/src/flo/cli.py +100 -0
- flo_pm-0.1.0/src/flo/config.py +290 -0
- flo_pm-0.1.0/src/flo/context.py +3147 -0
- flo_pm-0.1.0/src/flo/delivery.py +1147 -0
- flo_pm-0.1.0/src/flo/epics.py +829 -0
- flo_pm-0.1.0/src/flo/ids.py +34 -0
- flo_pm-0.1.0/src/flo/init.py +161 -0
- flo_pm-0.1.0/src/flo/menu.py +141 -0
- flo_pm-0.1.0/src/flo/migrate.py +61 -0
- flo_pm-0.1.0/src/flo/roadmap.py +1298 -0
- flo_pm-0.1.0/src/flo/site.py +352 -0
- flo_pm-0.1.0/src/flo/templates/context/README.md +184 -0
- flo_pm-0.1.0/src/flo/templates/context/TEMPLATE.md +45 -0
- flo_pm-0.1.0/src/flo/templates/context/favicon.svg +14 -0
- flo_pm-0.1.0/src/flo/templates/delivery.toml +29 -0
- flo_pm-0.1.0/src/flo/templates/epics.toml +19 -0
- flo_pm-0.1.0/src/flo/templates/flo.toml +32 -0
- flo_pm-0.1.0/src/flo/templates/issues/README.md +204 -0
- flo_pm-0.1.0/src/flo/templates/issues/TEMPLATE.md +37 -0
- flo_pm-0.1.0/src/flo/templates/issues/favicon.svg +12 -0
- flo_pm-0.1.0/src/flo/templates/labels-reports.toml +27 -0
- flo_pm-0.1.0/src/flo/templates/labels.toml +83 -0
- flo_pm-0.1.0/src/flo/templates/roadmap.toml +49 -0
- flo_pm-0.1.0/src/flo/templates/workpackages.toml +35 -0
- flo_pm-0.1.0/src/flo/theme.py +53 -0
- flo_pm-0.1.0/src/flo/vendor/mermaid.min.js +2314 -0
- flo_pm-0.1.0/src/flo/workpackages.py +728 -0
- flo_pm-0.1.0/tests/test_kettle.py +259 -0
- flo_pm-0.1.0/wheelhouse/.gitignore +1 -0
flo_pm-0.1.0/.gitignore
ADDED
flo_pm-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: flo-pm
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Static sites and reports from a repo's .issues/ and .context/ markdown
|
|
5
|
+
Project-URL: Repository, https://github.com/BramEsposito/flo-pm
|
|
6
|
+
Project-URL: Issues, https://github.com/BramEsposito/flo-pm/issues
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: markdown>=3.5
|
|
9
|
+
Requires-Dist: pyyaml>=6.0
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# flo
|
|
13
|
+
|
|
14
|
+
Static sites and reports from a repository's own markdown: an issue backlog
|
|
15
|
+
in `.issues/`, the project's design context in `.context/`, and release
|
|
16
|
+
reports read off both. No server and no database: the issue files live next
|
|
17
|
+
to the code they are about, and every page works straight from `file://`.
|
|
18
|
+
|
|
19
|
+
| Command | Builds | From |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `flo issues` | a filterable issues site, one page per issue | `.issues/*.md`, `[labels]` |
|
|
22
|
+
| `flo context` | a site of the project's scope files, checked for broken deep links | `.context/**/*.md` |
|
|
23
|
+
| `flo burnup` | a burnup chart: scope against closed, per release | the issues |
|
|
24
|
+
| `flo roadmap` | when each release can ship, theme by theme, at the planned pace | the issues + `[roadmap]` |
|
|
25
|
+
| `flo workpackages` | the open work grouped into packages, and each one's progress | the issues + `[workpackages]` |
|
|
26
|
+
| `flo epics` | every issue ever filed grouped by the part of the product it belongs to, with each epic's points left, pace and history | the issues + `[epics]` |
|
|
27
|
+
| `flo delivery` | what stands between a release and shipping, with code checks | the issues + `[delivery]` |
|
|
28
|
+
| `flo build` | all of the above that the project has inputs for | |
|
|
29
|
+
| `flo init` | sets a project up for all of it | |
|
|
30
|
+
| `flo migrate` | folds an older project's `labels.toml`, `roadmap.toml`, … into `flo.toml` | |
|
|
31
|
+
|
|
32
|
+
`examples/kettle/` is a complete project to look at: a pickup-ordering app
|
|
33
|
+
for a fictional bakery chain, with eighteen issues, a context directory and
|
|
34
|
+
every report configured. `cd examples/kettle && flo build` and open
|
|
35
|
+
`dist/issues-site/index.html`.
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
Globally, as a command available in every project:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
uv tool install flo-pm # or: pipx install flo-pm
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or per project, pinned with the rest of the dev tooling:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
uv add --dev flo-pm # then: uv run flo build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The package is `flo-pm` on PyPI (`flo` there is an unrelated project);
|
|
52
|
+
either way the command is `flo`, and it reads the `flo.toml` of whatever
|
|
53
|
+
project you run it in. Python 3.11+.
|
|
54
|
+
|
|
55
|
+
## Start a project
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
flo init --name Kettle --prefix KET --reports
|
|
59
|
+
flo build
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`init` writes `flo.toml` — flo's settings and the `[labels]` every issue is
|
|
63
|
+
checked against — an issues directory and a context directory, each with a
|
|
64
|
+
README that explains its conventions, a `TEMPLATE.md` to copy and an icon, and
|
|
65
|
+
a starter issue and scope file. `--reports` adds the `[roadmap]`,
|
|
66
|
+
`[workpackages]` and `[delivery]` blocks. It only ever adds — files, and
|
|
67
|
+
blocks to an existing `flo.toml` — so it is safe to run in a project that
|
|
68
|
+
already has some of them.
|
|
69
|
+
|
|
70
|
+
Both directories are [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
|
|
71
|
+
bundles as they stand: every markdown file `init` writes carries a `type`
|
|
72
|
+
(`Issue`, `Context`, `Guide`), the one key OKF requires, and the sites warn
|
|
73
|
+
about a file without one. `index.md` and `log.md`, the names OKF reserves,
|
|
74
|
+
are never read as issues or scopes.
|
|
75
|
+
|
|
76
|
+
The conventions are the substance: **one markdown file per issue, which never
|
|
77
|
+
moves; `status` is the only thing that says where it stands; one context file
|
|
78
|
+
per scope, split into AS IS and TO BE, with no history in it.** The two READMEs
|
|
79
|
+
`init` writes spell them out, and the sites warn when a file breaks them.
|
|
80
|
+
|
|
81
|
+
## `flo.toml`
|
|
82
|
+
|
|
83
|
+
Everything flo needs to know about a project, in one file with one clearly
|
|
84
|
+
marked block per concern: flo's own settings, then the project's data — the
|
|
85
|
+
label vocabulary and the plans the reports are drawn from. Found by walking up
|
|
86
|
+
from the working directory, so `flo` works from anywhere in the project. Paths
|
|
87
|
+
are relative to the file.
|
|
88
|
+
|
|
89
|
+
```toml
|
|
90
|
+
# ══ flo — where things are, what issues are called, how the sites look ══════
|
|
91
|
+
[project]
|
|
92
|
+
name = "Kettle" # shown on every page (default: the directory name)
|
|
93
|
+
id_prefix = "KET" # issues are KET-1, KET-2, … (default: ISS)
|
|
94
|
+
|
|
95
|
+
[paths]
|
|
96
|
+
issues = ".issues"
|
|
97
|
+
context = ".context"
|
|
98
|
+
out = "dist" # each site is a directory under it
|
|
99
|
+
|
|
100
|
+
[urls] # where a dev server serves each site, if one does
|
|
101
|
+
issues = "/issues/" # (defaults: /issues/, /context/, /burnup/, …)
|
|
102
|
+
|
|
103
|
+
[theme]
|
|
104
|
+
css = "flo-theme.css" # inlined at the end of every page's <head>
|
|
105
|
+
fonts = "https://fonts.googleapis.com/css2?family=…"
|
|
106
|
+
|
|
107
|
+
[menu] # the strip of links across the pages, in order
|
|
108
|
+
tools = ["issues", "context", "burnup", "roadmap", "workpackages", "epics", "delivery"]
|
|
109
|
+
home = { label = "Home", url = "/" }
|
|
110
|
+
|
|
111
|
+
# ══ labels — the vocabulary every issue is checked against ══════════════════
|
|
112
|
+
[labels.issue] # which frontmatter keys every issue must answer
|
|
113
|
+
[labels.status] # one section per label field, with its allowed values
|
|
114
|
+
[labels.assignee]
|
|
115
|
+
[labels.tags] # … and any field of your own: version, points, theme
|
|
116
|
+
|
|
117
|
+
# ══ roadmap — the plan `flo roadmap` lays the releases out by ═══════════════
|
|
118
|
+
[roadmap.plan] # start, pace, baseline
|
|
119
|
+
[[roadmap.release]] # each release, its reserve…
|
|
120
|
+
[[roadmap.release.theme]] # …and the themes it is scheduled in
|
|
121
|
+
|
|
122
|
+
# ══ workpackages — what each package of work is ═════════════════════════════
|
|
123
|
+
[workpackages] # the releases in scope, the baseline
|
|
124
|
+
[[workpackages.kind]]
|
|
125
|
+
[[workpackages.package]]
|
|
126
|
+
# ══ epics — what each epic is ════════════════════════════════════════════════
|
|
127
|
+
[[epics.epic]] # key, name, blurb; an issue's `epic` names one
|
|
128
|
+
|
|
129
|
+
# ══ delivery — the recommended path the delivery report follows ═════════════
|
|
130
|
+
[delivery.review] # the review date and the release it was for
|
|
131
|
+
[[delivery.lane]] # the order to clear the work in
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`examples/kettle/flo.toml` is a complete one, every block filled in. A project
|
|
135
|
+
without a `[roadmap]` simply has no roadmap — `flo build` skips it — and the
|
|
136
|
+
same goes for the other two report blocks.
|
|
137
|
+
|
|
138
|
+
Older projects kept the data blocks as files of their own in the issues
|
|
139
|
+
directory (`labels.toml`, `roadmap.toml`, `workpackages.toml`, `epics.toml`,
|
|
140
|
+
`delivery-review.toml`). flo still reads those, with a note, and `flo migrate`
|
|
141
|
+
folds them into `flo.toml` — comments and all — checking that each block reads
|
|
142
|
+
back as its file did before deleting the file.
|
|
143
|
+
|
|
144
|
+
Every command's flags default to these values, and still override them: `flo
|
|
145
|
+
roadmap --as-of 2026-11-01`, `flo issues --watch`. `flo <command> --help`
|
|
146
|
+
lists them.
|
|
147
|
+
|
|
148
|
+
## Theming
|
|
149
|
+
|
|
150
|
+
Every page ships flo's neutral theme — system fonts, a palette declared as
|
|
151
|
+
custom properties on `:root`, redefined for dark mode. A project's `[theme]
|
|
152
|
+
css` comes after it, so redefining a property wins. Define dark-mode values
|
|
153
|
+
with the pages' own selectors (`@media (prefers-color-scheme: dark) {
|
|
154
|
+
:root:not([data-theme="light"]) { … } }` and `:root[data-theme="dark"]`);
|
|
155
|
+
they are more specific than a bare `:root`. `examples/kettle/flo-theme.css`
|
|
156
|
+
covers the tokens each page reads.
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
uv venv && uv pip install -e . pytest
|
|
162
|
+
.venv/bin/python -m pytest
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
CI runs the tests on every push and pull request
|
|
166
|
+
(`.github/workflows/ci.yml`). A version tag publishes to PyPI: bump `version`
|
|
167
|
+
in `pyproject.toml`, commit, then `git tag v<version> && git push origin
|
|
168
|
+
v<version>` (`.github/workflows/publish.yml`, through PyPI trusted
|
|
169
|
+
publishing — no token is stored).
|
|
170
|
+
|
|
171
|
+
The test suite builds the Kettle example and a freshly initialised project,
|
|
172
|
+
and fails on any build warning — so a change to a generator, a template or the
|
|
173
|
+
example is checked end to end.
|
flo_pm-0.1.0/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# flo
|
|
2
|
+
|
|
3
|
+
Static sites and reports from a repository's own markdown: an issue backlog
|
|
4
|
+
in `.issues/`, the project's design context in `.context/`, and release
|
|
5
|
+
reports read off both. No server and no database: the issue files live next
|
|
6
|
+
to the code they are about, and every page works straight from `file://`.
|
|
7
|
+
|
|
8
|
+
| Command | Builds | From |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `flo issues` | a filterable issues site, one page per issue | `.issues/*.md`, `[labels]` |
|
|
11
|
+
| `flo context` | a site of the project's scope files, checked for broken deep links | `.context/**/*.md` |
|
|
12
|
+
| `flo burnup` | a burnup chart: scope against closed, per release | the issues |
|
|
13
|
+
| `flo roadmap` | when each release can ship, theme by theme, at the planned pace | the issues + `[roadmap]` |
|
|
14
|
+
| `flo workpackages` | the open work grouped into packages, and each one's progress | the issues + `[workpackages]` |
|
|
15
|
+
| `flo epics` | every issue ever filed grouped by the part of the product it belongs to, with each epic's points left, pace and history | the issues + `[epics]` |
|
|
16
|
+
| `flo delivery` | what stands between a release and shipping, with code checks | the issues + `[delivery]` |
|
|
17
|
+
| `flo build` | all of the above that the project has inputs for | |
|
|
18
|
+
| `flo init` | sets a project up for all of it | |
|
|
19
|
+
| `flo migrate` | folds an older project's `labels.toml`, `roadmap.toml`, … into `flo.toml` | |
|
|
20
|
+
|
|
21
|
+
`examples/kettle/` is a complete project to look at: a pickup-ordering app
|
|
22
|
+
for a fictional bakery chain, with eighteen issues, a context directory and
|
|
23
|
+
every report configured. `cd examples/kettle && flo build` and open
|
|
24
|
+
`dist/issues-site/index.html`.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
Globally, as a command available in every project:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
uv tool install flo-pm # or: pipx install flo-pm
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or per project, pinned with the rest of the dev tooling:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
uv add --dev flo-pm # then: uv run flo build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The package is `flo-pm` on PyPI (`flo` there is an unrelated project);
|
|
41
|
+
either way the command is `flo`, and it reads the `flo.toml` of whatever
|
|
42
|
+
project you run it in. Python 3.11+.
|
|
43
|
+
|
|
44
|
+
## Start a project
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
flo init --name Kettle --prefix KET --reports
|
|
48
|
+
flo build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`init` writes `flo.toml` — flo's settings and the `[labels]` every issue is
|
|
52
|
+
checked against — an issues directory and a context directory, each with a
|
|
53
|
+
README that explains its conventions, a `TEMPLATE.md` to copy and an icon, and
|
|
54
|
+
a starter issue and scope file. `--reports` adds the `[roadmap]`,
|
|
55
|
+
`[workpackages]` and `[delivery]` blocks. It only ever adds — files, and
|
|
56
|
+
blocks to an existing `flo.toml` — so it is safe to run in a project that
|
|
57
|
+
already has some of them.
|
|
58
|
+
|
|
59
|
+
Both directories are [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
|
|
60
|
+
bundles as they stand: every markdown file `init` writes carries a `type`
|
|
61
|
+
(`Issue`, `Context`, `Guide`), the one key OKF requires, and the sites warn
|
|
62
|
+
about a file without one. `index.md` and `log.md`, the names OKF reserves,
|
|
63
|
+
are never read as issues or scopes.
|
|
64
|
+
|
|
65
|
+
The conventions are the substance: **one markdown file per issue, which never
|
|
66
|
+
moves; `status` is the only thing that says where it stands; one context file
|
|
67
|
+
per scope, split into AS IS and TO BE, with no history in it.** The two READMEs
|
|
68
|
+
`init` writes spell them out, and the sites warn when a file breaks them.
|
|
69
|
+
|
|
70
|
+
## `flo.toml`
|
|
71
|
+
|
|
72
|
+
Everything flo needs to know about a project, in one file with one clearly
|
|
73
|
+
marked block per concern: flo's own settings, then the project's data — the
|
|
74
|
+
label vocabulary and the plans the reports are drawn from. Found by walking up
|
|
75
|
+
from the working directory, so `flo` works from anywhere in the project. Paths
|
|
76
|
+
are relative to the file.
|
|
77
|
+
|
|
78
|
+
```toml
|
|
79
|
+
# ══ flo — where things are, what issues are called, how the sites look ══════
|
|
80
|
+
[project]
|
|
81
|
+
name = "Kettle" # shown on every page (default: the directory name)
|
|
82
|
+
id_prefix = "KET" # issues are KET-1, KET-2, … (default: ISS)
|
|
83
|
+
|
|
84
|
+
[paths]
|
|
85
|
+
issues = ".issues"
|
|
86
|
+
context = ".context"
|
|
87
|
+
out = "dist" # each site is a directory under it
|
|
88
|
+
|
|
89
|
+
[urls] # where a dev server serves each site, if one does
|
|
90
|
+
issues = "/issues/" # (defaults: /issues/, /context/, /burnup/, …)
|
|
91
|
+
|
|
92
|
+
[theme]
|
|
93
|
+
css = "flo-theme.css" # inlined at the end of every page's <head>
|
|
94
|
+
fonts = "https://fonts.googleapis.com/css2?family=…"
|
|
95
|
+
|
|
96
|
+
[menu] # the strip of links across the pages, in order
|
|
97
|
+
tools = ["issues", "context", "burnup", "roadmap", "workpackages", "epics", "delivery"]
|
|
98
|
+
home = { label = "Home", url = "/" }
|
|
99
|
+
|
|
100
|
+
# ══ labels — the vocabulary every issue is checked against ══════════════════
|
|
101
|
+
[labels.issue] # which frontmatter keys every issue must answer
|
|
102
|
+
[labels.status] # one section per label field, with its allowed values
|
|
103
|
+
[labels.assignee]
|
|
104
|
+
[labels.tags] # … and any field of your own: version, points, theme
|
|
105
|
+
|
|
106
|
+
# ══ roadmap — the plan `flo roadmap` lays the releases out by ═══════════════
|
|
107
|
+
[roadmap.plan] # start, pace, baseline
|
|
108
|
+
[[roadmap.release]] # each release, its reserve…
|
|
109
|
+
[[roadmap.release.theme]] # …and the themes it is scheduled in
|
|
110
|
+
|
|
111
|
+
# ══ workpackages — what each package of work is ═════════════════════════════
|
|
112
|
+
[workpackages] # the releases in scope, the baseline
|
|
113
|
+
[[workpackages.kind]]
|
|
114
|
+
[[workpackages.package]]
|
|
115
|
+
# ══ epics — what each epic is ════════════════════════════════════════════════
|
|
116
|
+
[[epics.epic]] # key, name, blurb; an issue's `epic` names one
|
|
117
|
+
|
|
118
|
+
# ══ delivery — the recommended path the delivery report follows ═════════════
|
|
119
|
+
[delivery.review] # the review date and the release it was for
|
|
120
|
+
[[delivery.lane]] # the order to clear the work in
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`examples/kettle/flo.toml` is a complete one, every block filled in. A project
|
|
124
|
+
without a `[roadmap]` simply has no roadmap — `flo build` skips it — and the
|
|
125
|
+
same goes for the other two report blocks.
|
|
126
|
+
|
|
127
|
+
Older projects kept the data blocks as files of their own in the issues
|
|
128
|
+
directory (`labels.toml`, `roadmap.toml`, `workpackages.toml`, `epics.toml`,
|
|
129
|
+
`delivery-review.toml`). flo still reads those, with a note, and `flo migrate`
|
|
130
|
+
folds them into `flo.toml` — comments and all — checking that each block reads
|
|
131
|
+
back as its file did before deleting the file.
|
|
132
|
+
|
|
133
|
+
Every command's flags default to these values, and still override them: `flo
|
|
134
|
+
roadmap --as-of 2026-11-01`, `flo issues --watch`. `flo <command> --help`
|
|
135
|
+
lists them.
|
|
136
|
+
|
|
137
|
+
## Theming
|
|
138
|
+
|
|
139
|
+
Every page ships flo's neutral theme — system fonts, a palette declared as
|
|
140
|
+
custom properties on `:root`, redefined for dark mode. A project's `[theme]
|
|
141
|
+
css` comes after it, so redefining a property wins. Define dark-mode values
|
|
142
|
+
with the pages' own selectors (`@media (prefers-color-scheme: dark) {
|
|
143
|
+
:root:not([data-theme="light"]) { … } }` and `:root[data-theme="dark"]`);
|
|
144
|
+
they are more specific than a bare `:root`. `examples/kettle/flo-theme.css`
|
|
145
|
+
covers the tokens each page reads.
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
uv venv && uv pip install -e . pytest
|
|
151
|
+
.venv/bin/python -m pytest
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
CI runs the tests on every push and pull request
|
|
155
|
+
(`.github/workflows/ci.yml`). A version tag publishes to PyPI: bump `version`
|
|
156
|
+
in `pyproject.toml`, commit, then `git tag v<version> && git push origin
|
|
157
|
+
v<version>` (`.github/workflows/publish.yml`, through PyPI trusted
|
|
158
|
+
publishing — no token is stored).
|
|
159
|
+
|
|
160
|
+
The test suite builds the Kettle example and a freshly initialised project,
|
|
161
|
+
and fails on any build warning — so a change to a generator, a template or the
|
|
162
|
+
example is checked end to end.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Guide
|
|
3
|
+
title: Context conventions
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context
|
|
7
|
+
|
|
8
|
+
This directory records **Kettle's context**: standing, formalized facts,
|
|
9
|
+
designs and decisions. `.issues/` tracks work that still needs doing;
|
|
10
|
+
`.context/` tracks what the project *is* and what it is *meant to become*,
|
|
11
|
+
so neither has to be reconstructed from scattered conversations every time
|
|
12
|
+
it's relevant.
|
|
13
|
+
|
|
14
|
+
Three rules govern everything below:
|
|
15
|
+
|
|
16
|
+
1. **One file per scope.** Every scope gets a context file, and the
|
|
17
|
+
information for that scope is recorded **in that file only** — never
|
|
18
|
+
duplicated into a second file, an issue, or an agent's instructions file.
|
|
19
|
+
2. **Every file splits into AS IS and TO BE.** What exists today, and what is
|
|
20
|
+
designed but not built yet.
|
|
21
|
+
3. **No history.** Git log is the history.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. One file per scope, referenced by deep link
|
|
26
|
+
|
|
27
|
+
Each scope is written down **once**, in its own file. Anything elsewhere that
|
|
28
|
+
needs that information — another context file, an issue, a README, a code
|
|
29
|
+
comment, a commit message — **links to it instead of restating it**.
|
|
30
|
+
|
|
31
|
+
- Link with a **deep link to the heading**, not just the file, so the reader
|
|
32
|
+
lands on the fact rather than on a 600-line document:
|
|
33
|
+
- from inside `.context/` — `[refunds](payments.md#refunds)`
|
|
34
|
+
- from anywhere else in the repo —
|
|
35
|
+
`[refunds](.context/payments.md#refunds)`
|
|
36
|
+
- Anchors are the GitHub slug of the heading text: lowercased, spaces to `-`,
|
|
37
|
+
punctuation dropped (`### Refunds (v2, current)` → `#refunds-v2-current`).
|
|
38
|
+
Keep headings stable-ish; when you rename one, fix the links that pointed at
|
|
39
|
+
it (`grep -rn 'payments.md#old-anchor' --include='*.md' .`).
|
|
40
|
+
- If you catch yourself re-explaining something that lives in another scope's
|
|
41
|
+
file: delete the explanation, link to it. A summarizing sentence plus a deep
|
|
42
|
+
link is fine; a second copy of the facts is not — two copies drift, and then
|
|
43
|
+
neither is trustworthy.
|
|
44
|
+
- If a fact doesn't fit any existing scope, that's the signal to create a new
|
|
45
|
+
scope file, not to park it in the nearest one.
|
|
46
|
+
|
|
47
|
+
## 2. AS IS and TO BE
|
|
48
|
+
|
|
49
|
+
Every scope file has exactly these two top-level sections, in this order:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
# <Scope title>
|
|
53
|
+
|
|
54
|
+
intro: what this file is the source of truth for
|
|
55
|
+
|
|
56
|
+
## AS IS ← the current design: what is built and running today
|
|
57
|
+
### <sub-topic>
|
|
58
|
+
### <sub-topic>
|
|
59
|
+
|
|
60
|
+
## TO BE ← the designed-but-not-yet-built target state
|
|
61
|
+
### <sub-topic>
|
|
62
|
+
### <sub-topic>
|
|
63
|
+
|
|
64
|
+
## See also
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- **AS IS** — the design as it actually exists in the code right now. Cite
|
|
68
|
+
code as evidence: `src/orders/checkout.py:120-180`, `Basket.total`.
|
|
69
|
+
- **TO BE** — functionality that is *designed* but not built. Each entry says
|
|
70
|
+
what the target state is and links the issue that will build it
|
|
71
|
+
(`[[KET-40]]`). A TO BE entry with no issue behind it is a design
|
|
72
|
+
note, not a plan — say so (`**Issue:** none filed`).
|
|
73
|
+
- Keep the boundary sharp. Never let a TO BE design read as if it were live,
|
|
74
|
+
and mark status explicitly per sub-topic: **decided** / **confirmed** /
|
|
75
|
+
**to be decided**. Something that's built but behind a debug flag is AS IS —
|
|
76
|
+
and says so.
|
|
77
|
+
- When a TO BE item ships, **move it into AS IS and rewrite it in the present
|
|
78
|
+
tense**. Don't leave the old TO BE text behind as a record of what was
|
|
79
|
+
planned — that's history (rule 3).
|
|
80
|
+
- Either section may be empty: write `_Nothing designed beyond AS IS._` or
|
|
81
|
+
`_Not built yet._` rather than dropping the heading, so its absence never
|
|
82
|
+
has to be interpreted.
|
|
83
|
+
- **One exception: a catalog** — a file whose body is a list of like entries
|
|
84
|
+
(rules, an inventory of feature flags) may carry a **status per entry**
|
|
85
|
+
instead of the two blocks, since that is the same distinction at a finer
|
|
86
|
+
grain. It must say the word "catalog" in its first paragraph — that's how
|
|
87
|
+
the site recognises one — and every not-yet-implemented entry still links
|
|
88
|
+
its issue.
|
|
89
|
+
|
|
90
|
+
### Formatting within a section
|
|
91
|
+
|
|
92
|
+
Use the full toolbox — these files are read to answer a question fast, not
|
|
93
|
+
front to back:
|
|
94
|
+
|
|
95
|
+
- **Headings and subheadings** (`###`, `####`) per sub-topic — they're also
|
|
96
|
+
the deep-link targets other files point at.
|
|
97
|
+
- **Bulleted lists** for facts, constraints and caveats.
|
|
98
|
+
- **Numbered lists** for anything with an order: a flow, a sequence of steps,
|
|
99
|
+
a release procedure, ranked options.
|
|
100
|
+
- **Tables** for inventories: settings keys, endpoints, environment variables.
|
|
101
|
+
- **Diagrams** for anything with shape — a request flow, a state machine. ASCII
|
|
102
|
+
box drawings in a fenced block, or a fenced `mermaid` block; put the diagram
|
|
103
|
+
before the prose that explains it.
|
|
104
|
+
|
|
105
|
+
## 3. No history
|
|
106
|
+
|
|
107
|
+
These files describe the **current** state of the world, not how it got there.
|
|
108
|
+
|
|
109
|
+
- **Don't** write changelogs, "previously we…", "Update: X removed", dated
|
|
110
|
+
decision logs, or "kept for anyone revisiting" option write-ups.
|
|
111
|
+
- **Do** just state what is true now. When a fact changes, **overwrite** it
|
|
112
|
+
and bump `updated`.
|
|
113
|
+
- To consult how a fact got to be the way it is, use git: `git log -p --
|
|
114
|
+
.context/<scope>.md`, or `git log -S '<phrase>' -- .context/`.
|
|
115
|
+
- Two things that look like history and are not, so keep them:
|
|
116
|
+
- a *constraint* that happens to be dated — "the production schema is
|
|
117
|
+
deployed, so a stored field can't be renamed";
|
|
118
|
+
- **provenance** — "decided by Ada, 2026-09-25" against a rule or a
|
|
119
|
+
decision. That says who to ask whether it still holds, which is a present
|
|
120
|
+
fact about the rule, not a record of a change to it.
|
|
121
|
+
|
|
122
|
+
A dated checklist or a session log is not a scope file; the work in one
|
|
123
|
+
belongs in `.issues/`, and the narrative in git.
|
|
124
|
+
|
|
125
|
+
## Where a scope file goes
|
|
126
|
+
|
|
127
|
+
`.context/` is **flat** until it isn't: every scope file sits directly in
|
|
128
|
+
this directory while there are a dozen of them, because a directory tree would
|
|
129
|
+
only add places to look.
|
|
130
|
+
|
|
131
|
+
When the directory grows a cluster of three or more scopes about one subject,
|
|
132
|
+
group them in a subdirectory whose `README.md` is **the group's own scope
|
|
133
|
+
file**: AS IS / TO BE for what is true of the group as a whole, plus an index
|
|
134
|
+
of the children. Two files don't need a directory.
|
|
135
|
+
|
|
136
|
+
The cross-cutting axis is `area` (see **Frontmatter fields**), not the
|
|
137
|
+
directory — the site filters on it.
|
|
138
|
+
|
|
139
|
+
## Filename
|
|
140
|
+
|
|
141
|
+
`<scope>.md`, a short lowercase slug with `-`, one file per scope (e.g.
|
|
142
|
+
`payments.md`, `store-hours.md`). No numbering — scopes aren't a sequence, so
|
|
143
|
+
files are found and referenced by name.
|
|
144
|
+
|
|
145
|
+
## Creating a new scope file
|
|
146
|
+
|
|
147
|
+
Copy `TEMPLATE.md` to `<scope>.md` and fill it in.
|
|
148
|
+
|
|
149
|
+
## This directory is also a site
|
|
150
|
+
|
|
151
|
+
`flo context` renders this directory into a site and **checks the rules above
|
|
152
|
+
while it does** — a deep link whose `#anchor` names no heading, a reference to
|
|
153
|
+
a scope file or issue that doesn't exist, a missing `title`/`area`/`updated`, a
|
|
154
|
+
file with neither section, a TO BE entry with no issue behind it. Those all
|
|
155
|
+
render as perfectly ordinary pages, which is why they are worth a build
|
|
156
|
+
warning, so read the output after editing.
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
flo context # → the context site, under the output dir in flo.toml
|
|
160
|
+
flo context --watch # rebuild on every edit
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Frontmatter fields
|
|
164
|
+
|
|
165
|
+
- **type** — `Context`, always: the [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
|
|
166
|
+
concept kind, the one key OKF requires of every markdown file. With it this
|
|
167
|
+
directory is an OKF bundle as it stands; `index.md` and `log.md` are the
|
|
168
|
+
names OKF reserves, and the site never reads either as a scope
|
|
169
|
+
- **title** — short scope title
|
|
170
|
+
- **area** — one subsystem tag, from the same vocabulary as the `tags` in
|
|
171
|
+
`[labels.tags]` in `flo.toml`. Need a new one? Add it there first.
|
|
172
|
+
- **updated** — date of the last real change (YYYY-MM-DD); bump it whenever a
|
|
173
|
+
fact or decision in the file changes, not on cosmetic edits
|
|
174
|
+
|
|
175
|
+
## Cross-linking with `.issues/`
|
|
176
|
+
|
|
177
|
+
- Every TO BE sub-topic links the issue that will build it, as
|
|
178
|
+
`[[KET-NN]]` or `` `.issues/KET-NN-slug.md` `` — the site
|
|
179
|
+
turns both into links.
|
|
180
|
+
- Every issue that depends on a recorded fact deep-links into the AS IS
|
|
181
|
+
section holding it rather than restating it.
|
|
182
|
+
- `.issues/` is authoritative for *status of work*; `.context/` is
|
|
183
|
+
authoritative for *design*. If they disagree about whether something is
|
|
184
|
+
built, the issue file wins and this directory is stale — fix it.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Context
|
|
3
|
+
title: Short scope title
|
|
4
|
+
area:
|
|
5
|
+
updated: YYYY-MM-DD
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# <Scope title>
|
|
9
|
+
|
|
10
|
+
One or two sentences: what this file is the source of truth for. Deep-link to
|
|
11
|
+
other scope files instead of repeating what they already record
|
|
12
|
+
(`[refunds](payments.md#refunds)`).
|
|
13
|
+
|
|
14
|
+
## AS IS
|
|
15
|
+
|
|
16
|
+
What is built and running today. Delete nothing into history — overwrite.
|
|
17
|
+
|
|
18
|
+
### <Sub-topic>
|
|
19
|
+
|
|
20
|
+
- **Status:** confirmed / decided
|
|
21
|
+
- The fact itself, with evidence (`path/to/file.py:123`).
|
|
22
|
+
|
|
23
|
+
### <Sub-topic with shape>
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
A ──▶ B ──▶ C diagram first, prose after
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
1. Ordered step
|
|
30
|
+
2. Ordered step
|
|
31
|
+
|
|
32
|
+
## TO BE
|
|
33
|
+
|
|
34
|
+
Designed, not built yet. `_Not built yet._` if there's nothing.
|
|
35
|
+
|
|
36
|
+
### <Sub-topic>
|
|
37
|
+
|
|
38
|
+
- **Status:** decided / to be decided
|
|
39
|
+
- **Issue:** `.issues/KET-XX`
|
|
40
|
+
- The target state, in the future tense, and what it replaces in AS IS.
|
|
41
|
+
|
|
42
|
+
## See also
|
|
43
|
+
|
|
44
|
+
- `.issues/KET-XX` — related open work
|
|
45
|
+
- Other scope files this one deep-links into
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
|
2
|
+
<!-- Stacked layers: one scope per file, and the directory is the stack.
|
|
3
|
+
Deliberately not the issues site's icon (three list rows) — the two
|
|
4
|
+
sites are read side by side, and a tab strip is where they are told
|
|
5
|
+
apart. Themed both ways: the browser's chrome follows the OS, not the
|
|
6
|
+
page, so a single fill would be invisible on one of the two. -->
|
|
7
|
+
<style>
|
|
8
|
+
path { fill: #15171a }
|
|
9
|
+
@media (prefers-color-scheme: dark) { path { fill: #e7e9ec } }
|
|
10
|
+
</style>
|
|
11
|
+
<path d="M8 1 15 4.3 8 7.6 1 4.3Z"/>
|
|
12
|
+
<path d="M1 7.7 8 11 15 7.7 13.2 6.8 8 9.3 2.8 6.8Z"/>
|
|
13
|
+
<path d="M1 11.1 8 14.4 15 11.1 13.2 10.2 8 12.7 2.8 10.2Z"/>
|
|
14
|
+
</svg>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Context
|
|
3
|
+
title: Loyalty — points for regulars
|
|
4
|
+
area: loyalty
|
|
5
|
+
updated: 2026-09-29
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Loyalty
|
|
9
|
+
|
|
10
|
+
The loyalty scheme Crumb & Co wants for v1.1: why regulars would order through
|
|
11
|
+
Kettle rather than a marketplace.
|
|
12
|
+
|
|
13
|
+
## AS IS
|
|
14
|
+
|
|
15
|
+
_Not built yet._
|
|
16
|
+
|
|
17
|
+
## TO BE
|
|
18
|
+
|
|
19
|
+
### Earning and spending points
|
|
20
|
+
|
|
21
|
+
- **Status:** to be decided
|
|
22
|
+
- **Issue:** [[KET-12]]
|
|
23
|
+
- One point per euro spent on a `paid` order, credited when the order is
|
|
24
|
+
`collected` (see [order states](ordering.md#order-states)).
|
|
25
|
+
- 100 points buy a free coffee. Whether points expire is waiting on
|
|
26
|
+
Crumb & Co — decided by Sam once they answer.
|
|
27
|
+
|
|
28
|
+
### Accounts
|
|
29
|
+
|
|
30
|
+
- **Status:** decided
|
|
31
|
+
- **Issue:** [[KET-13]]
|
|
32
|
+
- Points need an account: email and a magic link, no passwords. An order
|
|
33
|
+
placed without an account earns nothing.
|
|
34
|
+
|
|
35
|
+
## See also
|
|
36
|
+
|
|
37
|
+
- [[KET-12]], [[KET-13]] — the v1.1 work
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Context
|
|
3
|
+
title: Menu — products, allergens and prices
|
|
4
|
+
area: menu
|
|
5
|
+
updated: 2026-09-25
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Menu
|
|
9
|
+
|
|
10
|
+
What Kettle sells, what is in it and what it costs. The menu is Crumb & Co's;
|
|
11
|
+
Kettle only shows it.
|
|
12
|
+
|
|
13
|
+
## AS IS
|
|
14
|
+
|
|
15
|
+
### Products and allergens
|
|
16
|
+
|
|
17
|
+
- **Status:** confirmed
|
|
18
|
+
- A product belongs to one category and carries a list of the fourteen EU
|
|
19
|
+
allergens as data (`src/menu/models.py:10-52`), never as free text.
|
|
20
|
+
- Every product page lists its allergens as text and as labelled icons.
|
|
21
|
+
- Which shops sell a product is a list on the product: the station shops
|
|
22
|
+
carry a shorter menu.
|
|
23
|
+
|
|
24
|
+
### Prices
|
|
25
|
+
|
|
26
|
+
- **Status:** confirmed
|
|
27
|
+
- One online price per product, the same in every shop.
|
|
28
|
+
- An order keeps the prices it was placed at; a price change never touches an
|
|
29
|
+
order that already exists.
|
|
30
|
+
|
|
31
|
+
## TO BE
|
|
32
|
+
|
|
33
|
+
### Signed-off price list
|
|
34
|
+
|
|
35
|
+
- **Status:** decided
|
|
36
|
+
- **Issue:** [[KET-18]]
|
|
37
|
+
- Online prices go live only once Crumb & Co has signed off the list. Some
|
|
38
|
+
products are 5% above the shop price, to cover the payment fees.
|
|
39
|
+
|
|
40
|
+
## See also
|
|
41
|
+
|
|
42
|
+
- [ordering](ordering.md#basket-and-checkout) — how prices are fixed on an order
|