Commit graph

8 commits

Author SHA1 Message Date
ee7ba6c6ff fix: round €/m² in Telegram, drop "Bilder nachladen" admin button, fix lightbox visibility
- notifications: round sqm_price to whole € in Telegram match messages
  (was emitting raw float like "12.345614 €/m²").

- wohnungen: remove the admin-only "Bilder nachladen (N)" button. It
  flickered into view whenever a freshly-scraped flat was still in
  pending state, which was effectively random from the user's point of
  view, and the manual backfill it triggered isn't needed anymore — new
  flats are auto-enriched at scrape time. Also drops the dead helpers
  it was the sole caller of: enrichment.kick_backfill,
  enrichment._backfill_runner, db.flats_needing_enrichment,
  db.enrichment_counts.

- lightbox: the modal didn't appear because Tailwind's Play CDN injects
  its own .hidden { display: none } rule at runtime, which kept fighting
  our class toggle. Switch the show/hide to inline style.display so no
  external stylesheet can mask it. Single-class .lightbox now only owns
  the layout — the initial-hidden state is on the element via
  style="display:none".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 12:48:14 +02:00
81d6b65eae feat(notifications): new match format with Gmaps + lazyflat deep-link
New Telegram match layout:
  Karl-Ziegler-Straße 7           (linked → Google Maps)
  12489 Treptow-Köpenick
  Miete: 944.12 (18.51 €/m²)
  Fläche: 51.0
  Zimmer: 2.0
  WBS: nicht erforderlich

  Zur original Anzeige            (→ flat URL)
  Zur lazyflat Seite              (→ /?flat=<id>)

Deep-link behavior on lazyflat: ?flat=<id> expands the matching row,
scrolls it into view, and pulses a yellow highlight for 3s. The query
param is stripped from history afterwards so reload stays clean.
Unknown flat IDs drop the param silently.

Helpers: _address_lines splits the scraper's "Street, PLZ, District"
into two display lines; _gmaps_url falls back to a maps.google query
when the payload has no explicit link; _wbs_label normalises the
German WBS variants to "erforderlich" / "nicht erforderlich".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:28:04 +02:00
64439fd42e feat(notifications): add Telegram test button
New "Test senden" button next to Speichern posts current form
credentials (not DB) to /actions/notifications/test, which fires a
test message and redirects back with a flash chip showing the outcome
(including the Telegram API's error description on failure).

telegram_send is now public and returns (ok, detail) so the UI can
surface real error messages ("chat not found", "Unauthorized", etc.).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:35:02 +02:00
d06dfdaca1 refactor: rename wohnungsdidi → lazyflat
Container names, FastAPI titles, email subjects, filenames, brand text,
session cookie, User-Agent, docstrings, README. Volume lazyflat_data and
/data/lazyflat.sqlite already used the new name, so on-disk data is
preserved; dropped the now-obsolete legacy-rename comments.

Side effect: SESSION_COOKIE_NAME change logs everyone out on deploy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:26:12 +02:00
eb73b5e415 correctness batch: atomic writes, task refs, hmac, import-star, pickle
Per review §2:

- web/db.py: new _tx() context manager wraps multi-statement writers in
  BEGIN IMMEDIATE … COMMIT/ROLLBACK (our connections run in autocommit
  mode, so plain `with _lock:` doesn't give atomicity). partnership_accept
  (UPDATE + DELETE) and cleanup_retention (3 deletes/updates) now use it.
- Fire-and-forget tasks: add module-level _bg_tasks sets in web/app.py and
  web/enrichment.py. A _spawn() helper holds a strong ref until the task
  finishes so the GC can't drop it mid-flight (CPython's event loop only
  weakly references pending tasks).
- apply/main.py: require_api_key uses hmac.compare_digest, matching web's
  check. Also imports now use explicit names instead of `from settings *`.
- apply/language.py: replace `from settings import *` + `from paths import *`
  with explicit imports — this is the pattern that caused the LANGUAGE
  NameError earlier.
- alert/utils.py: pickle-based hash_any_object → deterministic JSON+sha256.
  Cheaper, portable across Python versions, no pickle attack surface.
- web/notifications.py: /fehler links repointed to /bewerbungen (the
  former page doesn't exist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 19:14:26 +02:00
0c18f0870a rename to wohnungsdidi + didi logo + footer for all + seconds-only counter
- App is now called "wohnungsdidi" everywhere user-facing (page title,
  nav brand, login header, notification subjects, report filename,
  FastAPI titles, log messages)
- Brand dot replaced with an image of Didi (web/static/didi.webp),
  rendered as a round 2.25rem avatar in _layout + login
- "Programmiert für Annika ♥" footer now shows for every logged-in user,
  not only Annika
- Count-up shows only seconds ("vor 73 s") regardless of age — no
  rollover to minutes/hours
- Data continuity: DB file stays /data/lazyflat.sqlite and the Docker
  volume stays lazyflat_data so the rename doesn't strand existing data
- Session cookie renamed to wohnungsdidi_session (one-time logout on
  rollout)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:29:24 +02:00
0c58242ce7 map debug + coord backfill, remove email channel, countdown label
- Surface "X/Y passende Wohnungen mit Koordinaten" on the Karte view +
  admin-only "Koordinaten nachladen" button (POST /actions/backfill-coords)
  that geocodes missing flats via Google Maps directly from the web container
- Add googlemaps dep + GMAPS_API_KEY env to web service
- Light console.log in map.js ("rendering N/M markers", "building Leaflet…")
  so the browser DevTools shows what's happening
- Drop e-mail channel from notifications UI, notify dispatcher, and _alert_status;
  coerce legacy 'email' channel rows back to 'ui' on save
- Countdown said "Aktualisierung läuft…" next to "nächste Aktualisierung" →
  shortened to "aktualisiere…"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:42:21 +02:00
Moritz
c630b500ef multi-user: users, per-user profiles/filters/notifications, tab UI, apply forensics
* DB: users + user_profiles/filters/notifications/preferences; applications gets
  user_id + forensics_json + profile_snapshot_json; new errors table
  with 14d retention; schema versioning via MIGRATIONS list
* auth: password hashes in DB (argon2); env vars seed first admin; per-user
  sessions; CSRF bound to user id
* apply: personal info/WBS moved out of env into the request body; providers
  take an ApplyContext with Profile + submit_forms; full Playwright recorder
  (step log, console, page errors, network, screenshots, final HTML)
* web: five top-level tabs (Wohnungen/Bewerbungen/Logs/Fehler/Einstellungen);
  settings sub-tabs profil/filter/benachrichtigungen/account/benutzer;
  per-user matching, auto-apply and notifications (UI/Telegram/SMTP); red
  auto-apply switch on Wohnungen tab; forensics detail view for bewerbungen
  and fehler; retention background thread

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 10:52:41 +02:00