PROJECT_STATE.md
Rama main · réplica de lectura del repositorio original.
# Project State
## Accounting and reference data
- REST implements the household chart: hierarchical accounts, categories, tags, transaction templates, and flat household members; each supports the applicable create, read, update, list, delete, visibility, featured, and FQN restructure flows. Group visibility derives from active leaves, restructures rewrite whole subtrees atomically, and category moves also rewrite active budget category paths.
- Accounts have `owned`, `party`, `flow`, or fixed `system` types; categories have `expense` or `income` intent. System accounts are readable but immutable. Accounts may be single- or multi-currency, and only single-currency accounts carry credit-limit history.
- Applicable reads and list defaults are tombstone-aware and exclude hidden resources unless requested. Delete eligibility is surfaced rather than assumed, and all write-time reference and accounting-semantic checks remain service-owned.
- REST provides account balances, prefix registers, journal-record search, and server-derived month spend/income totals. Balances include native amounts, approximate USD aggregation, unconverted counts, and current credit-limit standing; month totals cover categorized flow records only.
- REST provides configurable household, Category, and Tag flow reports with scope-specific net semantics, movable anchored month/year windows, a separate global accounting-history range, ranked Account/Category breakdowns, stable server-applied contributor filters, selectable rolling trends, conversion disclosure, transfer exclusion, and fixed entity transaction previews.
## Ledger, rates, and lifecycle
- REST supports balanced journal transactions as full entries and as spend, income, refund, transfer, and two-currency exchange shortcuts. Writes can infer non-USD `amount_usd` from stored USD-pair rates; unresolved amounts remain unconverted.
- Transactions support one composable boolean filter DSL across record and transaction fields, including exact stable-ID literals for entity values, plus pagination, date anchoring, free-text search, and stable initiated/created/updated ordering; ETag-guarded identity-preserving full replacement with protected importer provenance and dependent records; independent derived class, shape, role, and display metadata; dry-run classification; record-level bulk category, tag, member, account, settlement, and reconciliation updates; and atomic replacement of one compatible non-system account common to selected transactions.
- Active transactions can be cancelled and restored; deletion is a separate tombstone action. Owned and party records carry pending/posted settlement dates. Expected recurring transactions are excluded from unfiltered lists; supplying any filter expression makes that expression solely responsible for lifecycle inclusion.
- Source exchange rates have CRUD and a read-only dense daily USD-rate snapshot. Loading identifies needed currencies, refreshes the snapshot, and backfills resolvable missing USD values.
- Refund and reimbursement record links are metadata-only pairwise associations. Imported-record storage retains provider-neutral metadata, raw provider payload, and external provenance; it does not imply a delivered import workflow.
## Reusable and scheduled transactions
- Transaction templates are hierarchical, versioned through full replacement, and stored as active/tombstoned templates with partial journal-record defaults. Template moves preserve the template FQN; canonical lists use shared FQN matching while preserving requested order, and bounded entry/navigation discovery uses backend ranking.
- Recurring definitions support shared FQN list filtering and ranked discovery plus schedule creation/replacement, pause/resume, universal defer, confirmation, cancellation, and expected-transaction review. The anchor identifies the authoritative next occurrence: the observable recurring catch-up operation materializes due occurrences as directly linked EXPECTED transactions and advances it, while confirming or dismissing those transactions does not move it. Transaction reads are non-mutating; future transaction-list positions are read-only projections, with Confirm next and Defer available only on the anchor projection.
## REST and client surfaces
- The REST API is OpenAPI-defined, exposes the implemented accounting, reference, template, recurring, rates, operation, settings, demo, health, and authentication contracts, and serves its generated spec at `/api/openapi.json`. Applicable timestamped collections support stable ascending and descending updated-date ordering. Transport validation and stable machine-readable JSON errors are in place.
- Every matched non-`GET` OpenAPI request is recorded best-effort in portable audit history with structured outcome metadata, caller-declared surface attribution, and eligible JSON payloads; login passwords are removed before persistence, bounded newest-first audit reads are available through REST, CLI, and MCP, and expired history can be compacted manually or monthly under ordinary retention settings.
- Generated REST-backed CLI and MCP catalogs independently select exposure for every OpenAPI operation. Both expose the delivered accounting/reference, rate, template, recurring, journal-record, settings, background-operation, and health flows; browser authentication is REST/UI-only, demo seeding is CLI-only, and MCP deliberately omits per-rate-ID reads.
- REST, generated MCP, and `mina db schema` expose the embedded current target accounting DDL for inspection; it is not the configured database's live schema or a database initialization path.
- `mina client --server URL` is a remote JSON CLI with optional `MINA_API_KEY`. `mina client --db PATH` runs the same selected REST operations against a one-shot in-process app: it has no listener, authentication, startup validation, or automatic operations, but waits for manually triggered exchange-rate, backup, recurring-catch-up, and audit-compaction runs to finish.
- `mina mcp stdio --server URL` is remote-only and uses an API key when authentication is enabled. `mina serve` also hosts the same registry as API-key-only Streamable HTTP MCP at `/mcp`; its origin policy permits no `Origin` but rejects non-loopback origins. Both transports publish shared accounting and mutation-safety instructions. No hand-written client-surface extensions ship.
## Web UI
- `mina serve` embeds the React UI at `/`; canonical root routes replace the legacy `/ui/` prefix. The shell resolves authentication status before rendering, uses server `HttpOnly` cookie sessions, and returns to login after a protected-request `401`.
- The browser provides page-aware keyboard shortcuts help via `?`, hover-only action shortcut hints, physical Control transaction-save shortcuts across editor focus targets, and the command palette with modifier-aware account register/filtered-Transactions actions; an overview with configurable household flow, active owned/party balances, and monthly activity; a featured-account strip that stays visible in roomy navigation and appears inside the compact Navigation sheet; searchable account, category, tag, and member management with URL-backed category intent filtering; account/group registers with settlement-day dates and an initiated-date fallback, plus a single-account shortcut to the URL-filtered Transactions browser; configurable Category/Tag flow overviews; member transaction drill-downs; a Settings screen; and a Status screen for health, build commit, database encryption and file size, plus URL-addressable background-operation and API audit-history browsers. Account, Category, and Tag display-label overrides affect presentation and picker discovery/order; hierarchy, navigation, and disambiguation remain FQN-based.
- Transaction browsing and account/group registers share one URL-addressable full transaction detail with native/USD display, lifecycle and settlement indicators, active recurring-definition provenance backlinks that open the definition editor while cancelled provenance remains plain text, transaction and expanded-record update metadata, and the same actions. Full-page entity tables and non-preview transaction/register tables share one row Tab stop, guarded one-time active-row focus on populated page entry, arrow/Home/End navigation, and active-row hover fills; fixed transaction previews and the Status audit log retain no entry autofocus. Available list searches accept guarded `/` and `Cmd/Ctrl+Shift+F` focus-and-select shortcuts and advertise both in page-aware help; transaction detail takes focus in browsers and follows row focus in registers. Recurring-definition editors link to the shared transaction browser by direct definition ID while retaining unsaved drafts. Transaction browsing adds URL-backed OR filter rows with explicit chip operators, recurring-definition FQN, hierarchy-scope, and ID filtering shared with REST/CLI/MCP, and exact read-only Advanced expressions, configurable stable ordering, date navigation for the default order, selection-based reference/status edits, and confirmed replacement of an account common to every selected transaction; transaction entry has global tab chords and is a route-independent modal for spend, income, refund, transfer, exchange, and advanced balanced entries, including pending creation, compatible template defaults with guarded modal `Cmd/Ctrl+Shift+F` search, transient Transactions-day date seeding with required blank dates elsewhere, first-empty create focus, explicit-save draft recovery and clearing with session-only sticky defaults, edit/duplicate, split, post, and cancel flows.
- Phone and short-tablet layouts remove the sidebar from page geometry, expose Navigation, page Controls, and active transaction Edit tools from a fixed full-width bottom toolbar, and present nested pickers as returning bottom sheets. Full-page tables use window scrolling, while phone transaction rows place description and memo on a full-width second line; roomier layouts retain the fixed sidebar and bounded table geometry.
- The UI manages backend-searchable hierarchical templates and recurring definitions plus transaction-native expected review, including ranked template use, reusable partial defaults, and recurring-definition drafts seeded from templates or non-generated active/cancelled transactions. Account, Category, Tag, and Template pickers compose six-row entity-owned ranked search, retain displayed result snapshots through replacement loading, prefer effective display titles with full FQNs available on hover, Meta, and drilled-in breadcrumbs, and preserve hierarchy navigation and exact-path selection. Account, Category, and Tag additionally keep local selected values, support separate creation availability, retain hidden selections, batch choices, and create eligible leaves; the one-shot Template picker applies the chosen stable ID without retaining a picker value. Member pickers use the same bounded search with flat name-based results and local hidden selected values.
- UI data remains REST-backed. IndexedDB holds only UI preferences, UI caches, and draft state; it never stores credentials or accounting data. The browser exposes substantial human workflows, not a claim of full REST parity.
## Runtime, operations, and deployment
- One long-running app instance composes REST, embedded UI, and embedded MCP. It opens/migrates accounting state before serving, starts configured background and startup work without blocking readiness, records app-local operation status, and cancels and joins work during shutdown.
- Exchange-rate loading starts from the configured Frankfurter cache and supports scheduled and manual targeted refreshes. Database backup runs manually, and on a schedule when configured; they copy only file-backed accounting databases to configured local targets and preserve database encryption. Recurring catch-up runs at long-running startup, at 00:01 server-local time daily, or manually. API audit-log compaction runs manually or on its configured UTC schedule, monthly by default, and uses a calendar-month retention boundary.
- Startup demo seeding can provision realistic, date-anchored transactions, templates, recurring definitions, and expected transactions in new state only. File-backed startup refuses demo seeding when the selected accounting schema already exists.
- Long-running file-backed startup runs configured `none`, `shallow`, or `full` validation after migration (`shallow` by default). `mina db validate` is a separate offline, read-only CLI diagnostic; neither is a REST capability. Runtime settings report the immutable resolved startup values, sources, and config-file location.
- Optional file-backed authentication is loaded once at startup from a separate, CLI-administered file. REST accepts browser sessions or revocable API keys; external MCP accepts API keys only. Authentication administration, auth state, API-key secrets, and database encryption keys are outside the accounting database and absent from ordinary settings output.
- The Docker image and Compose deployment support a noninteractive fresh installer, private generated bootstrap credentials and automation API key, authenticated encrypted storage, host UID/GID operation, read-only root filesystem, separate config/backup binds, named database/cache volumes, and localhost-only publishing by default. Mina serves plain HTTP, so non-loopback exposure requires a trusted network or TLS-terminating reverse proxy.
## Storage and process boundaries
- Accounting state is DuckDB in a selected schema, either attached from one portable database file or held in the process in-memory database. Upgrade-only migrations and schema-version tracking apply to that accounting location; multi-row ledger changes persist atomically. Mina instants retain their represented UTC time across host timezones, while civil dates remain timezone-free.
- File-backed databases are plaintext unless `MINA_DATABASE_ENCRYPTION_KEY` is supplied, when DuckDB AES-256-GCM is used. The key is environment-only; Status reports encryption state without revealing it.
- Each app also owns an opaque in-memory runtime schema for disposable operation runs and dense exchange-rate data. It is outside portable accounting state, migrations, backups, and database validation.
- Store code owns DuckDB lifecycle mechanics, qualified SQL, migrations, transactions, repository conversion, dynamic query allowlists, and database-error mapping. Accounting semantics, validation, and transport mappings remain outside the store.