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>
This commit is contained in:
parent
f1e26b38d0
commit
d06dfdaca1
15 changed files with 22 additions and 26 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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}"'},
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* wohnungsdidi — site styling.
|
||||
/* lazyflat — site styling.
|
||||
Imported via <link> from base.html. Tailwind utilities (via CDN) handle
|
||||
layout/spacing; this file owns our design tokens and component classes. */
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<div class="max-w-6xl mx-auto px-6 py-3 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="brand-dot"><img src="/static/didi.webp" alt=""></span>
|
||||
<h1 class="text-xl font-semibold">wohnungsdidi</h1>
|
||||
<h1 class="text-xl font-semibold">lazyflat</h1>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-sm">
|
||||
<span class="text-slate-500">{{ user.username }}{% if is_admin %} · <span class="chip chip-info">Administrator</span>{% endif %}</span>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="icon" type="image/webp" href="/static/didi.webp">
|
||||
<title>{% block title %}wohnungsdidi{% endblock %}</title>
|
||||
<title>{% block title %}lazyflat{% endblock %}</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<div class="flex items-center gap-3 mb-6">
|
||||
<span class="brand-dot"><img src="/static/didi.webp" alt=""></span>
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold leading-tight">wohnungsdidi</h1>
|
||||
<h1 class="text-2xl font-semibold leading-tight">lazyflat</h1>
|
||||
<p class="text-sm text-slate-500">Anmeldung erforderlich</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue