Items 1–12 of the interface review: - Larger UI font (UI_FONT_SIZE) across widgets, menus, dialogs, Treeview rows. - DRK-red header bar; window title shows entry count; runtime-drawn red-cross icon (also written to data/icon.png for the launcher). - Status bar colour-coded by severity; transient messages auto-clear after 8 s, queue-count messages stay. - Tab 1: more form spacing, digits-only PLZ, explicit "Auswahl entfernen" + Delete key for queue rows, confirm on "Warteschlange leeren", modal on duplicate save. - Tab 2: raw lat/lon columns replaced by one "Karte" column (checkmark / red "fehlt"); ▲/▼ arrow on the active sort column; hint line always shows the saved-entry count. - "Karte öffnen" with no coordinates shows a dialog, not just a status line. - Window size/position remembered between sessions (data/window.json). Verified by building and driving the window under Homebrew Python 3.12 / Tk 9; non-GUI smoke tests still pass. Docs updated (changelog, overview, improvements, data-model, setup, dev-notes). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3.2 KiB
Data model
data/orte.csv
Plain CSV, comma-separated, UTF-8, with a header row. Created automatically with just the header if it does not exist.
| Column | Type on disk | Meaning | Notes |
|---|---|---|---|
date |
string | Assignment date | Always stored as YYYY-MM-DD. Input is validated and normalized by parse_date() (accepts YYYY-MM-DD, DD.MM.YYYY, DD.MM.YY, YYYY/MM/DD); invalid input is rejected before saving. Rows written before this change may still hold non-ISO strings. |
city |
string | Place name | Free text. Used for autocomplete and duplicate detection (trimmed, case-insensitive). |
postal_code |
string | German PLZ | Optional. Kept as a string so leading zeros survive. Regex elsewhere accepts 4–5 digits. |
lat |
string | Latitude | Blank until geocoded. Rounded to 5 dp. Parsed with pd.to_numeric(errors="coerce") when building the map. |
lon |
string | Longitude | As above. |
Every column is read as a string (dtype={"postal_code": str, "lat": str, "lon": str}
plus city/date default object). Numeric conversion happens only where needed.
Row identity
There is no ID column. Rows are identified by their pandas DataFrame
index, which is reset to 0..n-1 after every delete. UI tables use that index
as the Treeview iid.
Implication: a geocode callback that is in flight while the user deletes a
different row can land on the wrong row, because indices shift. update_row /
_apply_edit_geocode guard against a missing index but not against a
reused one. Still open — see improvements.md.
The manual lat/lon fields in the edit dialog give a way to correct any row
that ends up wrong.
Duplicate detection
find_duplicates flags a queued row when an existing row matches on all three
of: date (string-equal), city (trimmed, lower-cased), postal_code
(trimmed). It only produces a status-bar hint; duplicates are still written.
Map aggregation
get_map_data groups by (city, lat, lon) and counts rows. Two entries for the
same city with different coordinates (e.g. Karlsruhe geocoded once to 76133
and once to 76185) produce two separate markers.
data/karte.html
Regenerated from scratch every time the user opens the map. Safe to delete; it is a build artefact, not data. Should be git-ignored if the project is ever put under version control.
data/backups/
Automatic timestamped copies of orte.csv, named orte-YYYYMMDD-HHMMSS.csv.
One is written at startup and one before every change (skipped when nothing
changed since the last backup). The newest 20 are kept; older ones are pruned.
Git-ignored. To restore, copy a backup over data/orte.csv while the app is
closed.
data/app.log
Rotating log file (512 KB × 3 generations). Git-ignored. Records saves, map generation, geocoding failures, and uncaught exceptions.
data/window.json
{"geometry": "<w>x<h>+<x>+<y>"} – the window size and position, saved on close
and restored on start. Git-ignored, per-machine. Safe to delete (window opens at
its default size).
data/icon.png
The red-cross window icon, drawn at first run and written here so the .desktop
launcher can point at it. Git-ignored (regenerated). Delete to force a redraw.