# FAPP — Free Appointment Propagation Protocol ## Purpose Decentralized psychotherapy appointment discovery over the QuicProQuo mesh network. In Germany, finding a psychotherapist takes 3–6 months. The KV (Kassenärztliche Vereinigung) system artificially limits slot visibility. FAPP enables licensed therapists to directly announce free appointment slots into a decentralized mesh, where patients can discover and reserve them without a central registry. ## Privacy Model - **Therapist identity is public.** Therapists are licensed professionals (Approbation). Their mesh identity is linked to a hashed Approbationsurkunde number. This is intentional — patients need to verify they are booking with a real therapist. - **Patient queries are anonymous.** Patients never reveal their identity when searching. SlotQuery messages carry no identifying information. Only when a patient decides to reserve a slot do they establish an E2E-encrypted channel to the therapist — and even then, the mesh sees only encrypted traffic to the therapist's address. ## Capability Flags FAPP extends the announce.rs capability bitfield: | Flag | Value | Description | |------|-------|-------------| | `CAP_FAPP_THERAPIST` | `0x0100` | Node is a licensed therapist publishing slots | | `CAP_FAPP_RELAY` | `0x0200` | Node caches and relays FAPP slot announcements | | `CAP_FAPP_PATIENT` | `0x0400` | Node can issue anonymous slot queries | ## Message Types ### 1. SlotAnnounce Therapist publishes free time slots into the mesh. **Fields:** - `id: [u8; 16]` — Unique announcement ID - `therapist_address: [u8; 16]` — MeshAddress of the therapist node - `fachrichtung: Vec` — Therapy specializations offered - `modalitaet: Vec` — Session modalities (Praxis, Video, Hybrid) - `kostentraeger: Vec` — Accepted payment/insurance types - `location_hint: String` — PLZ (postal code) only, never exact address - `slots: Vec` — Available time slots - `approbation_hash: [u8; 32]` — SHA-256 of the therapist's Approbation number - `sequence: u64` — Monotonically increasing per therapist (dedup/supersede) - `ttl_hours: u16` — Time-to-live in hours (default: 168 = 7 days) - `timestamp: u64` — Unix seconds at creation - `signature: [u8; 64]` — Ed25519 signature over all fields except signature and hop_count - `hop_count: u8` — Current propagation hop count - `max_hops: u8` — Maximum propagation hops **Propagation:** Like MeshAnnounce — flooded to neighbors, deduped by `(therapist_address, sequence)`. Higher sequence supersedes lower. Expired announcements (timestamp + ttl_hours exceeded) are dropped. ### 2. SlotQuery Patient requests available slots matching criteria. Anonymous — no patient identity attached. **Fields:** - `query_id: [u8; 16]` — Random query identifier for response correlation - `fachrichtung: Option` — Filter by specialization - `modalitaet: Option` — Filter by modality - `kostentraeger: Option` — Filter by insurance type - `plz_prefix: Option` — Filter by PLZ prefix (e.g. "80" for München area) - `earliest: Option` — Earliest acceptable slot (Unix seconds) - `latest: Option` — Latest acceptable slot (Unix seconds) - `slot_type: Option` — Filter by appointment type - `max_results: u8` — Maximum number of results requested - `hop_count: u8` — Current hop count - `max_hops: u8` — Maximum query propagation hops - `return_path: Vec<[u8; 16]>` — Onion-style return path (mesh addresses) **Propagation:** Forwarded like announces but with shorter TTL. Relay nodes with cached SlotAnnounces can respond directly. ### 3. SlotResponse Matching slots returned to the querier via the return path. **Fields:** - `query_id: [u8; 16]` — Correlates to the original SlotQuery - `matches: Vec` — Matching slot announcements (full, so patient can verify signatures) ### 4. SlotReserve Patient claims a specific slot. E2E encrypted to the therapist. **Fields:** - `slot_announce_id: [u8; 16]` — ID of the SlotAnnounce being reserved - `slot_index: u16` — Index into the SlotAnnounce's slots vector - `patient_ephemeral_key: [u8; 32]` — X25519 ephemeral public key for reply encryption - `encrypted_contact: Vec` — Patient contact info, encrypted to therapist's key ### 5. SlotConfirm Therapist confirms or rejects a reservation. **Fields:** - `slot_announce_id: [u8; 16]` — Original SlotAnnounce ID - `slot_index: u16` — Slot index - `confirmed: bool` — Whether the reservation is accepted - `encrypted_details: Vec` — Appointment details, encrypted to patient's ephemeral key ## Data Model ### Fachrichtung (Therapy Specialization) | Variant | Description | |---------|-------------| | `Verhaltenstherapie` | Cognitive behavioral therapy (CBT) | | `TiefenpsychologischFundiert` | Psychodynamic therapy | | `Analytisch` | Psychoanalysis | | `Systemisch` | Systemic therapy | | `KinderJugend` | Child and adolescent psychotherapy | ### Modalitaet (Session Modality) | Variant | Description | |---------|-------------| | `Praxis` | In-person at the therapist's practice | | `Video` | Video session (Videosprechstunde) | | `Hybrid` | Either in-person or video | ### Kostentraeger (Insurance/Payment) | Variant | Description | |---------|-------------| | `GKV` | Gesetzliche Krankenversicherung (statutory health insurance) | | `PKV` | Private Krankenversicherung (private health insurance) | | `Selbstzahler` | Self-pay | ### SlotType (Appointment Type) | Variant | Description | |---------|-------------| | `Erstgespraech` | Psychotherapeutische Sprechstunde (initial consultation) | | `Probatorik` | Probatorische Sitzungen (trial sessions) | | `Therapie` | Regular therapy session | | `Akut` | Akutbehandlung (acute/crisis treatment) | ### TimeSlot - `start_unix: u64` — Start time in Unix seconds - `duration_minutes: u16` — Duration (typically 50 or 25 minutes) - `slot_type: SlotType` — Type of appointment ## Anti-Spam 1. **Approbation hash binding.** The `approbation_hash` field contains SHA-256 of the therapist's Approbation number. While mesh nodes cannot verify this against a registry, it creates accountability — a therapist's identity is tied to a real credential. 2. **Signature verification.** All SlotAnnounces are Ed25519-signed. Relay nodes reject unsigned or invalid announcements. 3. **Rate limiting.** Relay nodes enforce a maximum announcement rate per therapist address (e.g., max 10 SlotAnnounces per hour per therapist_address). 4. **Sequence-based dedup.** Each therapist maintains a monotonic sequence counter. Relay nodes only accept announces with sequence >= last seen for that therapist. 5. **TTL enforcement.** Expired announcements are garbage collected. Default TTL is 7 days. 6. **Hop limit.** SlotAnnounces have a max_hops field (default 8) to prevent infinite propagation. ## Wire Format All FAPP messages use CBOR serialization (ciborium), consistent with MeshEnvelope and MeshAnnounce. ## No Central Registry Slots live exclusively in the mesh. Relay nodes with `CAP_FAPP_RELAY` cache active SlotAnnounces and respond to queries. There is no central database, no API server, no single point of failure. The mesh IS the registry.