managarten/services
Till JS bcc21ca785 feat(geocoding): privacy hardening — sensitive-query block + coord
quantization + extended cache TTL for public answers

Three independent defenses limit what public geocoding APIs (Photon,
Nominatim) can learn from our outbound traffic:

1. **Sensitive-query block** (`lib/sensitive-query.ts`)
   Queries matching the medical/mental-health/crisis-service keyword
   list (Hausarzt, Psychiater, Klinikum, HIV, Frauenhaus, …) are
   never forwarded to public APIs. The chain detects sensitivity at
   the route layer and runs the search in localOnly mode — providers
   with `privacy: 'public'` are filtered out before iteration begins.
   When no local provider is available (Pelias stopped), a sensitive
   query returns ok:true with results:[] and notice:
   'sensitive_local_unavailable' so the UI can show a sensible
   message instead of "no results".

   The keyword list is documented inline. False negatives are the
   risk; false positives just produce a 0-result UX hit (better
   trade-off).

2. **Coordinate quantization** (`lib/privacy.ts`)
   Forward-search focus.lat/lon: rounded to 2 decimals (~1.1km).
     Enough for the bias to work, hides exact GPS.
   Reverse-geocoding lat/lon: rounded to 3 decimals (~110m).
     City-block resolution — sufficient for "what's near me?",
     avoids reverse-geocoding the user's exact front door.
   Pelias always gets full precision; quantization only on the way
   out to public APIs. New `privacy: 'local' | 'public'` field on
   the GeocodingProvider interface drives this.

3. **Extended cache TTL for public answers**
   New `cache.publicTtlMs` config option, default 7 days (vs. 24h
   for local-provider answers). LRU cache extended with optional
   `ttlOverrideMs` per entry. Same query from N users → 1 outbound
   request to Photon/Nominatim. Strongest privacy lever we have
   over public providers (we can't change their logging, only the
   rate at which we feed them queries).

Threat coverage:
   ✓ User IP / identity hidden (already true — wrapper is the proxy)
   ✓ Exact GPS hidden (quantization)
   ✓ Sensitive query content protected (block)
   ~ Non-sensitive query content visible (acceptable trade-off)
   ~ Aggregate profiling reduced ~10–100× (cache)
   ✗ TLS-level traffic analysis, compelled disclosure (out of scope)

Tests: 141 (was 115). New coverage:
- privacy.test.ts: quantization rules (locks the privacy claim)
- sensitive-query.test.ts: positive matches across categories +
  documented false positives we accept
- chain.test.ts: localOnly mode end-to-end including the load-
  bearing assertion that public providers' search() must NEVER be
  called when the chain is in localOnly mode (no race window)
- cache.test.ts: per-entry ttlOverride longer + shorter than default

Live smoke verified end-to-end:
- "Hausarzt Konstanz" with Pelias down → no public API call,
  notice: 'sensitive_local_unavailable'
- "Konstanz" → falls through to Photon, notice: 'fallback_used'
- Reverse with high-precision GPS → Photon receives quantized
  coords, returns city-block-level result
2026-04-28 16:04:56 +02:00
..
mana-ai fix(mana-ai): copy missing workspace deps into Docker installer stage 2026-04-28 15:42:20 +02:00
mana-analytics fix(feedback): POST /api/v1/feedback liest appId aus X-App-Id-Header 2026-04-28 15:16:11 +02:00
mana-api-gateway chore: complete ManaCore → Mana rename (docs, go modules, plists, images) 2026-04-07 12:26:10 +02:00
mana-auth fix: 4 boot-time noise + correctness bugs surfaced by post-deploy smoke 2026-04-28 14:56:24 +02:00
mana-crawler fix(mana-crawler): default DATABASE_URL to mana_platform in dev 2026-04-15 18:18:19 +02:00
mana-credits fix(mana-credits): correct pnpm workspace filter (@mana/credits-service, not @mana/credits) 2026-04-27 14:27:18 +02:00
mana-events feat(llm-aliases): M5 — migrate consumers to MANA_LLM aliases 2026-04-26 21:26:03 +02:00
mana-geocoding feat(geocoding): privacy hardening — sensitive-query block + coord 2026-04-28 16:04:56 +02:00
mana-image-gen feat(mana-image-gen): replace Mac flux2.c implementation with Windows GPU diffusers 2026-04-08 13:02:42 +02:00
mana-landing-builder fix(tsconfig): unblock shared-types consumers 2026-04-21 18:53:55 +02:00
mana-llm fix(mana-llm): copy aliases.yaml into Docker image 2026-04-28 15:47:48 +02:00
mana-mail fix(broadcast): track route paths + shared-branding tsconfig 2026-04-21 18:30:47 +02:00
mana-mcp docs(mana-mcp,mana-ai): CLAUDE.md coverage for M1 agent-loop primitives 2026-04-23 14:25:14 +02:00
mana-media fix(mana-media): HEIC uploads from Chrome — sniff + transcode at the edge 2026-04-25 13:46:13 +02:00
mana-notify fix(mana-auth) + chore: rewrite /api/v1/auth/login JWT mint, remove Matrix stack 2026-04-08 16:32:13 +02:00
mana-persona-runner fix(personas): exact tool_use_id pairing + CI drift audit 2026-04-23 15:34:52 +02:00
mana-research feat(llm-aliases): M5 — migrate consumers to MANA_LLM aliases 2026-04-26 21:26:03 +02:00
mana-search chore(docker): drop obsolete services/mana-search/docker-compose.dev.yml 2026-04-23 15:27:19 +02:00
mana-stt chore(mac-mini): remove all AI service infrastructure (moved to Windows GPU) 2026-04-08 13:06:40 +02:00
mana-subscriptions chore(db): enforce pgSchema isolation with a lint script 2026-04-20 14:45:59 +02:00
mana-sync docs(plans): mark llm-fallback-aliases SHIPPED, add M-by-M commit table 2026-04-26 21:27:57 +02:00
mana-tts feat(profile): voice interview with pre-rendered TTS audio + Orpheus/Zonos backends 2026-04-17 15:22:52 +02:00
mana-user refactor(shared-tailwind): rewrite themes.css to single-layer shadcn convention 2026-04-09 01:13:06 +02:00
mana-video-gen chore(matrix): final scrub of stale matrix references 2026-04-08 16:47:54 +02:00
mana-voice-bot fix(mana-voice-bot): move default port 3050 → 3024 + Windows GPU deployment notes 2026-04-08 13:14:57 +02:00
news-ingester refactor(shared-rss): extract RSS parsing + Readability into one package 2026-04-15 22:30:44 +02:00