tane/CLAUDE.md

66 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md — Tanemaki
Context for AI agents (Claude Code) working in this repo. Read this first, then [`docs/design/open-decisions.md`](docs/design/open-decisions.md) (the **live decision log**).
## What this is
**Tanemaki** (種まき, "sow/scatter seeds"; short: **Tane**) — a **local-first, decentralized** app to manage and share traditional seeds. First app on a generic commons engine. Web: `tanemaki.app`. Package id: `org.comunes.tane`. See [`VISION.md`](VISION.md) for the human explanation and [`PLAN.md`](PLAN.md) for the origin analysis (with a "Nota de vigencia" reconciling evolved decisions).
## Golden rules (do not violate)
- **English for ALL code**: identifiers, class/field/column names, comments, commit messages, branch names, and technical specs. No exceptions.
- **User-facing strings are NEVER hardcoded** — always via i18n. The app is multilingual by design.
- **International by design, not Spain-first.** Tane targets the whole world, not one country or region. This is not just UI strings: it constrains **bundled data and assets** too.
- **Locale-keyed data, never mono-locale**: any catalog/reference data with human-readable names (species common names, vernacular names, units, categories) MUST be a locale-keyed map (`{ "es": [...], "en": [...], "ar": [...] }`), extensible to any language — never a single hardcoded language. Starter datasets may ship a small locale set, but the *schema*, code paths, and copy must never assume es/en only, and comments/notes must not brand the data as "Iberian/Spanish".
- **RTL is a first-class requirement**: layouts, widgets, and tests must work under RTL (Arabic, Hebrew, Persian). Use directional (`start`/`end`) not physical (`left`/`right`) insets/alignment; verify with `Directionality`.
- **Scripts & fonts**: bundled fonts must cover the scripts we claim to support (Latin + at least RTL/Arabic and CJK as they land); don't hardcode a Latin-only font stack.
- **OCR / language models**: bundled OCR traineddata and any language resource are pluggable per locale, not fixed to `eng`/`spa`. Match the data pack to the user's locale(s); the current es/en starter set is a seed, not the ceiling.
- **No locale-specific assumptions** in formatting, sorting, dates, numbers, name order — go through `intl`/ICU, never ad-hoc.
- **No plaintext at rest, ever** — the inventory DB is encrypted (SQLCipher). No plaintext logs/temp/caches. See [`docs/design/security-privacy.md`](docs/design/security-privacy.md).
- **Local-first**: everything works offline, no account, no central server. Online only enriches (degrades gracefully).
- **Progressive disclosure**: only `Variety.label` is mandatory; every other field optional. Audience is everyone 1080; simple by default, depth on demand. Never build "two modes".
- **Human words in the UI, never tech jargon.** User-facing copy speaks by *intent* (what it does for the person), not by *mechanism*. File formats and internals (CSV, JSON, HLC, CRDT, LWW, UUID…) are implementation details and MUST NOT appear in labels, subtitles, dialogs or messages. E.g. "Save a backup" / "Restore a backup" (not "Export JSON"); "Export to a spreadsheet" (a spreadsheet is a human concept; "CSV" is not). Format-named i18n *keys* (`exportJson`) are fine — they're code; only their *values* must be human. When a feature is genuinely for power users, reframe it or bury it under progressive disclosure — don't leak the jargon.
- **License: AGPL-3.0.** Keep new deps compatible.
- **Tests, near-TDD.** Every behavior is covered by automated tests (unit / widget / integration); **do NOT rely on manual testing.** Write tests first for domain logic (`commons_core` is pure Dart — ideal for TDD). Nothing merges without tests covering the new behavior; CI gates it. See [`docs/design/testing.md`](docs/design/testing.md).
- Discussion/design docs may be in Spanish; code and specs in English.
## Stack & structure
- **Flutter/Dart**, monorepo via **pub workspaces**. Target Android/iOS/desktop.
- **Drift** (SQLite) + **SQLCipher** for the encrypted local DB. Versioned step-by-step migrations, schemas exported to `drift_schemas/`, migration tests in CI. See [`docs/design/data-model.md`](docs/design/data-model.md) §5.
- i18n from day one (e.g. `flutter_localizations` + `intl`/`slang`).
```
tane/
pubspec.yaml # pub workspace root
packages/
commons_core/ # identity, Party/Group, TrustEdge, Offer, Pledge, transport (Nostr)+CRDT+sync, geohash discovery. NO seed specifics.
apps/
app_seeds/ # Tanemaki: Variety/Lot/Movement/Species, germination, plant-family units, UI, i18n, commons_ui (embedded for now)
```
Dependency direction: **`app_seeds``commons_core`, never the reverse.** Boundary rules in [`docs/design/core-domain-boundary.md`](docs/design/core-domain-boundary.md).
## Data model (decided, `schemaVersion = 1`)
Three levels: **`Variety`** (identity/accession) → **`Lot`** (a batch you hold: `harvest_year`, quantity, `offer_status`, germination) → **`Movement`** (append-only event log = history + provenance DAG + Plantare). Plus `Species` (bundled Wikidata/GBIF catalog), `VernacularName`, `Attachment`, `ExternalLink`, `GerminationTest`, `Party`, `SeedBank`, `Offer`, `Plantare`. Every mutable row: client `UUIDv7`, `created_at`, HLC `updated_at`, `last_author`, `is_deleted` (soft delete/tombstone), `schema_row_version`. CRDT: LWW scalars, OR-Set collections, grow-only `Movement`. Full spec: [`docs/design/data-model.md`](docs/design/data-model.md).
Decided schema details: `Quantity` is a shared value type (Lot + Movement); `offer_status` only on Lot; `category` free text prefilled from `Species.family`. Quantity units are **plant-aware** (cob/pod/ear/head…), not just kitchen units (§2.3.1). A Variety can hold multiple Lots with different years AND units at once.
## Identity & crypto (decided)
- **One identity** = a **Duniter/Ğ1-style root seed** (does profile, certifications, Ğ1). From it, **deterministically derive** a **secp256k1** subkey for **Nostr** (messaging/offers) — because Duniter has no messaging. User backs up ONE thing (the seed, as a printable recovery **QR**).
- At-rest DB key = a separate internal symmetric key in the OS keystore (unlocked by device biometric/PIN); NOT a user password. Backups also encrypted; key travels via the QR. See [`docs/design/backup-and-recovery.md`](docs/design/backup-and-recovery.md).
## Phasing — build order
**Block 1 (NOW): Inventory.** Shippable alone, useful with zero network. This is the current target.
**Block 2 (later): the social leap** — offers + messaging + relays + web of trust — big and indivisible; needs its own round (and ideally funding). Do NOT start Block 2 now.
Social layer (for later) uses: Nostr (offers NIP-99, DMs NIP-17), Duniter-style **web of trust** (Duniter/Ğ1 compatible, ~5 certifications), optional **Ğ1** currency (levels: price → wallet deep-link → optional WoT import). Cold-start via real Ğ1 seed groups + fairs. See [`docs/design/network-trust.md`](docs/design/network-trust.md) and [`docs/design/g1-integration.md`](docs/design/g1-integration.md).
## Where things live
- Live decision log: [`docs/design/open-decisions.md`](docs/design/open-decisions.md) — check before deciding anything.
- First code steps: [`docs/design/first-sprint.md`](docs/design/first-sprint.md).
- Prior art / valuable mockups: [`docs/mockups/`](docs/mockups/) (inventory, item, search, profile, chat — the UI spec).
- Git: bare at `~/repos/tane.git`; working clone here. Commit messages in English.