Commit Graph

43 Commits

Author SHA1 Message Date
6264bac99a Schaden melden: Foto als Pflichtfeld fuer Mieter, Vorschau in Ticket-Liste 2026-08-13 19:32:54 +00:00
e979ce7f1c Putzplan zu WG-Kalender erweitert: freie Ereignisse (Einkaufen/Gaeste-Party/Ruhe-Lernen/Sonstiges) fuer Mieter 2026-08-13 19:08:24 +00:00
6d017c993d Fix: Endgueltig-loeschen fuer zurueckgezogene Einladungen auch fuer Vermieter freigeben (nicht nur Admin) 2026-08-13 18:52:19 +00:00
dd7077a214 Putzplan von Mietern selbst pflegbar, Belegupload bei Ausgaben, Warmmiete in Kaltmiete/Nebenkosten/WLAN-Kosten aufgesplittet 2026-08-13 18:36:45 +00:00
ab8e9058e1 Mieterdaten: Vertrags-Eckdaten anzeigen und für Vermieter jederzeit editierbar machen 2026-08-13 18:09:09 +00:00
23d58e48d9 Sidebar: Mieter zu Mieterverwaltung mit Untermenüs Mietereinladungen/Mieterdaten umbauen 2026-08-13 18:03:09 +00:00
89d2a911e1 Fälligkeit der Miete bei Vertragserstellung (1./15.) + endgültiges Löschen zurückgezogener Einladungen 2026-08-13 17:45:29 +00:00
3111f64ecd Einladung: Vertragsbeginn/-ende inkl. datumsbewusster Zimmer-Plausibilitätsprüfung 2026-08-13 17:28:12 +00:00
41c18d078f Merge: Namensfeld bei Einladung + Vertragslaufzeit-Plausibilitätsprüfung 2026-08-13 17:24:28 +00:00
e36a65e63c Name des Mieters bei Einladung erfassen und anzeigen 2026-08-13 17:24:01 +00:00
e6b16ea74e Backend: Datumsbewusste Zimmerverfuegbarkeits-Pruefung (Plausibilitaetsabfrage) fuer Vertragsneuanla 2026-08-13 17:14:47 +00:00
1ac31b1032 Ankündigungen: Mieter können Handwerker/Schornsteinfeger-Termine bestätigen
Jeder Mieter kann für Ankündigungen mit Termin markieren, ob die Person
tatsächlich da war ('War da'/'War nicht da') — nicht nur der Vermieter.
Ankündigungen mit Termin erscheinen jetzt außerdem als Eintrag im
gemeinsamen Putzplan-Kalender, inkl. Rückmeldestatus.
2026-08-13 13:49:40 +00:00
778cb94b3a Müll-Erinnerung gemeinschaftlich abhakbar machen
Jeder Mieter kann eine Mülltonne als rausgestellt markieren; danach
verschwindet die Erinnerung für alle Mieter, nicht nur für den, der sie
abgehakt hat.
2026-08-13 13:31:55 +00:00
b15ba77336 Nachrichten-Übersicht für Mieter + Vermieter-Ankündigungen hinzufügen
Neue Ankündigungen (z. B. Schornsteinfeger, Handwerkertermin), nur vom
Vermieter anlegbar, für alle sichtbar. Zusätzlich eine gebündelte
'Für dich diese Woche'-Übersicht für Mieter mit fälligem Putzplan,
fälliger Miete, anstehendem Mülltermin und Ankündigungen der nächsten
7 Tage.
2026-08-13 13:24:21 +00:00
fdf98a70e5 Smart-Lock-Gastcodes zu Smart-Lock/Alarmanlagen-Code umgebaut
Statt zeitlich begrenzter Gästecodes, die jeder selbst ausstellen konnte,
gibt es jetzt einen dauerhaften Code je Mieter, den ausschließlich der
Vermieter vergibt/widerruft. Der Mieter sieht nur seinen eigenen Code
(read-only).
2026-08-13 12:55:29 +00:00
f576cddf6a Putzplan: feste Bereichsliste durch frei erweiterbare Bereiche ersetzen
Vermieter kann jetzt eigene Putzbereiche anlegen (CleaningAreaOption
statt festem Enum). Neue Standardbereiche: Balkon oben, Terrasse unten,
Gehweg unten, Flur unten (Eingangstür), Flur Wendeltreppe, Flur oben,
Bad oben, Bad unten, Wohnzimmer, Küche.
2026-08-13 12:44:53 +00:00
78810002b4 Passwort-ändern-Funktion für alle Rollen hinzufügen
Neuer Endpoint POST /v1/auth/change-password (verlangt aktuelles Passwort
zur Bestätigung) sowie Modal + Button im Topbar für Vermieter und Mieter.
2026-08-13 12:38:23 +00:00
72008ac59b Auto-create a contract when a room-assigned invitation is accepted
Accepting an invitation with a roomId previously only set User.roomId
— no Contract row was created. Since every tenant-facing feature
(Miet-Ampel, Vertragsdokumente, Kündigungsfristen, ...) is driven by
Contract, not User.roomId, the tenant would silently show up nowhere
despite "having" a room. Now the accept transaction also creates an
active Contract (rent/deposit defaulted from the room's baseRent/
utilityPauschal, same defaults already used by the "Wieder aufnehmen"
flow) and marks the room OCCUPIED, unless the room already has an
active contract (guards against a stale/duplicate invite race).
2026-08-13 12:02:03 +00:00
e77e33d7ff Require phone, current address and ID copy for new tenants
Accepting an invitation as a TENANT now mandates phone number, current
first-residence address (Erstwohnsitz), and both sides of an ID
document — the accept endpoint rejects the request with a clear error
if any are missing. A Schufa credit report upload stays optional, but
if provided its issue date must be within the last 3 months or the
request is rejected.

New User fields: phoneNumber was already there; added
firstResidenceAddress, idDocumentFrontUrl, idDocumentBackUrl,
schufaDocumentUrl, schufaDocumentDate. Kept nullable at the DB level
(existing accounts have none of this and shouldn't be broken) —
enforcement lives in the accept-invitation route, not a DB constraint.

Landlords now see a completeness badge ("Profil vollständig" /
"Unvollständig: X fehlt") plus a Schufa freshness badge on each
contract card in Verträge & Abrechnung, with direct download links for
the uploaded ID/Schufa files.
2026-08-13 11:25:57 +00:00
3e87ff3476 Allow re-admitting an archived tenant via a brand-new contract
Adds "Wieder aufnehmen" to each archived contract card: landlord picks
a vacant room, move-in date, rent and deposit, then POST
/contracts/reactivate creates a fresh Contract row for that user (new
id, new terms, no carried-over documents/signature) and re-assigns the
room. The old contract is never touched — it stays exactly as-is in
the archive as a historical record, per the requirement that the
original tenancy documentation must be preserved even after rejoining.

New GET /contracts/vacant-rooms lists rooms with no active contract,
used to populate the room picker and prefill sensible rent/deposit
defaults from the room's base rent.
2026-08-13 11:10:20 +00:00
a6fb15cd41 Add tenant move-out with permanent archive instead of deletion
Landlords can now remove a tenant from their room via a "Mieter
ausziehen lassen" button on the contract card. This never deletes
anything: POST /contracts/:id/move-out sets Contract.isActive=false
(with an endDate), frees the room (User.roomId=null,
Room.status=VACANT) so it can be re-assigned via the existing invite
flow, and leaves the contract row — along with every linked payment,
ticket, rating, handover protocol, and contract document — untouched
and permanently queryable.

GET /contracts/documents now only lists active contracts; the new
GET /contracts/archive (landlord/admin only) lists deactivated ones,
rendered in a new "Archiv — ausgezogene Mieter" section on the
Verträge-page with their historical documents still downloadable.
2026-08-13 10:59:16 +00:00
410db93c30 Restructure generated contract as a full-format rental agreement
Rewrites contractDocumentGenerator.ts from a short summary into a
proper Wohnraummietvertrag layout: numbered §§ for Vertragsparteien,
Mieträume, Mietzeit, Miete/Nebenkosten, Kaution, Instandhaltung/
Schönheitsreparaturen, Hausordnung, Tierhaltung/Untervermietung,
Mietanpassung, sonstige Vereinbarungen, salvatorische Klausel, plus
signature lines for both landlord and tenant (with the drawn signature
embedded once signed) and a page-footer disclaimer instead of a
top-of-document warning box.

Adds Contract.landlordName/landlordAddress/propertyAddress so the
document can show a real letterhead — addresses default to a
"please fill in" placeholder rather than a fabricated address, since
this is a real WG's data. Landlord fills them once via new fields in
the contract generator form; persisted per contract like the other
template options.
2026-08-13 10:37:57 +00:00
bba4fc318b Add click-based contract generator + digital tenant signature
Landlords configure a contract via checkboxes/selects (WLAN included,
furnished, utility billing model, notice period, deposit, rent
adjustment clause) and generate a PDF (pdfkit) that's automatically
attached to the contract's document list. Tenants sign their own
contract in-app by drawing a signature on a canvas; signing embeds the
signature image into a freshly generated final PDF and marks the
contract as signed with a timestamp.

New: Contract.wifiIncluded/furnished/utilityBillingModel (+ new
UtilityBillingModel enum), Contract.tenantSignatureUrl/signedAt.
New endpoints: POST /contracts/:id/generate-document (landlord/admin),
POST /contracts/:id/sign (tenant on own contract, or landlord/admin).

Explicitly a documentation template generated from app data, not a
legally reviewed contract — noted in the PDF itself.
2026-08-13 10:23:27 +00:00
0179517979 Scope inventory list to own room + shared items for tenants
Tenants could previously see every other tenant's private room
inventory including purchase prices. Now matches the app's standard
visibility rule: own room + roomId=NULL (shared) items only; landlord/
admin unchanged (see everything).
2026-08-13 10:08:17 +00:00
a8dc999180 Add multi-file contract document uploads (Verträge & Abrechnung)
Replaces the unused, never-wired-up single contractPdfUrl field with
contractDocumentUrls (String[]) so landlords can attach several files
per contract (signed lease, addenda, ...) instead of just one. New
endpoints: GET /contracts/documents (tenant sees own contract only,
landlord sees all — same visibility rule as the rest of the app),
POST/DELETE /contracts/:id/documents (landlord/admin only). Frontend
reuses the existing FileReader-to-data-URL upload pattern already used
for inventory photos, so files are stored inline like everywhere else
in this app rather than introducing a new storage mechanism.
2026-08-13 09:52:56 +00:00
aa59ab452a Replace flat trash list with a real month-calendar view (FullCalendar)
Rebuilds the "Müll-Kalender" as a proper color-coded FullCalendar (v6,
MIT-licensed, CDN, no build step) month grid instead of a bare list of
type+date rows. Adds a manual "Kalender aktualisieren" action for
landlords (POST /v1/trash-schedule/sync) that re-runs the same KAW
sync job as the daily cron, instead of letting them delete individual
calendar entries by clicking — accidental single-click deletion of
official data was too easy and had no real justification, since a
missing date just gets re-added by the next sync anyway.
2026-08-13 09:20:54 +00:00
d69e07f00d Add Homematic IP smart lock integration (Access Point + App setup)
The lock in this WG is a Homematic IP door lock (keypad + alarm), not
Nuki/Tuya as originally specced — confirmed with the user. Homematic IP
has no official self-service partner API for Access-Point-only setups
(no local CCU), so this uses the actively-maintained open-source
`homematicip` Python library (implements the same reverse-engineered
cloud protocol used by the official app) via two scripts rather than
reimplementing the HTTP/HMAC handshake from scratch — lower risk of
subtly wrong protocol details.

- scripts/hmip_register.py: non-interactive pairing (connection
  request -> wait for the physical blue-button press on the Access
  Point -> auth token). Writes progress to a status file so the API
  can poll it instead of blocking a request for up to ~6 minutes.
- scripts/hmip_control.py: list-devices / lock / unlock via
  HMIP_ACCESS_POINT + HMIP_AUTH_TOKEN env vars (not CLI args, so they
  don't leak into process listings).
- routes/smartLock.ts: POST /smartlock/pairing/start + GET .../status
  (LANDLORD/ADMIN, one-time setup), GET /smartlock/devices
  (LANDLORD/ADMIN), POST /smartlock/devices/:id/:lock|unlock (any
  authenticated user — this is the tenant-facing "keyless door" use
  case from the spec). All lock/unlock routes 409 until pairing has
  produced HMIP_ACCESS_POINT/HMIP_AUTH_TOKEN.

Does NOT cover temporary guest PIN codes on the keypad itself — that's
handled through Homematic IP's own "eSchlüssel" app feature, which
isn't exposed by this API; guest codes remain DB-only as before.
2026-08-13 08:21:19 +00:00
762e17a864 Wire up OneSignal push delivery: register endpoint + reminder jobs
sendPushNotification() (services/notificationService.ts) already called
the real OneSignal API correctly, but two things made it unreachable:
no endpoint ever set User.pushToken, and no job existed for the two
push-based requirements beyond rent dunning — cleaning check-in
reminders and the trash-calendar evening push. Both CleaningTask and
TrashSchedule already had an unused `reminderSentAt` column, so the
schema anticipated this and was just never wired up.

- PUT /v1/auth/push-token: registers the current device's OneSignal
  Player ID.
- jobs/cleaningReminderJob.ts, jobs/trashReminderJob.ts: same
  find-due/send-once/mark-reminderSentAt pattern as the existing
  dailyDunningJob.ts. Safe to run without OneSignal credentials
  configured — sendPushNotification degrades to an in-app Notification
  log when ONESIGNAL_APP_ID/API_KEY or a user's pushToken are absent.

Not done here (needs real third-party setup from the user, same as the
Cloudflare tunnel token pattern): ONESIGNAL_APP_ID/API_KEY in .env, and
a frontend OneSignal Web SDK integration (service worker, VAPID keys)
to actually populate pushToken from a real browser.
2026-08-13 07:47:42 +00:00
791b9bb01e Add peer rating system for tenants
Implements the previously-deferred "Bewertungssystem für Zwischenmieter"
requirement, which existed only as a vague idea with no model, route, or
UI. Design (confirmed with user): any authenticated user can rate any
tenant (1-5 + optional comment), freestanding (not tied to a contract,
creatable any time), visible only to LANDLORD/ADMIN — tenants can submit
ratings but not view them, to keep WG-internal friction out of the open.

- prisma: TenantRating model + User relations. Also pins the Prisma
  Client `output` path explicitly: since schema.prisma lives at the repo
  root (no package.json there) while node_modules only exists under
  backend/, `prisma generate`'s root-inference walked up past the repo
  and wrote into an unrelated ancestor directory when invoked from a
  fresh checkout. The explicit relative output keeps repo-root schema +
  backend-only deps working the same locally and in Docker.
- backend: GET/POST /v1/ratings (role-gated read), GET /v1/ratings/tenants
  (name+room only, any authenticated user, for the picker).
- dashboard: rating form for everyone, landlord-only ratings/summary view.
2026-08-13 07:39:32 +00:00
4ba0100d31 Add 1-click PDF export for tickets (craftsman handoff)
Implements the "1-Klick-PDF-Export für Handwerker" requirement from
the ticketing module spec, which existed only as a schema stub
(HandoverProtocol.pdfUrl) with no actual generator anywhere in the
codebase. Adds a server-side PDF endpoint (pdfkit, no headless
browser needed) summarizing a ticket's category, priority, status,
room, reporter and description, plus a "PDF" button in the landlord
cockpit that downloads it via an authenticated blob fetch (the API
uses a Bearer token, not cookies, so a plain <a href> wouldn't carry
auth).
2026-08-13 07:27:01 +00:00
ca6d851a70 Dateien nach "backend/src/routes" hochladen 2026-08-12 21:55:35 +00:00
1dc1eade8f Dateien nach "backend/src/routes" hochladen 2026-08-12 21:38:33 +00:00
e33aadaa90 Dateien nach "backend/src/routes" hochladen 2026-08-12 21:38:03 +00:00
9c99d3b631 Add cleaning-calendar and cleaning-absences endpoints 2026-08-12 19:37:04 +00:00
669aed188c Add tenants list endpoint for cleaning-task assignment 2026-08-12 18:56:47 +00:00
57ee85292c Add Putzplan cleaning-tasks route 2026-08-12 18:50:23 +00:00
efcbcab0d8 Restrict cockpit summary to own data + shared areas for tenants 2026-08-12 18:24:28 +00:00
ffea782e96 Add tickets API with room-scoped access control for tenants 2026-08-12 18:22:42 +00:00
bd96bb2db1 add backend/src/routes/invitations.ts 2026-08-12 17:48:25 +00:00
b20eec366f update backend/src/routes/auth.ts 2026-08-12 17:45:55 +00:00
b7df0455a5 update backend/src/routes/cockpit.ts 2026-08-12 17:45:53 +00:00
b0989f31f2 add backend/src/routes/cockpit.ts 2026-08-12 16:28:51 +00:00
17abbf2a33 add backend/src/routes/bankingWebhook.ts 2026-08-12 16:28:50 +00:00