Commit Graph

12 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 e381e371ea contracts-check: OpenAPI header expects the {host} server variable (D-123)
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 f1abb0d2ef Server gate: cargo audit
Build Kvitt images / build (push) Failing after 51s
The server gate becomes cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo audit && cargo test
(CLAUDE.md, server/README.md). The pre-commit hook runs cargo audit --no-fetch only when server/Cargo.lock or a
server Cargo.toml is staged, and skips with a message when cargo-audit or the advisory database is missing.
First run: 0 advisories, 0 warnings over 319 crates; no audit.toml needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-19 19:36:54 +02:00
jacobh2 8660b7fa16 Server gap pass: invite-partner subcommand, CLI and drain tests, push info log (D-113, D-114)
- kvitt-server invite-partner: a partner invite by the admin as E-12 does (cancels the pending one, 72 h, link with
  ?from=<admin>), exit 2 household full, 3 no admin; README lines in server/ and infra/.
- Tests: invite-partner, migrate (schema at SCHEMA_VERSION, idempotent), healthcheck (200, 503, nothing listening),
  serve SIGTERM drain (in-flight request finishes, new connections refused, exit 0; gives up after SHUTDOWN_DRAIN).
- Push sender: one info line "push sent" per message with push_type, devices_sent, devices_targeted and 8-character
  device-id tails (SPEC §8.7 aggregates); per-device line stays at debug.
- tools/contracts-check.py: stale TODO(spec) replaced by the §9.11 CS-5 citation; shapes updated for invite_kind
  (D-086), app_version_name (D-090) and fid (D-096), 134 checks pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 22:12:28 +02:00
jacobh2 61f92c81c5 pre-commit hook: Android tests through gradle-serial.sh with JDK 25 on PATH, JAVA_HOME untouched; installer replaces an older Kvitt hook
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 22:11:07 +02:00
jacobh2 2fac1ecba0 tools: one Gradle lock helper (gradle-lock.sh) for gradle-serial.sh and clean-builds.sh
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 22:11:07 +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 c277ee37c2 M2b: Android skeleton, :core:model contract, :domain passing all vectors
Gradle project in android/ with every module of SPEC §6.2 (build-logic convention plugins, version catalog,
architecture check in check), :core:model types and repository interfaces of §14.2.4 and §14.5, :domain
implementing §14.5.2 and §14.5.4 (125 vector cases), scenario-driven fakes with the empty scenario, Room 3
entities and KvittDatabase v1 with exported schema, :app shell with Hilt, en/sv strings with MissingTranslation
as a lint error, Roborazzi goldens of the empty screen in light and dark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:25:19 +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
jacobh2 cab3e935d6 SPEC v0.1 and project rules for Kvitt
Write SPEC.md v0.1 from the owner interview (requirements, data model,
stack, API outline, security, business rules, deployment, milestones,
UX sprint brief, contracts). Fill the CLAUDE.md blanks, move the Gradle
pin files into android/, point the tools at android/ and server/, and
record the git bootstrap exception in the handoff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:39:02 +02:00
jacobh2 8bef22afb2 Scaffold: agent starter kit (seeded from Ebb)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 20:15:40 +02:00