8 Commits

Author SHA1 Message Date
jacobh2 a86ad241f1 Server and contracts: public URL on port 443 (D-124)
Kvitt is served on the default HTTPS port through Nginx Proxy Manager, so the
OpenAPI server is https://{host} (contracts/openapi.yaml and openapi.rs
PUBLIC_SERVER_URL), examples E-7 public_url and E-12 link are
https://kvitt.example.invalid without a port, tools/contracts-check.py expects
the portless header, and the server's tests, config message and README name
no port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 20:22:09 +02:00
jacobh2 c9abd24c77 Server: no built-in public host, no trusted proxy by default; OpenAPI server variable host (D-123)
KVITT_PUBLIC_URL is required: every command refuses to start without it (compose
always sets it). KVITT_TRUSTED_PROXY defaults to none, which the rate limiter never
resolves. contracts/openapi.yaml and the utoipa document: servers[].url
https://{host}:8443 with variable host (default kvitt.example.invalid). E-7 and E-12
examples on kvitt.example.invalid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 20:11:46 +02:00
jacobh2 f56dcbe5f7 Server: FCM HTTP v1 target in fid instead of deprecated token (D-083 follow-up)
The stored fcm_token is the Firebase Installation ID; HTTP v1 deprecates
message.token (accepted only during the transition) in favour of message.fid.
Push examples and push_fcm tests follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 15:17:18 +02:00
jacobh2 8c607153c0 M12e: contract pass (pair invite kind, admin name in invite links, sync failed flag, rejection actor, device version name, template id, update check result, untouched accounts, D-027 re-stamp, PushEvent in :core:model, snackbar hosts)
Server: E-3 invite_kind; E-12 link ?from=<admin name>, E-4 passes it into kvitt://invite;
X-Kvitt-App-Version-Name stored in devices.app_version_name (migration 0003, schema 3);
OpenAPI and examples follow. Phone: :core:model, :core:fakes, :data, features and :app
updated together; goldens re-recorded for S-20 (version name) and new S-1/S-22 states.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 15:00:56 +02:00
jacobh2 e6768121d6 SPEC v0.9: M12b and M12c outcomes (D-055 to D-058), U2 values, UX-9 (D-059, M12d)
- D-055 build-time copy of the keyword table, D-056 parseCategoryKeywords,
  D-057 enum declaration orders, D-058 E-7 example shows server_version
  15 and 16 and its test compares them again.
- D-051 fulfilled: §9.7 hex values from docs/ux/design-spec.md §2.3;
  design-spec.md binding, strings.csv the source of string resources.
- D-059: ExpenseEditorOptions.frequentCategoryIds and
  CategoryRepository.deletable; new milestone M12d with PLAN-M12d and
  prompts/M12d.md; M7a-f depend on M6 and M12d.
- suggestCategory readings (null when other is archived), §11.2 landed
  marks and the 2026-10-18 dry run, dev stack on schema 2, PLAN-M12b
  SQLite 3.51.x, design-spec §6 notes in PLAN-M6/M7c/M7f; HANDOFF rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 08:34:45 +02:00
jacobh2 6eaccec7ac M12b: category contract v2 on the server (schema 2, fourteen defaults, finer import mapping)
- migrations/0002_categories_v2.sql, byte-identical to contracts/schema/migrations/0002_categories_v2.sql
  (SPEC §14.1.1), with an identity test; SCHEMA_VERSION = 2 (E-1 reports it, the importer's check follows).
- Seed test on a fresh database (the fourteen rows of AC-7.2, server_version 11 to 14) and an upgrade test of a
  v1 database in use (0001 applied through the migrator, then users, a custom, a renamed and an archived default,
  an account, a recurring template, expenses): every earlier row unchanged, the four rows above the old
  sequence, foreign_key_check empty, schema_version 2, a pull from the old cursor returns exactly the four rows.
- DefaultCategoryKey with the fourteen keys (wire enum and contracts/openapi.yaml); icons 33 and colours 14
  (§9.7) in validation.
- The two category examples M12a held back (E-26 response-default, sync/pull-page-categories-v2) and its
  contracts-check patch for them and the enum.
- Importer: splitwise_categories.csv per the §10.8 v0.8 table (D-053), DEFAULT_KEYS of fourteen, synthetic
  fixtures for the finer mapping (Insurance/Försäkringar to insurance among them), a schema-1 refusal test.
- Test harnesses seed users at server_version 15/16 (after the fourteen seeds); pull counts 10 -> 14.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 08:25:22 +02:00
jacobh2 aa765bbb48 Contracts for 14 default categories and the category suggestion (UX-3, UX-8)
- contracts/schema/migrations/0002_categories_v2.sql: server migration 0002 rebuilds categories with the
  14-key default_key CHECK, inserts housing, insurance, children and fees with server_versions taken from
  the global sequence, sets schema_version 2. server-v1.sql unchanged.
- contracts/category-keywords.csv: the keyword table of the suggestion (148 entries, from docs/ux).
- contracts/test-vectors/suggest_category.json: 65 Kotlin-only cases of CS-4 to CS-6.
- contracts/examples/E-1-health: schema_version 2.
- tools/contracts-check.py: reference suggestCategory, keyword-table checks, 0002 load checks on a fresh
  and an in-use database, plain icon/color check, new icon and colour tokens.
- android/domain: suggestCategory (CS-4 to CS-6, code points, platform NFC and categories through
  UnicodeText), vector runner for suggest_category, eight vector files.
- server/crates/kvitt-domain/tests/vectors.rs: suggest_category is Kotlin-only.

The OpenAPI DefaultCategoryKey extension and the two new category examples are held back until the
server's wire types know the new keys (M12b).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 08:10:57 +02:00
jacobh2 c6df2ab8f5 M1: contracts and vectors (SPEC v0.1, schema 1)
contracts/openapi.yaml (OpenAPI 3.1, E-1..E-33, error shape and the
exhaustive error code enum, device bearer scheme), contracts/schema/
server-v1.sql (SPEC §14.1 verbatim), seven test-vector files per §14.5.5,
80 examples (every JSON body of §14.3.4, every error code, sync pull/push,
every FCM push type), and tools/contracts-check.py (stdlib-only reference
of §9.1, §9.3, §9.4 and §14.5.4 plus shape checks; the M1 gate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:57:59 +02:00