diff --git a/README.md b/README.md index 0f5b45d..8b04227 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# wohnungsdidi +# lazyflat Combined deployment of **flat-alert** (reliable scraper) and **flat-apply** (experimental auto‑applier) behind a single authenticated web UI. @@ -51,7 +51,7 @@ Because `apply/` is still experimental, the system is hardened around it: ## Deployment on Coolify -1. **Create repo**: push this monorepo to `ssh://git@git.moritz.run:2222/moritz/wohnungsdidi.git`. +1. **Create repo**: push this monorepo to `ssh://git@git.moritz.run:2222/moritz/lazyflat.git`. 2. **New Coolify resource** → *Docker Compose* → point it at this repo. Coolify will read `docker-compose.yml` and deploy all three services on one network. 3. **Domain**: set `flat.lab.moritz.run` on the `web` service only. Coolify diff --git a/alert/main.py b/alert/main.py index 204d4ee..f73c811 100644 --- a/alert/main.py +++ b/alert/main.py @@ -87,7 +87,7 @@ class FlatAlerter: if __name__ == "__main__": - logger.info("starting wohnungsdidi alert service") + logger.info("starting lazyflat alert service") alerter = FlatAlerter() while True: try: diff --git a/apply/main.py b/apply/main.py index 9de9425..059b7c6 100644 --- a/apply/main.py +++ b/apply/main.py @@ -82,7 +82,7 @@ async def lifespan(_app: FastAPI): yield -app = FastAPI(lifespan=lifespan, title="wohnungsdidi-apply", docs_url=None, redoc_url=None) +app = FastAPI(lifespan=lifespan, title="lazyflat-apply", docs_url=None, redoc_url=None) @app.get("/health") diff --git a/docker-compose.yml b/docker-compose.yml index 43ca255..0fe4cc3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: web: build: ./web - container_name: wohnungsdidi-web + container_name: lazyflat-web restart: unless-stopped depends_on: apply: @@ -25,15 +25,13 @@ services: - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - ANTHROPIC_MODEL=${ANTHROPIC_MODEL:-claude-haiku-4-5-20251001} volumes: - # Legacy volume name — kept so Coolify reuses the existing data volume - # after the rename from lazyflat → wohnungsdidi. - lazyflat_data:/data expose: - "8000" apply: build: ./apply - container_name: wohnungsdidi-apply + container_name: lazyflat-apply restart: unless-stopped expose: - "8000" @@ -47,7 +45,7 @@ services: alert: build: ./alert - container_name: wohnungsdidi-alert + container_name: lazyflat-alert restart: unless-stopped depends_on: web: diff --git a/web/app.py b/web/app.py index 62f1d9a..b7918f7 100644 --- a/web/app.py +++ b/web/app.py @@ -1,5 +1,5 @@ """ -wohnungsdidi web app. +lazyflat web app. Tabs: - / → Wohnungen @@ -54,7 +54,7 @@ async def lifespan(_app: FastAPI): yield -app = FastAPI(lifespan=lifespan, title="wohnungsdidi", docs_url=None, redoc_url=None, openapi_url=None) +app = FastAPI(lifespan=lifespan, title="lazyflat", docs_url=None, redoc_url=None, openapi_url=None) app.mount("/static", StaticFiles(directory="static"), name="static") diff --git a/web/db.py b/web/db.py index ec3d398..3e01c95 100644 --- a/web/db.py +++ b/web/db.py @@ -1,5 +1,5 @@ """ -SQLite data layer for wohnungsdidi. +SQLite data layer for lazyflat. Multi-user: users, per-user profiles/filters/notifications/preferences. All per-user rows are 1:1 with users. Errors and forensics are retained diff --git a/web/enrichment.py b/web/enrichment.py index cd6fdcd..0b6e00f 100644 --- a/web/enrichment.py +++ b/web/enrichment.py @@ -127,7 +127,7 @@ def _download_images(flat_id: str, urls: list[str], referer: str) -> int: r = requests.get( raw_url, headers={"Referer": referer, - "User-Agent": "Mozilla/5.0 (wohnungsdidi enricher)"}, + "User-Agent": "Mozilla/5.0 (lazyflat enricher)"}, timeout=IMAGE_TIMEOUT, stream=True, ) diff --git a/web/notifications.py b/web/notifications.py index 0320bf9..59268ea 100644 --- a/web/notifications.py +++ b/web/notifications.py @@ -72,14 +72,14 @@ def on_match(user_id: int, flat: dict) -> None: body = f"Neue passende Wohnung: {addr}\nMiete: {rent} €\nZimmer: {rooms}\n{link}" md = (f"*Neue passende Wohnung*\n[{addr}]({link})\n" f"Miete: {rent} € · Zimmer: {rooms}\n{PUBLIC_URL}") - notify_user(user_id, "match", subject="[wohnungsdidi] passende Wohnung", body_plain=body, body_markdown=md) + notify_user(user_id, "match", subject="[lazyflat] passende Wohnung", body_plain=body, body_markdown=md) def on_apply_ok(user_id: int, flat: dict, message: str) -> None: addr = flat.get("address") or flat.get("link") body = f"Bewerbung erfolgreich: {addr}\n{message}" md = f"*Bewerbung erfolgreich*\n{addr}\n{message}" - notify_user(user_id, "apply_ok", subject="[wohnungsdidi] Bewerbung OK", body_plain=body, body_markdown=md) + notify_user(user_id, "apply_ok", subject="[lazyflat] Bewerbung OK", body_plain=body, body_markdown=md) def on_apply_fail(user_id: int, flat: dict, message: str) -> None: @@ -87,5 +87,5 @@ def on_apply_fail(user_id: int, flat: dict, message: str) -> None: body = f"Bewerbung fehlgeschlagen: {addr}\n{message}\n{PUBLIC_URL}/bewerbungen" md = (f"*Bewerbung fehlgeschlagen*\n{addr}\n{message}\n" f"[Bewerbungen ansehen]({PUBLIC_URL}/bewerbungen)") - notify_user(user_id, "apply_fail", subject="[wohnungsdidi] Bewerbung fehlgeschlagen", + notify_user(user_id, "apply_fail", subject="[lazyflat] Bewerbung fehlgeschlagen", body_plain=body, body_markdown=md) diff --git a/web/routes/admin.py b/web/routes/admin.py index 62cbeab..d49a84b 100644 --- a/web/routes/admin.py +++ b/web/routes/admin.py @@ -136,7 +136,7 @@ def tab_logs_export(request: Request): e["ip"], ]) body = buf.getvalue().encode("utf-8") - filename = "wohnungsdidi-protokoll" + filename = "lazyflat-protokoll" if q.get("from"): filename += f"-{q['from']}" if q.get("to"): filename += f"-bis-{q['to']}" filename += ".csv" diff --git a/web/routes/bewerbungen.py b/web/routes/bewerbungen.py index ad9f1d9..3da26ef 100644 --- a/web/routes/bewerbungen.py +++ b/web/routes/bewerbungen.py @@ -43,7 +43,7 @@ def bewerbung_zip(request: Request, app_id: int): with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as zf: zf.writestr( "README.txt", - f"wohnungsdidi application report\n" + f"lazyflat application report\n" f"application_id={a['id']}\n" f"flat_id={a['flat_id']}\n" f"provider={a['provider']}\n" @@ -95,7 +95,7 @@ def bewerbung_zip(request: Request, app_id: int): zf.writestr(f"snapshots/{idx:02d}_{label}.html", html) buf.seek(0) - filename = f"wohnungsdidi-report-{a['id']}.zip" + filename = f"lazyflat-report-{a['id']}.zip" return StreamingResponse( buf, media_type="application/zip", headers={"Content-Disposition": f'attachment; filename="{filename}"'}, diff --git a/web/settings.py b/web/settings.py index 343450b..5df1d2e 100644 --- a/web/settings.py +++ b/web/settings.py @@ -25,7 +25,7 @@ AUTH_PASSWORD_HASH: str = _required("AUTH_PASSWORD_HASH") # --- Session cookie ----------------------------------------------------------- SESSION_SECRET: str = getenv("SESSION_SECRET") or secrets.token_urlsafe(48) -SESSION_COOKIE_NAME: str = "wohnungsdidi_session" +SESSION_COOKIE_NAME: str = "lazyflat_session" SESSION_MAX_AGE_SECONDS: int = int(getenv("SESSION_MAX_AGE_SECONDS", str(60 * 60 * 24 * 7))) COOKIE_SECURE: bool = getenv("COOKIE_SECURE", "true").lower() in ("true", "1", "yes", "on") @@ -43,8 +43,6 @@ ALERT_SCRAPE_INTERVAL_SECONDS: int = int(getenv("ALERT_SCRAPE_INTERVAL_SECONDS", # --- Storage ------------------------------------------------------------------ DATA_DIR: Path = Path(getenv("DATA_DIR", "/data")) DATA_DIR.mkdir(parents=True, exist_ok=True) -# Legacy filename — kept so existing data under /data/lazyflat.sqlite stays -# reachable across the rename to wohnungsdidi. Not user-facing. DB_PATH: Path = DATA_DIR / "lazyflat.sqlite" # Retention (errors / audit / application forensics). Default 14 days. diff --git a/web/static/app.css b/web/static/app.css index 4d1fef6..0382c07 100644 --- a/web/static/app.css +++ b/web/static/app.css @@ -1,4 +1,4 @@ -/* wohnungsdidi — site styling. +/* lazyflat — site styling. Imported via from base.html. Tailwind utilities (via CDN) handle layout/spacing; this file owns our design tokens and component classes. */ diff --git a/web/templates/_layout.html b/web/templates/_layout.html index 2969efa..418414f 100644 --- a/web/templates/_layout.html +++ b/web/templates/_layout.html @@ -8,7 +8,7 @@
-
Anmeldung erforderlich