Release Notes — 3. April 2026
Diese Version vervollständigt das Downgrade-Over-Limit-Durchsetzungssystem – die vollständige Reihe von Backend-, Frontend-, E-Mail- und UI-Änderungen, die sicherstellen, dass die App Situationen korrekt behandelt, in denen die vorhandenen Daten einer Unit die Limits des neuen (niedrigeren) Plans nach einem Abonnement-Downgrade überschreiten.
Downgrade-Durchsetzung: Vollständige Over-Limit-Ressourcenbehandlung
Übersicht
Wenn ein Arbeitsbereich-Eigentümer von PRO auf FREE (oder von ENTERPRISE auf PRO) downgradet, können die vorhandenen Daten die Limits des neuen Plans überschreiten. Diese Version stellt sicher, dass jede Schicht des Systems – API, UI, Benachrichtigungen – diese Limits korrekt durchsetzt und kommuniziert.
Betroffene Limits:
| Ressource | FREE-Limit | PRO-Limit |
|---|---|---|
| Teammitglieder | 3 | 20 |
| Projekte (pro Arbeitsbereich) | 3 | Unbegrenzt |
| Aufgaben (pro Arbeitsbereich) | 15 | 70 |
| Zeiteinträge (pro Arbeitsbereich) | 100 | 1.000 |
Backend-Durchsetzung
Schreibsperre für gesperrte Benutzer
Alle Schreib-Endpunkte (POST, PUT, PATCH, DELETE) für Projekte, Aufgaben, Teams und Zeiteinträge sind jetzt durch die requireNotOverLimitLocked-Middleware geschützt. Benutzer, deren Konto aufgrund eines Downgrades gesperrt wurde, erhalten bei jedem Schreibversuch eine 403 ACCOUNT_LOCKED-Antwort.
Timer-Start-Sperre
Der startTimer()-Endpunkt erzwingt das Zeiteintrags-Limit für den Arbeitsbereich. Der Versuch, einen neuen Timer zu starten, wenn der Arbeitsbereich sein Zeiteintrags-Limit erreicht oder überschritten hat, gibt 403 LIMIT_EXCEEDED zurück.
Team-Einladungssperre
Der inviteUser()-Endpunkt prüft maxTeamMembers gegen das aktuelle Tier, bevor eine Einladung gesendet wird. Einladungen, die das Limit überschreiten, geben 403 LIMIT_EXCEEDED zurück.
Mitglieder-Sperre bei Downgrade (Webhook)
Wenn ein customer.subscription.updated- oder customer.subscription.deleted-Ereignis empfangen wird und das Tier sinkt, wird markExcessMembersAsLocked() automatisch ausgeführt:
- Fragt alle
active- undpending-Mitglieder ab (beide zählen zur Nutzung) - Sperrt die neuesten Mitglieder, die das neue Limit überschreiten
- Sendet Benachrichtigungs-E-Mails an jedes gesperrte Mitglied
E-Mail-Benachrichtigungen
Downgrade-Zusammenfassungs-E-Mail (Eigentümer)
Der Arbeitsbereich-Eigentümer erhält sofort beim Downgrade eine E-Mail mit allen Over-Limit-Ressourcen:
- Anzahl gesperrter Teammitglieder
- Anzahl überschüssiger Projekte
- Links zur Behebung jedes Problems (Team, Projekte, Upgrade)
Zugriff-eingeschränkt-E-Mail (Gesperrte Mitglieder)
Jedes Mitglied, dessen Zugriff gesperrt ist, erhält eine persönliche Benachrichtigungs-E-Mail mit:
- Konto wurde downgegradet
- Zugriff ist jetzt eingeschränkt
- Wen kontaktieren, um den vollen Zugriff wiederherzustellen
Frontend: Over-Limit-UI
Globales Banner für gesperrte Benutzer
Benutzer mit isOverLimitLocked: true sehen ein dauerhaftes Warnbanner in der gesamten Anwendung (gerendert in AppShell):
„Ihr Kontozugriff ist aufgrund eines Plan-Downgrades eingeschränkt. Kontaktieren Sie den Arbeitsbereich-Eigentümer, um den Zugriff wiederherzustellen."
Over-Limit-Banner auf allen Ressourcenseiten
| Seite | Banner-Bedingung |
|---|---|
| Projekte | current > max Projekte |
| Aufgaben | current >= max Aufgaben |
| Zeiterfassung | current >= max Zeiteinträge |
| Teammitglieder | current > max Mitglieder (Fix: war >=) |
Alle Banner enthalten einen Upgrade-Aktionsbutton.
Überschüssige Projekt-Nur-Lesen-Banner
- Projektdetailseite — ein Warnbanner erscheint, wenn das Projekt als
isExcessProject: truemarkiert ist - Projektaufgaben-Tab — Aufgabenerstellung ist deaktiviert mit einem erklärenden Banner
Fehlerbehebungen
Mitglieder-Sperrabfrage: Ausstehende Mitglieder eingeschlossen
markExcessMembersAsLocked() fragte zuvor nur status: 'active'-Mitglieder ab. Da pending-Mitglieder auch zum Nutzungslimit zählen, verursachte dies eine Unstimmigkeit.
Fix: Die Abfrage verwendet jetzt { status: { $in: ['active', 'pending'] } }.
Unit-Modell-Tier-Limits korrigiert
Der Pre-Save-Hook des Unit-Modells hatte hartcodierte Werte (FREE: 5 Mitglieder, PRO: 25 Mitglieder), die mit den maßgebenden Werten in tiers.config.ts kollidierten.
Fix: Pre-Save-Hook verwendet jetzt die korrekten Werte: FREE: 3, PRO: 20.
Zusammenfassung
| Bereich | Änderung |
|---|---|
| Backend | requireNotOverLimitLocked-Middleware auf alle Schreibrouten angewendet |
| Backend | markExcessMembersAsLocked enthält jetzt auch pending-Mitglieder |
| Backend | Unit.model.ts Pre-Save-Hook-Limits korrigiert (FREE: 3, PRO: 20) |
| Backend | Downgrade-Webhook sendet Zusammenfassungs-E-Mail an Eigentümer |
| Frontend | Teammitglieder-Banner: >= → > (strikt über Limit) |
| Frontend | AppShell.tsx: globales dauerhaftes Banner für gesperrte Benutzer |
| Scripts | manual-downgrade-to-free.mjs hinzugefügt |
| Scripts | test-downgrade-enforcement.mjs hinzugefügt |
Verfügbarkeit: Alle Pläne (Durchsetzung gilt automatisch bei Downgrade)