Phase 81.0
organized-app-importer
Backup JSON → local roster with CRDT diff + dry-run + at-rest encryption
New package jw-meeting-scheduler. Imports the JSON exported from organized-app web/desktop into a per-congregation local SQLite store. Mapper PersonType → flat PersonRecord: gender derived from separate male/female booleans, status derived from publisher_baptized/unbaptized.active, only active privileges, eligible_assignments flattened+deduped, last_updated = max(updatedAt) across Timestamped fields. Recursive walk of the nested SchedWeek picking up dict slots {value, type, updatedAt} → AssignmentHistoryEntry with aula auto-detected (suffix _B→aux_class_1, _C→aux_class_2). run_import pipeline with dry-run flag + compute_person_diff classifies added/updated/kept_local/unchanged. Opt-in at-rest encryption with FieldEncryptor + PBKDF2 salt derived from congregation_id.
What was delivered
- load_backup with Pydantic OrganizedAppBackup envelope + F51 PersonType schema list.
- map_person: gender derived from separate male/female booleans, status from publisher_baptized/unbaptized.active + statusHistory, only active privileges (end_date empty or future), eligible_assignments flattened+deduped sorted by code value.
- slugify_person_id with NFD diacritic strip + intra-word decoration strip (Juan Pérez → juan-perez, O'Connor → oconnor).
- map_schedule_week recursive walk of the dict tree picking up {value, type, updatedAt} slots, aula auto-detected from field suffix.
- SchedulerStore SQLite with compound index (person_id, assignment_code, meeting_date DESC) for fast rotation queries.
- CRDT guard in upsert_person: if existing.last_updated ≥ rec.last_updated, no write (local newer wins).
- record_history with INSERT OR IGNORE by entry_id (idempotent).
- FieldEncryptor wrapper with salt b'jw-meeting-scheduler/v1:' + congregation_id → same passphrase + different congregation = different keys (verified in tests with Fernet InvalidToken).
- run_import pipeline with dry-run flag + ImportDiff (added/updated/kept_local/unchanged) rendered in Rich table.
- jw scheduler import --backup --congregation [--dry-run] [--passphrase] CLI complete.
- 26 scheduler tests (5 models + 3 crypto + 4 loader + 5 person_mapper + 4 schedule_mapper + 7 store + 4 diff + 4 pipeline) + 2 CLI tests.
- Guide docs/guias/meeting-scheduler-import.md with quickstart + encryption recipes.