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.
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.
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).
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.
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.
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.
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.
Adds trashCalendarSyncJob.ts, which pulls Restmüll/Biomüll/Gelbe Tonne/
Papiertonne dates for Nackenheim (CityId 35, Verbandsgemeinde Bodenheim)
from the public, keyless API behind lk.kaw-mainz-bingen.de's official
waste calendar, and upserts them into trash_schedule. Adds a unique
(type, date) constraint to prevent duplicate entries on reruns. Run via
`npm run trash-sync:run`, same standalone-script pattern as the other
reminder jobs.
Prisma 5.22's generator wants the explicit output to point at the
internal .prisma/client directory (which @prisma/client forwards to),
not the @prisma/client package directory itself — pointing it there
directly made `prisma generate` fail outright ("replace ... with
../backend/node_modules/.prisma/client").
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.