Files
Fuchs_Intranet/Fuchs/Docs/Decisions
StefanandClaude Opus 4.8 af445c015e Add backend-authoritative invoice draft editing (ADR 0006/0007)
Move the invoice draft editor to a backend single source of truth: an
in-memory InvoiceDraftSession (per-token, cached) holds the editable payload,
server-computed sums/VAT and validation, plus an automatic change history. The
browser posts single edits; the server recomputes and signals the editing
session over a dedicated SignalR hub (DraftPreviewHub) to re-fetch.

This reverses the previously-documented stateless editor (EVAL_live_invoice_editing,
INVOICE_LIFECYCLE §10), by explicit product decision — captured in ADR 0006 and 0007
plus the live-draft-editing concept doc.

Backend (this milestone):
- InvoiceDraftSession + ChangeHistoryEntry data holders
- InvoiceDraftCalculator: pure port of quantChange/invSumUpdate (§13b, VAT-by-rate)
  and consistency checks — fully unit-tested
- IInvoiceDraftCache/InvoiceDraftCache: in-memory store with idle sliding TTL
- IInvoiceDraftService/InvoiceDraftEditService: open (payload or DB reload), patch,
  build state, flush via existing RegisterInvoiceAsync (no new persistence), preview
  from cache, discard (DB reload), history
- InvoiceDraftExpiryService: pre-expiry warning + eviction-with-reason
- DraftPreviewHub + IDraftNotifier/DraftNotifier: targeted draftReady/draftExpiring/
  draftClosed signals per draft token
- inv/dopen|dstate|dpatch|dpreview|dsave|dhistory|ddiscard|dclose endpoints; save
  reports success/failure via the existing EventService
- DI + hub mapping in Program.cs

Frontend (additive foundation): $fis.draft SignalR client for /draftpreview.
The editor DOM inversion (routing deltas, rendering from server state) is the
next, separately-verified step; existing endpoints are unaffected.

Tests: 30 new (calculator, cache, expiry, patch/history, flush); 306 total passing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 13:29:35 +02:00
..

Decisions

This folder holds Architecture Decision Records (ADRs) — short, immutable records of a specific technical choice, why it was made, and what it implies going forward.

What belongs here

A decision, not a how-to. If it answers "why do we do X this way, and what else did we consider," it's a decision. If it explains "how subsystem X currently works," that belongs in ../Concepts instead (and a decision often triggers a concept doc to be created/updated).

File naming

NNNN-kebab-case-title.md, four-digit zero-padded, sequential across the whole folder (0001-..., 0002-...). Never reuse or renumber.

Required YAML frontmatter

Every decision file starts with:

---
status: Accepted        # Proposed | Accepted | Superseded
date: 2026-07-03         # date the decision was accepted
applyTo:                 # glob(s) — files/areas this decision governs
  - "Fuchs/Notifications/**"
supersededBy: ""         # filename of the decision that replaced this one, if any
---

Agents (Claude, Copilot, Codex) must scan the YAML frontmatter of every file in this folder first (cheap — no need to read the body) and only read the full body of decisions whose applyTo glob matches the files they're about to touch, or whose subject is otherwise clearly relevant to the task. This keeps decision-following cheap even as the folder grows.

Body template

# NNNN — Title

## Context
What problem/situation forced a choice.

## Decision
What was decided, stated plainly.

## Consequences
What this implies for future code — constraints, follow-ups, trade-offs
accepted knowingly.

## Alternatives considered
Options that were rejected and why (optional but preferred).

Rules

  • Decisions are immutable once Accepted. Do not edit the Decision/ Consequences of an existing file to reverse it. Instead, write a new decision, set its applyTo/subject accordingly, and set the old file's status: Superseded + supersededBy: NNNN-new-file.md.
  • Follow existing decisions. Before implementing anything in an area covered by an Accepted decision, read it and conform to it. If you believe a decision is wrong, raise it with the user rather than silently deviating.
  • Capture new decisions as they happen. Whenever the user (or the code you're writing) settles a non-obvious architectural or cross-cutting choice — not a routine implementation detail — add a decision here in the same change, and create/update the matching concept doc in ../Concepts.