aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-07-01-smaller-issues-design.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-07-01 11:43:36 +0200
committerDanilo M. <danix@danix.xyz>2026-07-01 11:43:36 +0200
commit60e15f9ced98c270a48d58ac000738afb78c2d7e (patch)
tree2e5cbeb814da52113b7d8af069143354dfc3a129 /docs/superpowers/specs/2026-07-01-smaller-issues-design.md
parent4588f4bf54ae6eefd7a75904d81ce2256afb805d (diff)
downloadfirefly-cli-60e15f9ced98c270a48d58ac000738afb78c2d7e.tar.gz
firefly-cli-60e15f9ced98c270a48d58ac000738afb78c2d7e.zip
docs: spec for smaller ISSUES.md items (tx list --flat, account create --if-not-exists, date semantics doc)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'docs/superpowers/specs/2026-07-01-smaller-issues-design.md')
-rw-r--r--docs/superpowers/specs/2026-07-01-smaller-issues-design.md92
1 files changed, 92 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-07-01-smaller-issues-design.md b/docs/superpowers/specs/2026-07-01-smaller-issues-design.md
new file mode 100644
index 0000000..af6ee85
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-01-smaller-issues-design.md
@@ -0,0 +1,92 @@
+# Smaller ISSUES.md items — design (v0.3.6)
+
+Three items from `~/Documents/Finances/ISSUES.md` "Smaller" section, shipped
+together as one PATCH bump (two new optional flags plus a doc fix; the CLI
+contract only gains, nothing breaks).
+
+## #2 Document `--since`/`--until` date semantics (doc-only)
+
+**Finding (verified against Firefly source):** `tx list`'s `start`/`end`
+params filter on `transaction_journals.date`
+(`app/Helpers/Collector/Extensions/TimeCollection.php` `setRange`, lines
+570-596: `where('transaction_journals.date', '>=', ...)` / `'<='`). That column
+is the transaction's single date field — the date the user sets on the tx.
+Firefly journals have no separate book/entry date, so there is no value-vs-book
+ambiguity to resolve: the filter is on the tx date, which is the value date.
+
+**Change:** SKILL.md `tx list` section states that `--since`/`--until` filter
+on the transaction date (the date set on the tx), inclusive on both ends.
+No code, no test, not independently version-worthy.
+
+## #1 `tx list --flat`
+
+**Problem:** `tx list` JSON nests every journal's splits under
+`transactions[]`, even for single-split journals (the common case), forcing
+scripts to reach through the array for one element.
+
+**Change:** add `--flat` to `tx list`. When set, post-process the unwrapped
+rows into one object per split, merging the split's fields up to top level with
+the journal `id` repeated, and dropping the `transactions[]` key.
+
+**Multi-split handling:** one flat row per split (approved). Single-split → one
+clean object; a journal with N splits → N objects sharing the same `id`.
+Uniform shape, matches the explode `--human` already does.
+
+**Where:** new helper `output.flatten_tx(rows)`. It keeps the raw Firefly split
+field names (e.g. `source_name`, `destination_name`, `category_name`,
+`currency_code`) rather than renaming them the way `--human`'s `_tx_rows` does —
+JSON output stays close to the API. The journal-level `id` is carried onto each
+flat row; any other journal-level attributes are dropped (the split holds the
+useful fields). Handler in `commands/transaction.py` `cmd_list` applies
+`flatten_tx` to the unwrapped rows only when `args.flat`, on both the `--all`
+and single-page paths, right before `output.emit`.
+
+**Scope:** stdout JSON only. `flatten_tx` is applied only in the JSON path;
+when `ctx.human`, it is skipped so the existing `--human` table (which already
+explodes splits via `_tx_rows`) renders unchanged. So `--flat --human` renders
+the same table as `--human` alone.
+
+**Test:** unit — single-split journal flattens to one object with no
+`transactions` key and the split fields at top level; a two-split journal
+yields two objects sharing the id; `--human` output is unchanged (still uses
+the nested explode).
+
+## #3 `account create --if-not-exists`
+
+**Problem:** `account create` returns full account JSON on success but a bare
+`{"error": ...}` when the name is already in use, so idempotent import scripts
+must special-case that error.
+
+**Change:** add `--if-not-exists` to `account create`. When set, before the
+POST, try `ctx.resolver.account(name)`:
+- found → emit that account's JSON (same flattened shape as a create) with an
+ added `"existed": true`, exit 0.
+- not found (`ResolutionError`) → fall through to the normal create.
+
+Detecting existence via the resolver (exact-name lookup that already raises on
+missing) avoids parsing Firefly's 422 validation-error string, which is
+brittle. One extra lookup, only when the flag is set.
+
+**Edge:** without `--if-not-exists`, behavior is unchanged (a name clash still
+surfaces Firefly's error, exit 1). The extra `"existed": true` key only appears
+on the collision path; a fresh create is byte-for-byte as today.
+
+**Test:** unit — `--if-not-exists` on an existing name returns the resolved
+account with `existed: true` and does NOT POST; `--if-not-exists` on a new name
+(resolver raises ResolutionError) POSTs normally; without the flag, existing
+behavior (POST, no pre-lookup) is preserved.
+
+## Cross-cutting
+
+- **Version:** v0.3.6, PATCH. Two new optional flags + a doc fix; existing
+ callers and JSON shapes are unchanged. Bump `pyproject.toml` and
+ `firefly_cli/__init__.py` together.
+- **Expandability rule:** module edits (`transaction.py`, `account.py`,
+ `output.py`), unit tests, SKILL.md updates for all three, regenerate
+ completion (`python scripts/gen_completion.py > completions/firefly.bash`).
+ No new `--type`-style enum values, so `FLAG_VALUES` is untouched; the two new
+ boolean flags appear in completion automatically via the registry.
+- **Release:** signed commit(s), signed tag `v0.3.6`, push `--follow-tags`
+ (one origin push reaches both remotes). Also mark the three items resolved in
+ `~/Documents/Finances/ISSUES.md` (that file is outside the repo, not
+ committed).