Projekt P-5050 · Kunde K-1050 · Dok-Nr. P-5050-K2a · Stand 27.10.2026, 13:48 Uhr

Konzept im ÜberblickWas Bululu kann

Kapitel 04 von 16

Bewerben und Arbeitgeber

Wie sich Bewerber in drei Schritten bewerben und ihre Bewerbungen verfolgen, und wie Betriebe Stellen anlegen, Bewerbungen bearbeiten und ihr Team verwalten.

  • Lesezeit rund 108 Min.
  • Für Bewerber, Betriebe

Auf einen Blick

Das Wichtigste aus diesem Kapitel in einer Minute. Alle Einzelheiten stehen darunter.

  • Bewerben mit Code statt KennwortWer sich zum ersten Mal bewirbt, bekommt einen 6-stelligen Code per E-Mail. Damit ist die Adresse bestätigt, und das Konto entsteht ohne Kennwort.
  • Lebenslauf als Datei oder FotoIm zweiten Schritt laden Bewerber einen Lebenslauf hoch oder fotografieren ihn mit dem Handy. Gespeicherte Unterlagen sind schon angehakt und gehen automatisch mit.
  • Ein Bereich für jeden BewerberBewerber sehen den Stand jeder Bewerbung, beantworten Einladungen, speichern Termine im Kalender und schreiben mit dem Betrieb im Postfach.
  • Betriebe arbeiten mit „Heute zu tun“Die Übersicht zeigt neue Bewerbungen, wartende Antworten und ablaufende Stellen. Jeder Betrieb legt Mitarbeiter-Konten selbst an, als Admin oder Recruiter.
  • Anzeigen automatisch übersetztStellenanzeigen werden im Hintergrund ins Englische und Türkische übersetzt und als maschinelle Übersetzung gekennzeichnet. Verbindlich bleibt die deutsche Fassung.
30Tageläuft eine Stelle, danach ist sie pausiert und jederzeit verlängerbar
10MBdarf ein Lebenslauf als PDF oder Foto groß sein
30Tagebleibt Gelöschtes im Papierkorb, bevor es endgültig verschwindet
Von Ihnen gebraucht
  • Die Löschfristen bestätigen; sie lassen sich später ohne Programmierung ändern.
Stand 16:29: vollständig (Teil 1 bis 7) · 26.10. Bewertung Runde 2: automatische Übersetzung der Anzeigen (en/tr) als Teil von 2a (1.18, H143, H144, Paket 2a.11a) · 26.10. ergänzt: Einhängepunkt Vorab-Fragen im Bewerben-Fenster (B1), Quelle je Bewerbung (B4), Mehrfach-Beschäftigungsart und Befristung im Stellenformular (B5, B2), Mail-Dienst aus 1a · 26.10. Sicherheit: zweiter Faktor auch als E-Mail-Code (1.2, 1.9 Nr. 4, H137, H138, Mail A12), Mail bei Anmeldung von neuem Gerät mit „Das war ich nicht“ (1.2, H139, Mail A13), Kennwort-Regeln mit Maß und wachsende Wartezeit statt Kontosperre (1.1 Nr. 3, H55, H140), erneute Kennworteingabe vor heiklen Aktionen (H141), Sicherheitsprotokoll anmeldungen (Teil 3); Prüfliste in _planung/sicherheit.md · 26.10. Nomad: Firmen legen Mitarbeiter-Konten selbst an (1.14 Nr. 2, Rollen Admin und Recruiter) · 22.10. nachgeprüft: B-Fundstellen am Entwurf, Usability 3.x/A–D und Änderungsliste eingearbeitet, Mails gegen T 6.2–6.4

Stand 22.10.2026, Nomad. Grundlage: PLAN-BACKEND Fassung 5 (Zeitplan 2a, Bewerber: Erste Bewerbung, Ein Konto je Person, Status, Bewerberbereich, Benachrichtigungen; Arbeitgeber; Menüs; Listen; Auswählen; Zustände; Laden und Rückmeldung; Lebensläufe; Sicherheit und Datenschutz), USABILITY-KONZEPT (3.1 bis 3.12, A bis D), TEXTE-UND-MAILS 1.1, 1.4, 1.6, 1.7, 1.8, 2, 3.1 bis 3.3, 4.1 bis 4.4, 5.1 bis 5.5, 6.0 bis 6.4, 7.1, 7.2, 7.4, FUNKTIONEN-CHECK, AENDERUNGSLISTE-GESAMTKONZEPT, Entwurf B (anmelden.html, mein-bereich.html, firmen-bereich.html, stelle.html, assets/style.css, assets/app.js), Karten 1a und 1b.

Umfang 2a laut Zeitplan: Anmelden und Konten mit zweitem Faktor, Einwilligungen, Mindestbewerbung mit Datei (Bewerben-Fenster über der Stelle), Bewerberbereich (Bewerbungen, Reiter Lebenslauf schlank: Persönliches und Datei, Postfach, Merkliste und Job-Alarme aus dem Konto), Benachrichtigungen, Einladung mit Kalender-Datei · Firmen-Registrierung, Firmenprofil bearbeiten (Logo, Text, Ansprechperson), Stellen (Formular mit Vorschau, Entwurf, bearbeiten, kopieren, beenden, verlängern), Bewerbungen mit Notizen, Postfach der Firma, Team mit Einladung und Rollen, Live-Aktualisierung (Abfrage alle 60 s, 1.16; Server-Sent Events erst 2b.9) · automatische Übersetzung der Stellenanzeigen nach Englisch und Türkisch im Hintergrund (1.18; Kundenliste „Zum Livegang“, Plan Sprachen). Nicht in 2a (nur als Abgrenzung): Lebenslauf-Baukasten mit Stationen, Deckblatt, Anschreiben-Vorlage, Bewerbungsmappe als PDF, KI-Texte, Übersetzung von Inhalten und Firmenprofilen (Plan Sprachen: Profile bleiben zum Start deutsch), Verwaltung (Prüfen, Anfragen, Firmen und Nutzer, Werbung, Inhalte, Einstellungen = Abschnitt 3), Premium-Anfrage und Top-Stellen (Abschnitt 3, Haken ist hier vorbereitet), Meldungen (3), COPLA-Schnittstelle (2b/3), Bewerberansprache und Bezahlen.

Was 1a/1b schon bauen und hier nur benutzt wird (nicht doppelt geplant): Seitenrahmen, Kopf mit Konto-Knopf-Platz, Toasts, Sprachwahl (1a 1.1, 2.1), Stellenkarte mit Varianten (1a), Leerzustand, Platzhalter, Sonderseiten, Seitenkopf, Band, Sortierung, Kontaktformular, Honigfeld und Bremse (1b 2.1), Mail-Dienst mit Warteschlange, Rahmen und Kopfzeilen (1a 2.2 dienste/mail, Fundament; Vorlagen b15 bis b17 und v04 aus 1b), Gerätespeicher mit Merkliste und inseratEntwurf (1a/1b), Tabellen firmen, stellen, stellen_adressen, stellen_uebersetzungen, fachbereiche, plz, job_alarme, mail_warteschlange, einstellungen, protokoll (1a/1b Teil 3), Hintergrund-Startpunkt pg-boss (1a), Merkliste- und Job-Alarm-Seiten (1b 1.9, 1.10; hier nur der Konto-Zweig), Firmenprofil öffentlich (1b 1.3), Ausprobieren-Entwurf (1b W5).

Fundstellen: B:anmelden.html:107 = Datei und Zeile in entwurf-b/; css:919 = assets/style.css; js:1236 = assets/app.js; T bewerben.senden = Textschlüssel aus TEXTE-UND-MAILS; U 3.4 = Usability-Bildschirm; P Arbeitgeber = Abschnitt im Plan; FC 7 = Befund im FUNKTIONEN-CHECK.

1

Seiten

Alle Seiten für Anmelden, Bewerben, den Bewerberbereich und den Firmenbereich, jeweils mit Inhalt und Bedienung.

Diese Tabelle ist die Adressliste aller Bereichsseiten: Bewerberbereich unter /mein-bereich/… (Gruppe (konto)), Konto-Einstellungen, Papierkorb und Zielseiten unter /konto/…, Firmenbereich unter /firma/… (Gruppe (firma)); der Plan („Aufbau im Repo“) und Karte 1a A3 verweisen hierher. Adressen in Mails, weiter=-Regeln und Tests nehmen diese Schreibweise.

Adressen unter /[locale]/…. Öffentliche Zugänge liegen in app/[locale]/(oeffentlich)/, die angemeldeten Bereiche in app/[locale]/(konto)/ (Bewerber, Layout mit Reitern aus B mein-bereich.html:113–118) und app/[locale]/(firma)/ (Firma, Layout aus B firmen-bereich.html:117–122). Beide Bereichs-Layouts prüfen die Sitzung auf dem Server (ohne Sitzung → /anmelden?weiter=…), setzen noindex und zeigen oben den Bereichskopf von B (bereich-kopf: Begrüßung h1, rechts ein Knopf; B mein-bereich.html:97–101, firmen-bereich.html:98–102) sowie die Reiterleiste (reiter mit role=tablist, B mein-bereich.html:112, firmen-bereich.html:116; js reiter() js:356–383). Die Reiter sind echte Links auf eigene Adressen in <nav aria-label> mit aria-current="page" (kein JS-Tabpanel wie in B; die CSS-Regel .reiter [role="tab"][aria-selected="true"] wird auf .reiter [aria-current="page"] umgeschrieben, Optik bleibt; aktiver Reiter wird beim Laden in den sichtbaren Bereich gescrollt; Zahl-Kreis mit Vorlesetext „Postfach, 2 ungelesen“; U A.1). D-5 (entschieden 26.10.): Am Handy wird der letzte Reiter am rechten Rand angeschnitten gezeigt, damit man sieht, dass es weitere gibt: Die Reiterleiste hat rechts keinen Innenabstand und kein Abschluss-Element, der Überlauf bleibt sichtbar, die Scrollleiste bleibt wie in B ausgeblendet (css:626); Breite der Reiter unverändert. Test reiter.test.ts: bei 390 px Breite ragt der fünfte Reiter über den Rand. Die Übersicht ist die Startseite des Bereichs und kein Reiter: Jede Unterseite trägt über der h1 die Zeile „‹ Übersicht“, „Mein Bereich“ steht im Konto-Menü (U 4, U 7 Punkt 8). Seitentitel nach Muster „Bewerbungen · Firmenbereich · bululu“, nach jedem Wechsel bekommt die h1 den Fokus (U A.1). Der Konto-Knopf oben rechts (P Menüs, „neu gegenüber B, im Stil von B“) liegt im Seitenrahmen 1a (Platz vorgesehen) und wird hier gefüllt (Teil 2).

NrSeiteAdresseB-DateiDaten
1Anmelden/anmelden?modus=anmeldenregistrierenfirma&weiter=anmelden.htmlkonten, sitzungen
2Kennwort vergessen / neu, zweiter Faktor (App oder E-Mail-Code), Konto sichern, Zielseiten Konto/anmelden/kennwort · /anmelden/kennwort-neu?t= · /anmelden/faktor · /konto/sichern?t= · /konto/bestaetigt?t=anmelden.html:144–153 (vergessen-Box)konten, konto_tokens, faktor, faktor_mail_codes, anmeldungen
3Bewerben-Fenster/stelle/[adresse]#bewerben (Dialog über 1a-Stelle)stelle.html:103–156bewerbungen, bewerbungs_entwuerfe, dateien
4Bewerberbereich: Übersicht/mein-bereichmein-bereich.html:124–134bewerbungen, einladungen, merkliste_konto
5Bewerbungen und Bewerbung/mein-bereich/bewerbungen · /mein-bereich/bewerbungen/[id]mein-bereich.html:136–139 + Konzept U 3.5/3.6bewerbungen, nachrichten, einladungen
6Postfach (Bewerber)/mein-bereich/postfach · /mein-bereich/postfach/[bewerbungId]firmen-bereich.html:196–209 (Chat-Optik)nachrichten
7Lebenslauf (schlank)/mein-bereich/lebenslaufmein-bereich.html:160–180 (B-Reiter mit Stationen und Mappe, erst 2b), Felder aus Einstellungen :184–189konten, dateien
8Merkliste, Job-Alarme (Konto-Zweig)/merkliste · /mein-bereich/job-alarmemein-bereich.html:141–158merkliste_konto, job_alarme
9Einstellungen (Konto-Menü, alle Rollen)/konto/einstellungenmein-bereich.html:182–193konten, faktor, geraete, einwilligungen
10Firmenbereich: Übersicht/firmafirmen-bereich.html:128–138stellen, bewerbungen
11Stellen, geöffnete Stelle, Stelle neu/bearbeiten/firma/stellen · /firma/stellen/[id] (Firmen-Sicht) · /firma/stellen/neu · /firma/stellen/[id]/bearbeitenfirmen-bereich.html:140–149, 156–194stellen, bewerbungen
12Bewerbungen der Firma, Bewerbung/firma/bewerbungen · /firma/bewerbungen/[id]firmen-bereich.html:151–154bewerbungen, notizen, nachrichten, einladungen
13Postfach (Firma)/firma/postfach · /firma/postfach/[bewerbungId]firmen-bereich.html:196–209nachrichten
14Firmenprofil bearbeiten/firma/profilfirmen-bereich.html:212–227firmen, dateien (Logo)
15Team/firma/team · /einladung?t= (Zielseite)neu (B hat „Nutzer verwalten“ nur als Menüpunkt firmen-bereich.html:107 im „…“-Menü :103–113)firmen_nutzer, firmen_einladungen
16Live-Aktualisierung (ohne Seite)/api/live?seit= (Abfrage alle 60 s; SSE erst 2b.9)neuFachtabellen
17Papierkorb (Bewerber, Firma)/konto/papierkorb · /firma/papierkorbneu (Zeilen-Optik firmen-bereich.html:140–149)stellen, bewerbungs_notizen, job_alarme, bewerbungs_entwuerfe (je geloescht_am; dateien nicht, 1.17 Nr. 2)

1.1 Anmelden, Registrieren, Firma registrieren

Datei (oeffentlich)/anmelden/page.tsx · Teile in anmelden/_formular/. Drei Modi über ?modus= (B hat den Umschalter Anmelden/Registrieren :106–109 und die Rollen-Wahl :111–123; U 3.1/3.2 trennen Bewerber und Firma). Handy = Desktop (Layout anmelde-layout mit Karte anmelde-karte, css:600).

NrBereichBausteineB-FundstelleHinweis
1Kopfh1 (T oeffentlich.anmelden.titel; registrieren: oeffentlich.registrieren.titel; firma: oeffentlich.firmaReg.titel), Satz (T …einleitung)anmelden.html:95–102 (h1 :96)B-Titel „Willkommen zurück“ wird durch T ersetzt.
2Umschalterumschalter (css:601–603) zwei button[data-modus][aria-pressed] Anmelden · Registrieren:106–109wird zu zwei Links auf ?modus=; Modus „firma“ hat keinen Umschalter, sondern den Link oeffentlich.anmelden.neuFirma unter dem Formular. Rollen-Radios (fieldset.rollen :111–123) entfallen (Konto ist rollenlos, P Ein Konto je Person).
3Anmeldenform.formular: E-Mail (:127), Kennwort mit „Zeigen“ (:133, js data-zeigen in anmelden() js:917, Klick :942), „Kennwort vergessen?“ (:131 → /anmelden/kennwort), Haken „Angemeldet bleiben“ (T …angemeldetBleiben, vorgewählt; neu gegenüber B, check wie :136), Knopf (:138):110–143Server-Aktion anmelden() (Better Auth, Teil 2). Anmelden ohne Kennwort, für alle Konten gleich: unter dem E-Mail-Feld der Rand-Knopf T oeffentlich.anmelden.codeSenden „Ohne Kennwort anmelden: Code per E-Mail“; ein Klick zeigt darunter Satz T .codeHinweis („Wenn es ein Konto mit {mail} gibt, haben wir einen Code geschickt.“), Code-Feld .codeFeld, Textlink „Code erneut senden“ und Knopf .codeAnmelden (A12 Fassung anmelden, faktorMail.ts, 3 je 15 Minuten); gibt es kein Konto, geht keine Mail, die Seite antwortet gleich (_planung/sicherheit.md Nr. 15); das Kennwort bleibt der Hauptweg der Seite. Richtiger Code meldet an; hat das Konto einen Faktor, folgt bei Art app der App-Code, bei Art mail das Kennwort. Falscher Code: fehler.faktor.falschMail. Mit zweitem Faktor → /anmelden/faktor (Nr. 1.2). weiter= nur auf eigene Adressen (Test). Unbestätigte Adresse: Anmelden geht, Bereich zeigt Zeile „Bitte E-Mail bestätigen“ (P Ein Konto je Person). Links unten: oeffentlich.anmelden.neuBewerber, .neuFirma. Fehler: fehler.anmelden.falsch (ein Satz für E-Mail und Kennwort, T 7.6). Fehlversuche (26.10., _planung/sicherheit.md Nr. 11): jede Anmeldung schreibt anmeldungen (Teil 3; IP, Gerät grob, Zeit, Ergebnis); ab dem 3. Fehlversuch je Konto in 15 Minuten steht T fehler.anmelden.vergessenHinweis „Kennwort vergessen? Neues Kennwort anfordern“ hervorgehoben unter dem Feld (Link /anmelden/kennwort); ab dem 5. Fehlversuch in 15 Minuten je Konto wartet die Anmeldung 1 Minute, mit jedem weiteren Fehlversuch doppelt so lang, höchstens 15 Minuten (fehler.versuche.anmelden mit {minuten}, T 4.4); je IP greift dieselbe Staffel erst ab 50 Fehlversuchen in 15 Minuten (einstellungen.sicherheit.bremse_ip_fehlversuche, Karte 3 1.11 Nr. 6) mit dem eigenen Satz fehler.versuche.netz „Aus Ihrem Netz kamen gerade viele Anmeldeversuche. Bitte versuchen Sie es in {minuten} Minuten noch einmal.“; keine dauerhafte Kontosperre. Sperrliste (Karte 3 1.15): wirkt nicht auf das Anmelden, weder IP noch Mail oder Domain; gesperrte Konten → fehler.gesperrt.konto. Erfolg: Token-Wechsel der Sitzung, Zeile ergebnis erfolg; unbekannte Gerätekennung → zusätzlich Mail A13 (1.2 „Konto sichern“, H139), nicht bei Anmeldung per E-Mail-Code.
4Registrieren (Bewerber)Felder bewerben.vorname, .nachname, .mail, .kennwortNeu (+ .kennwortRegel), Haken bewerben.zustimmung mit Links, Knopf oeffentlich.registrieren.anlegen:124–137 (data-nur="registrieren")B hat ein Feld „Name“ (:125); T trennt Vor- und Nachname → zwei Felder in zwei. Aktion kontoAnlegen() → B01-Bestätigungsmail (T 6.2), Zielseite T 3.3 „Konto angelegt, bitte bestätigen“. Honigfeld + Bremse (1b). Vergeben: fehler.feld.mailVergeben.
5Firma registrierenzwei Blöcke fieldset: „Ihr Betrieb“ (firmenname, strasse, plz, ort, telefon) · „Ihr Zugang“ (ihrName, mail, kennwort, zustimmung mit agbLink) · Knopf oeffentlich.firmaReg.knopfneu, Felder im Stil :125–137Aktion firmaRegistrieren(): Konto (oder vorhandenes Konto nach Anmeldung) + firmen (zustand registriert) + firmen_nutzer (admin). Mail F01 „Registrierung bestätigen“ (T 6.4), Zielseite T 3.3 „Firma registriert“. weiter=stelle-neu (1b W5): nach Bestätigung → /firma/stellen/neu mit inseratEntwurf aus dem Gerätespeicher. Ort über plz-Tabelle prüfen (fehler.feld.ortUnbekannt).
6Kein Faktor-Hinweisunter dem Firmen-Formular steht kein Hinweis auf den zweiten Faktor; die B-info-box (anmelden.html:139–142) entfälltDie Empfehlung kommt als Zeile firma.heute.faktor mit Knopf „Einrichten“ in „Heute zu tun“ (1.10 Nr. 2), sobald die erste Stelle online ist, also sobald Bewerberdaten kommen können.

1.2 Kennwort, zweiter Faktor, Zielseiten Konto

Dateien anmelden/kennwort/page.tsx, anmelden/kennwort-neu/page.tsx, anmelden/faktor/page.tsx, (oeffentlich)/konto/bestaetigt/page.tsx. Aufbau wie B vergessen-Box (anmelden.html:144–153: h2 tabindex -1, Satz, ein Feld, Knopf, Bestätigung bestaetigung[role=status]).

FallAdresseInhaltHinweis
Kennwort vergessen/anmelden/kennwortoeffentlich.kennwort.titel, .text, Feld E-Mail, .anfordern, .zurueck; nach Senden Satz wie B :151 (T 3.2)immer dieselbe Antwort, ob Konto existiert oder nicht (B-Satz). Mail A01 „Kennwort zurücksetzen“ (T 6.3) mit Token 60 Minuten. Dieselbe Aktion kennwortLinkAnfordern({mail, weiter}) ruft das Bewerben-Fenster (1.3 Nr. 2, N-1); weiter wandert in den Token (konto_tokens.weiter) und in den Link.
Neues Kennwort/anmelden/kennwort-neu?t=oeffentlich.kennwortNeu.titel, .feld (+ bewerben.kennwortRegel), .knopfgültig → Kennwort gesetzt, alle anderen Sitzungen beendet, Mail A02 „Kennwort geändert“ (T 6.3), danach angemeldet → Bereich, oder zurück auf weiter (N-1: Stelle mit #bewerben, Fenster öffnet in Schritt 2). Ungültig: fehler.link.falsch/.abgelaufen (1b Fehlerseite) + „Link neu anfordern“.
Zweiter Faktor (Anmeldung)/anmelden/faktorArt app: oeffentlich.faktor.titel, .text, .feld (6 Ziffern, inputmode=numeric, autocomplete one-time-code), .knopf, Link .keinZugriff → Feld .codeFeld. Art mail (26.10.): .mailTitel „Code aus Ihrer E-Mail“, .mailText „Wir haben einen 6-stelligen Code an {mailTeil} geschickt. Er gilt 10 Minuten.“, dasselbe Feld und derselbe Knopf, Textlink .mailErneut „Code erneut senden“ (frühestens nach 60 Sekunden, Satz .mailErneutWarten; höchstens 3 Codes je 15 Minuten, danach .mailZuOft), statt .keinZugriff der Satz .keinZugriffMail „Kein Zugriff auf Ihr Postfach? Rufen Sie uns an: 0203/73997996.“ (kein Code-Feld, F3)TOTP (App, ±1 Schritt, Wiederverwendung gesperrt) oder E-Mail-Code (fachlich/konto/faktorMail.ts: 6 Ziffern aus sicherem Zufall, Hash in faktor_mail_codes, 10 Minuten, einmalig; Mail A12 geht sofort, ohne Warteschlangen-Verzögerung über die Vorrang-Spur der Warteschlange); Wiederherstellungscodes 10 Stück einmalig nur bei Art app. Fehler fehler.faktor.falsch bei Art app, fehler.faktor.falschMail bei Art mail, 5 Fehlversuche je Code → App: fehler.versuche.code (15 Minuten, T 4.4); Mail: Code verfällt, fehler.faktor.abgelaufen + „Code erneut senden“. Welche Art gilt, steht in faktor.art (Teil 3). Sicherheit: _planung/sicherheit.md Nr. 13.
Faktor Pflicht (Firma)/anmelden/faktor?einrichten=1oeffentlich.faktor.pflichtTitel „{firma} verlangt einen Code bei jeder Anmeldung“, .pflichtText, .einrichten „Schutz einrichten“ → Einrichtung wie Einstellungen (1.9 Nr. 4, Wahl App oder E-Mail-Code)wenn firmen.faktor_pflicht und der Nutzer keinen Faktor hat: Sitzung ist „halb“ (nur diese Seite erreichbar). Beide Arten erfüllen die Pflicht (Satz T firma.team.faktorPflichtSatz in 1.14 Nr. 3); nur die Verwaltung verlangt die App (Karte 3 1.12).
Konto sichern (neues Gerät, 26.10.)/konto/sichern?t=Schritt 1 (GET, nur Anzeige): konto.sichern.titel „Konto sichern“, .frage „Wir melden alle Geräte ab, danach legen Sie ein neues Kennwort fest.“ + Knopf .bestaetigen „Ja, alle Geräte abmelden“ (POST); Schritt 2: .text, Feld wie Neues Kennwort, .knopf, danach .fertig + Knopf „Anmelden“Ziel des Knopfs „Das war ich nicht“ in Mail A13 (Token konto_tokens zweck sichern, 24 Stunden, einmalig). Der Link selbst ändert nichts (_planung/sicherheit.md Nr. 29: Firmen-Postfächer rufen Links vorab auf); erst der Knopf ruft kontoSichern(token) per POST: beendet alle Sitzungen des Kontos (auch die, die gerade die Seite geöffnet hat), dann Formular neues Kennwort → kennwortNeu (A02, Protokoll kennwort_geaendert mit Grund „Konto sichern“); abgelaufen → fehler.link.abgelaufen ohne „neu anfordern“ (stattdessen Weg über Kennwort vergessen, Satz T konto.sichern.abgelaufen). A13 geht bei jeder erfolgreichen Anmeldung, deren Gerätekennung (Browser + Betriebssystem aus der Browser-Kennung, dienste/auth/geraete.ts) in den letzten 12 Monaten keine erfolgreiche Anmeldung dieses Kontos hatte, nicht bei der allerersten Anmeldung nach der Registrierung und nicht bei einer Anmeldung per E-Mail-Code, auch nicht im Bewerben-Fenster.
E-Mail bestätigt/konto/bestaetigt?t=GET zeigt T 3.3 „Fast geschafft: noch ein Tipp“ mit genau einem Knopf oeffentlich.bestaetigt.knopf „Ja, {mail} ist meine Adresse“; danach T 3.3 „E-Mail bestätigt“ + Knopf in den Bereich (Bewerber: „Stellen suchen“ bzw. „Meine Bewerbungen“, Firma: „Zum Firmenbereich“)der POST setzt konten.bestaetigt_am (Bewerbungen warten seit dem Code-Schritt im Bewerben-Fenster nicht mehr auf diese Bestätigung, 1.3 Nr. 2, C36); Firma: zustand registriert bleibt, bis erste Stelle veröffentlicht. Link älter 7 Tage: fehler.link.abgelaufen + „E-Mail erneut senden“ (nur angemeldet).
Faktor zurückgesetzt (Verwaltung, Abschnitt 3)/konto/faktor-reset?t= · /konto/faktor-reset/abbrechen?t=nur Adresse reserviert; Seiten kommen mit Abschnitt 3 (FC 9: Mails A04/A08), beide als Anzeige mit einem Knopf, erst der POST wirkt (_planung/sicherheit.md Nr. 29)hier nicht gebaut.

1.3 Bewerben-Fenster

Datei (oeffentlich)/stelle/[adresse]/_bewerben/ (ergänzt 1a Stelle): BewerbenDialog.tsx (Client, <dialog> wie B stelle.html:103–156, js kurzbewerbung() js:756–834), Schritte als eigene Teile. Öffnet über „Jetzt bewerben“ (1a, B :100), Adresse #bewerben, bei bewerbungsweg karriereseite nicht vorhanden (1a). Drei Schritte (T bewerben.schritt1–3, U 3.4; B hat zwei + Erfolg, Fortschrittsbalken :111 bekommt drei Segmente).

NrBereichBausteineB-FundstelleHinweis
1Kopfdialog__kopf: h2 (T bewerben.kopf mit {stelle}, {firma}), Schließen (icon-btn data-dialog-zu):104–110Natives <dialog> mit showModal(): beim Öffnen und bei jedem Schritt-Wechsel Fokus auf die Schritt-Überschrift „Schritt 1 von 3: Ihre E-Mail“ (B setzt ihn ins erste Feld, js:770; U A.2), Fortschritt als drei Striche aria-hidden, Text „Schritt 2 von 3“. Esc und ✕ schließen; Klick auf den Hintergrund schließt nur, solange nichts eingegeben wurde (B js:781; U A.1); am Handy bildschirmfüllend. Schließen mit angefangenem Entwurf: Entwurf bleibt 7 Tage (bewerbungs_entwuerfe), Toast T 3.2 „Entwurf gespeichert“; an der Stelle erscheint beim nächsten Besuch „Sie haben eine Bewerbung angefangen“ als Text am Platz des Knopfes (P Lebensläufe, T 7.4, U A.2). Dort und in den Bewerbungen (1.5 Nr. 1, Marke „Nicht fertig“) lässt sich der Entwurf mit „Verwerfen“ in den Papierkorb legen (1.17; bewerbungs_entwuerfe.geloescht_am, Rückgängig T 3.1 konto.rg.entwurfVerwerfen); der stille Verfall nach 7 Tagen löscht endgültig ohne Papierkorb.
2Schritt 1 E-Mailnur das Feld bewerben.mail (autocomplete=email, inputmode=email), Knopf T bewerben.weiter1 „Mit dieser E-Mail weiter“; nach Weiter prüft kontoStatus(mail), das neue Feld wird höflich angesagt und bekommt den Fokus (U 3.4, A.2): Konto vorhanden, für jedes vorhandene Konto gleich, mit oder ohne Kennwort → Ansage T bewerben.kontoGefundenAnsage „Konto gefunden. Code an {mail} senden oder mit Kennwort anmelden.“, Satz .kontoVorhanden, Hauptknopf .codeSenden „Code an {mail} senden“ (A12 Fassung anmelden) mit Code-Schritt wie unten, darunter Textlink .kontoMitKennwort „Mit Kennwort anmelden“, der das Kennwortfeld aufklappt (.kennwort, .kennwortVergessen: Textlink unter dem Feld; N-1, entschieden 26.10., Annahme C34: ein Klick sendet sofort Mail A01 an die in Schritt 1 eingetippte Adresse (Server-Aktion kennwortLinkAnfordern({mail, weiter}), dieselbe Bremse und dieselbe neutrale Antwort wie /anmelden/kennwort), das Fenster bleibt offen und zeigt an Stelle des Links den Satz T bewerben.kennwortLinkUnterwegs; der Link in der Mail führt auf /anmelden/kennwort-neu?t=…&weiter=/stelle/[adresse]#bewerben, nach dem neuen Kennwort ist die Person angemeldet und landet in der Stelle mit geöffnetem Fenster in Schritt 2, der Entwurf ist vorbelegt; weiter nur auf eigene Adressen); bei Faktor folgt nach Code oder Kennwort im selben Schritt der zweite Schritt (bewerben.faktor = oeffentlich.faktor.*; FC 7): Art app → App-Code; Art mail → nach Kennwort der E-Mail-Code, nach E-Mail-Code das Kennwort; kein Konto → die Schritt-Überschrift wechselt sichtbar und mit Fokus auf T bewerben.schritt1Konto „Schritt 1 von 3: Ihr Konto“, darunter .neuHinweis „Mit dieser E-Mail gibt es noch kein Konto. Ihr Name, dann ein Code aus Ihrer E-Mail, und es geht weiter.“ + vorname, nachname, Haken .zustimmung (Haken, so in den Nutzungsbedingungen beschrieben; Dokument „Offene Fragen“ R8); Knopf T bewerben.codeSenden „Code an {mail} senden“. Kein Kennwort in Schritt 1: nach dem Knopf wechselt die Schritt-Überschrift auf T bewerben.schritt1Code „Schritt 1 von 3: Code aus Ihrer E-Mail“, Name und Haken schrumpfen zur Zeile T bewerben.nameZeile „{vorname} {nachname} · ändern“ (Textlink klappt die Felder wieder auf), und das Code-Feld aus faktor/CodeFeld (6 Ziffern, inputmode=numeric, autocomplete=one-time-code) bekommt den Fokus; darüber Satz .codeHinweis „Wir haben einen Code an {mail} geschickt. Er gilt 10 Minuten.“ mit der vollen, eben getippten Adresse und daneben Textlink .mailAendern „E-Mail ändern“, Textlink .codeErneut „Code erneut senden“ (frühestens nach 60 s, höchstens 3 je 15 Minuten, dieselbe Bremse wie der E-Mail-Faktor, faktorMail.ts mit Zweck bewerben, Mail A12 Fassung bewerben), nach 60 s unter dem Code-Feld der Satz bewerben.spam, Knopf .codePruefen „Weiter zum Lebenslauf“; richtiger Code → kontoAnlegenMitCode(): konten-Zeile mit bestaetigt_am = jetzt, kennwort_hash leer, Sitzung sofort, Protokoll konto_angelegt_code; die Adresse ist damit bestätigt, es gibt keinen Zustand „wartet auf Bestätigung“ und keine Mails B02 bis B04 mehr. Falscher Code: fehler.faktor.falschMail; 5 falsche Codes → Code verfällt, .codeAbgelaufen + „Code erneut senden“. Ein Kennwort kann die Person später in Einstellungen › Kennwort setzen (1.9 Nr. 3); bis dahin meldet sie sich mit Code an (1.1 Nr. 3):115–124 (data-form-kontakt: Vorname, Nachname, E-Mail, Telefon freiwillig, Link „Anmelden“ :123; vier Felder → E-Mail allein, Link „Schon registriert? Anmelden“ entfällt, U 3.4)Angemeldet: Schritt 1 ist übersprungen, Kopf zeigt „als {name}“. Konto-Anlage in Schritt 1 erst mit richtigem Code (Sitzung sofort, konten.bestaetigt_am gesetzt, kein Kennwort); wird das Fenster vor dem Code geschlossen, entsteht kein Konto, danach bleibt nur der Entwurf (kein B01 aus dem Fenster; B01 gehört allein zur Seite Registrieren, 1.1 Nr. 4). kontoStatus(mail) liefert nur „neu“ oder „vorhanden“, nie ob ein zweiter Faktor besteht (_planung/sicherheit.md Nr. 15: Bremse 10 je IP und Stunde, hinter dem Honigfeld); hat das vorhandene Konto einen Faktor, folgt der zweite Schritt erst nach richtigem Code oder Kennwort; der Aufbau (Code-Knopf vorn, Kennwort aufklappbar) ist für Konten mit und ohne Kennwort gleich. Bremse und Honigfeld.
3Schritt 2 LebenslaufTelefon (.telefon, Pflicht, Beschriftung mit Grund „damit der Betrieb Sie anrufen kann“, vorbelegt aus konten.telefon), Ablagefläche ablage „Lebenslauf wählen oder Foto machen“ (echtes input type=file accept="application/pdf,image/*", das Wort „Foto“ steht auf dem Knopf; .ablageFormate: PDF, JPG, PNG, HEIC bis 10 MB; N-2, entschieden 26.10., Annahme C35: Fotos verkleinert und kodiert der Browser vor dem Hochladen in ablage/verkleinern.ts (createImageBitmap + Canvas → JPG, längste Kante 2.000 px, Qualität 0,85; Metadaten und Ortsangaben fallen dabei weg; HEIC nur, wo der Browser es dekodiert, sonst geht die Datei unverändert an den Server-Rückfall); hochgeladen wird die kleine Datei, die 10-MB-Grenze gilt für das Ergebnis; Word nicht zum Livegang, bei Word-Datei erklärt das Fenster, wie man als PDF speichert, G58; Handy: Kamera über capture; Hochladen als <progress> mit Namen), nach Wahl .ablageGewaehlt + .ablageAndere + .ablageWeiteresFoto (mehrere Fotos = mehrere Dateien einer Bewerbung, höchstens 10); hat das Konto Unterlagen (1.7 Nr. 3, „Meine Unterlagen“): alle als Liste mit Haken schon angehakt und mitgeschickt, je Zeile abwählbar, darunter .ablageAndere für weitere Dateien; neue Dateien aus dem Fenster kommen mit Haken T bewerben.auchSpeichern „Auch für künftige Bewerbungen speichern“ (angehakt) in „Meine Unterlagen“; Knöpfe .zurueck (Rand) + „Weiter zum Absenden“; keine freiwilligen Felder in diesem Schritt; nach der Ablage der Einhängepunkt FragenBlock.tsx „Fragen des Betriebs“: wird nur gerendert, wenn die Stelle Zeilen in stellen_fragen (1a Teil 3) hat und einstellungen.funktionen.fragen an ist; zum Livegang trifft beides nicht zu, der Baustein ist eine leere Hülle mit Test (rendert nichts, Schritt-Zähler bleibt „2 von 3“). Antworten gingen später nach bewerbungs_antworten (Teil 3); das Stellenformular bekommt den Fragen-Teil erst mit der Freischaltung, nach dem Livegang:126–143 (data-form-unterlagen, Ablage :127–131, B-Formate PDF, Word oder Foto)„Mit meinem Bululu-Lebenslauf“ (B profil-wahl :133–136, T .mitProfil) erst 2b (Profil mit Station); Block ist hier nicht gebaut (Funktion lebenslaufBaukasten aus). Upload sofort beim Wählen über Server-Aktion dateiHochladen() → dateien (zustand hochgeladen → geprueft), Fortschritt in der Ablage; Fehler fehler.datei.* (T 4.2); der Server prüft Typ, Größe, Pixelmaße und Viren, verkleinert aber nichts (C35).
4Schritt 3 Absendenzusammenfassung als <dl> in drei Zeilen (T .zusammenfassung, .zfStelle, .zfLebenslauf, .zfKontakt), eingeklappt als <details> .nachricht „Nachricht an den Betrieb (freiwillig)“ (Textfeld, 2.000 Zeichen; Vorlagentext erst mit der Anschreiben-Vorlage 2b), Pflicht-Haken .einwilligung mit Datenschutz-Link, Knöpfe .zurueck + „Bewerbung senden“ (orange, voll breit; beim Senden aria-disabled mit „Wird gesendet“, nicht disabled, U A.2)neu als Schritt (U 3.4 Schritt 3); Nachricht-Feld und Einwilligungs-Haken stehen in B in Schritt 2 (:137–138) und wandern hierher, Knöpfe wie :139–142Aktion bewerbungSenden(): bewerbungen (zustand neu; die Adresse ist seit Schritt 1 bestätigt, C36), einwilligungen (weitergabe, Textfassung), Dateien werden der Bewerbung zugeordnet, Entwurf gelöscht; Mails: Bewerber B05 „Bewerbung angekommen“ (T 6.2); Firma (an alle Firmennutzer je ihrer Einstellung) F03 „Neue Bewerbung“ sofort oder F04 täglich gesammelt. Ein Konto von der Seite Registrieren mit noch unbestätigter Adresse (1.1 Nr. 4) durchläuft im Fenster denselben Code-Schritt, bevor es senden kann (setzt bestaetigt_am). Erneute Bewerbung auf dieselbe Stelle, solange eine Bewerbung läuft oder nach einer Absage: fehler.bewerben.schonBeworben (T 4.3) mit Link „Meine Bewerbungen“; nach Verfall oder Rückzug ist eine neue Bewerbung möglich (G60). Zählung (U C.1): zaehleImBrowser sendet bewerben_geoeffnet (weg) beim Öffnen und bewerben_schritt (schritt 1 mit konto neu/bestand, schritt 2 mit art datei/foto) nach jedem erfolgreichen Weiter; ohne Cookies, nur Tagessummen.
5Erfolgerfolg (role status, Fokus auf die Überschrift): eine Fassung (U 3.4 Schritt 4): Haken-SVG, „Ihre Bewerbung ist bei {firma} angekommen.“ + Satz, was jetzt passiert (T 3.3), Knopf .meineBewerbungen → /mein-bereich/bewerbungen, Textlink .weitereStellen schließt:145–154B-Text „Ihre Bewerbung ist unterwegs“ (:147) und B-Kasten „Konto anlegen“ (:149–152) entfallen (Konto besteht). Die frühere zweite Fassung „Fast geschafft: Bitte E-Mail bestätigen“ mit „E-Mail erneut senden“ und „Adresse ändern“ entfällt, weil der Code in Schritt 1 die Adresse bestätigt (C36).

Ohne JS: das Fenster ist eine Seite /stelle/[adresse]/bewerben mit denselben drei Schritten als normale POST-Formulare (Annahme C1). Bewerben ist erlaubt, solange fachlich/stelle/sichtbarkeit.ts istOeffentlichSichtbar() ja sagt (Zustand aktiv oder pruefung, Firma nicht gesperrt; eine Stelle in Prüfung ist auf Bululu sichtbar, P, 1a W5, C20). Sonst zeigt 1a kein „Bewerben“; ein offener Entwurf dazu wird beim Öffnen mit fehler.bewerben.stelleWeg (T 4.3) verworfen, und bewerbungSenden() lehnt mit demselben Schlüssel ab.

1.4 Bewerberbereich: Übersicht

Datei (konto)/mein-bereich/page.tsx · Teile in mein-bereich/_uebersicht/. Layout (konto)/layout.tsx: Bereichskopf (h1 T konto.hallo {vorname}, nur Vorname; rechts kein Knopf, B-Knopf „Stellen suchen“ :101, Satz „Ihr Bereich als Bewerber“ :98 und „…“-Menü :102–109 entfallen, U 3.5), Reiter T konto.reiter.bewerbungen (+ Zahl bei Statusänderung seit dem letzten Besuch) · .lebenslauf · .postfach (+ .neuZahl ungelesen) · .merkliste · .jobAlarme (P Menüs; B :113–118 hat Übersicht/Einstellungen als Reiter, beide fallen: Übersicht = /mein-bereich selbst, Einstellungen ins Konto-Menü).

NrBereichBausteineB-FundstelleHinweis
1Zeile „Bitte E-Mail bestätigen“info-box mit Knopf „Erneut senden“ (T 7.1 Zeile Bestätigung)css info-box (1b 617–619)nur bei konten.bestaetigt_am leer; Erneut senden 60 s Sperre.
2Jetzt wichtigbox jetzt-wichtig: h2 T konto.uebersicht.wichtig, höchstens 5 Zeilen je ein Satz mit einem Knopf (nur der erste farbig), Reihenfolge fest nach T 7.1 und U 4 (Blockierendes → mit Frist → wartend auf mich → Hinweis ohne Frist: E-Mail bestätigen, Einladung „Zusagen“, ungelesene Nachricht „Lesen“, Bewerbung geöffnet als reine Information ohne Knopf (verschwindet nach dem Ansehen), gemerkte Stelle läuft ab „Bewerben“, Telefon fehlt „Ergänzen“); die sechste Zeile wird „und {n} weitere“ mit Link in den Reiterneu (P Menüs „Jetzt wichtig“; Optik kachel-Box B :125–129 als Liste)Baustein jetztwichtig/ (Teil 2), auch Firma (7.2). Leer: ruhiger Kasten „Alles erledigt. Sobald sich ein Betrieb meldet, steht es hier, und Sie bekommen eine E-Mail.“ + „Stellen suchen“ (U 3.5). Desktop: „Jetzt wichtig“ links breit, Nr. 3 und 4 rechts schmal.
3Ihre Bewerbungenh2 konto.uebersicht.ihreBewerbungen, die letzten drei Zeilen wie 1.5 Nr. 1, Link .alleBewerbungen „Alle {n} ansehen“; ohne Bewerbung fehlt der Block (dann trägt „Jetzt wichtig“ den Satz und „Stellen suchen“)neu; ersetzt die drei Zahlen-Kacheln B :125–129 (U 3.5: eine Zahl beantwortet keine Frage)Daten aus bewerbungenBewerber(kontoId, {limit: 3}); js-Zähler data-kachel-* (js:1065–1066) entfallen.
4Gemerkth2 .gemerkt, die letzten drei gemerkten Stellen (Stellenkarte „zeile“ 1a) je mit „Bewerben“; leer fehlt der BlockneuDie grüne Box „Lebenslauf aktuell?“ (B :130–133) entfällt; sie erscheint nur als Zeile „Telefonnummer fehlt im Lebenslauf. → Ergänzen“ in „Jetzt wichtig“ (U 3.5). Keine Werbung im Login-Bereich.

1.5 Bewerbungen und Bewerbung (mit Postfach-Verlauf)

Dateien mein-bereich/bewerbungen/page.tsx (Liste) und bewerbungen/[id]/page.tsx (eine Bewerbung); Teile in _liste/ und _bewerbung/. B zeigt nur eine Liste (:136–139, js meinBereich() js:1059–1064); U 3.5/3.6 liefern Liste und Detail.

NrBereichBausteineB-FundstelleHinweis
1Listepanel-kopf h2 konto.bewerbungen.titel mit Anzahl im Satz („7 Bewerbungen“, ohne B-Erklärsatz :137); gruppiert statt gefiltert: Gruppe „Offen“, darunter eingeklappt .gruppeAbgeschlossen „Abgeschlossen ({n})“ (Absage, Zurückgezogen, Stelle nicht mehr offen); Filter-Pillen .alle · .offen · .abgeschlossen (Optik data-stellen-filter B firmen-bereich.html:143–146) erst ab 20 Bewerbungen (U 3.6); ul.bewerbungen je Zeile (ganze Zeile klickbar auf die geöffnete Bewerbung, ein Tab-Halt): Firma (Monogramm/Logo 1a), Stellentitel, Firma, Ort, „Beworben vor {n} Tagen“ (.beworbenVor), Status-Marke rechts (T 5.1 Bewerbersicht: E-Mail bestätigen · Angekommen · Vom Betrieb geöffnet · Einladung zum Gespräch · Gespräch am {datum} · Anderer Termin erbeten · Termin abgesagt · Zusage · Absage · Zurückgezogen · Stelle nicht mehr offen · Nicht fertig · Nicht abgeschickt), Punkt .ungelesen bei neuer Nachricht (mit verstecktem Wort):136–139, js meinBereich() js:1054–1066 (füllt data-bewerbungen; B verlinkt nur auf die Stelle)Sortierung: neueste zuerst (U 3.6), abgeschlossene in ihrer Gruppe darunter. Keine Bedienelemente in der Zeile (P). Leer: T 2 „Noch keine Bewerbungen“ + Knopf → /jobs. Live: neue Nachricht/Status kommt über SSE (1.16).
2Bewerbung: Kopf„‹ Übersicht“-Zeile (konto.bewerbung.zurueck → Liste), h1 Stelle bei Firma, Link .stelleAnsehen (1a-Stelle; beendet → Marke statt Link), Status-Chip; Hauptknopf je Zustand: (entfällt, C36) „E-Mail erneut senden“, Einladung „Zusagen“, neue Nachricht „Antworten“, sonst keinerneu (U 3.6)
3Zeitstrahlol.zeitstrahl (T 5.2: Gesendet → Angekommen → Vom Betrieb geöffnet → Einladung/Zusage/Absage), aktueller Schritt markiert, „Jetzt ist der Betrieb dran“ nur bei offenem Stand und Firma aktivneuFirma gesperrt: Satz fehler.postfach.firmaGesperrt statt Zeitstrahl-Hinweis (P Gesperrte Firma, FC 6).
4Einladungbox einladung (nur Zustand eingeladen): Datum, Uhrzeit, Ort oder Online-Link (.onlineLink), Ansprechperson; Knöpfe .zusagen (farbig), .andererTermin (Rand, Fenster mit .andererTerminTitel/-Feld/-Senden), .absagen (Text, Fenster .absagenTitel/.absagenGrund freiwillig/.absagenSenden); nach Zusage Link .kalender „In Kalender speichern“ (ICS) und der Satz „Wir erinnern Sie am Vortag“ (T 5.1 status.eingeladenZugesagt)neu (U 3.6)Antwort schreibt einladungen.antwort + Nachricht in den Verlauf + Mail F05 an die Ansprechperson der Einladung (T 6.4); Zusage/Absage des Bewerbers ändert den Bewerbungsstatus nicht (nur die Firma setzt Zusage/Absage; P Arbeitgeber). ICS über /api/kalender/[einladungId].ics (nur eigene; Datei: Titel „Vorstellungsgespräch {firma}“, Ort/Link, 1 h Dauer; Erinnerung am Vortag = Mail B09, nur bei zugesagtem Termin, T 6.2).
5Nachrichtenchat (B firmen-bereich.html:198–209: chat__verlauf :200 mit chat__kopf und chat__nachrichten, Blasen blase/blase ich css:703, chat__eingabe Feld + Senden :203–207), Anhang-Knopf .anhang (nur Bewerber, bis 10 MB)firmen-bereich.html:196–209, css chatBaustein postfach/Verlauf.tsx (Teil 2); schreibgeschützt mit Satz fehler.postfach.* nach Absage, Rückzug, Stelle beendet, Kontolöschung, Sperre (P Postfach, G39); der Satz ersetzt Eingabe und Knopf ganz (kein ausgegrautes Feld, U A.2). Eingehende Nachrichten erscheinen über Live ohne Neuladen, aber ohne Live-Ansage (kein Echtzeit-Chat, U A.2). Senden → nachrichten + B12/F07 „Neue Nachricht“ (T 6.2/6.4, je Benachrichtigungs-Einstellung).
6Unterlagenbox .unterlagen: Datei(en) der Bewerbung mit Download (nur eigene, über /api/datei/[id]), .unterlagenStand „Stand beim Absenden“neuMappe/PDF (.mappe, .mappeAnsehen) erst 2b.
7ZurückziehenTextlink .zurueckziehen ganz unten → Fenster T 3.3 „Bewerbung zurückziehen“ (Kennwort nicht nötig), danach Status Zurückgezogen, Postfach gesperrt; Rückgängig-Muster (U A.6): ein Knopf „Rückgängig“ ersetzt den gedrückten Knopf und bekommt den Fokus, Toast zusätzlich, Frist nach Einstellung des Kontos (Standard 10 s, T 3.1)neuRückgängig innerhalb der Frist stellt Zustand wieder her (keine F-Mail in der Frist; Mail F06 „Bewerbung zurückgezogen“ an die Firmennutzer mit Benachrichtigung „Neue Bewerbung“ erst nach Ablauf, T 6.4). Einwilligung weitergabe → widerrufen (P Lebensläufe Einwilligung).
8Absage geöffnetÜberschrift „Absage von {firma}“, darunter der Text der Firma, kein Rot, kein großes Symbol; direkt darunter „Diese drei Stellen passen zu Ihrer Suche“ mit drei ähnlichen Stellen (Abfrage „ähnliche Stellen“ aus 1a) je mit „Bewerben“neu (U 3.6, 5.3)Nichts, was Hoffnung oder Angst erzeugt: keine Notizen, keine Bewertung, keine Lesebestätigung.

1.6 Postfach (Bewerber)

Dateien mein-bereich/postfach/page.tsx und postfach/[bewerbungId]/page.tsx (U 3.12). Jeder Verlauf gehört zu genau einer Bewerbung; es ist derselbe Verlauf wie in der geöffneten Bewerbung (1.5 Nr. 5), nur ein zweiter Zugang. Kopf: h1 „Postfach“, Satz „{n} ungelesen“, Umschalter-Pille „Nur ungelesene“; Suchfeld erst ab 10 Verläufen. Liste (B chat__liste :199), neueste Nachricht zuerst, ungelesene fett mit Punkt und dem versteckten Wort „ungelesen“: Logo · Firma · Stelle · letzte Zeile · Zeit. Handy: Tippen öffnet den Verlauf als eigenen Bildschirm (Kopf mit Firma, Link „Zur Bewerbung“, Zurück-Pfeil; Blasen B blase, eigene rechts mit verstecktem Vorsatz „Sie:“; Eingabe unten fest, Anhang-Knopf). Desktop: zweispaltig wie B chat (Liste links ein Drittel, Verlauf rechts, erster ungelesener vorausgewählt, offener Verlauf mit aria-current, Auswahl setzt den Fokus auf die Überschrift des Verlaufs). Nach dem Senden bleibt der Fokus in der Eingabe, Meldung „Gesendet“. Schreibgeschützt: der Satz „Diese Bewerbung ist abgeschlossen. Nachrichten sind nicht mehr möglich.“ ersetzt Eingabe und Knopf ganz. Mehrfachauswahl (Baustein auswahl/) mit Sammelaktion „Als gelesen markieren“ (G82). Keine Online-Anzeige, kein „tippt gerade“, keine Lesebestätigung mit Uhrzeit. Leer: „Hier erscheinen Nachrichten von Betrieben, bei denen Sie sich beworben haben.“ (T 2). Firma genauso (1.12 Nr. 8).

1.7 Lebenslauf (schlank zum Livegang)

Datei mein-bereich/lebenslauf/page.tsx · Teile in _lebenslauf/. P Bewerberbereich: „Persönliches (Name, Telefon, Wohnort) und ‚Ihre Datei: lebenslauf.jpg · Andere Datei‘; in 2b wächst er zum Baukasten“ (FC 5).

NrBereichBausteineB-FundstelleHinweis
1Kopfh2 konto.lebenslauf.titel, Satz .fortschritt nur mit Baukasten (2b) → hier stattdessen .telefonErgaenzen als Hinweis, wenn Telefon fehltmein-bereich.html:160–163Fortschrittsbalken (B) erst 2b.
2Persönlichesform.formular.box .persoenliches: .name (Vor- und Nachname, zwei Felder), .telefon, .wohnort (Ort mit Vorschlägen 1a data-wo); speichert je Feld sofort (P Zwischenspeichern), Zeile „Gespeichert {uhrzeit}“ (T 3.2)mein-bereich.html:185–189 (Felder Name :186 und Wohnort :189 aus „Einstellungen“ von B; Telefon hat B nicht)E-Mail-Feld (B :187) hier nicht; die Adresse steht lesend mit dem Weg „rufen Sie uns an“ in Einstellungen › Kennwort und E-Mail (1.9 Nr. 3, Karte 3 1.4a). Sprache-Hinweis .aufDeutsch.
3Meine Unterlagen (T konto.lebenslauf.unterlagen)box mit Liste: Lebenslauf (zweck lebenslauf, höchstens einer) und bis zu 9 weitere Dateien (zweck anhang mit Art T .artZeugnis · .artZertifikat · .artFuehrerschein · .artSonstiges), je Zeile Name, Art, Datum, „Ansehen“ (Download eigene), „Ersetzen“, „Entfernen“; darunter Ablage wie im Bewerben-Fenster mit Art-Auswahl; .keineDatei (Leerzustand mit Ablage)neu (Ablage stelle.html:127–131)Alle Unterlagen sind bei der nächsten Bewerbung angehakt und gehen automatisch mit. Entfernen wirkt wie Ersetzen (Rückgängig, kein Papierkorb). Ersetzen ist kein Löschen: die alte Datei bekommt nur den Rückgängig-Hinweis (T 3.1 konto.rg.dateiErsetzt, Frist nach Einstellung) und keinen Papierkorb-Eintrag (Einfachheit B6, 26.10.: sonst taucht „Papierkorb (1)“ auf, ohne dass die Person etwas gelöscht hat); nach der Frist setzt dateien.loeschen_ab, gesendete Bewerbungen zeigen weiter auf sie (W8), die Datei selbst bleibt deshalb bis zur Frist der letzten Bewerbung.
4Abgrenzung 2bErfahrung, Ausbildung, Nachweise, Sprachen, Kenntnisse, Anlagen, Deckblatt, Mappe-PDF (B :163–178, konto.lebenslauf.erfahrung … .mappe)Schlüssel bleiben in T 1.7, Bausteine kommen 2b; Reiter zeigt keinen Hinweis auf das Kommende (P Menüs: nichts, was es nicht gibt).

1.8 Merkliste und Job-Alarme (Konto-Zweig)

Dieselben Seiten wie 1b 1.9/1.10 (P Menüs). Angemeldet: merkliste/page.tsx liest merkliste_konto (Server, Reiter-Zahl konto.reiter), beim ersten Anmelden Zusammenführung Gerät → Konto mit Toast oeffentlich.ok.merklisteUebernommen (1b 1.9). Erinnerung „gemerkte Stelle läuft in 5 Tagen ab“ = Mail B13 (T 6.2) je Einstellung, einmal je gemerkter Stelle (merkliste_konto.erinnert_am). job-alarme/page.tsx (neu, Adresse /mein-bereich/job-alarme, Reiter): Liste der Alarme des Kontos (Was, Wo, Umkreis, Takt, Zustand T 5.5; Zeilen-Knöpfe „Ändern“, „Abbestellen“ (Zustand abbestellt, Rückgängig) und im „…“ „Löschen“ (legt den Alarm in den Papierkorb 1.17, job_alarme.geloescht_am, Rückgängig T 3.1 konto.rg.jobAlarmLoeschen); B mein-bereich.html:146–158 Formular data-alarm-neu als „Neuen Job-Alarm anlegen“ unten, Felder wie 1b mit zusätzlicher Takt-Option „keine E-Mail, nur speichern“ = gespeicherte Suche mit Knopf „Treffer ansehen“, P Benachrichtigungen). Beim Anmelden werden Alarme mit derselben Mail dem Konto zugeordnet (1b Teil 3 konto_id). Ändern über Formular 1b 1.11 ohne Token (Sitzung).

1.9 Einstellungen (Konto-Menü, alle Rollen)

Datei (konto)/konto/einstellungen/page.tsx · Teile in _einstellungen/; Zugang über Konto-Knopf oben rechts (Teil 2 kontomenue/). Reihenfolge P Menüs: Benachrichtigungen, Bedienung, Kennwort und E-Mail; darunter die Zwischenüberschrift T konto.einst.gruppeSicherheit „Sicherheit und Daten“ mit Anmeldung zusätzlich schützen (zweiter Faktor), Geräte, Einwilligungen, Daten herunterladen, Konto löschen; alle als zugeklappte Karten (details wie 1b FAQ, css 930–936), nur die erste offen. B hat ein einziges Formular (mein-bereich.html:184–193, Haken „Zweiten Faktor … nutzen“ :191); „Meine Daten herunterladen“ und „Konto löschen“ stehen in B ohne Funktion im „…“-Menü (:105–106).

NrKarteInhaltHinweis
1BenachrichtigungenHaken je Art (T 1.7 konto.einst.benachr*: Bewerber: neue Nachricht (bnNachricht), Statusänderung (bnStand), gemerkte Stelle läuft ab (bnMerkliste); Firmennutzer zusätzlich: neue Bewerbung sofort/täglich (fnBewerbung/fnTaeglich), Stelle läuft ab und abgelaufen als ein Schalter (fnAblauf: F08 und F09), Premium (fnPremium)), speichert sofort; der Job-Alarm-Takt liegt am Alarm selbst (1.8), kein Haken hierimmer: Konto, Kennwort, Sicherheit (nicht abschaltbar, Satz). Tabelle benachrichtigungen (Teil 3).
2Bedienung (T konto.einst.bedienung)keine Sprachwahl mehr in der Karte: die Sprachwahl im Kopf (1a) schreibt angemeldet konten.sprache mit, Mails folgen ihr; sonst nur die Haken aus Nr. 1; kein Haken „Weniger Bewegung“ (die Betriebssystem-Einstellung prefers-reduced-motion wird beachtet, U D) und keine Auswahl der Rückgängig-Zeit: sie ist fest 10 SekundenDie verzögerte Ausführung (dienste/verzoegert.ts) nimmt einstellungen.fristen.rueckgaengig_sekunden. Mails gehen erst nach dieser Frist. Die Karte „Bedienung“ entfällt, wenn sie leer wäre (Bewerber ohne Firmen-Haken).
3Kennwort und E-Mail (T konto.einst.kennwort)oben die aktuelle Adresse lesend T konto.einst.mailAktuell „Ihre E-Mail-Adresse: {mail}“ mit dem Satz T konto.einst.mailAendernHinweis „Adresse ändern: rufen Sie uns an, 0203/73997996, oder schreiben Sie uns“; darunter aktuelles Kennwort, neues (+ Regel „mindestens 10 Zeichen“), Knopf; danach A02 und andere Sitzungen beendet. Konto ohne Kennwort (C36): statt „aktuelles Kennwort“ der Satz T konto.einst.keinKennwort „Sie melden sich mit einem Code per E-Mail an. Mit einem Kennwort geht es schneller.“ und nur das neue Kennwort (kennwortSetzen.ts, A02)fehler.feld.kennwortAltFalsch, .kennwortKurz, .kennwortGleich, neu .kennwortHaeufig (26.10.: dienste/auth/kennwort.ts prüft gegen eine lokale Liste der 100.000 häufigsten Kennwörter im Projekt und gegen E-Mail-Adresse, Vorname, Nachname der Person; keine Zwangs-Sonderzeichen, kein Ablauf; _planung/sicherheit.md Nr. 10). Gilt überall, wo ein Kennwort gesetzt wird (Registrieren, Firma registrieren, Bewerben-Fenster, Kennwort neu, Einladung, Konto sichern).
4Anmeldung zusätzlich schützen (T konto.einst.faktor, Satz T .faktorSatz „Beim Anmelden kommt zusätzlich ein Code.“)aus: Wahl T konto.einst.faktorArt „So bekommen Sie den Code“ als zwei Pillen .faktorArtApp „Authenticator-App (empfohlen)“ (Satz .faktorArtAppSatz) · .faktorArtMail „Code per E-Mail“ (Satz .faktorArtMailSatz mit der Konto-Adresse); Konto ohne Kennwort: statt der Pille .faktorArtMail der Satz T .faktorErstKennwort „Code per E-Mail: Legen Sie zuerst ein Kennwort fest.“ mit Link auf Karte 3; App: Knopf „Einrichten“ → Fenster: QR-Code + Geheimnis als Text, Code-Feld, danach im selben Fenster die 10 Wiederherstellungscodes mit Rand-Knopf .faktorCodesSpeichern „Codes als Datei speichern“ und Knopf „Fertig“ (kein eigener Pflichtschritt, die Codes bleiben in der Karte abrufbar; T 1.7 konto.einst.faktor*); E-Mail: Knopf .faktorMailEinrichten „Code an {mail} senden“ → Fenster mit Code-Feld (A12), danach fertig, keine Wiederherstellungscodes; an: .faktorAnApp „Eingerichtet am …, Authenticator-App“ bzw. .faktorAnMail „…, Code per E-Mail“, „Codes neu erzeugen“ nur bei Art app, bei Art mail zusätzlich .faktorUmstellen „Auf App umstellen“ (Einrichtung wie App; danach faktor.art app, alte Codes bleiben), „Abschalten“ (gesperrt, wenn Firma Pflicht hat: Satz). Abschalten, Umstellen und Codes neu erzeugen verlangen die erneute Bestätigung. Knöpfe und Meldungen sagen „Schutz einrichten“, „Schutz abschalten“, nie „zweiter Faktor“.B :191 Haken wird Karte. Mail A03 mail.a.faktorAn „Anmeldung zusätzlich geschützt“ mit {faktorArt} (App oder E-Mail-Code), beim Abschalten A09 mail.a.faktorAus „Zusätzlicher Schutz abgeschaltet“ an die Person selbst (T 6.3). Verwaltungskonten: nur App (Karte 3 1.12, D34). 26.10., H138.
5GeräteListe der Sitzungen (Gerät/Browser und Betriebssystem aus der Browser-Kennung, letzte Nutzung, „Dieses Gerät“, dazu nur bei Firmen- und Verwaltungskonten T konto.einst.geraetIp „zuletzt von {ip}“ mit der gekürzten IP-Adresse der Anmeldung dieser Sitzung, z. B. „91.12.…“, aus anmeldungen über sitzungen.anmeldung_id; fehlt die Zeile (älter als 30 Tage), fehlt der Zusatz; Bewerber sehen keine IP), „Abmelden“ je Zeile, „Überall abmelden“P Sicherheit Sitzungen; IP nur im Sicherheitsprotokoll anmeldungen 30 Tage (Annahme C2, 26.10. geändert; Karte 3 D36).
6EinwilligungenBewerber: je Bewerbung „Weitergabe an {firma}, erteilt am {datum}“ lesend + Link „Bewerbung zurückziehen“ (P Bewerberbereich, FC 17); Textfassung aufklappbarB :190 Haken „Betriebe dürfen mich … ansprechen“ wird mit; keine eigene Einwilligung. Keine freiwillige Einwilligung zum Livegang → Karte zeigt nur die Liste; ohne Bewerbung fehlt die Karte.
7Daten herunterladenKnopf → ZIP (JSON je Tabelle + Dateien) im Hintergrund, Mail A05 mit Link auf diese Karte (T 6.3); der Download selbst nur angemeldet als Kontoinhaber über /api/datei/[id] (zweck export, 24 Stunden), nie über einen Token im Link (_planung/sicherheit.md Nr. 29)Hintergrund-Aufgabe datenexport.
8Konto löschenFenster T 3.3 „Konto löschen“ nach der Bestätigung über kennwortbestaetigung/; Folgen-Satz (Bewerbungen bleiben beim Betrieb bis zur Frist als Nachweis, P) ; Mail A06 „Konto gelöscht“letzter Admin einer Firma: fehler.team.letzterAdmin → erst Firma löschen oder Admin ernennen. Löschung: Konto anonymisiert; Dateien ohne Bewerbungsverweis sofort gelöscht, Dateien gesendeter Bewerbungen bleiben bis zur letzten Bewerbungsfrist (Nachweis, loeschen_ab); Bewerbungen gelten mit konten.geloescht_am als gesperrt.

1.10 Firmenbereich: Übersicht

Datei (firma)/firma/page.tsx; Layout (firma)/layout.tsx: Bereichskopf h1 Firmenname (B firmen-bereich.html:98, ohne Satz „Ihr Firmenbereich.“ :99), rechts Knopf firma.kopf.neueStelle „Neue Stelle“ als Rand-Knopf btn-rand (B :102 ist btn-primary; der einzige farbige Knopf der Übersicht ist der Knopf der ersten „Heute zu tun“-Zeile) → /firma/stellen/neu, am Handy in der Leiste unten (Klebeleiste wie B stelle.html:98; U 3.8), Reiter firma.reiter.stellen · .bewerbungen (+ Zahl neu, :119) · .postfach · .firmenprofil (nur Admin) · .team (nur Admin) (P Menüs; B-Reiter :117–122 heißen Übersicht, Meine Stellen, Bewerbereingang, Neue Stelle, Nachrichten, Firmenprofil; Reiter Übersicht :117, Neue Stelle :120 und das „…“-Menü :103–113 entfallen). Firma gesperrt → Erklärseite fehler.gesperrt.firma (T 4.4) statt Bereich. Mehrere Firmen: Wechsel im Konto-Menü (Sitzung trägt firma_id).

NrBereichBausteineB-FundstelleHinweis
1Bestätigungs-Zeilewie 1.4 Nr. 1; zusätzlich Hinweis „Veröffentlichen geht nach der Bestätigung“
1aErste Anmeldung ohne Stellestatt „Heute zu tun“ ein Block mit drei Schritten als Haken-Liste „Konto angelegt ✓ · Erste Stelle anlegen ○ · Bewerbungen empfangen ○“ und großem Knopf „Erste Stelle anlegen“ (farbig)neu (U 3.8)nur solange die Firma keine Stelle hat (auch keinen Entwurf).
2Heute zu tunBaustein jetztwichtig, höchstens 5 Zeilen nach T 7.2 und U 3.8: „{n} neue Bewerbungen, davon {m} für {stelle}“ → „Ansehen“ (Bewerbungen, Filter Neu) · „{name} wartet seit {n} Tagen auf eine Antwort“ → „Antworten“ (öffnet die Bewerbung) · „Stelle „{titel}“ läuft in {n} Tagen ab“ → „Verlängern“ (sofort, Toast, kein Formular) · „Stelle „{titel}“ ist pausiert seit {datum}“ → „Verlängern“ + Textlink T firma.stellen.besetztBeenden „Besetzt? Beenden“ · „„{titel}“ ist seit fast 6 Monaten pausiert, in {n} Tagen schließen wir {m} offene Bewerbungen ab“ → „Verlängern“ (14 Tage vor dem automatischen Abschluss, 1.11 Nr. 4, T 7.8 firma.heute.pausiertAbschluss) · „{n} ungelesene Nachrichten“ → „Postfach“ · Stelle nachbessern (Abschnitt 3 setzt den Zustand) · „Schützen Sie Ihr Konto mit einem zweiten Code“ → „Einrichten“ · „Ihr Firmenprofil hat noch kein Logo“ → „Logo hochladen“ · „Stelle „{titel}“ wartet auf Prüfung durch Bululu, in der Regel bis morgen. Bewerber sehen sie schon.“ (Information ohne Knopf)neuDen Hinweis „Frau Lenz hat das vor 5 Minuten geöffnet“ gibt es erst mit 2b.9. Leer: Satz mit der nächsten Frist „Nichts zu tun. Ihre {n} Stellen laufen, die nächste bis {datum}.“ ohne Knopf.
3Ihre Stellenkompakt je Stelle eine Zeile: Titel · „noch {n} Tage“ · „{n} Bewerbungen ({m} neu)“, klickbar auf die geöffnete Stelle (1.11 Nr. 1b); höchstens 5, dann „Alle Stellen“ersetzt die drei Zahlen-Kacheln B :129–133 (U 3.8: Zahl steht am Ding)Desktop: „Heute zu tun“ links breit, „Ihre Stellen“ rechts.
4Premium-HinweisB :134–138 „Mehr Sichtbarkeit mit Premium“ mit „Pakete ansehen“ (grün, Mitte) entfälltU 3.8 sieht stattdessen einen ruhigen Kasten ganz unten vor („Mehr Sichtbarkeit: Top-Stellen stehen oben in der Liste.“ + „Premium anfragen“ als Rand-Knopf, einmal wegklickbar, nie bei aktivem Premium); er kommt mit der Premium-Anfrage in Abschnitt 3, bis dahin fehlt er. Keine Pakete (P).

1.11 Stellen, Stelle neu und bearbeiten

Dateien firma/stellen/page.tsx (Liste), stellen/[id]/page.tsx (geöffnete Stelle, Firmen-Sicht), stellen/neu/page.tsx, stellen/[id]/bearbeiten/page.tsx (Bearbeiten = dasselbe Formular), Teile _liste/, _stelle/, _formular/. B: Liste :140–149 mit Filter-Pillen und js firmenBereich() → stellenZeichnen() js:1144–1162 (füllt data-meine-stellen); Formular mit Live-Vorschau :156–194 (data-editor, data-inserat, data-vorschau, js inseratEditor() js:835–900 wie 1b Ausprobieren).

NrBereichBausteineB-FundstelleHinweis
1Listepanel-kopf h2 firma.stellen.titel (ohne Satz „Jede Anzeige läuft 30 Tage“ :141, die Restlaufzeit steht an jeder Zeile); Gruppen statt Pillen (U 3.9), leere Gruppen fehlen: „Braucht Aufmerksamkeit“ (Nachbessern, läuft ab ≤ 5 Tage, pausiert seit höchstens 14 Tagen, Entwurf, wartet auf Prüfung, gesperrt) · „Aktiv“ · „Pausiert“ (abgelaufene Stellen, jederzeit verlängerbar; T 7.8 firma.stellen.gruppePausiert) · „Beendet“ (eingeklappt, mit Anzahl); Pillen firma.stellen.pilleAlle · .pilleAktiv · .pilleLaeuftAb · .pillePausiert · .pilleBeendet (B :143–146) und ein Suchfeld nach Titel erst ab 8 Stellen; Zeile: Titel (Link → geöffnete Stelle, Firmen-Sicht; B :1148 verlinkt auf stelle.html), Ort, Art, Status-Chip, „noch {n} Tage“ bei laufenden Stellen, „{n} Bewerbungen ({m} neu)“ als Text, rechts genau ein Rand-Knopf je Zustand: läuft ab/pausiert „Verlängern“ mit dem Textlink T firma.stellen.besetztBeenden „Besetzt? Beenden“ daneben · Entwurf „Weiter bearbeiten“ · wartet auf Prüfung keiner (Chip „Prüfung, bis morgen“) · Nachbessern „Bearbeiten“ (Chip „Bitte ergänzen: {grund}“) · gesperrt keiner · aktiv „Bewerbungen ({m} neu)“ als Knopf · beendet „Erneut schalten“; alles andere im „…“ der Zeile: Bearbeiten, Kopieren, Beenden, Löschen (nur Admin, nur Entwurf/pausiert/beendet ohne offene Bewerbungen; legt die Stelle in den Papierkorb, 1.17):140–149, js:1144–1162 (B-Zeile hat immer „Verlängern“ bzw. „Wieder online“ als Knopf)Sortierung innerhalb der Gruppen: neueste Änderung zuerst. Auswahl-Leiste (P Auswählen: Strg/Umschalt-Klick, Strg+A, Esc) für Beenden und Verlängern mehrerer Stellen, Baustein auswahl/ (Teil 2). Rückgängig bei Beenden und Löschen nach dem Muster U A.6 (Knopf „Rückgängig“ an der Stelle des gedrückten Knopfes, Frist nach Einstellung, T 3.1). Marke „Als Top-Stelle“ nur mit Premium (Abschnitt 3; Haken im Formular hier vorbereitet, versteckt). Unter der Liste Textlink „Papierkorb ({n})“ (nur bei n > 0) → /firma/papierkorb (1.17).
1bGeöffnete Stelle (Firmen-Sicht)Kopf wie die öffentliche Stelle (1a), darunter Reihe Zustand · Restlaufzeit · Aufrufe (Zahl ohne Kurve, aus dienste/zaehler/aufrufe.ts) · Bewerbungen; Knöpfe „Bearbeiten“ (Rand) · „Verlängern“ (läuft ab oder pausiert, Rand) · „…“ (Kopieren, Beenden, Löschen nur Admin; Premium anfragen und „Als Top-Stelle“ mit Abschnitt 3); darunter die Bewerbungen dieser Stelle als Liste wie 1.12 Nr. 1neu (U 3.9; in B nicht vorhanden)„Alles, was mit einer Stelle zu tun hat, erreicht man von der Stelle aus“ (P). Nach „Veröffentlichen“ landet die Firma hier mit Toast „Online. Läuft bis {datum}.“, bei der ersten Stelle einer neuen Firma „Online für Bewerber. Bululu prüft sie bis morgen, dann erscheint sie auch bei Google und im Job-Alarm.“ (U 3.11).
2FormularÜberschrift „Neue Stelle“, rechts klein „Entwurf gespeichert {uhrzeit}“ (sobald das erste Feld gefüllt ist, nur sichtbar, keine Ansage); formular box am Desktop links mit Live-Vorschau rechts (inserat-vorschau B :166–193, css:585), am Handy eine Spalte; Felder nach 1a Teil 3 stellen in drei Blöcken mit h2 (U 3.11): Block 1 „Die Stelle“: Titel mit (m/w/d) (Beispiel als Platzhalter, Prüfung), Fachbereich (Auswahl aus Tabelle), Beschäftigungsart (4 Pillen mit Mehrfachwahl, Vollzeit vorgewählt, mindestens eine bleibt gewählt; 1a W3 B, 26.10.), Arbeitsort + PLZ (Standard Firmensitz, Vorschläge 1a), Erforderliche Deutschkenntnisse (enum deutschstufe aus 1a: keine, grund, gut, sehr_gut, also 4 Pillen, Standard „Grundkenntnisse“); Block 2 „Der Text“: Aufgaben · Das brauchen Sie · Gut, aber nicht nötig (freiwillig, eingeklappt) · Das bieten wir (freiwillig, vorbelegt aus firmen.bieten (Firmenprofil 1.13 Nr. 3), sonst aus der letzten Stelle) (je Listenfeld ein Punkt je Zeile, Hinweis in der Beschriftung, Baustein listenfeld/); Block 3 „Bedingungen und Bewerbung“ mit drei sichtbaren Dingen und einem eingeklappten Rest: Gehalt von/bis mit Einheit als Pillen, „pro Monat“ vorgewählt (freiwillig, Pflicht wenn einstellungen.gehalt_pflicht), Start (freiwillig, Datum oder sofort), Ansprechperson (siehe unten); darunter <details> T firma.neu.weitereAngaben „Weitere Angaben (freiwillig)“, zugeklappt, mit den vier Angaben, die ein Betrieb für die meisten Stellen nie ändert (Vorgaben bleiben; beim Bearbeiten einer Stelle offen, sobald eine davon vom Standard abweicht): Befristung (freiwillig, erste Zeile im eingeklappten Teil: zwei Pillen „Unbefristet“ · „Befristet“, keine vorgewählt; bei „Befristet“ erscheint das Datumsfeld „bis“, freiwillig; schreibt 1a stellen.befristet/befristet_bis; T firma.neu.befristung, .befristungUnbefristet, .befristungBefristet, .befristetBis, T 7.9; Anzeige nur in den Eckdaten der Stelle, F2 A), Haken „Sozialversicherungspflichtig“ direkt nach der Befristung, Homeoffice (Ja/Nein, Standard Nein), Bewerbungsweg (Standard „über Bululu“, „eigene Karriereseite“ blendet das https-Adressfeld erst auf Wahl ein); die Ansprechperson steht sichtbar im Block (Auswahl aus dem Team, Standard: ich; ob ihr Telefon in Anzeigen steht, legt die Person einmal unter Team fest, 1.14, firmen_nutzer.telefon_in_anzeigen); Pillen-Gruppen als fieldset mit legend; das Pflichtfeld-Zählen und die Live-Vorschau lesen auch die eingeklappten Felder; unten Fortschrittssatz „Noch {n} Pflichtangaben: {liste}“ + firma.neu.veroeffentlichen (farbig, B :181; am Handy unten fest); am Handy daneben Rand-Knopf „Vorschau“ (bildschirmfüllend, so wie Bewerber sie sehen):167–194Kein Knopf „Zwischenspeichern“ (B :182 entfällt, das System speichert selbst; U 3.11). Live-Vorschau am Desktop inert mit aria-label „Vorschau, so sehen Bewerber die Anzeige“ (U A.2). B hat ein freies Textfeld „Anzeigentext“ (:176) + KI-Knopf (:175): ersetzt durch die Feldstruktur (Gesamtkonzept 5.3, 1a Teil 3); KI-Knopf entfällt (2b). Import-Zeile „Vorhandene Anzeige übernehmen“ (data-import :158–165) entfällt (Idee, nicht beauftragt). Entwurf speichert jedes Feld sofort (P Zwischenspeichern), „Veröffentlichen“ prüft Pflichtfelder (fehler.feld., fehler.stelle.; Fehler am Feld in einem Satz, erstes fehlendes Feld bekommt den Fokus, dazu dringende Meldung „{n} Angaben fehlen“, U 3.11/A.2), setzt veroeffentlicht_am und laeuft_bis und den Zustand: aktiv, oder pruefung, wenn fachlich/pruefung/noetig.ts ja sagt (firmen.geprueft false UND Schalter einstellungen.pruefung.neue_firmen an UND firmen.pruefstufe normal UND kein aktives Premium; D25). Bei pruefung ruft stelleVeroeffentlichen() in derselben Transaktion pruefungAnlegen() (Karte 3: Zeile in pruefungen, frist_am = nächster Werktag 9:00, V01 in die Warteschlange) und legt F21 mail.f.stellePruefung „Stelle wartet auf Prüfung“ an die Person, die veröffentlicht hat, in die Warteschlange (T 6.4); F10 mail.f.freigegeben kommt aus Karte 3. Steht die Firma noch auf zustand registriert, wird sie dabei aktiv (auch bei pruefung). Unbestätigte Mail → Fehlertext am Knopf (P), es entsteht keine Prüfung. Vorbelegung aus inseratEntwurf (1b W5) beim ersten Aufruf von /firma/stellen/neu, danach Gerätespeicher leeren. Kopieren = neuer Entwurf mit Feldern und Titel „{titel} (Kopie)“. Änderung von Titel oder Firmenname in den ersten 30 Tagen nach der Freigabe der Firma (firmen.geprueft_am) erzeugt eine Zeile in der Gruppe „nachprüfen“ der Verwaltung. Nachbessern-Zustand (Abschnitt 3: nach „Ablehnen“ in der Prüfung oder „Offline nehmen“ nach einer Meldung) nutzt dasselbe Formular mit Grund-Zeile oben; „Veröffentlichen“ aus nachbessern geht immer in pruefung mit erneut_eingereicht und neuer Prüfzeile (pruefung_art nachbesserung), unabhängig von noetig.ts, damit die beanstandete Stelle einen zweiten Blick bekommt (Annahme C22).
3Vorschau rechtsvorschau-karte (css:586–589) mit Stellenkarte „zeile“ (1a) live aus den Feldern:185–192, js:841–889
4Ablauf-AktionenVerlängern: laeuft_bis = heute + einstellungen.laufzeit_tage (Standard 30), beliebig oft, solange die Stelle aktiv, läuft ab oder pausiert (abgelaufen) ist, ohne zeitliche Grenze; Toast „30 Tage verlängert“, kein Fenster. Pausiert: eine abgelaufene Stelle ist nicht öffentlich (1a Sichtbarkeit, 410), für die Firma sichtbar mit Chip „Pausiert seit {datum}“ (T 5.4, überall dieselbe Formulierung: Zeile, „Heute zu tun“, Mail F09) und bleibt so, bis die Firma sie verlängert, beendet oder löscht; der Nachtlauf fasst die Stelle selbst nicht an. Beenden: zustand beendet, offene Bewerbungen → „Stelle beendet“ (B14 neutral, T 6.2), Rückgängig nach Einstellung (davor keine Mails); erreichbar über „…“, den Textlink „Besetzt? Beenden“ in Stellenzeile und „Heute zu tun“ und den Textlink in Mail F09 (führt nach Anmeldung in die Firmensicht der Stelle mit geöffnetem Fenster „Stelle beenden? {n} offenen Bewerbern sagen wir ab.“; erst der Knopf beendet, der Link selbst ändert nichts, _planung/sicherheit.md Nr. 29; danach Toast „Beendet. {n} Bewerbern sagen wir ab.“ und Rückgängig; H203); Erneut schalten: nur beendet, Kopie als Entwurf (Annahme C3); Löschen: nur Admin, Fenster T 3.3, legt die Stelle in den Papierkorb (1.17; stellen.geloescht_am), Rückgängigneu (P Lebensläufe Stelle)Hintergrund (stellen-ablauf.ts): täglich laeuft_ab-Mail F08 (5 Tage vorher) an Ansprechperson und Admins, abgelaufen F09 (sagt: pausiert, jederzeit verlängerbar). Datenschutz: offene Bewerbungen (neu, gesichtet, eingeladen) auf einer Stelle, die seit einstellungen.fristen.pausiert_abschluss_monate (6) abgelaufen ist, werden automatisch abgeschlossen (zustand stelle_beendet, abgeschlossen_am, B14 neutral an den Bewerber; ab da läuft die 6-Monats-Löschfrist der Bewerbung); 14 Tage davor steht eine Zeile in „Heute zu tun“ (1.10 Nr. 2), Verlängern stoppt den Abschluss, die Frist zählt dann ab dem nächsten Ablauf neu; die Stelle selbst bleibt pausiert. Schnittstellen-Stellen: ohne Laufzeit-Mails (FC 12, Abschnitt 3).

1.12 Bewerbungen der Firma, eine Bewerbung, Postfach der Firma

Dateien firma/bewerbungen/page.tsx, bewerbungen/[id]/page.tsx, firma/postfach/page.tsx; Teile _liste/, _bewerbung/. B: Bewerbereingang :151–154 mit js firmenBereich() js:1164–1195 (füllt data-eingang; Status-Auswahl status-wahl und Notiz-Feld notiz je Zeile) und Chat :196–209 (Liste chat__liste :199 + Verlauf; js:1199 ff.).

NrBereichBausteineB-FundstelleHinweis
1Listeh2 firma.bewerbungen.titel + Satz „{n} Bewerbungen, {m} neu“ (B-Erklärsatz :152 entfällt); Filter in einer Zeile: Auswahl „Stelle: Alle ▾“ und Pillen „Neu · Offen · Alle“ (Standard „Offen“ = Neu + Gesichtet + Eingeladen; U 3.10); fest neueste zuerst, am Desktop über die Spaltenköpfe umsortierbar, kein Sortier-Knopf; Zeile (ganze Zeile klickbar, ein Tab-Halt auf dem Namen): Initialen-Kreis, Name, Stelle, „heute“/„vor {n} Tagen“, Status-Chip (T 5.1 Firmensicht), Punkt bei ungelesener Nachricht (mit verstecktem Wort), leise Marke „seit {n} Tagen ohne Antwort“ (Zustand Neu oder Gesichtet ab Tag 3, T 5.1), „Konto gelöscht“ wenn zutreffend; keine Bedienelemente in der Zeile (P):151–154, js:1164–1195 (Status-Select und Notiz in der Zeile entfallen: Aktionen im Detail)Auswahl-Leiste für „Absagen“ mehrerer (P Auswählen; Fenster mit einer Vorlage für alle). Leer: T 2.
2Bewerbung: Kopf‹ Zurück, h1 Name, Stelle (Link auf die geöffnete Stelle), „beworben vor {n} Tagen“, Status-Chip; kein Kollegen-Hinweis zum Livegang (2b.9: Satz „Frau Lenz hat das vor 5 Minuten geöffnet“, wenn eine Kollegin kurz vorher hier war (aus ereignisse); Kontaktzeile: Telefon (antippen ruft an) und E-Mail aktuell aus dem Konto des Bewerbers, weicht die Nummer vom Stand beim Absenden ab, steht „aktuelle Nummer“ daneben (P Mappe); „Gesichtet“ wird beim ersten Öffnen durch einen Firmennutzer ohne Mail gesetzt (geoeffnet_am, geoeffnet_von), nie durch die Verwaltung (FC 14)neu (U 3.10)
3Handlungsleiste je Zustandim Quelltext direkt nach dem Kopf, am Handy unten fest, am Desktop oben rechts: neu/gesichtet: firma.bewerbung.einladen (orange) + .absagen (Rand), „Zusage“ hinter „…“; eingeladen: .zusage (orange), .neuerTermin (Rand), .absagen (Text); Zusage/Absage/zurückgezogen/beendet: keine Leiste, nur Chip mit Datum (U 3.10, U 7)neuJeder Knopf öffnet ein Fenster mit Vorlage aus T 6.1 (vorlage.firma.einladung, .zusage, .absage, .neuerTermin) zum Bearbeiten; erst „Senden“ setzt den Status, schreibt die Nachricht in den Verlauf und schickt B07 Einladung / B08 Neuer Termin / B10 Zusage / B11 Absage (T 6.2). Einladen-Fenster: Datum, Uhrzeit, Ort oder Online-Link, Ansprechperson (select Team, vorbelegt Ansprechperson der Stelle) → einladungen + ICS im Mail-Anhang; „Neuer Termin“ = neue Einladung, alte als ersetzt. Rückgängig bei Einladung und Absage nach dem Muster U A.6 (Frist nach Einstellung; B07/B11 erst danach, T 6.2). Ein Zustand entsteht nur durch eine Handlung, nie durch ein Auswahlfeld (B status-wahl js:1182 und die sofortige Mail-Meldung js:1187 entfallen).
4Verlauf (Firmensicht)ol.verlauf T 5.3 (Eingegangen, Gesichtet von {name}, Eingeladen, Antwort des Bewerbers, Zusage/Absage)neu
5UnterlagenDateien der Bewerbung: Bilder als Ansicht, PDF als Download (P Dateien), Zugriff nur Firmennutzer (Rechte-Prüfung je Datei), Nachricht des BewerbersneuMappe-Ansicht 2b. Öffnen durch Verwaltung mit Grund → Protokoll (Abschnitt 3).
6Notizenbox notizen unten (nach der Entscheidung): ein Textfeld „Notiz (nur für Ihr Team)“, speichert sofort, darunter „zuletzt geändert von {name}, {zeit}“; kein Speichern-Knopf; Textlink „Notiz löschen“ unter dem Feld (nur wenn Text da ist; legt die Notiz in den Papierkorb 1.17, Rückgängig T 3.1 firma.rg.notizLoeschen); nur Firmennutzer, nie Bewerber (U 3.10)js:1183 (Notiz-Feld notiz, B speichert im Gerät)Tabelle bewerbungs_notizen (eine Notiz je Bewerbung; geloescht_am gesetzt = im Papierkorb, das Feld ist dann leer). Wiederherstellen setzt den Text zurück; steht inzwischen eine neue Notiz da, kommt der alte Text mit Datumszeile darunter.
7NachrichtenVerlauf-Baustein wie 1.5 Nr. 5 (ohne Anhang, P: Anhänge nur vom Bewerber), in der Eingabezeile Textknopf „Vorlage einfügen“; ungelesen zählt für die Firma gemeinsam (Admin und Recruiter)firmen-bereich.html:198–209Mail B12 „Neue Nachricht“ an den Bewerber je Einstellung.
7aVorherige / NächsteKnöpfe „Vorherige Bewerbung“ / „Nächste Bewerbung: {name}“ am Ende und Pfeiltasten ← → (nur wenn der Fokus nicht in einem Textfeld steht), innerhalb des aktuellen Filtersneu (U 3.10, A.2)
8Postfach (Firma)wie 1.6 (Liste, eigener Verlauf-Bildschirm am Handy, zweispaltig am Desktop, „Nur ungelesene“, Mehrfachauswahl „Als gelesen markieren“); Zeile: Initialen · Name · Stelle · letzte Zeile · Zeit; im Verlauf Textknopf „Vorlage“; Leer: „Hier erscheinen Nachrichten Ihrer Bewerber. Schreiben Sie ihnen aus der Bewerbung heraus.“ + „Bewerbungen“ (Rand):196–210 (Optik der Liste: chat__liste :199; Reiter heißt „Postfach“ statt „Nachrichten“ :121)U 3.12

1.13 Firmenprofil bearbeiten

Datei firma/profil/page.tsx (nur Admin; Recruiter sieht im Reiter-Platz nur den Link firma.profil.ansehen → /firmen/[adresse], P Rechte). B :212–227 (data-firmenprofil, Felder Firmenname, Ort, Webseite, Telefon, Über uns, Knopf „Speichern“).

NrBereichBausteineB-FundstelleHinweis
1Logologo-feld: Vorschau (Monogramm 1a, wenn leer), Ablage „Logo wählen“ (PNG, JPG, WebP bis 2 MB; kein SVG, P Dateien), „Entfernen“B :215 (firmenkasten__kopf: Monogramm + Knopf „Logo hochladen“ ohne Funktion); Ablage wie Bewerbender Browser verkleinert das Logo vor dem Hochladen auf Anzeigegröße (längste Kante 800 px, PNG bleibt PNG wegen Transparenz, JPG/WebP → WebP; ablage/verkleinern.ts, N-2, C35), der Server prüft Typ, Größe (2 MB), Maße (höchstens 1.000 px) und Viren und speichert ohne Neukodierung; firmen.logo_datei_id; das Logo ist öffentlich, sobald die Virenprüfung es freigibt (dateien.zustand geprueft), ohne Freigabe durch die Verwaltung. Unter dem Logo-Feld steht T firma.profil.logoOeffentlich „Öffentlich seit {datumKurz}“ (dateien.geprueft_am), während der Virenprüfung T gemeinsam.datei.hochladen „Wird hochgeladen“; ohne Logo kein Satz.
2StammdatenFirmenname, Straße, PLZ, Ort (Vorschläge), Telefon + Haken „Telefon öffentlich zeigen“ (firmen.telefon_frei, 1b), Webseite (https, fehler.feld.webseite):216–223 (B: Firmenname, Ort, Webseite, Telefon)Jede Änderung speichert sofort, Zeile „Gespeichert {uhrzeit}“ (P Zwischenspeichern); B-Knopf „Speichern“ (:225) entfällt. Firmenname oder Ort geändert → neue firmen.adresse über 1a firmenAdresseBilden(), alte Adresse in firmen_adressen (301). Firmenname geändert innerhalb von 30 Tagen nach der ersten Freigabe → Zeile in pruefungen mit art aenderung und zustand offen in der Gruppe „Automatisch freigegeben, nachprüfen“ (Karte 3 1.2, D27, C10); die Änderung ist sofort sichtbar. Inline-Styles :214, :225 → Klassen.
3Über unsTextfeld (Absätze, 2.000 Zeichen) → firmen.beschreibung (1b 1.3 zeigt es); darunter Listenfeld firma.profil.bieten „Das bieten wir“ (ein Punkt je Zeile) → firmen.bieten, Vorlage für neue Stellen (1.11 Nr. 2), öffentlich nicht gezeigt:224Hinweis „Bitte auf Deutsch“ (P Sprachen).
4Ansprechperson des Betriebsselect aus Team (Name, Telefon aus konten) → firmen.ansprechperson_id; wird Vorbelegung für neue Stellenneu (P 2a „Firmenprofil … Ansprechperson“)Öffentlich zeigt das Profil keine Person (1b 1.3 hat keine Zeile; nur Stellen zeigen ihre Ansprechperson). Annahme C5.
5Link öffentlichTextlink firma.profil.ansehen → /firmen/[adresse]neuAdresse aus firmen.adresse (1a). Solange die Firma registriert (noch keine Stelle veröffentlicht) ist, liefert 1b das Profil nur für angemeldete Nutzer dieser Firma (Besucher 404); der Link funktioniert also ab dem ersten Tag.
6Firma löschenganz unten, nur Admin: Textlink firma.profil.firmaLoeschen → Fenster nach Muster „Konto löschen“ mit Kennwort (P Firma löschen): Stellen beendet, offene Bewerbungen „Stelle beendet“ (B14 neutral), Nutzer-Mitgliedschaft endet, Mail F18 an alle Firmennutzer; der Export-ZIP der Firma liegt 30 Tage in den Einstellungen der bisherigen Admins (Karte „Daten herunterladen“, Abschnitt „Exporte“), Download nur angemeldet, kein Link mit Token in F18 (_planung/sicherheit.md Nr. 29)neu (FC 6)Zustand geloescht; Firma verschwindet aus 1b-Listen.

1.14 Team

Datei firma/team/page.tsx (nur Admin) · Teile _team/; Zielseite (oeffentlich)/einladung/page.tsx?t=. Kein B-Bildschirm (nur Menüpunkt „Nutzer verwalten“ firmen-bereich.html:107, „Bald verfügbar“); Optik: Liste wie Stellen-Zeilen, Formular wie formular box.

NrBereichBausteineHinweis
1ListeZeile je Nutzer: Name, E-Mail, Rolle-Chip (Admin · Recruiter), Faktor-Marke „2. Faktor aktiv“, letzte Anmeldung, Haken „Telefon in Anzeigen zeigen“ (firmen_nutzer.telefon_in_anzeigen, je Person und Firma einmal; U 3.11; 1a Arbeitgeber-Kasten liest ihn); „…“: Rolle ändern, Entfernen (nicht beim letzten Admin: Knopf fehlt + Satz fehler.team.letzterAdmin); angelegte Konten ohne Kennwort stehen in derselben Liste mit dem Zustand T firma.team.eingeladen „wartet auf Kennwort, E-Mail vom {datumKurz}“ statt Rolle-Chip-Zusatz und mit „…“: „E-Mail erneut senden“, „Zurückziehen“Entfernen: firmen_nutzer.zustand entfernt, der entfernende Admin wird Ansprechperson aller Stellen und offenen Einladungen der Person (P Arbeitgeber), Toast mit Rückgängig (Frist nach Einstellung) nennt das (T 3.1). Nach Ablauf der Frist Mail F19 mail.f.teamEntfernt „Aus dem Team entfernt“ an die entfernte Person (T 6.4).
2Mitarbeiter anlegenFormular: Vorname, Nachname, E-Mail, Rolle (Admin · Recruiter), Überschrift firma.team.anlegen „Mitarbeiter anlegen“, Knopf firma.team.anlegenKnopf „Konto anlegen“ → firmen_einladungen (Token 7 Tage), Mail F02 „Ihr Konto im Team“ (T 6.4); danach Toast T firma.team.anlegenOk „{name} bekommt jetzt eine E-Mail und legt das Kennwort selbst fest, gültig bis {datumKurz}.“ und die Zeile „wartet auf Kennwort“ in der ListeNomad 26.10.: Jede Firma legt Mitarbeiter-Konten selbst an. Zielseite /einladung?t=: ohne Konto → nur noch Kennwort festlegen (Name und Mail stehen schon da; hat die Verwaltung nur die Mail eingetragen, Karte 3 H126/H127, fragt die Seite den Namen mit ab; die Mail gilt mit dem Klick als bestätigt), bei Faktor-Pflicht der Firma gleich danach Faktor einrichten, dann Beitritt; Adresse hat schon ein Konto → Anmelden und „Einladung annehmen“ (ein Konto je Person, nie ohne Zustimmung angehängt); danach Toast T 3.2 und Firmenbereich. Kennwörter vergibt nie der Admin. Abgelaufen: fehler.link.abgelaufen. Mail-Adresse bereits Mitglied: fehler.team.schonImTeam.
3Schalter Faktor-Pflichtcheck „Zweiter Faktor für alle Nutzer dieser Firma Pflicht“ (firmen.faktor_pflicht), Satz T firma.team.faktorPflichtSatz „App oder Code per E-Mail, beides zählt.“ (T 7.10), Satz, wer ihn noch nicht hat (Zahl)P Arbeitgeber; wirkt bei der nächsten Anmeldung (1.2); beide Faktor-Arten erfüllen die Pflicht (26.10.). Beim Einschalten Mail F20 mail.f.faktorPflicht „{firma} verlangt ab jetzt einen Code bei jeder Anmeldung“ an alle Nutzer der Firma ohne zweiten Faktor (T 6.4).

1.15 Konto-Menü oben rechts (ohne eigene Seite)

Baustein kontomenue/ (Teil 2) im Seitenrahmen 1a: Knopf mit Monogramm des Namens (Optik sprache__knopf-Stil B anmelden.html:60, Ausklapp ausklapp; Name „Konto von {vorname} {nachname}“, aria-expanded, darin normale Links, kein ARIA-„menu“, Esc schließt und gibt den Fokus zurück; U A.1), Einträge P Menüs: Mein Bereich (Bewerber: /mein-bereich; Firma: /firma) · Wechsel zu Bewerber / {Firma} (nur bei Mitgliedschaften; setzt Sitzungs-Firma) · Einstellungen · Papierkorb ({n}) (nur, wenn der Papierkorb des gewählten Bereichs etwas enthält; Bewerber → /konto/papierkorb, Firma → /firma/papierkorb; 1.17) · Hilfe und Kontakt (öffnet den passenden Hilfe-Artikel: Firmen-Sitzung → /ratgeber/hilfe-betriebe, sonst /ratgeber/hilfe-bewerber; Karte 1b 1.6, B21; von dort führt der Schluss-Block auf /kontakt) · Abmelden. Ohne Sitzung zeigt der Kopf wie B „Anmelden“ (orange) und „Stelle inserieren“ (grün, :61–62); angemeldet ersetzt das Konto-Menü den Anmelden-Knopf, „Stelle inserieren“ führt für Firmennutzer auf /firma/stellen/neu.

1.16 Live-Aktualisierung (ohne Seite)

Zum Livegang ohne Dauerverbindung: Reiter-Zahlen (ungelesen, neue Bewerbungen) kommen mit jeder Seite vom Server; der Client-Baustein live/ fragt in offenen Listen und Verläufen alle 60 Sekunden GET /api/live?seit={zeitpunkt} ab (Rechte-Prüfung wie die Liste; liefert Zähler und neue Zeilen seit dem Zeitpunkt aus den Fachtabellen, keine eigene Tabelle) und fügt neue Zeilen nicht selbst ein: über der Liste erscheint die ruhige Zeile T gemeinsam.live.neu „{n} neue … · anzeigen“ (aria-live polite, z. B. „2 neue Bewerbungen · anzeigen“); erst der Klick lädt sie oben in die Liste, Auswahl und Scrollstand bleiben; dieselbe Abfrage frischt die Reiter-Zahlen, die Zahlen von „Heute zu tun“ und in der Verwaltung die Zahl-Kreise auf; den offenen Verlauf lädt er ohne Ansage nach (kein Echtzeit-Chat, U A.2). Server-Sent Events mit Tabelle ereignisse und LISTEN/NOTIFY (W6) kommen nach dem Livegang (Baureihenfolge 2b.9); keine Browser-Push-Benachrichtigungen (nicht beauftragt).

1.17 Papierkorb (Firma und Bewerber)

Dateien (firma)/firma/papierkorb/page.tsx und (konto)/konto/papierkorb/page.tsx; Baustein papierkorb/ (Teil 2.1), Aktionen fachlich/papierkorb/* (Teil 2.2, 3.2). Nomad 26.10.: ein Papierkorb für beide Seiten, für vieles, was man anlegen und löschen kann. Bisher hatte nur die Verwaltung einen (Inhalte, Karte 3 1.10); die Regeln sind dieselben: Löschen setzt geloescht_am (Lesen filtert überall), der Rückgängig-Hinweis (T 3.1, Frist C6) bleibt, nach einstellungen.fristen.papierkorb_tage (30, Karte 3) löscht der Nachtlauf (fristen.ts) endgültig. Optik aus vorhandenen Bausteinen, nichts Neues gestaltet: panel-kopf h2 gemeinsam.papierkorb.titel + Satz gemeinsam.papierkorb.satz, Zeilen wie die Stellenliste (1.11 Nr. 1), Leerzustand wie T 2, Fenster (Teil 2 fenster/) nur für „Papierkorb leeren“.

NrBereichBausteineHinweis
1Was hineingeht (Firma)Stellen in jedem löschbaren Zustand (Entwurf, pausiert, beendet; nur Admin, ohne offene Bewerbungen, 1.11 Nr. 1) · Notizen zu Bewerbungen (1.12 Nr. 6)Nicht: Team-Mitglieder und Einladungen (Zustand mit Rückgängig und Übernahme der Stellen, unnötig), Logo (eine Datei, neu wählen ist ein Klick), Firma löschen (eigener Ablauf mit Export und Fristen, 1.13 Nr. 6), eigene Vorlagen (gibt es in 2a nicht: Vorlagen kommen aus T 6.1, „Das bieten wir“ ist ein Profilfeld).
2Was hineingeht (Bewerber)Job-Alarme (1.8 „Löschen“) · verworfene Bewerbungsentwürfe (1.3, 1.5), also nur bewusst GelöschtesNicht: ersetzte Lebenslauf-Dateien, Merkliste (Rückgängig genügt, 1b W1), Bewerbung zurückziehen (Zustand, 1.5 Nr. 7), Konto löschen (eigener Ablauf, 1.9 Nr. 8), Nachrichten und Einwilligungen (werden nicht gelöscht), Geräte (Sitzungen). Eine versendete Bewerbung behält ihren Verweis auf die Datei (W8).
3ZugangTextlink gemeinsam.papierkorb.link „Papierkorb ({n})“ (btn-text, klein) unter der jeweiligen Liste: Stellen (Firma); Job-Alarme und Bewerbungen (Bewerber); dazu Eintrag im Konto-Menü (1.15); beides nur bei n > 0Baustein PapierkorbLink.tsx, Zahl kommt vom Server mit der Seite. Kein Reiter, kein Menüpunkt bei leerem Papierkorb (P Menüs: nichts, was es nicht gibt).
4Listeul Zeilen (Optik Stellenzeile): Art als Chip (gemeinsam.papierkorb.art*: Stelle · Entwurf · Notiz zu {name} · Job-Alarm · Bewerbungsentwurf), Name (Stellentitel, Alarm „{was} in {wo}“, Stelle des Entwurfs), gemeinsam.papierkorb.geloeschtVon „von {name}“ (nur Firma), gemeinsam.papierkorb.geloeschtVor „gelöscht {datumKurz} · noch {m} Tage“, rechts Rand-Knopf gemeinsam.papierkorb.wiederherstellen und Textknopf .endgueltig; neueste zuerst; Gruppen nach Art erst ab 8 EinträgenKeine Mehrfachauswahl im Papierkorb. Kopf rechts Rand-Knopf gemeinsam.papierkorb.leeren → Fenster .leerenFrage mit Knopf „Endgültig löschen“ (einzige Nachfrage, weil nicht umkehrbar; P Bedienregeln).
5Wiederherstellengeloescht_am leeren. Stelle: geloescht_am leeren genügt, der Fachzustand (Entwurf, pausiert, beendet) war nie verändert, sie steht wieder in ihrer Gruppe; Notiz: Text zurück ins Feld, steht inzwischen eine neue Notiz da, kommt der alte Text mit Datumszeile darunter; Job-Alarm: Zustand wie vorher (abbestellt bleibt abbestellt); Bewerbungsentwurf: wieder am Platz des Knopfes an der Stelle, sofern die Stelle noch bewerbbar ist (sonst fehler.bewerben.stelleWeg, der Eintrag bleibt)Toast gemeinsam.papierkorb.wiederhergestellt, kein Rückgängig (der Weg zurück ist „Löschen“).
6Endgültig löschen, leerenZeile löschen. Stelle mit abgeschlossenen Bewerbungen (offene verhindern das Löschen schon vorher): Zeile bleibt als zustand geloescht ohne Firmen-Sicht hinter ihren Bewerbungen, bis deren 6-Monats-Frist abgelaufen ist, dann weg (Bewerber sieht bis dahin den Titel ohne Link); Notiz, Alarm, Entwurf: sofort weg (ersetzte Lebenslauf-Dateien laufen ohne Papierkorb über dateien.loeschen_ab, 1.7 Nr. 3)Toast gemeinsam.papierkorb.endgueltigOk ohne Rückgängig. Der Nachtlauf macht dasselbe nach papierkorb_tage (fristen.ts, H134).
7Rechte und DatenschutzWer löschen darf, darf wiederherstellen und endgültig löschen (fachlich/rechte.ts); Recruiter sieht nur Notizen (Stellen löscht nur der Admin), Admin alles der Firma; Bewerber nur eigene Einträge (RLS wie die Ursprungstabellen)Inhalte im Papierkorb zählen beim Datenexport (A05, F18) und bei den Löschfristen mit (eine Bewerbung läuft nicht länger, weil ihr Entwurf im Papierkorb liegt); Konto löschen (1.9 Nr. 8) und Firma löschen (1.13 Nr. 6) leeren den Papierkorb sofort. Protokoll (1a) schreibt papierkorb_wiederhergestellt und papierkorb_endgueltig mit Art und Kennung.

1.18 Übersetzung der Stellenanzeigen (ohne eigene Seite; Hintergrund)

Zugesagt zum Livegang (Kundenliste: „Stellenanzeigen werden automatisch übersetzt“; Plan Sprachen: „beim Veröffentlichen und nach jeder Änderung im Hintergrund“; Karte 0 Teil 2: Azure, Europa-Rechenzentrum, Monatsgrenze). Tabelle stellen_uebersetzungen liegt seit 1a (Platzhalter), die Anzeige mit Hinweis und Umschalter seit 1a 1.3 (A7). Hier kommt der Dienst, die Hintergrundaufgabe und die Anzeige der echten Übersetzung dazu. Paket 2a.11a (), Annahme C33.

NrBereichWas passiertHinweis
1AuslöserZeilen mit stand geprueft (gelieferte Fassung, z. B. COPLA-Englisch, Karte 3 1.13) werden nie auf wartet gesetzt; der COPLA-Abgleich schreibt en mit zustand fertig, stand geprueft. fachlich/stelle/schreiben.ts: veroeffentlichen() und jede Änderung eines Textfeldes (titel, einleitung, aufgaben, brauchen, gut_nicht_noetig, bieten) einer Stelle im Zustand aktiv, pruefung oder nachbessern legt je freigegebener Sprache aus einstellungen.sprachen_frei (ohne de) eine Zeile in stellen_uebersetzungen an oder setzt sie auf zustand wartet und quelle_geaendert_am = jetzt; danach hintergrund.einreihen('stellen-uebersetzen', {stelle_id}) (pg-boss, Warteschlange uebersetzung, Parallelität 1, Verzögerung 2 Minuten, damit mehrere Änderungen kurz nacheinander nur einen Lauf auslösen). Kopieren, verlängern, erneut schalten lösen nichts aus (Text unverändert).Nur, wenn einstellungen.funktionen.uebersetzung und einstellungen.uebersetzung.anzeigen_automatisch an sind (Karte 3 1.11 Nr. 1 und 3); sonst bleibt die Zeile bei nochNichtUebersetzt.
2Dienstdienste/uebersetzung/azure.ts: `uebersetzen(texte: string[], von: 'de', nach: 'en' \'tr') gegen Azure AI Translator (Text API 3.0, Region aus AZURE_REGION, Schlüssel AZURE_UEBERSETZER_SCHLUESSEL, Karte 0 Teil 4), HTML-Modus für die Listenfelder (textType=html, Absätze und <li> bleiben), Zeitlimit 20 s, Wiederholung bei 429/5xx mit pg-boss-Rückzug (3 Versuche: 5, 30, 120 Minuten). index.ts wählt den Dienst: azure, in Tests stummel (Übersetzung = „[en] “ + Text). Monatsgrenze liegt im Azure-Konto (Karte 0 B05, Kosten Teil 12); der Dienst zählt zusätzlich Zeichen je Monat in zaehler_tag` („uebersetzung_zeichen“) für die Zustandsanzeige.Keine Personendaten: nur die sechs Textfelder gehen hinaus (Ansprechperson, Adresse, Firma nicht); Offene Fragen R7.
3Aufgabehintergrund/aufgaben/stellen-uebersetzen.ts: liest alle Zeilen der Stelle mit zustand wartet, übersetzt die sechs Felder in einem Aufruf je Sprache, schreibt titel, einleitung, aufgaben, brauchen, gut_nicht_noetig, bieten, stand maschinell, uebersetzt_am = jetzt, zustand fertig, versuche. Fehler: zustand fehler, fehler_text (gekürzt, ohne Schlüssel), versuche + 1; nach dem dritten Fehler bleibt die Zeile auf fehler, Protokoll-Eintrag (dienste/protokoll, Art uebersetzung_fehler), und einstellungen.uebersetzung.fehler_anzahl zählt hoch. Erfolg setzt einstellungen.uebersetzung.letzte_am.Ist der deutsche Text seit dem Start der Übersetzung erneut geändert (quelle_geaendert_am neuer als beim Lesen), wird das Ergebnis verworfen und die Zeile bleibt wartet (nächster Lauf).
4Anzeige1a 1.3 zeigt in /en/ und /tr/ die Zeile mit zustand fertig: übersetzter Titel groß, deutscher Titel klein mit lang="de", Hinweis T gemeinsam.sprache.maschinell „Mit KI übersetzt. Verbindlich ist die deutsche Fassung.“ (1b 1.12, KI-Kennzeichnung), Umschalter T .deutschZeigen / .uebersetzungZeigen an Ort und Stelle (Gerätespeicher merkt die Wahl je Sitzung, H144); fehlt die Zeile oder ist sie wartet/fehler, deutscher Text mit T .nochNichtUebersetzt (unverändert seit 1a). Google: JSON-LD bleibt deutsch (inLanguage de), hreflang je Sprache (1a 1.3). Suche und Job-Alarm suchen weiter im deutschen Text (Plan: Begriffslisten der Fachbereiche).stand geprueft (von Hand gegengelesen, Verwaltung) kommt mit 2b.5; bis dahin zeigt jede Übersetzung den Hinweis.
5VerwaltungKarte 3 1.11 Nr. 3: Schalter „Anzeigen automatisch übersetzen“ (einstellungen.uebersetzung.anzeigen_automatisch), Zustand „Letzte Übersetzung {zeit} · {n} Fehler · {zeichen} Zeichen diesen Monat“, Knopf „Übersetzung erneut starten“ (setzt alle Zeilen fehler auf wartet, reiht die Aufgabe je Stelle ein, fehler_anzahl = 0); „Heute zu tun“ beim Super Admin: T verwaltung.heute.uebersetzung „Übersetzung von {anzahl} Anzeigen fehlgeschlagen.“ → Erneut starten (Karte 3 1.1 Nr. 1, T 7.3). Zählt in H119.Schalter aus: laufende Aufgaben enden leer, vorhandene Übersetzungen bleiben sichtbar (Rückgängig-Toast mit Folgen-Satz wie Karte 3 1.11).
6Testpruefung/hintergrund/stellen-uebersetzen.test.ts mit Stummel: Veröffentlichen legt zwei Zeilen wartet an; Lauf schreibt fertig mit Stummel-Text; Fehler im Stummel → fehler, versuche 1, Protokoll; Änderung während des Laufs → bleibt wartet; Schalter aus → keine Zeile. pruefung/seiten/stelle.test.ts (1a) ergänzt: /tr/ zeigt übersetzten Titel, Hinweis und Umschalter; ohne Zeile den deutschen Text. Kein Aufruf des echten Dienstes im Test.Prüfart Nachtlauf: Zustand (nach Fristen-Lauf; die Testadresse hat den Azure-Schlüssel aus Karte 0 Teil 2).
2

Bausteinkatalog-Ergänzung (nur Neues gegenüber 1a/1b)

Wiederverwendbare Teile wie Konto-Menü, Postfach, Datei-Ablage, Papierkorb und Anmeldeschutz, die für diese Bereiche neu gebaut werden.

Dieser Abschnitt beschreibt nur die technische Umsetzung. Mit dem Schalter „Technische Angaben“ blenden Sie ihn ein.

Regel wie 1a/1b. CSS von B bleibt in stile/b/style.css; Neues nur beim Baustein mit vorhandenen Werten. Die angemeldeten Bereiche nutzen dieselben Bausteine wie die öffentlichen Seiten (kein zweites Design).

2.1 Neue gemeinsame Bausteine

Baustein (Ordner)DateienAus B: HTMLAus B: CSS-KlassenAus B: app.jsBenutzt von
kontomenue/KontoMenue.tsx (Client: Knopf + Ausklapp, Wechsel Firma/Bewerber über Server-Aktion)anmelden.html:60 (Ausklapp-Muster), firmen-bereich.html:103–113 („…“-Menü)sprache__knopf (css:129), ausklapp (css:132), mehr-menue (css:634–635)data-ausklapp-Logik js:259–300 (1a Sprachwahl)Seitenrahmen 1a (angemeldet)
bereich/BereichKopf.tsx (h1 + höchstens ein Rand-Knopf, nur Firma „Neue Stelle“; U 4), UebersichtZeile.tsx („‹ Übersicht“ über der h1 jeder Unterseite), Reiter.tsx (Links mit aria-current, Zahl-Marke zahl-klein), BestaetigenZeile.tsxmein-bereich.html:93–121, firmen-bereich.html:94–125bereich-kopf (css:622–625), reiter (626–629), zahl-klein (631), panel-kopf (661–662); die Kacheln uebersicht-raster/kachel (css:636–640) entfallen (U 3.5, 3.8)reiter() mit data-zu-reiter js:356–383 entfällt (echte Adressen)(konto)/layout, (firma)/layout
jetztwichtig/JetztWichtig.tsx (bis 5 Zeilen, je ein Satz und ein Knopf oder reine Information, nur der erste Knopf farbig, sechste Zeile „und {n} weitere“, Leer-Satz), zeilen.ts (Regeln Bewerber T 7.1, Firma T 7.2; Reihenfolge U 4)neu, Optik boxbox, btn-kleinÜbersicht Bewerber, Übersicht Firma; ab 3 Verwaltung (T 7.3)
ablage/Ablage.tsx (Client: Datei wählen, Kamera, Fortschritt, Fehler je Datei), verkleinern.ts (Client, N-2/C35: Bilder je Zweck verkleinern und neu kodieren, createImageBitmap + Canvas, Zielmaße lebenslauf 2.000 px JPG · logo 800 px · werbemotiv unverändert kodiert · ratgeberbild 1.600 px WebP; HEIC nur, wenn der Browser es dekodiert; schlägt die Verkleinerung fehl, geht die Originaldatei hoch und der Server entscheidet), pruefen.ts (Typ am Inhalt, Größe, Anzahl, Pixelmaße; Server und Client)stelle.html:127–131ablage (css:549–552); Hinweis- und Dateizeile neu mit vorhandenen WertendateiGewaehlt() in kurzbewerbung() js:798Bewerben-Fenster, Lebenslauf (Datei), Firmenprofil (Logo), Postfach-Anhang
statuschip/StatusChip.tsx (Bewerbung Bewerber-/Firmensicht, Stelle Firmensicht, Einladung, Alarm; Wörter aus T 5.1, 5.4, 5.5)Status-Marken in den B-Zeilen (js:1063, 1152, 1181)status, status--neu, --gesichtet, --eingeladen, --absage, --aktiv, --laeuft, --archiv (css:648–656); fehlende Zustände neu mit vorhandenen FarbenSTATUS-Tabelle in app.js (Wörter werden durch T ersetzt)Listen und Details beider Bereiche
postfach/Verlauf.tsx (Client: Blasen, Eingabe, Anhang-Knopf nur Bewerber, Schreibschutz-Satz), nachricht.ts (Prüfung 4.000 Zeichen)firmen-bereich.html:196–209chat (css:692), chat__liste (693), chat__verlauf (699), chat__kopf (700), chat__nachrichten (702), blase (703), chat__eingabe (706)Chat-Demo in firmenBereich() js:1199 ff.Bewerbung (Bewerber), Bewerbung (Firma), Postfach beider Seiten (Liste.tsx + Verlauf)
fenster/Fenster.tsx (natives <dialog> mit showModal(), Fokus beim Öffnen auf die Überschrift, beim Schließen zurück auf den Auslöser, aria-labelledby/aria-describedby, Hintergrund-Klick schließt nur ohne Eingabe; Kopf, Inhalt, Knopfzeile; Varianten bestätigen · mit Kennwort · mit Vorlage; U A.1)stelle.html:103–112 (Dialog-Rahmen)dialog__kopf (css:539), dialog__inhalt (542), fortschritt (543)data-dialog-zuBewerben, Zurückziehen, Einladen/Absagen/Zusage, Konto löschen, Firma löschen, Stelle löschen, Faktor einrichten
auswahl/Auswahl.tsx (Client: Mehrfachauswahl mit Maus und Tastatur: Klick, Umschalt/Strg-Klick, Strg+A, Esc; Leiste unten mit Aktionen und „{n} ausgewählt“)neu (P Auswählen)neu: auswahl-leiste, ist-gewaehlt (gibt es in B nicht; nur vorhandene Farbwerte)Stellen (Firma), Bewerbungen (Firma), Postfach beider Seiten („Als gelesen markieren“, G82); Merkliste erst, wenn gewünscht (1b W1)
listenfeld/ListenFeld.tsx (Textfeld „ein Punkt je Zeile“ → text[]; Vorschau als ul)firmen-bereich.html:176 (Textarea)feld, feld-zeile (css:613)Stellenformular (Aufgaben, Brauchen, Gut nicht nötig, Bieten)
live/LiveClient.tsx (Abfrage alle 60 s über GET /api/live?seit=; SSE erst 2b.9), typen.tsneubeide Bereiche (Layout), Reiter-Zahlen
zeitstrahl/Zeitstrahl.tsx (Bewerber T 5.2), Verlauf.tsx (Firma T 5.3)neuschritte (1b css:368–375 als Vorlage)Bewerbung beide Sichten
faktor/FaktorEinrichten.tsx (Client: Wahl App oder E-Mail-Code; App: QR + Geheimnis, Code, danach Wiederherstellungscodes mit „Codes als Datei speichern“; E-Mail: Code senden, Code, fertig ohne Wiederherstellungscodes, F3), CodeFeld.tsx (6 Ziffern, one-time-code), CodeErneut.tsx (Textlink mit 60-Sekunden-Sperre, nur Art mail)neu, Felder wie anmelden.html:127–133formular, feld, passwort (css:614–616)Anmelden/faktor, Einstellungen, Bewerben-Fenster (Code im Schritt 1), Verwaltung faktor-einrichten (nur App, Karte 3)
kennwortbestaetigung/KennwortBestaetigen.tsx (Client: kleines Fenster T gemeinsam.kennwortBestaetigen.titel „Zur Sicherheit: Ihr Kennwort“, .text, Feld, .knopf „Weiter“; Server-Aktion kennwortBestaetigen(kennwort) setzt sitzungen.kennwort_bestaetigt_am; Konto ohne Kennwort (C36): dasselbe Fenster mit T .titelCode „Zur Sicherheit: Code an {mail} senden“, .textCode, Knopf .codeSenden, dann Code-Feld aus faktor/CodeFeld (A12 Fassung bestaetigen, faktorMail.ts Zweck bestaetigen) und codeBestaetigen(code), das dieselbe Spalte setzt; gilt 5 Minuten, danach fragt die nächste heikle Aktion erneut), mitKennwort(aktion) (Hülle, die eine Server-Aktion ablehnt, wenn kennwort_bestaetigt_am älter als 5 Minuten ist: fehler.kennwortBestaetigen.noetig)neu (26.10., _planung/sicherheit.md Nr. 9; Fenster-Rahmen aus fenster/)dialog, formular, feld, passwortFaktor abschalten, umstellen, Codes neu erzeugen (1.9 Nr. 4), Konto löschen (1.9 Nr. 8, ersetzt das Kennwortfeld im Fenster), Firma löschen (1.13), Verwaltung: Firma löschen, Bewerberkonto löschen, E-Mail-Adresse ändern (Karte 3 1.4) · H141
papierkorb/PapierkorbListe.tsx (Client: Zeilen mit Art-Chip, Name, „gelöscht {datum} · noch {m} Tage“, Knöpfe „Wiederherstellen“ und „Endgültig löschen“ je Zeile, keine Mehrfachauswahl (1.17, C18); Kopf-Knopf „Papierkorb leeren“ mit Fenster), PapierkorbLink.tsx (Textlink „Papierkorb ({n})“ unter einer Liste, nur bei n > 0)firmen-bereich.html:140–149 (Zeilen-Optik), stelle.html:103–112 (Fenster)zeile, status (Chip), btn-rand, btn-text, auswahl-leiste (aus auswahl/), Leerzustand 1a/firma/papierkorb, /konto/papierkorb (1.17); Link unter Stellen (Firma), Job-Alarme, Bewerbungen (Bewerber); Konto-Menü

Erweiterungen vorhandener Bausteine: seitenrahmen/Kopf.tsx (1a) bekommt den Konto-Zustand (Anmelden-Knopf ↔ KontoMenue; „Stelle inserieren“ zielt für Firmennutzer auf /firma/stellen/neu); Stellenkarte.tsx Variante „vorschau“ (Formular rechts) und „firma“ (Zeile in der Stellenliste mit Status-Chip); Fehlerseite.tsx Fälle „gesperrt (Firma, Konto)“, „Rechte“; kontaktformular/ unverändert; stelle/[adresse]/page.tsx (1a) bindet _bewerben/BewerbenDialog.tsx ein und zeigt am Platz des Bewerben-Knopfes als Text „Beworben am {datum} · Stand ansehen“ bzw. „Sie haben hier eine Bewerbung angefangen. Weiter“ (U A.2) sowie die Firmen-Vorschau (?vorschau=, nur Firmennutzer der Firma und Verwaltungsrollen nomad/verwaltung, Karte 3 1.4 Nr. 3).

2.2 Fachlich und Dienste (neu)

OrdnerDateienInhalt
dienste/auth/better-auth.ts (Konfiguration: E-Mail + Kennwort, TOTP-Plugin, Sitzungen 30/14 Tage, „angemeldet bleiben“), sitzung.ts (sitzung() auf dem Server → {konto, firma?, rolle}, erforderlich(rolle)), kennwort.ts (Argon2id über Better Auth; Regel 10 bis 128 Zeichen, keine Zwangs-Sonderzeichen; Prüfung gegen dienste/auth/haeufige-kennwoerter.txt (100.000 Einträge, im Projekt, kein Dienst eines Dritten; Datei im Bau in ein Set geladen) und gegen E-Mail, Vorname, Nachname), geraete.ts (Sitzungen auflisten/beenden; Gerätekennung aus der Browser-Kennung; neuesGeraet(kontoId, kennung) prüft gegen konto_geraete der letzten 12 Monate und trägt die Kennung nach jeder erfolgreichen Anmeldung dort ein), anmeldungen.ts (anmeldungSchreiben({kontoId?, mail?, ip, geraet, ergebnis}), wartezeit(kontoId, ip) → Sekunden aus den Fehlversuchen der letzten 15 Minuten: ab 5 Fehlversuchen 60 s, je weiterem verdoppelt, höchstens 900 s), ip.ts (echte IP aus X-Forwarded-For, nur wenn die Anfrage von einem Host aus VERTRAUTE_WEITERLEITER kommt, sonst die Verbindungs-IP; Karte 0 Teil 4), faktorMail.ts (Code erzeugen, senden über A12, prüfen, 3 je 15 Minuten)Better Auth mit Drizzle-Adapter; Tabellen in Teil 3. Verwaltungs-Rollen erst Abschnitt 3 (Faktor-Pflicht dort erzwungen, nur App). Sicherheits-Prüfliste _planung/sicherheit.md Nr. 9 bis 13.
fachlich/konto/anlegen.ts (kontoAnlegen von der Seite Registrieren mit Kennwort und B01; kontoAnlegenMitCode aus dem Bewerben-Fenster ohne Kennwort, bestaetigt_am sofort, C36; bestätigen per POST der Zielseite, erneut senden), felder.ts, loeschen.ts, export.ts (ZIP), einstellungen.ts (Benachrichtigungen, Sprache), faktor.ts (einrichten, prüfen, Codes, abschalten), kennwortSetzen.ts (erstes Kennwort für Konten ohne Kennwort, 1.9 Nr. 3), token.ts (Hash, Zwecke: bestaetigen, kennwort, einladung, export, sichern)
fachlich/bewerbung/anlegen.ts (bewerbungSenden; Entwurf → Bewerbung; Zustände; Einwilligung), entwurf.ts (bewerbungsEntwurfSpeichern/lesen; verwerfen legt in den Papierkorb 1.17; stiller Verfall 7 Tage), status.ts (gesichtet beim Öffnen durch Firmennutzer; einladen, zusage, absage mit Nachricht; zurueckziehen mit Rückgängig-Frist = verzögerte Ausführung; erste Einladung, Zusage, Absage oder Nachricht der Firma setzt erste_antwort_am), liste.ts (bewerbungenBewerber, bewerbungenFirma mit Filtern), notizen.ts, felder.ts (Typ, Status je Sicht)Verzögerte Aktionen (Rückgängig) laufen über dienste/verzoegert.ts (pg-boss-Job mit fester Frist einstellungen.fristen.rueckgaengig_sekunden, Standard 10, Karte 3 D23; abbrechbar; der Auftrag trägt Konto, Firma und Rolle des Auslösers und prüft darf() beim Ausführen erneut, bricht still ab, wenn die Bewerbung inzwischen zurückgezogen, die Firma gesperrt oder die Person entfernt ist; End-Check Befund 9) statt im Browser (so wirkt Rückgängig auch nach Tab-Wechsel, Annahme C6).
fachlich/einladung/anlegen.ts (Termin, Ort/Link, Ansprechperson; ICS erzeugen), antworten.ts (zusagen, andererTermin, absagen → Nachricht + F05), ics.ts (RFC 5545, Europe/Berlin), erinnerung.ts (Vortag, Hintergrund)
fachlich/nachricht/senden.ts (Bewerber ↔ Firma, Schreibschutz-Regeln), lesen.ts (gelesen_am je Sicht, ungelesen-Zähler Firma gemeinsam), liste.ts (Postfach beide)
fachlich/stelle/ergänzt: schreiben.ts (entwurfSpeichern je Feld, veroeffentlichen mit Prüfung, kopieren, beenden mit Rückgängig, verlaengern, erneutSchalten, loeschen), rechte.ts (Rolle × Handlung, P Rechte), vorschau.ts (Stelle für die Firma vor Veröffentlichung), ablauf.ts (Hintergrund: laeuft_ab-Mail, abgelaufen = pausiert ohne Frist, offene Bewerbungen pausierter Stellen nach 6 Monaten abschließen; die Stelle selbst bleibt)1a abfragen.ts bleibt.
fachlich/papierkorb/liste.ts (Einträge je Bereich: Firma aus stellen und bewerbungs_notizen, Bewerber aus job_alarme und bewerbungs_entwuerfe, je geloescht_am gesetzt; ersetzte Lebenslauf-Dateien nie, 1.7 Nr. 3), loeschen.ts (in den Papierkorb legen: geloescht_am, geloescht_von; verzögert über dienste/verzoegert.ts für Rückgängig), wiederherstellen.ts (geloescht_am leeren, Folgen je Art nach 1.17 Nr. 5), endgueltig.ts (Zeile löschen; Stelle mit Bewerbungen bleibt als zustand geloescht hinter ihren Bewerbungen bis zu deren Frist; Datei erst, wenn keine Bewerbung mehr auf sie zeigt), leeren.ts (alle Einträge des Bereichs endgültig)Rechte: wer löschen darf, darf wiederherstellen und endgültig löschen (fachlich/rechte.ts); fristen.ts ruft endgueltig.ts nach papierkorb_tage.
fachlich/firma/ergänzt: registrieren.ts, profil-schreiben.ts (Feld sofort), logo.ts, team.ts (einladen, annehmen, rolle, entfernen mit Übernahme der Stellen, faktorPflicht), loeschen.ts (Firma löschen: Stellen, Bewerbungen, Nutzer, F18), rechte.ts (gemeinsam mit stelle/rechte.ts: eine Tabelle rolle × handlung)
fachlich/datei/hochladen.ts (Stream auf verschlüsselten Datenträger, Typ am Inhalt, Größe und Pixelmaße je Zweck prüfen, bei JPG die Metadaten-Segmente ohne Neukodierung entfernen; kein Verkleinern auf dem Server (N-2, C35); einziger Rückfall: HEIC → JPG mit Verkleinerung, nur für Zweck lebenslauf, nur wenn der Browser es nicht konnte, höchstens 3 je Konto und Tag), pruefen.ts (ClamAV-Anbindung, Zustand geprueft/gesperrt), ausliefern.ts (Rechte: Eigentümer, Firma der Bewerbung, Verwaltung mit Grund; dazu der Fall „öffentlich“ ohne Sitzung, nur für geprüfte Dateien dieser Zwecke: logo (geprüft genügt), werbemotiv einer Kampagne im Zustand geplant oder laeuft, ratgeberbild eines veröffentlichten Inhalts (Zwecke aus Karte 3); alles andere nie öffentlich), loeschen.tsVirenprüfung gestört → Datei bleibt gesperrt (P Dateien).
fachlich/zaehler/ungelesen.ts (Zähler aus den Fachtabellen: neue Bewerbungen, ungelesene Nachrichten; gelesen beim Seitenwechsel und alle 60 Sekunden, kein Dauer-Strom, Live-Strom erst 2b.9)
fachlich/rechte.tsdarf(sitzung, handlung, ding): jede Aktion und jede Seite prüft selbst (P Sicherheit, doppelt mit RLS)Tabelle Rolle × Handlung in Teil 4.
dienste/db/rls.tsRollen und Rechte nach Karte 0 Teil 7 (einzige Quelle: bululu_<u>_oeffentlich, _formular, _konto, _verwaltung, _hintergrund); hier nur SET LOCAL app.konto_id / app.firma_id / app.support_id / app.stufe in der Transaktion der Anfrage auf dem Pool der Rolle (dienste/db/client.ts, ein Pool je Rolle); Policies je Tabelle (Teil 3)eigene Datei db/migrationen/0003_rechte.sql; Test rls.test.ts: zwei Anfragen nacheinander auf demselben Pool erben nichts voneinander
dienste/mail/vorlagen/b01, b05, b07–b14 (Bewerber; B02 bis B04 entfallen, C36; B06 ist bewusst keine Mail; B15–B17 Job-Alarm aus 1b, B18/B19 mit Abschnitt 3), a01–a03, a05–a07, a09 (Konto; A04/A08 mit Abschnitt 3), f01–f09, f18–f21 (Firma; F10–F17 kommen mit Abschnitt 3) als React-E-Mail mit Text-Fassung, ICS-Anhang bei Einladung; versand-regel.ts (Benachrichtigungs-Einstellung je Konto, „immer“-Arten)Nummern nach T 6.2–6.4; Sammelmail „neue Bewerbungen täglich“ als Hintergrund-Aufgabe
dienste/verzoegert.tsverzögerte Jobs (Rückgängig); dienste/sse.ts erst 2b.9
hintergrund/aufgaben/konto-unbestaetigt.ts (unbestätigte Konten von der Seite Registrieren ohne Bewerbung nach 30 Tagen löschen; keine B01 aus dem Bewerben-Fenster mehr, C36), stellen-ablauf.ts (F08 5 Tage vorher, F09 abgelaufen = pausiert; offene Bewerbungen auf Stellen, die seit einstellungen.fristen.pausiert_abschluss_monate (6) abgelaufen sind, abschließen mit B14, 14 Tage davor Zeile in „Heute zu tun“; die Stelle selbst bleibt pausiert), bewerbungen-sammel.ts (F04 täglich um einstellungen.job_alarm_versandzeit (07:00, 1b) gesammelt für Nutzer mit Einstellung „täglich“), einladung-erinnerung.ts (B09 am Vortag eines zugesagten Gesprächs), merkliste-ablauf.ts (B13 genau am Tag „laeuft_bis minus einstellungen.fristen.ablauf_mail_tage“ (5, wie F08), nur wenn keine Bewerbung des Kontos auf die Stelle besteht; einmal je Eintrag über merkliste_konto.erinnert_am, mehrere Stellen desselben Kontos am selben Tag in einer Mail), fristen.ts (Bewerbungen 6 Monate nach Abschluss, Konten 24 Monate ohne Anmeldung: A07 + 3 Monate, Papierkorb-Einträge von Firma und Bewerber nach einstellungen.fristen.papierkorb_tage (30, Karte 3) endgültig über fachlich/papierkorb/endgueltig.ts), datenexport.ts (A05)pg-boss wie 1a
dienste/uebersetzung/azure.ts (Azure AI Translator, HTML-Modus, Zeitlimit, Zeichenzählung), stummel.ts (Tests), index.ts (wählt nach Umgebung)1.18 Nr. 2; Schlüssel aus Karte 0 Teil 4; nur die sechs Textfelder der Stelle, keine Personendaten
hintergrund/aufgaben/stellen-uebersetzen.tsWarteschlange uebersetzung, Parallelität 1, Verzögerung 2 Minuten, 3 Versuche mit Rückzug; schreibt stellen_uebersetzungen, einstellungen.uebersetzung.letzte_am / .fehler_anzahl; Protokoll bei Fehler1.18 Nr. 3; Auslöser in fachlich/stelle/schreiben.ts
sprachen/{de,en,tr}/anmelden.json, bewerben.json, konto.json, firma.json, status.json, mail-*.jsonSchlüssel aus T 1.4, 1.6, 1.7, 1.8, 2, 3, 4, 5, 6, 7.1, 7.2

2.3 Nur in 2a (seitenspezifisch)

OrtDateien
(oeffentlich)/anmelden/page.tsx · _formular/Anmelden.tsx · Registrieren.tsx · FirmaRegistrieren.tsx (alle Client) · kennwort/page.tsx · kennwort-neu/page.tsx · faktor/page.tsx
(oeffentlich)/konto/bestaetigt/page.tsx · (oeffentlich)/einladung/page.tsxZielseiten aus Mails
(oeffentlich)/stelle/[adresse]/_bewerben/BewerbenDialog.tsx · Schritt1.tsx · Schritt2.tsx · Schritt3.tsx · Erfolg.tsx · EntwurfZeile.tsx · (oeffentlich)/stelle/[adresse]/bewerben/page.tsx (ohne JS)
(konto)/layout.tsx · mein-bereich/page.tsx · _uebersicht/IhreBewerbungen.tsx · Gemerkt.tsx · bewerbungen/page.tsx · _liste/BewerbungenListe.tsx · Filter.tsx · bewerbungen/[id]/page.tsx · _bewerbung/Kopf.tsx · Einladung.tsx (Client) · Unterlagen.tsx · Zurueckziehen.tsx (Client) · AbsageAehnliche.tsx · postfach/page.tsx · postfach/[bewerbungId]/page.tsx · lebenslauf/page.tsx · _lebenslauf/Persoenliches.tsx (Client) · Datei.tsx (Client) · job-alarme/page.tsx · _alarme/AlarmListe.tsx · AlarmNeu.tsx
(konto)/konto/einstellungen/page.tsx · _einstellungen/Benachrichtigungen.tsx · Bedienung.tsx · Kennwort.tsx · Faktor.tsx · Geraete.tsx · Einwilligungen.tsx · Export.tsx · Loeschen.tsx (Client je Karte)
(firma)/layout.tsx · firma/page.tsx · _uebersicht/IhreStellen.tsx · ErsteSchritte.tsx · stellen/page.tsx · _liste/StellenListe.tsx (Client, Auswahl, Gruppen) · ZeilenMenue.tsx · stellen/[id]/page.tsx · _stelle/Kopfreihe.tsx · stellen/neu/page.tsx · stellen/[id]/bearbeiten/page.tsx · _formular/StellenFormular.tsx (Client) · Vorschau.tsx · Ansprechperson.tsx · bewerbungen/page.tsx · _liste/BewerbungenFirma.tsx (Client, Auswahl) · bewerbungen/[id]/page.tsx · _bewerbung/Kopf.tsx · Knoepfe.tsx (Client, Fenster mit Vorlage) · Verlauf.tsx · Unterlagen.tsx · Notizen.tsx (Client) · VorherigeNaechste.tsx · postfach/page.tsx · postfach/[bewerbungId]/page.tsx · profil/page.tsx · _profil/Logo.tsx · Stammdaten.tsx · UeberUns.tsx · Ansprechperson.tsx · FirmaLoeschen.tsx · team/page.tsx · _team/Liste.tsx · Einladen.tsx · FaktorPflicht.tsx
app/api/live/route.ts · app/api/datei/[id]/route.ts · app/api/kalender/[id].ics/route.ts · app/api/auth/[...all]/route.ts (Better Auth)
db/migrationen/0003_konten.sql + rueckweg · 0003_rechte.sql (RLS) · musterdaten/konten.ts · bewerbungen.ts · firmen-nutzer.ts · nachrichten.ts

Nicht übernommen aus B (bewusst): Reiter „Übersicht“, „Neue Stelle“, „Einstellungen“ als Reiter (P Menüs); „…“-Menü mit Rechnungen, Statistiken, Pakete (gibt es nicht); Premium-Band mit „Pakete ansehen“ (firmen-bereich.html:134–137); Import-Zeile „Link übernehmen“ (:158–163); KI-Knopf (:175, 2b); Rollen-Radios auf Anmelden (:112–120); Deckblatt-Wahl, Mappe-PDF, Stationen (mein-bereich.html:165–180, 2b); Haken „Betriebe dürfen mich ansprechen“ (:190, kommt als Schalter mit; Status-Select in der Bewerber-Zeile (Aktionen im Detail, P); Inline-Styles (Klassen).

3

Datenmodell-Ergänzung

Was Bululu zu Konten, Bewerbungen, Nachrichten, Einladungen, Dateien und Teams speichert und wer was sehen darf.

Dieser Abschnitt beschreibt nur die technische Umsetzung. Mit dem Schalter „Technische Angaben“ blenden Sie ihn ein.

Migration db/migrationen/0003_konten.sql (+ Rückweg) und 0003_rechte.sql (RLS-Policies). Regeln wie 1a/1b (UUID v7, angelegt_am/geaendert_am, echte Felder). Better Auth bringt eigene Tabellen (user, session, account, verification, twoFactor); sie werden über den Drizzle-Adapter auf die hier genannten Namen abgebildet (konten, sitzungen, konto_zugang, konto_tokens, faktor); abweichende Pflichtspalten von Better Auth bleiben zusätzlich (Annahme C7). konto_zugang: id, konto_id FK (cascade), anbieter text (zum Livegang nur „credential“), anbieter_konto_id text, kennwort_hash text leer (leer bei Konten ohne Kennwort, C36), angelegt_am, geaendert_am; eindeutig (anbieter, anbieter_konto_id). Das Probe-Paket 1a.2a bestätigt die Abbildung, bevor 2a.1 sie anlegt.

konten

FeldTypHinweis
iduuid PK
mailcitext, eindeutig
bestaetigt_amtimestamptz, leerleer = unbestätigt
anredeenum anrede: herr, frau, ohne; Standard ohnefür die Ansprechperson einer Stelle bei der Bundesagentur (Salutation); im Konto freiwillig
vorname, nachnametext, je ≤ 30Name für Begrüßung, Bewerbung, Team; Nachname ist bei der Bundesagentur Pflicht
telefontext, leerBewerbung liest hier (P Mappe)
wohnort, plz_idtext, FK plz, leerLebenslauf Persönliches
sprachetext (de/en/tr)Mails und Bereich
kennwort_hashtext, leer erlaubtArgon2id (Better Auth); leer bei Konten aus dem Bewerben-Fenster (C36): Anmelden dann per Code an die E-Mail (A12, Zweck anmelden), bis die Person in den Einstellungen ein Kennwort setzt
faktor_aktivboolean, Standard falsezweiter Faktor eingerichtet, Art in faktor.art (app oder mail, 1.9 Nr. 4); Geheimnis und Codes in faktor
lebenslauf_datei_iduuid FK dateien, leerLebenslauf in „Meine Unterlagen“; weitere Unterlagen sind dateien mit konto_id, zweck anhang, unterlage_art (zeugnis, zertifikat, fuehrerschein, sonstiges) und ohne bewerbung_id
sichtbar_fuer_betriebeboolean, Standard trueProfil für Betriebe und Ansprache; ohne Wirkung und ohne Oberfläche, bis 3BS mit Paket A4 funktionen.bewerberansprache einschaltet
zustandenum konto_zustand: aktiv, gesperrt, geloescht„unbestätigt“ ist kein Zustand, sondern bestaetigt_am leer; Entsperren setzt aktiv, bestaetigt_am bleibt, wie es war; gesperrt/entsperrt durch Verwaltung (3) mit sperr_grund
sperr_grundtext, leer
letzte_anmeldung_amtimestamptz, leerFrist 24 Monate
geloescht_amtimestamptz, leeranonymisiert: mail → „geloescht-{id}“, Name leer
Index(mail); (zustand, letzte_anmeldung_am)

konto_geraete: konto_id FK, kennung text (Browser-Name · Betriebssystem-Name, ohne Fassung, ohne IP), zuletzt_am timestamptz; Schlüssel (konto_id, kennung); geschrieben bei jeder erfolgreichen Anmeldung, gelesen von neuesGeraet() für Mail A13; Nachtlauf löscht Zeilen älter als einstellungen.fristen.geraete_monate (12); RLS wie konten; Konto löschen räumt sie mit.

sitzungen: id, konto_id FK, token_hash eindeutig, firma_id FK firmen leer (gewählte Firma), geraet text (Browser-Kennung, keine IP), anmeldung_id FK anmeldungen leer (die Anmeldung, aus der die Sitzung entstand; liefert der Geräte-Liste die gekürzte IP; bleibt leer, wenn die Zeile nach 30 Tagen gelöscht ist), kennwort_bestaetigt_am timestamptz leer (erneute Kennworteingabe, 5 Minuten, H141), laeuft_ab_am (30 Tage Bewerber-Sicht, 14 Tage sobald firma_id gesetzt), zuletzt_genutzt_am, faktor_bestaetigt boolean. Index (konto_id), (laeuft_ab_am).

faktor: konto_id PK, art enum faktor_art (app, mail; 26.10.), geheimnis_verschluesselt text leer (nur app), eingerichtet_am, codes_hash text[] (10 Wiederherstellungscodes, je Hash, verbraucht = entfernt), letzter_code_zeitpunkt (Wiederverwendung sperren, nur app).

faktor_mail_codes: id, zweck enum code_zweck, mail text (kleingeschrieben, Pflicht), konto_id FK leer (leer bei zweck bewerben, solange es noch kein Konto gibt), entwurf jsonb leer (nur bei bewerben: Vorname, Nachname, Zustimmung mit Textfassung und Zeit aus Schritt 1; wird beim richtigen Code zum Konto und zur Einwilligung, dann geleert), code_hash text, laeuft_ab_am (+10 Minuten), genutzt_am leer, fehlversuche smallint Standard 0 (5 → Code ungültig), angelegt_am; Index (mail, angelegt_am). Höchstens 3 Zeilen je Adresse und 15 Minuten (Bremse je Adresse, nicht je Konto; Prüfung im Code). Zeilen älter als 1 Stunde löscht fristen.ts, mit ihnen den Entwurf.

anmeldungen: id, konto_id FK leer (unbekannte Adresse: leer), mail_hash text leer (nur bei unbekannter Adresse, für die Bremse je Adresse), ip inet, geraet text (Browser und Betriebssystem grob, aus der Browser-Kennung), ergebnis enum anmelde_ergebnis (erfolg, kennwort_falsch, faktor_falsch, gebremst, gesperrt, neues_geraet), zeitpunkt timestamptz. Index (konto_id, zeitpunkt), (ip, zeitpunkt). 30 Tage (einstellungen.fristen.anmeldungen_tage, Karte 3 1.14), kein Export in „Meine Daten“ außer den eigenen Zeilen (Konto-Bezug). Lesen: die Person über die Geräte-Liste (gekürzte IP), die Verwaltung je Firma und Konto (Karte 3 1.16), der Alarm-Lauf, die Bremse, der Haken „auch IP-Adressen sperren“. RLS: die Konto-Rolle liest nur eigene Zeilen, schreibt nie direkt; dienste/auth/anmeldungen.ts schreibt beim Anmelden über die Datenbank-Funktion anmeldung_schreiben() mit der Rolle bululu_<u>_formular (Karte 0 Teil 7 „Schreiben ohne Anmeldung“).

konto_tokens: id, konto_id FK, zweck enum token_zweck (bestaetigen, kennwort, export, adresse_neu, sichern), token_hash eindeutig, wert text leer (neue Adresse), laeuft_ab_am, genutzt_am. Bestätigen 7 Tage, Kennwort 60 Minuten, Export 24 Stunden, Sichern 24 Stunden (A13).

einwilligungen: id, konto_id FK, art enum einwilligung_art (nutzung, weitergabe; die Sichtbarkeit für Betriebe ist ein Schalter, keine Einwilligung,, bezug_id uuid leer (Bewerbung bei weitergabe), textfassung_id uuid FK inhalte_fassungen_historie leer (Rechtstext-Fassung, Tabelle aus Karte 3; leer, solange der Text aus dem Einspielskript 1b stammt), textfassung text (Schlüssel des Rechtstexts + Stand-Datum, immer gefüllt), erteilt_am, widerrufen_am leer. Index (konto_id, art).

benachrichtigungen: konto_id FK, art enum benachr_art (nachricht = bnNachricht/fnNachricht, status = bnStand, merkliste_ablauf = bnMerkliste, bewerbung_neu = fnBewerbung mit takt, ablauf = fnAblauf für F08 und F09, premium = fnPremium; genau die Schalter aus T 1.7/6.4), an boolean, takt enum (sofort, taeglich) nur bei bewerbung_neu; PK (konto_id, art). Fehlende Zeile = an. Der Job-Alarm-Takt liegt in job_alarme.takt (1b), nicht hier.

firmen (ergänzt): ansprechperson_id uuid FK konten leer, recruiter_darf_ansprechen boolean Standard true, bieten text[] leer („Das bieten wir“ als Vorlage für neue Stellen, 1.13 Nr. 3), faktor_pflicht boolean Standard false, logo_datei_id bekommt den FK dateien (1a Platzhalter), bestaetigt_am (Mail-Bestätigung des ersten Admins; Kopie aus konten für Abfragen), geloescht_am.

firmen_nutzer: id, firma_id FK, konto_id FK, rolle enum firma_rolle (admin, recruiter), zustand enum (aktiv, entfernt), telefon_in_anzeigen boolean Standard false (Haken „Telefon in Anzeigen zeigen“, 1.14; 1a Arbeitgeber-Kasten liest ihn für die Ansprechperson der Stelle), eingeladen_von FK konten leer, beigetreten_am, entfernt_am. UNIQUE (firma_id, konto_id). Letzter Admin: Prüfung im Code + Trigger.

firmen_einladungen: id, firma_id FK, vorname, nachname (je ≤ 30, vom Admin eingetragen, werden beim Anlegen des Kontos übernommen), mail citext, rolle, token_hash eindeutig, eingeladen_von FK, laeuft_ab_am (7 Tage), angenommen_am leer, zurueckgezogen_am leer. Index (firma_id, mail).

stellen (ergänzt): ansprechperson_id bekommt den FK konten (Annahme C8), erstellt_von FK konten, geaendert_von, beendet_am, verlaengert_am, geloescht_am timestamptz leer (im Papierkorb, Lesen filtert; 1.17), geloescht_von FK konten leer, kopie_von FK stellen leer; die Rückfall-Felder ansprech_anrede/-vorname/-nachname/-telefon (1a Teil 3) bleiben für Stellen ohne Konto-Ansprechperson (Schnittstelle, Import); Stellen aus dem Formular füllen nur ansprechperson_id, Telefon kommt aus konten.telefon und erscheint nur mit firmen_nutzer.telefon_in_anzeigen (1a A21).

stellen_uebersetzungen (ergänzt, 1.18; Tabelle aus 1a Teil 3 mit titel, einleitung, aufgaben, brauchen, gut_nicht_noetig, bieten, stand, quelle_geaendert_am): zustand enum uebersetzung_zustand (wartet, fertig, fehler; Standard wartet), versuche smallint Standard 0, fehler_text text leer, uebersetzt_am timestamptz leer; Index (zustand) für den Lauf. Lesen in 1a abfragen.ts liefert nur zustand fertig. Löschfrist: Zeilen fallen mit der Stelle (FK on delete cascade, Karte 3 Fristen unverändert).

bewerbungs_entwuerfe: id, konto_id FK, stelle_id FK, telefon, nachricht, datei_ids uuid[], schritt smallint, angelegt_am, geaendert_am, geloescht_am leer (Papierkorb nach „Verwerfen“, 1.17); UNIQUE (konto_id, stelle_id); stiller Verfall nach 7 Tagen ohne Änderung löscht endgültig (Hintergrund), Einträge im Papierkorb erst nach papierkorb_tage.

bewerbungen

FeldTypHinweis
iduuid PK
konto_idFK kontenbleibt nach Kontolöschung (anonymisiertes Konto)
stelle_id, firma_idFKfirma_id Kopie für RLS und Listen
zustandenum bewerbung_zustand: neu, gesichtet, eingeladen, zusage, absage, zurueckgezogen, stelle_beendet, geloeschtT 5.1 übersetzt je Sicht; einen Zustand „wartet auf Bestätigung“ oder „verfallen“ gibt es nicht, weil der Code im Bewerben-Fenster die Adresse vor dem Senden bestätigt (C36)
name_stand, mail_stand, telefon_standtextMomentaufnahme beim Absenden (P Mappe: Kontaktzeile zeigt „aktuelle Nummer“, wenn konten.telefon abweicht)
nachrichttext, leeran den Betrieb
quelleenum quelle (1a Teil 3): direkt, google, job_alarm, merkliste, folgen, geteilt, unbekanntHerkunft der Bewerbung für die Arbeitgeber-Statistik nach dem Livegang: aus dem Adress-Parameter von der Stellenseite, den das Bewerben-Fenster beim Öffnen liest (ohne JS als verstecktes Feld der Seite /bewerben); ohne Parameter direkt. Kein Cookie, keine IP, kein Referrer
gesendet_amtimestamptz
bestaetigt_amtimestamptz, leerMail-Bestätigung → zustand neu, B05 an den Bewerber, F03/F04 an die Firma
geoeffnet_am, geoeffnet_vontimestamptz, FK konten, leererstes Öffnen durch Firmennutzer (nie Verwaltung)
erste_antwort_amtimestamptz, leererste Einladung, Zusage, Absage oder Nachricht der Firma; für „wartet seit {n} Tagen“ und die Antwortzeit (U C.2, U D)
entschieden_amtimestamptz, leerZusage/Absage/Rückzug/beendet
abgeschlossen_amtimestamptz, leerStart der 6-Monats-Frist
ungelesen_firma, ungelesen_bewerbersmallintZähler aus nachrichten (gepflegt per Trigger)
letzte_aenderung_amtimestamptzSortierung
Indizes(firma_id, zustand, letzte_aenderung_am desc); (konto_id, letzte_aenderung_am desc); (stelle_id, zustand); UNIQUE (konto_id, stelle_id) wo zustand not in (zurueckgezogen) (G60)

bewerbung_dateien: bewerbung_id FK, datei_id FK, reihenfolge; PK (bewerbung_id, datei_id).

bewerbungs_antworten: bewerbung_id FK, frage_id FK stellen_fragen, antwort_ja boolean leer, antwort_text text leer (≤ 500); PK (bewerbung_id, frage_id). Zum Livegang schreibt niemand hinein; RLS wie bewerbungen; Export und Löschfrist hängen an der Bewerbung.

bewerbungs_notizen: id, bewerbung_id FK UNIQUE (eine Notiz je Bewerbung, U 3.10), firma_id (Kopie), geaendert_von FK konten, text (2.000), angelegt_am, geaendert_am, geloescht_am leer (Papierkorb, 1.17), geloescht_von FK konten leer.

nachrichten: id, bewerbung_id FK, firma_id (Kopie), von enum (bewerber, firma), von_konto_id FK, text (4.000), datei_id FK leer (nur bewerber), gesendet_am, gelesen_am leer (Gegenseite; Firma gemeinsam), art enum (nachricht, system) (system = Statuswechsel-Zeilen im Verlauf). Index (bewerbung_id, gesendet_am).

einladungen: id, bewerbung_id FK, firma_id, termin_am timestamptz, dauer_min smallint Standard 60, ort text leer, online_link text leer, ansprechperson_id FK konten, nachricht_id FK nachrichten, zustand enum einladung_zustand (gesendet, zugesagt, abgesagt, neuer_termin, ersetzt), antwort_text leer, beantwortet_am leer, erinnert_am leer. Index (bewerbung_id), (termin_am) für Erinnerung.

dateien: id, konto_id FK leer (Eigentümer; Pflicht bei lebenslauf, bewerbung, anhang, logo; leer bei Dateien ohne Konto aus Karte 3: werbemotiv eines Werbekunden, zertifikat, ratgeberbild der Verwaltung), firma_id FK leer (Logo), zweck enum datei_zweck (lebenslauf, bewerbung, anhang, logo; Karte 3 ergänzt werbemotiv, zertifikat, ratgeberbild), unterlage_art enum leer (zeugnis, zertifikat, fuehrerschein, sonstiges; nur bei zweck anhang in „Meine Unterlagen“,, name_original, typ (erkannt), groesse_bytes, pfad text (verschlüsselter Datenträger, kein Pfad unter /public; Auslieferung nur über /api/datei/[id] und ausliefern.ts, öffentlich allein im dort beschriebenen Fall „öffentlich“), zustand enum datei_zustand (hochgeladen, geprueft, gesperrt, geloescht), geprueft_am, loeschen_ab date leer (ersetzte Lebenslauf-Datei nach der Rückgängig-Frist, 1.7 Nr. 3; Datei ohne Bewerbungsverweis: Ende der Frist, sonst Ende der letzten Bewerbungsfrist); kein geloescht_am: Dateien liegen nie im Papierkorb. Regel für die drei Lösch-Kennzeichen: zustand geloescht setzt nur der Fristen-Lauf beim physischen Löschen, loeschen_ab plant es, geloescht_am gibt es hier nicht. Index (konto_id, zweck), (zustand).

ereignisse (Live, erst 2b.9, nicht in 0003): id bigserial, zeitpunkt, konto_id leer, firma_id leer, art enum (bewerbung, nachricht, einladung, stelle), ding_id, daten jsonb (nur Anzeige-Felder: Titel, Name, Zustand; nie gefiltert, nur für den Strom). 24 Stunden, danach gelöscht. Index (konto_id, id), (firma_id, id).

merkliste_konto (1b angekündigt): konto_id FK, stelle_id FK, gemerkt_am, erinnert_am timestamptz leer (B13 gesendet); PK (konto_id, stelle_id).

job_alarme (1b): konto_id wird beim Anmelden gefüllt (Mail gleich), takt „keine“ nur mit konto_id (bereits 1b). Ergänzt: geloescht_am leer (Papierkorb nach „Löschen“ im Konto, 1.17); Versand (B15) und Listen lesen nur Zeilen ohne geloescht_am.

protokoll (1a): ab 2a geschrieben für: Faktor ein/aus/umgestellt (Art), Kennwort geändert (auch über „Konto sichern“), Konto gesichert (A13-Link genutzt), Konto gelöscht, Firma gelöscht, Nutzer entfernt, Stelle veröffentlicht/beendet/gelöscht (Papierkorb), Papierkorb wiederhergestellt/endgültig/geleert (Art und Kennung), Datei geöffnet (nur Verwaltung mit Grund, Abschnitt 3), Einwilligung erteilt/widerrufen.

einstellungen (ergänzt): fristen {bewerbung_monate: 6, konto_inaktiv_monate: 24, konto_inaktiv_nachfrist_monate: 3, entwurf_tage: 7, konto_unbestaetigt_tage: 30, einladung_team_tage: 7, pausiert_abschluss_monate: 6 (offene Bewerbungen auf einer pausierten Stelle abschließen, 1.11 Nr. 4); bewerbung_ohne_antwort_monate: 6; papierkorb_tage: 30 kommt aus Karte 3 und gilt auch für Firma und Bewerber}, sitzung {bewerber_tage: 30, firma_tage: 14; Karte 3 ergänzt verwaltung_stunden: 8}, funktionen (1a) um lebenslaufBaukasten: false, mappePdf: false, kiTexte: false, uebersetzung: true (zugesagt zum Livegang, 1.18; ohne AZURE_UEBERSETZER_SCHLUESSEL bleiben die Zeilen auf wartet und die Seite zeigt den deutschen Text); uebersetzung {anzeigen_automatisch: true, letzte_am: null, fehler_anzahl: 0} (Karte 3 1.11 Nr. 3 zeigt und schaltet sie).

RLS (0003_rechte.sql): Rollen nach Karte 0 Teil 7 (einzige Quelle); hier die Policies der Konto-Rolle bululu_<u>_konto: je Anfrage SET LOCAL app.konto_id und app.firma_id (gewählte Firma, nur wenn firmen_nutzer aktiv), im Support-Modus zusätzlich app.support_id (Karte 3 1.5). Policies: konten (eigene Zeile), sitzungen/faktor/konto_tokens/einwilligungen/benachrichtigungen (eigene), bewerbungen/nachrichten/einladungen/bewerbung_dateien (konto_id = eigene ODER firma_id = app.firma_id), bewerbungs_notizen (nur firma_id UND app.support_id leer), dateien (Eigentümer ODER über bewerbung_dateien die Firma; Logo: Firma), stellen, firmen (öffentlich lesen aktiv ODER eigene Bewerbung auf eine Stelle der Firma, auch bei gesperrter Firma lesend; schreiben nur eigene mit Rolle admin, Prüfung im Code), firmen_nutzer/firmen_einladungen (eigene Firma), merkliste_konto/job_alarme (eigene). Schreiben ohne Sitzung (Registrieren, Code anfordern, Zähler, Sicherheitsprotokoll) läuft nie über diese Rolle, sondern über die Funktionen der Rolle bululu_<u>_formular (Karte 0 Teil 7). Ein Test je Tabelle mit fremder Firma (Teil 4), dazu je Tabelle ein Test „nicht zu wenig“: Bewerber liest Titel und Firmenname einer beendeten Stelle und einer gesperrten Firma seiner Bewerbung.

3.2 Abfragen und Aktionen 2a (Signaturen)

  • Konto: kontoAnlegen({vorname, nachname, mail, kennwort, sprache, zustimmung}) → {kontoId} (Seite Registrieren, B01 sofort; gesperrte Adresse oder IP (Karte 3 gesperrt() in dienste/sperrliste.ts) → fehler.gesperrt.neutral, nichts schreiben), bewerbenCodeAnfordern({mail, vorname, nachname, zustimmung}) → ok (A12 Zweck bewerben, Bremse 3 je 15 Minuten, Honigfeld, Sperrliste wie kontoAnlegen) und kontoAnlegenMitCode({mail, code}) → {kontoId} (richtiger Code → konten mit bestaetigt_am, ohne Kennwort, Sitzung; C36), kontoStatus(mail) → 'neu'|'vorhanden' (gebremst 10 je IP und Stunde, nur im Bewerben-Fenster nach Honigfeld; verrät weder Faktor noch Kennwort, sicherheit.md Nr. 15), mailBestaetigen(token), bestaetigungErneut(kontoId) (60 s), adresseAendern(kontoId, neueMail) (nur unbestätigt), anmelden({mail, kennwort, bleiben}) (prüft die Sperrliste nicht, Karte 3 D44; prüft gesperrtes Konto, Wartezeit aus anmeldungen, schreibt anmeldungen, A13 bei neuem Gerät), faktorPruefen(code|wiederherstellungscode) (app und mail), faktorMailCodeSenden() (3 je 15 Minuten, A12), kennwortVergessen(mail) (immer gleiche Antwort), kennwortNeu(token, kennwort), kennwortAendern(alt, neu), kontoSichern(token) (alle Sitzungen beenden, dann kennwortNeu), faktorEinrichten(art) → {geheimnis, qr} | {gesendetAn}, faktorBestaetigen(code) → {codes[]}, faktorUmstellen() (mail → app, mit Kennwortbestätigung), faktorAbschalten() (mit Kennwortbestätigung), kennwortBestaetigen(kennwort) (5 Minuten), geraete(), geraetAbmelden(id), ueberallAbmelden(), einstellungSetzen(art, an, takt?), datenExport(), kontoLoeschen(kennwort).
  • Bewerbung: bewerbungsEntwurf(stelleId) → Entwurf|null, entwurfSpeichern(stelleId, felder), entwurfVerwerfen(stelleId) (verzögert, Papierkorb), dateiHochladen(zweck, datei) → {dateiId, zustand}, bewerbungSenden({stelleId, telefon, dateiIds, nachricht, einwilligung, quelle}) → {bewerbungId, zustand}, bewerbungenBewerber(filter), bewerbung(id) (Sicht nach Rolle), bewerbungZurueckziehen(id) (verzögert 10 s, rueckgaengig(jobId)), einladungAntworten(id, antwort, text?), nachrichtSenden(bewerbungId, text, dateiId?), gelesenSetzen(bewerbungId).
  • Firma: firmaRegistrieren({betrieb…, zugang…}) → {firmaId} (firmen.adresse über 1a firmenAdresseBilden(name, ort); gesperrte Adresse wie kontoAnlegen), profilFeldSpeichern(feld, wert) (name oder ort → neue adresse, alte in firmen_adressen), logoSetzen(dateiId), teamEinladen(mail, rolle), einladungAnnehmen(token), rolleAendern(nutzerId, rolle), nutzerEntfernen(nutzerId) (verzögert nach Rückgängig-Frist; Übernahme der Stellen), faktorPflichtSetzen(an), firmaLoeschen(kennwort).
  • Stellen: stellenFirma(filter, sort), stelleEntwurfAnlegen(vorbelegung?) → {stelleId}, stelleFeldSpeichern(stelleId, feld, wert), stelleVeroeffentlichen(stelleId) → {zustand: 'aktiv'|'pruefung'} | {fehler[]} (eine Transaktion: Pflichtprüfung, Zustand nach noetig.ts bzw. immer pruefung aus nachbessern (C22), firmen.zustand registriert → aktiv, bei pruefung pruefungAnlegen() aus Karte 3 + F21, Protokoll), stelleKopieren, stelleBeenden (verzögert, B14), stelleVerlaengern (laeuft_bis = heute + laufzeit_tage; aktiv, läuft ab oder pausiert, ohne zeitliche Grenze), stelleErneutSchalten (nur beendet), stelleLoeschen (Admin; verzögert, in den Papierkorb).
  • Bewerbungen Firma: bewerbungenFirma({stelleId?, zustand?, seite}), bewerbungOeffnen(id) (setzt gesichtet, nur Firmennutzer), einladen(id, {termin, ort|link, ansprechpersonId, text}), zusage(id, text), absage(id, text) und einladen (verzögert nach Rückgängig-Frist), neuerTermin(id, …), notizSpeichern(bewerbungId, text) (sofort), notizLoeschen(bewerbungId) (verzögert, Papierkorb), absageMehrere(ids, text).
  • Papierkorb (1.17): papierkorb(bereich: 'firma'|'konto') → {eintraege[]}, papierkorbWiederherstellen(ids), papierkorbEndgueltig(ids), papierkorbLeeren(bereich); hinein legen die bestehenden Aktionen stelleLoeschen, notizLoeschen, jobAlarmLoeschen(id) (1b, ergänzt um geloescht_am), entwurfVerwerfen,; alle verzögert nach Rückgängig-Frist (C6).
  • Live: GET /api/live?seit={zeitpunkt} (Abfrage alle 60 s; SSE mit Last-Event-ID erst 2b.9).
  • Zählung (1a zaehle): bewerbung_gesendet {fachbereich, mitKonto}, konto_angelegt {quelle}, firma_registriert, stelle_veroeffentlicht, einladung, absage, zusage; keine IP, keine Konto-Kennung in den Zählern.
4

Handlungen je Rolle in 2a

Jeder Knopf für Bewerber, Admins und Recruiter mit Wirkung, Rechten und dem Test, der ihn absichert.

Aus der Aktionen-Matrix (FUNKTIONEN-CHECK, Bewerber und Firma) und P Rechte. Nummern laufen nach 1b weiter (H55 ff.). Tests wie 1a/1b ohne Browser (PGlite mit RLS-Policies, Testing Library im jsdom); Mails aus der Warteschlange gelesen; je Endpunkt ein Test mit der Sitzung einer fremden Firma (P Sicherheit) in pruefung/rechte/fremde-firma.test.ts.

Rolle × Handlung (Firma) (P Rechte, FC 15): Admin alles; Recruiter: Stellen anlegen, bearbeiten, veröffentlichen, kopieren, verlängern, beenden, erneut schalten, Top-Haken (3), Bewerbungen öffnen, einladen, zusagen, absagen, Notizen, Postfach; nicht: Stelle löschen, Firmenprofil (nur Link „So sehen Bewerber Ihren Betrieb“), Team, Premium anfragen (3), Firma löschen. Verstoß → fehler.rechte.recruiter (T 4.4), Server lehnt ab (nicht nur ausgeblendet). Papierkorb (1.17): wer etwas löschen darf, darf es wiederherstellen und endgültig löschen; der Recruiter sieht im Firmen-Papierkorb nur Notizen (Stellen und Entwürfe löscht nur der Admin), der Admin alles.

NrRolle · BildschirmKnopf/Link (Wortlaut T)WirkungTest (Datei · prüft)
H55Besucher · Anmelden„Anmelden“Sitzung (30 Tage, „Angemeldet bleiben“), Weiterleitung weiter= nur eigene Adressen; Faktor → /anmelden/faktor; Zeile in anmeldungen; die Sperrliste prüft das Anmelden nicht (Karte 3 1.15 Nr. 3, D44); gesperrtes Konto → fehler.gesperrt.konto; wachsende Wartezeit je Konto, je IP erst ab 50 Fehlversuchen mit eigenem Satz (H140)pruefung/seiten/anmelden.test.ts · falsches Kennwort fehler.anmelden.falsch, 5 Fehlversuche in 15 Minuten → fehler.versuche.anmelden mit 1 Minute, danach 2, 4 … bis 15 Minuten, nach 15 Minuten ohne Versuch wieder frei; IP auf der Sperrliste → Anmeldung geht trotzdem; fremde Adresse in weiter → /mein-bereich
H56Besucher · Anmelden„Konto anlegen“konten (zustand aktiv, bestaetigt_am leer), B01 in Warteschlange, Zielseite „Konto angelegt“; vergeben → fehler.feld.mailVergeben (kein Hinweis, ob Konto existiert, nur im Registrieren-Modus)anmelden.test.ts + pruefung/fachlich/konto/anlegen.test.ts · Kennwort < 10 Zeichen, Zustimmung Pflicht, Honigfeld still
H57Besucher · Firma registrieren„Firma registrieren“konten + firmen (registriert) + firmen_nutzer (admin), F01, Zielseite; mit weiter=stelle-neu Merker in Sitzungpruefung/seiten/firma-registrieren.test.ts · Ort unbekannt, zweites Registrieren derselben Mail → Anmelden-Hinweis, inseratEntwurf wird nach Bestätigung zur Entwurfs-Stelle
H58Alle · Mail B01/F01Link → Zielseite (nur Anzeige, „Fast geschafft: noch ein Tipp“) → Knopf „Ja, {mail} ist meine Adresse“GET ändert nichts; POST setzt bestaetigt_am; Zielseite mit Knopf in den Bereich; Token 7 Tage (sicherheit.md Nr. 29)pruefung/seiten/konto-bestaetigt.test.ts · zweiter Klick harmlos, abgelaufen → fehler.link.abgelaufen
H59Alle · Kennwort„Link anfordern“ · Mail A01 „Neues Kennwort“ · „Kennwort speichern“gleiche Antwort ob Konto oder nicht; Token 60 min; neues Kennwort beendet andere Sitzungen, A02pruefung/fachlich/konto/kennwort.test.ts · unbekannte Mail sendet nichts, Token einmalig
H60Alle · Faktor (App)„Bestätigen“ (Code) · „Wiederherstellungscode nutzen“Sitzung faktor_bestaetigt, Token-Wechsel; Code verbraucht; 5 Fehlversuche → 15 Minutenpruefung/fachlich/konto/faktor.test.ts · TOTP-Fenster ±1 Schritt, Wiederverwendung desselben Codes abgelehnt, Code-Liste schrumpft
H61Besucher/Bewerber · Stelle„Jetzt bewerben“ → Fenster Schritt 1 „Mit dieser E-Mail weiter“ · „Code an {mail} senden“ · „Mit Kennwort anmelden“ · „E-Mail ändern“ · „Code erneut senden“ · „Kennwort vergessen?“ im Fenster (N-1)kontoStatus (nur neu/vorhanden); neu: Name + Zustimmung → A12 (Zweck bewerben) → richtiger Code → Konto ohne Kennwort, bestaetigt_am gesetzt, Sitzung (C36); vorhanden (gleich, ob mit oder ohne Kennwort, damit niemand erfährt, welcher Fall vorliegt): Hauptknopf „Code an {mail} senden“ (A12, Zweck anmelden) und Textlink „Mit Kennwort anmelden“, der Kennwortfeld und „Kennwort vergessen?“ aufklappt, danach ggf. zweiter Schritt; Code-Schritt mit voller Adresse und „E-Mail ändern“; angemeldet: Schritt übersprungen; Kennwort vergessen: A01 mit weiter=/stelle/[adresse]#bewerben, Fenster bleibt offen, Satz „Link unterwegs“pruefung/seiten/bewerben.test.ts · vier Wege, vorhandenes Konto mit und ohne Kennwort zeigt denselben Aufbau (Code-Knopf vorn), „E-Mail ändern“ führt zurück und behält den Namen, Zustimmung Pflicht bei neu, falscher Code 5× → verfallen, 3 Codes je 15 Minuten, Konto entsteht erst nach richtigem Code, kontoStatus verrät keinen Faktor, Faktor-Konto verlangt Code; pruefung/fachlich/konto/kennwort-link.test.ts · A01 in der Warteschlange mit weiter-Adresse, fremde weiter-Adresse verworfen, Link öffnet Stelle mit Fenster Schritt 2
H62Bewerber · Fenster Schritt 2Ablage, „Andere Datei wählen“, „Weitere Seite fotografieren“, „Weiter zum Absenden“Browser verkleinert Fotos vor dem Hochladen (N-2); dateien (hochgeladen → geprueft), Entwurf gespeichert; Telefon Pflicht; alle Unterlagen aus „Meine Unterlagen“ angehakt, abwählbar; neue Datei mit „Auch für künftige Bewerbungen speichern“ landet im Kontobewerben.test.ts + pruefung/bausteine/ablage/verkleinern.test.ts (Testbild 4.000 px → längste Kante 2.000 px, JPG, ohne EXIF; Fehler → Originaldatei) + pruefung/fachlich/datei/hochladen.test.ts · Typ am Inhalt (PDF mit .jpg-Namen), 11 MB abgelehnt fehler.datei.zuGross, 5.000 px abgelehnt fehler.datei.bildZuGross, JPG-Metadaten entfernt, HEIC → JPG nur im Rückfall, Server verkleinert sonst nichts
H63Bewerber · Fenster Schritt 3„Bewerbung senden“bewerbungen neu, einwilligungen weitergabe, B05, F03/F04 je Einstellung sofort/täglich an alle Firmennutzer mit dieser Einstellung; Erfolg mit Fokus; Entwurf gelöschtpruefung/fachlich/bewerbung/anlegen.test.ts · zweite Bewerbung auf dieselbe Stelle fehler.bewerben.schonBeworben, Stelle nicht öffentlich sichtbar (istOeffentlichSichtbar() false: weder aktiv noch pruefung, oder Firma gesperrt) → fehler.bewerben.stelleWeg, Stelle in pruefung → Bewerbung geht durch, Einwilligung mit Textfassung gespeichert, unbestätigt → keine F03
H64Bewerber · Fenster Schritt 1 (Code)Code-Feld → „Weiter zum Lebenslauf“ · „Code erneut senden“A12 Zweck bewerben in der Warteschlange (Vorrang); richtiger Code legt das Konto an (bestaetigt_am, kein Kennwort) und öffnet Schritt 2; falscher Code fehler.faktor.falschMail, 5× verfallen; erneut frühestens nach 60 s (C36)pruefung/fachlich/konto/code.test.ts · Code 10 Minuten, einmalig, Bremse 3 je 15 Minuten, Mail A12 in der Fassung des Zwecks
H65Bewerber · Fenster schließenSchließen-Knopf, EscEntwurf bleibt 7 Tage; Toast; vor dem Code geschlossen: kein Konto; nach dem Code geschlossen: Konto besteht bestätigt, keine Mail (C36)bewerben.test.ts · Entwurf nach Wiederöffnen vorbelegt; kein Konto ohne Code
H66Bewerber · Übersicht„Jetzt wichtig“-Knöpfe, „Ihre Bewerbungen“, „Gemerkt“ (je „Bewerben“), „Stellen suchen“ (nur im Leer-Satz), „Erneut senden“Ziele; Reihenfolge nach T 7.1; 60 s Sperrepruefung/seiten/mein-bereich.test.ts · 5 Zeilen Maximum, Reihenfolge Einladung vor Nachricht
H67Bewerber · BewerbungenGruppe „Abgeschlossen“ aufklappen · Filter Alle/Offen/Abgeschlossen (ab 20) · Zeile öffnenListe neueste zuerst, abgeschlossene eingeklappt unten; Status-Wörter Bewerbersichtpruefung/seiten/bewerbungen.test.ts · „gesichtet“ wird „Vom Betrieb geöffnet“, (entfällt, C36)-Zeile mit Hinweis
H68Bewerber · Bewerbung„Zusagen“ · „Anderer Termin“ · „Absagen“ (Einladung) · Kalender-Dateieinladungen.zustand, Nachricht (system + Text) im Verlauf, F05 an Firma; ICS nur für eigene Einladungpruefung/fachlich/einladung/antworten.test.ts + ics.test.ts · ICS Zeitzone Europe/Berlin, fremde Einladung 404
H69Bewerber · BewerbungNachricht „Senden“ (+ Anhang)nachrichten, ungelesen_firma +1, B12/F07 je Einstellung; Schreibschutz nach Absage/Rückzug/beendet/Sperrepruefung/fachlich/nachricht/senden.test.ts · Schreibschutz-Fälle je Zustand, Anhang nur Bewerber, 4.001 Zeichen → fehler.feld.zuLang
H70Bewerber · Bewerbung„Bewerbung zurückziehen“ → Fenster → Knopf „Rückgängig“verzögert um die feste Rückgängig-Zeit (10 s, einstellungen.fristen.rueckgaengig_sekunden); danach zurueckgezogen, Einwilligung widerrufen, F06; Rückgängig bricht abpruefung/fachlich/bewerbung/zurueckziehen.test.ts + pruefung/dienste/verzoegert.test.ts
H71Bewerber · LebenslaufFelder Name/Telefon/Wohnort (sofort) · Meine Unterlagen: „Hochladen“ mit Art · „Ersetzen“ · „Entfernen“ · „Ansehen“konten.*, lebenslauf_datei_id; alte Datei nur mit Rückgängig (kein Papierkorb, B6), danach dateien.loeschen_ab; gesendete Bewerbungen verweisen weiter auf sie (W8)pruefung/seiten/lebenslauf.test.ts · Telefon leer → Zeile in „Jetzt wichtig“
H72Bewerber · Job-Alarme„Ändern“ · „Abbestellen“ (Rückgängig) · „Anlegen“ mit Takt „keine“ · „Treffer ansehen“job_alarme mit konto_id, takt keine erlaubt; Alarme gleicher Mail beim Anmelden übernommenpruefung/seiten/job-alarme.test.ts · Übernahme beim ersten Anmelden, „keine“ ohne Konto abgelehnt (1b)
H73Bewerber · Merkliste (Konto)Herz, „Entfernen“, Übernahme vom Gerätmerkliste_konto; Toast oeffentlich.ok.merklisteUebernommenpruefung/seiten/merkliste-konto.test.ts · Dubletten beim Zusammenführen einmal
H74Alle · EinstellungenBenachrichtigungen (Haken) · Bedienung · Kennwort ändern · Faktor einrichten/abschalten · Geräte abmelden · Einwilligungen lesen · Daten herunterladen · Konto löschenbenachrichtigungen; konten.sprache; A02; faktor + Codes + A03 (Abschalten: A09); sitzungen gelöscht; Export-Job + A05; Löschung (anonymisiert, Dateien ohne Bewerbungsverweis weg, übrige bis zur Bewerbungsfrist, Papierkorb sofort geleert, Bewerbungen über geloescht_am gesperrt) + A06; letzter Admin → fehler.team.letzterAdminpruefung/seiten/einstellungen.test.ts + pruefung/fachlich/konto/loeschen.test.ts, export.test.ts · Export enthält alle eigenen Tabellen, keine fremden Notizen
H75Alle · Konto-Menü„Mein Bereich“ · „Wechsel zu {Firma}/Bewerber“ · „Einstellungen“ · „Hilfe und Kontakt“ · „Abmelden“Sitzung firma_id setzen (laeuft_ab auf 14 Tage), Abmelden löscht Sitzungpruefung/bausteine/kontomenue.test.ts · Wechsel nur zu aktiven Mitgliedschaften
H76Firma · Übersicht„Heute zu tun“, „Ihre Stellen“, „Erste Stelle anlegen“, „Neue Stelle“ (Rand)Ziele; Zeilen nach T 7.2; „Verlängern“ aus der Zeile sofortpruefung/seiten/firma-uebersicht.test.ts
H77Firma · StellenGruppen (Pillen und Suche ab 8) · Zeilen-Knopf je Zustand · „…“: Bearbeiten, Kopieren, Beenden, Löschen · geöffnete Stelle · Auswahl-Leiste „Beenden“/„Verlängern“ · Link „Papierkorb ({n})“Zustände P Lebensläufe; Beenden verzögert nach Frist + B14 an offene Bewerbungen (stelle_beendet); Löschen nur Admin und ohne offene Bewerbungen, legt in den Papierkorb (H131)pruefung/seiten/stellen.test.ts + pruefung/fachlich/stelle/schreiben.test.ts · Recruiter: Löschen fehlt und Server lehnt ab; Verlängern setzt laeuft_bis = heute + laufzeit_tage, auch bei einer seit 400 Tagen pausierten Stelle; Beenden-Rückgängig stellt aktiv wieder her, keine B14
H78Firma · Stelle neu/bearbeitenFelder (sofort gespeichert, Zeile „Entwurf gespeichert {uhrzeit}“) · „Veröffentlichen“ · „Vorschau“ (Handy)Entwurf; veröffentlichen prüft Pflichtfelder, (m/w/d), https bei Karriereseite, Ansprechperson aus Team; Stelle einer ungeprüften Firma → pruefung + pruefungAnlegen() + F21, nur wenn Prüfung nötig (Karte 3 noetig.ts, D25: geprueft false, Schalter an, Stufe normal, kein Premium), sonst sofort aktiv ohne F21; aus nachbessern immer pruefung mit erneut_eingereicht (C22); Firma registriert → aktiv; unbestätigte Mail → Fehler am Knopf; inseratEntwurf übernommenpruefung/fachlich/stelle/veroeffentlichen.test.ts · alle Pflichtfeld-Fehler als Liste, pruefung-Stelle nicht in sitemap (1b), aber in suchen() (1a), aktiv erscheint in suchen() (1a), pruefungen-Zeile und V01 entstehen in derselben Transaktion, firmen.zustand wird aktiv, Vorschau nur eigene Firma und Verwaltung
H203Firma (Admin/Recruiter) · Stellenzeile, „Heute zu tun“, Mail F09Textlink „Besetzt? Beenden“ (Mail: „Stelle ist besetzt: beenden und Bewerbern absagen“)dieselbe Aktion wie „Beenden“ im „…“: zustand beendet, Rückgängig 10 s, danach B14 an offene Bewerber; aus der Mail nach Anmeldung die Firmensicht mit Fenster „Stelle beenden?“, erst der Knopf wirkt (sicherheit.md Nr. 29); Toast „Beendet. {n} Bewerbern sagen wir ab.“pruefung/fachlich/stelle/ablauf.test.ts · Beenden aus Zeile, Übersicht und Mail-Weg gleich; GET der Mail-Adresse ändert nichts
H79Firma · BewerbungenFilter Stelle/Status · Zeile öffnen · Auswahl „Absagen“bewerbungOeffnen setzt gesichtet + geoeffnet_von (nur beim ersten Mal, nur Firmennutzer); Mehrfach-Absage verzögertpruefung/seiten/firma-bewerbungen.test.ts · zweites Öffnen ändert geoeffnet_am nicht; Bewerbung fremder Firma 404 (RLS)
H80Firma · Bewerbung„Einladen“ · „Zusage“ · „Neuer Termin“ · „Absagen“ (Fenster mit Vorlage, „Senden“)Status erst beim Senden; Nachricht in Verlauf; einladungen + ICS-Anhang; B07/B08/B10/B11 (T 6.2); Absage verzögert 10 s mit Rückgängigpruefung/fachlich/bewerbung/status.test.ts · Knöpfe je Zustand, Vorlage mit Platzhaltern gefüllt, Mail enthält ICS, Absage-Rückgängig ohne Mail
H81Firma · Bewerbung, PostfachNotiz (sofort gespeichert) · Nachricht senden (+ „Vorlage einfügen“) · Unterlagen öffnen · Vorherige/Nächste · „Als gelesen markieren“ (Auswahl-Leiste im Postfach, auch Bewerber-Postfach 1.6)bewerbungs_notizen (nur Firma, nicht im Support-Modus); nachrichten + B12; Datei nur mit Rechte-Prüfung; gelesenSetzen() für mehrere Verläufe, Zähler ungelesen_firma/ungelesen_bewerberpruefung/fachlich/bewerbung/notizen.test.ts, pruefung/api/datei.test.ts, pruefung/fachlich/nachricht/lesen.test.ts · Bewerber sieht keine Notiz (RLS + Sicht), fremde Firma 404, Sammel-Gelesen setzt nur eigene Verläufe
H82Firma (Admin) · FirmenprofilLogo wählen/entfernen · Felder sofort · Ansprechperson · „So sehen Bewerber Ihren Betrieb“ · „Firma löschen“firmen.*; Logo verkleinert; Firmenname innerhalb 30 Tagen nach der ersten Freigabe geändert → pruefungen-Zeile art aenderung; Löschen: Stellen beendet, Bewerbungen stelle_beendet + B14, Mitgliedschaften entfernt, Papierkorb der Firma sofort geleert, F18pruefung/seiten/firmenprofil-bearbeiten.test.ts (Firmenname 10 Tage nach Freigabe geändert → eine Zeile „nachprüfen“, nach 31 Tagen keine) + pruefung/fachlich/firma/loeschen.test.ts · Recruiter: Seite 403 fehler.rechte.recruiter; SVG-Logo abgelehnt; Löschung lässt Bewerbungen bis Frist
H83Firma (Admin) · Team„Konto anlegen“ (Mitarbeiter anlegen) · „Erneut senden“ · „Zurückziehen“ · Rolle ändern · „Entfernen“ (Rückgängig) · Faktor-Pflicht-Schalterfirmen_einladungen + F02; Entfernen verzögert, Übernahme der Stellen/Einladungen durch den Admin, F19 an die entfernte Person; letzter Admin nicht entfernbar; faktor_pflicht → F20 an Nutzer ohne Faktor, nächste Anmeldung halbe Sitzungpruefung/fachlich/firma/team.test.ts · letzter Admin, Übernahme der ansprechperson_id, Pflicht erzwingt /anmelden/faktor?einrichten=1
H84Besucher/Konto · Mail F02„Kennwort festlegen“ · „Einladung annehmen“ohne Konto Kennwort festlegen (Name vorbelegt) + Beitritt; mit Konto Anmelden + Beitritt; abgelaufen; schon Mitgliedpruefung/seiten/einladung.test.ts
H85Alle · Live(ohne Knopf)Abfrage GET /api/live?seit= liefert nur eigene Zähler und Zeilen; fremde Firma nie (SSE erst 2b.9)pruefung/api/live.test.ts · Zeile fremder Firma fehlt, seit liefert nur Neueres, Antwort ohne Sitzung 401
H86HintergrundFristen und Mails30 Tage unbestätigte Konten ohne Bewerbung; F08 (5 Tage), F09; offene Bewerbungen auf seit 6 Monaten pausierten Stellen → stelle_beendet + B14, Zeile „Heute zu tun“ 14 Tage davor, die Stelle bleibt pausiert; F04 täglich; B09 Vortag; B13 Merkliste-Ablauf; Bewerbungen 6 Monate nach Abschluss gelöscht (Dateien mit); Konten 24 Monate (A07) + 3pruefung/hintergrund/*.test.ts je Aufgabe · Stichtage, keine Mail an abgeschaltete Arten, „immer“-Arten trotz Abschaltung
H87Alle · fremde Firmajede Aktion und Adresse aus Teil 3.2 mit Sitzung einer anderen Firma403/404, keine Zeile sichtbar, kein Schreibenpruefung/rechte/fremde-firma.test.ts · Liste aller Aktionen aus fachlich/* wird per Wächter mit diesem Test abgeglichen (fehlender Fall = Testfehler)
H131Firma (Admin, Recruiter) · Stellen, Bewerbung„Löschen“ (Stelle, Entwurf; nur Admin) · „Notiz löschen“ · Link „Papierkorb ({n})“legt in den Papierkorb (geloescht_am, geloescht_von) nach der Rückgängig-Frist, Toast T 3.1 (firma.rg.loeschenOhneBewerbung/.loeschenMitBewerbung/.entwurfLoeschen/.notizLoeschen); Listen und Suche zeigen die Zeile nicht mehr; Link nur bei n > 0pruefung/fachlich/papierkorb/loeschen.test.ts · Rückgängig in der Frist lässt geloescht_am leer; Stelle mit offener Bewerbung lehnt ab; Recruiter: Stelle löschen 403, Notiz löschen geht; Zähler im Link stimmt
H132Firma (Admin, Recruiter) · Papierkorb„Wiederherstellen“ · „Endgültig löschen“ · „Papierkorb leeren“ (Fenster)1.17 Nr. 5 und 6; Recruiter sieht nur Notizen; Protokollpruefung/seiten/papierkorb.test.ts + pruefung/fachlich/papierkorb/wiederherstellen.test.ts · Stelle kommt im alten Zustand zurück; Notiz-Text zurück bzw. unter die neue Notiz; Stelle mit abgeschlossenen Bewerbungen bleibt als geloescht hinter den Bewerbungen; Recruiter sieht keine Stellen-Einträge; fremde Firma 404
H133Bewerber · Job-Alarme, Bewerben-Fenster und Bewerbungen, Papierkorb„Löschen“ (Alarm) · „Verwerfen“ (Entwurf) · im Papierkorb „Wiederherstellen“ · „Endgültig löschen“ · „Papierkorb leeren“geloescht_am an job_alarme, bewerbungs_entwuerfe; Toasts T 3.1 (konto.rg.jobAlarmLoeschen, .entwurfVerwerfen); Wiederherstellen nach 1.17 Nr. 5; ersetzte Lebenslauf-Datei: nur Rückgängig (H71), nie im Papierkorb (B6)pruefung/seiten/papierkorb.test.ts (Konto-Teil) + pruefung/fachlich/papierkorb/endgueltig.test.ts · ersetzte Datei liegt nicht im Papierkorb, gesendete Bewerbung öffnet sie weiter; Entwurf einer nicht mehr bewerbbaren Stelle lässt sich nicht wiederherstellen; Alarm im Papierkorb bekommt keine B15; fremdes Konto sieht nichts
H134Hintergrund · Papierkorb, pausierte StellenFristenfristen.ts: Einträge älter als papierkorb_tage (30) endgültig wie 1.17 Nr. 6; stellen-ablauf.ts: offene Bewerbungen auf seit pausiert_abschluss_monate (6) abgelaufenen Stellen → stelle_beendet + abgeschlossen_am + B14, 14 Tage davor Zeile firma.heute.pausiertAbschluss; Konto- und Firmenlöschung leeren den Papierkorb sofortpruefung/hintergrund/papierkorb.test.ts, stellen-ablauf.test.ts · Stichtage; Verlängern am Tag 13 der Vorwarnung stoppt den Abschluss; Stelle bleibt pausiert; eine seit 400 Tagen pausierte Stelle wird nicht gelöscht; nach Kontolöschung ist der Papierkorb leer
H137Alle · Faktor (E-Mail-Code), Anmelden und Bewerben-Fenster Schritt 1„Bestätigen“ (Code aus Mail A12) · „Code erneut senden“ · „Wiederherstellungscode nutzen“faktor_mail_codes: Code gehasht, 10 Minuten, einmalig; A12 sofort in der Fassung des Zwecks; falscher Code fehler.faktor.falschMail; nach einer Anmeldung per E-Mail-Code ist der zweite Schritt bei Art mail das Kennwort, nie ein zweiter E-Mail-Code; erneut frühestens nach 60 s, höchstens 3 je 15 Minuten; 5 Fehlversuche → Code verfällt; Erfolg → Sitzung faktor_bestaetigt, Token-Wechselpruefung/fachlich/konto/faktor-mail.test.ts · abgelaufener Code abgelehnt, zweite Nutzung abgelehnt, vierter Code in 15 Minuten → fehler.faktor.mailZuOft, Verwaltungskonto mit Art mail kommt nicht nach /verwaltung (Karte 3 D34); Code-Anmeldung eines Kontos mit Art mail verlangt danach das Kennwort, keinen zweiten Code
H138Alle · Einstellungen › Anmeldung zusätzlich schützenPillen „Authenticator-App (empfohlen)“ / „Code per E-Mail“ · „Code an {mail} senden“ · „Code prüfen“ · „Auf App umstellen“faktor.art app oder mail; Einrichtung per App endet mit 10 Wiederherstellungscodes, per E-Mail ohne Codes (F3); A03 mit {faktorArt}; Umstellen mail → app nach Kennwortbestätigung (H141), Protokoll faktor_umgestelltpruefung/seiten/einstellungen.test.ts · App-Weg endet mit Codes, E-Mail-Weg ohne; Konto ohne Kennwort sieht keine Pille „Code per E-Mail“; Umstellen ohne Kennwortbestätigung → fehler.kennwortBestaetigen.noetig; Firma mit Faktor-Pflicht nimmt beide Arten (halbe Sitzung endet)
H139System · Anmelden von neuem Gerät, Mail A13A13 „Neue Anmeldung bei Ihrem Konto“ mit Knopf „Das war ich nicht“ → /konto/sichern?t= (nur Anzeige) → „Ja, alle Geräte abmelden“ (POST) → „Neues Kennwort speichern“A13 bei erfolgreicher Anmeldung mit unbekannter Gerätekennung (12 Monate, konto_geraete), nicht bei der ersten Anmeldung nach Registrierung und nicht bei Anmeldung per E-Mail-Code; Link 24 h einmalig (konto_tokens sichern); der Abruf des Links ändert nichts, erst der Knopf beendet alle Sitzungen, dann Kennwort-neu-Formular, A02, Protokoll konto_gesichertpruefung/fachlich/konto/neues-geraet.test.ts · bekanntes Gerät: keine Mail; unbekanntes: eine Mail; unbekanntes Gerät mit Anmeldung per Code: keine A13; Link beendet Sitzungen, bevor das Formular erscheint; abgelaufener Link → Satz mit Weg „Kennwort vergessen“; Verwaltungskonto → zusätzlich Betriebsmail (Karte 3 1.16)
H140Alle · Anmelden, jedes Kennwort-FeldHinweis „Kennwort vergessen? Neues Kennwort anfordern“ · Kennwort-Prüfungab 3 Fehlversuchen je Konto in 15 Minuten Link hervorgehoben; Kennwort mindestens 10, höchstens 128 Zeichen, nicht in der Liste häufiger Kennwörter, nicht E-Mail/Vorname/Nachname → fehler.feld.kennwortKurz/.kennwortHaeufigpruefung/fachlich/konto/kennwort.test.ts, anmelden-bremse.test.ts · „passwort123“ abgelehnt, „Max Mustermann“ für Max Mustermann abgelehnt, 10 Zeichen ohne Sonderzeichen angenommen; Hinweis erscheint beim 3. Fehlversuch, nicht beim 2.
H141Alle · heikle AktionenFenster „Zur Sicherheit: Ihr Kennwort“ → „Weiter“; Konto ohne Kennwort: „Zur Sicherheit: Code an {mail} senden“ → Code → „Weiter“sitzungen.kennwort_bestaetigt_am (auch nach richtigem Code, A12 Fassung bestaetigen); gilt 5 Minuten; nötig für: Faktor abschalten, umstellen, Codes neu erzeugen, Konto löschen, Firma löschen, Verwaltung: Firma löschen, Bewerberkonto löschen, E-Mail-Adresse ändern (Karte 3 1.4)pruefung/bausteine/kennwortbestaetigung.test.ts · Aktion ohne Bestätigung → fehler.kennwortBestaetigen.noetig; nach 6 Minuten erneut nötig; falsches Kennwort zählt als Fehlversuch in anmeldungen; Konto ohne Kennwort kann sein Konto per Code löschen
H143Automatik · Übersetzung der AnzeigenVeröffentlichen oder Textänderung einer Stelle (H78)Zeilen wartet in stellen_uebersetzungen je Sprache aus sprachen_frei; Aufgabe stellen-uebersetzen (1.18 Nr. 1 bis 3) schreibt fertig mit Text und uebersetzt_am, bei Fehler fehler + versuche + Protokoll, nach 3 Versuchen fehler_anzahl in einstellungen.uebersetzung; nur mit Schalter anpruefung/hintergrund/stellen-uebersetzen.test.ts · Stummel: wartet → fertig, Fehler → fehler/versuche/Protokoll, Änderung während des Laufs bleibt wartet, Schalter aus → keine Zeile
H144Besucher · Stelle (/en/, /tr/)Umschalter „Deutsch zeigen“ / „Übersetzung zeigen“ am Hinweis „Mit KI übersetzt“zeigt die deutsche bzw. übersetzte Fassung an Ort und Stelle (Client, ohne Neuladen; ohne JS Link mit ?fassung=de), Wahl im Gerätespeicher je Sitzung; Hinweis bleibt sichtbarpruefung/seiten/stelle.test.ts · /tr/ mit Zeile fertig: übersetzter Titel, deutscher Titel lang="de", Hinweis, Umschalter; ohne Zeile: deutscher Text mit nochNichtUebersetzt, kein Umschalter

Nicht-Handlungen, die ein Test sichert: kein „Gesichtet“ durch Verwaltung (H79, vorbereitet für 3); Bewerber sieht nie Notizen, nie den Firmensicht-Status („Neu“), nie geoeffnet_von; Verwaltung tritt in 2a nicht auf (Rolle existiert nur in RLS-Vorbereitung); die Übersetzung schickt nie Ansprechperson, Adresse oder Firmenname an den Dienst (H143); Mails an Firmennutzer gehen nie an entfernte; noindex auf allen (konto)/(firma)-Seiten; kein Zählpixel; Dateien nie unter /public; Bausteinliste je Seite (waechter/bausteinliste.ts +16 Seiten); Wortliste: kein „Paket“, „Abo“, „Rechnung“ im Firmenbereich.

5

Zustände je Seite

Was jede Seite zeigt, wenn sie leer ist, lädt, ein Fehler auftritt oder Rechte fehlen.

SeiteleerlädtFehlernicht gefunden / Rechtenicht mehr verfügbar
AnmeldenentfälltKnopf „Wird gesendet …“ aria-disabled (1b-Muster)fehler.anmelden.falsch (ein Satz für Mail und Kennwort, T 7.6), fehler.versuche.anmelden (Bremse), fehler.netz.*Konto gesperrt → fehler.gesperrt.konto (Erklärseite); Firma gesperrt → Anmelden geht, Firmenbereich zeigt fehler.gesperrt.firmaKonto gelöscht = unbekannt (gleiche Meldung)
Registrieren / Firma registrierenentfälltwie obenFeldfehler (fehler.feld.mail, .mailVergeben, .kennwortKurz, .zustimmung, .ortUnbekannt, .plz), Honigfeld still
Kennwort / Faktor / ZielseitenentfälltServer-SeiteToken falsch/abgelaufen (fehler.link.*) + „Link neu anfordern“; Code falsch: App fehler.faktor.falsch, E-Mail-Code fehler.faktor.falschMail; 5 × → App fehler.versuche.code, E-Mail-Code verfällt
Bewerben-FensterentfälltSchritt-Wechsel sofort; Verkleinern im Browser als „Foto wird vorbereitet“ (T gemeinsam.datei.vorbereiten, 7.12), dann Upload mit Fortschritt je Datei; Senden „Wird gesendet …“Feldfehler je Schritt; Datei fehler.datei.* (Typ, Größe, Anzahl; Virenprüfung läuft noch = fehler.datei.pruefungLaeuft, man kann weiterarbeiten; Virenprüfung gestört = fehler.datei.pruefungGestoert); Netz: Eingaben bleiben (Entwurf)Stelle beim Senden nicht mehr öffentlich sichtbar (weder aktiv noch pruefung, oder Firma gesperrt) → fehler.bewerben.stelleWeg + „Ähnliche Stellen“ (1a)schon beworben → fehler.bewerben.schonBeworben + „Meine Bewerbungen“
Übersicht Bewerberkeine Bewerbungen: „Ihre Bewerbungen“ fehlt, „Jetzt wichtig“ trägt den Satz und „Stellen suchen“; nichts zu tun: Kasten „Alles erledigt …“ + „Stellen suchen“; nichts gemerkt: „Gemerkt“ fehlt (U 3.5)Server-Seiteerror.tsx
Bewerbungen0: T 2 „Noch keine Bewerbungen“ + „Stellen ansehen“; Filter ohne Treffer: T 2 je FilterPlatzhalter-Zeilen nur beim Nachladen über LiveLadefehler fehler.netz.allgemeinBewerbung fremd/unbekannt → 404abgeschlossene Gruppe unten; Stelle beendet: Titel ohne Link
Bewerbungkeine Nachrichten: Verlauf zeigt nur System-Zeilen + EingabeSenden „Wird gesendet …“Netz: Text bleibt im Feld; Schreibschutz-Satz: fehler.postfach.abgeschlossen (ein Satz für Absage, Rückzug, Stelle beendet), fehler.postfach.firmaGesperrt, beim gesperrten eigenen Konto konto.postfach.kontoGesperrt (T 7.7); Firmensicht: fehler.postfach.bewerberGesperrt, fehler.postfach.kontoGeloescht404Einladung ersetzt: alte eingeklappt
Postfach0: T 2 „Noch keine Nachrichten“Server-Seiteerror.tsx
Lebenslaufkeine Datei: .keineDatei mit Ablage; Telefon leer: HinweisFeld „Gespeichert …“ je Feld, Upload-Fortschrittfehler.feld.telefon, fehler.datei.*; Netz: „Nicht gespeichert, erneut versuchen“ (fehler.netz.gespeichertNicht)
Job-Alarme / Merkliste (Konto)wie 1b, zusätzlich T 2 „Noch kein Job-Alarm“wie 1bwie 1b
Einstellungenkeine Bewerbung: Karte Einwilligungen fehlt; kein Faktor: Karte zeigt „Einrichten“je Karte eigener KnopfzustandKennwort falsch fehler.feld.kennwortAltFalsch; Faktor-Code falsch: App fehler.faktor.falsch, E-Mail-Code fehler.faktor.falschMail; Export läuft schon: Satzletzter Admin beim Löschen: fehler.team.letzterAdmin
Übersicht Firmakeine Stellen: Block „Erste Schritte“ mit „Erste Stelle anlegen“ (U 3.8); nichts zu tun: Satz mit der nächsten FristServer-Seiteerror.tsxFirma gesperrt → Erklärseite statt Bereich; registriert ohne Bestätigung → Zeile oben
Stellen0: T 2 „Noch keine Stellen“ + „Neue Stelle“; Filter leer: Satz je FilterPlatzhalter beim NachladenNetzfremde Stelle 404Nachbessern/gesperrt (3): Chip + Satz, Zeilen-Menü eingeschränkt
Stelle neu/bearbeitenTeam ohne zweite Person: Ansprechperson vorbelegt (einzige)„Gespeichert 12:03“ je Feld; Veröffentlichen „Wird geprüft …“Fehler am Feld in einem Satz, erstes fehlendes Feld bekommt den Fokus, dringende Meldung „{n} Angaben fehlen“ (U 3.11, A.2); unbestätigte Mail: Satz am Knopf; Entwurf-Konflikt (zwei Tabs): letzter gewinnt, Hinweis (Annahme C9)404 fremdaktiv und bearbeitet: Änderungen sofort live (keine erneute Prüfung, Annahme C10)
Bewerbungen Firma0: T 2 „Noch keine Bewerbungen“ (je Stelle)Platzhalter beim NachladenNetz404 fremdzurückgezogen/beendet: ohne Knöpfe
Bewerbung Firmakeine Notizen: Feld allein; keine Datei (nur Nachricht): SatzFenster „Wird gesendet …“Vorlage leer → fehler.feld.nachrichtLeer; Termin in der Vergangenheit fehler.feld.datumVergangen404Bewerber-Konto gelöscht: Kontaktzeile „Konto gelöscht“, Postfach gesperrt (fehler.postfach.kontoGeloescht), Unterlagen bleiben bis Frist
Firmenprofilkein Logo: Monogramm; keine Beschreibung: leeres Feld mit Platzhalter (B :224)„Gespeichert …“ je Feld, Logo-Fortschrittfehler.datei.logo* (SVG, 2 MB, bildZuGross), fehler.feld.webseite (T 7.6)Recruiter 403 fehler.rechte.recruiter
Teamnur ich: Liste mit einer Zeile, Formular „Mitarbeiter anlegen“ offenKonto anlegenfehler.team.schonImTeam, .schonEingeladen, fehler.feld.mailRecruiter 403Einladung abgelaufen: Zeile grau mit „Erneut senden“
Papierkorb (Firma, Bewerber)0: gemeinsam.papierkorb.leer, „‹ Übersicht“-Zeile; der Link „Papierkorb ({n})“ und der Konto-Menü-Eintrag fehlen dannServer-Seite; Knöpfe „Wird ausgeführt …“ aria-disabledNetz; Eintrag inzwischen endgültig gelöscht (anderer Tab, Nachtlauf) → Zeile verschwindet mit Satz fehler.papierkorb.wegRecruiter sieht nur Notizen; fremde Firma 404Stelle mit Bewerbungen nach „Endgültig löschen“: aus dem Papierkorb weg, Bewerbungen bleiben bis zu ihrer Frist (Titel ohne Link)
LiveVerbindungsaufbau still; Rückfall nach 5 s ohne StromVerbindungsabbruch: Wiederaufnahme mit Last-Event-ID, nach 3 Fehlschlägen Abfrage 30 s; nie Toast

Rückmeldung nach Klick (P Laden und Rückmeldung, U A.6): sofort speichernde Felder zeigen „Gespeichert {uhrzeit}“ neben dem Feld-Block; Fenster-Knöpfe „Wird gesendet …“ aria-disabled; Rückgängig nach U A.6: Knopf „Rückgängig“ ersetzt den gedrückten Knopf und bekommt den Fokus, Toast zusätzlich, Frist nach Einstellung (Standard 10 s) (Zurückziehen, Einladen, Absagen, Beenden, Löschen, Entfernen, Alarm abbestellen oder löschen, Entwurf verwerfen, Notiz löschen, Lebenslauf-Datei ersetzen; was dabei in den Papierkorb geht, steht in 1.17); Toast hält, solange Maus oder Fokus darin sind, Info-Toasts ohne Rückgängig stehen 6 s; Ladebalken ab 0,3 s, Platzhalter in Form des Inhalts, bei Netzfehler bleiben Eingaben erhalten (G80); Sitzung abgelaufen: Eingaben bleiben, nach dem Anmelden zurück an dieselbe Stelle (U A.6); Live-Einträge in Listen mit aria-live polite („1 neue Bewerbung“), nie aria-live assertive, eingehende Nachrichten im Verlauf ohne Ansage; Reiter-Zahlen ändern sich ohne Ansage.

6

Dateien mit geschätzter Größe und Wegweiser-Zeilen

Liste der Programmdateien mit geschätztem Umfang und Bau-Reihenfolge, als Wegweiser für die Programmierung.

Dieser Abschnitt beschreibt nur die technische Umsetzung. Mit dem Schalter „Technische Angaben“ blenden Sie ihn ein.

Richtwert 600 Zeilen, Notbremse 1.500; Schätzungen in Zeilen; nur Neues und Geändertes gegenüber 1a/1b.

6.1 Dateiliste

DateiZ.Inhalt
(oeffentlich)/anmelden/page.tsx · _formular/Anmelden.tsx · Registrieren.tsx · FirmaRegistrieren.tsx · kennwort/page.tsx · kennwort-neu/page.tsx · faktor/page.tsx60 · 140 · 120 · 180 · 60 · 70 · 110Client-Formulare, ohne JS als POST
(oeffentlich)/konto/bestaetigt/page.tsx · (oeffentlich)/einladung/page.tsx60 · 120Zielseiten
(oeffentlich)/stelle/[adresse]/_bewerben/BewerbenDialog.tsx · Schritt1.tsx · Schritt2.tsx · FragenBlock.tsx · Schritt3.tsx · Erfolg.tsx · EntwurfZeile.tsx · bewerben/page.tsx160 · 160 · 150 · 30 · 120 · 60 · 30 · 90Dialog aus B stelle.html:103–156; FragenBlock leere Hülle (B1)
(konto)/layout.tsx · mein-bereich/page.tsx · _uebersicht/ (2) · bewerbungen/page.tsx · _liste/ (2) · bewerbungen/[id]/page.tsx · _bewerbung/ (4) · postfach/page.tsx · lebenslauf/page.tsx · _lebenslauf/ (2) · job-alarme/page.tsx · _alarme/* (2)80 · 60 · 60+40 · 70 · 140+50 · 90 · 60+160+60+90 · 70 · 50 · 120+110 · 60 · 120+120
(konto)/konto/einstellungen/page.tsx · _einstellungen/* (8 Karten)70 · je 60–150Faktor.tsx 150, Loeschen.tsx 90
(firma)/layout.tsx · firma/page.tsx · _uebersicht/IhreStellen.tsx · ErsteSchritte.tsx · stellen/page.tsx · _liste/StellenListe.tsx · ZeilenMenue.tsx · stellen/[id]/page.tsx · _stelle/Kopfreihe.tsx · stellen/neu/page.tsx · stellen/[id]/bearbeiten/page.tsx · _formular/StellenFormular.tsx · Vorschau.tsx · Ansprechperson.tsx90 · 60 · 60 · 40 · 70 · 220 · 90 · 90 · 60 · 50 · 60 · 320 · 60 · 50StellenFormular größte Client-Datei (unter 600)
(firma)/firma/bewerbungen/page.tsx · _liste/BewerbungenFirma.tsx · bewerbungen/[id]/page.tsx · _bewerbung/Kopf.tsx · Knoepfe.tsx · Verlauf.tsx · Unterlagen.tsx · Notizen.tsx · postfach/page.tsx70 · 180 · 100 · 70 · 220 · 60 · 80 · 110 · 70
(firma)/firma/profil/page.tsx · _profil/Logo.tsx · Stammdaten.tsx · UeberUns.tsx · Ansprechperson.tsx · FirmaLoeschen.tsx · team/page.tsx · _team/Liste.tsx · Einladen.tsx · FaktorPflicht.tsx60 · 120 · 130 · 50 · 50 · 90 · 60 · 140 · 80 · 50
(konto)/konto/papierkorb/page.tsx · (firma)/firma/papierkorb/page.tsx · bausteine/papierkorb/PapierkorbListe.tsx · PapierkorbLink.tsx · fachlich/papierkorb/liste.ts · loeschen.ts · wiederherstellen.ts · endgueltig.ts · leeren.ts · pruefung/seiten/papierkorb.test.ts · pruefung/fachlich/papierkorb/*.test.ts (3) · pruefung/hintergrund/papierkorb.test.ts60 · 60 · 180 · 30 · 90 · 70 · 90 · 110 · 40 · 200 · je 80–150 · 80Papierkorb (1.17, H131–H134); 0003_konten.sql ergänzt geloescht_am an stellen, bewerbungs_notizen, bewerbungs_entwuerfe, job_alarme
bausteine/kontomenue/KontoMenue.tsx · bereich/BereichKopf.tsx · Reiter.tsx · BestaetigenZeile.tsx · jetztwichtig/JetztWichtig.tsx · zeilen.ts · ablage/Ablage.tsx · pruefen.ts · statuschip/StatusChip.tsx · postfach/Verlauf.tsx · nachricht.ts · fenster/Fenster.tsx · auswahl/Auswahl.tsx · listenfeld/ListenFeld.tsx · live/LiveClient.tsx · NeuZeile.tsx · zeitstrahl/Zeitstrahl.tsx · Verlauf.tsx · faktor/FaktorEinrichten.tsx · CodeFeld.tsx110 · 40 · 60 · 40 · 80 · 120 · 220 · 90 · 70 · 200 · 30 · 120 · 180 · 70 · 140 · 40 · 60 · 60 · 160 · 50
bausteine/seitenrahmen/Kopf.tsx (+40) · stellenkarte/Stellenkarte.tsx (+50) · sonderseiten/Fehlerseite.tsx (+30) · (oeffentlich)/stelle/[adresse]/page.tsx (+40)Änderungen
dienste/auth/better-auth.ts · sitzung.ts · kennwort.ts · haeufige-kennwoerter.txt · geraete.ts · anmeldungen.ts · ip.ts · faktorMail.ts · dienste/db/rls.ts · dienste/verzoegert.ts120 · 90 · 90 · (Daten) · 100 · 120 · 40 · 110 · 110 · 90Sicherheit 26.10.: Kennwort-Liste, anmeldungen, IP aus vertrauten Weiterleitern, E-Mail-Code
(oeffentlich)/konto/sichern/page.tsx · bausteine/kennwortbestaetigung/* · faktor/CodeErneut.tsx · dienste/mail/vorlagen/a12.tsx · a13.tsx · pruefung/fachlich/konto/faktor-mail.test.ts · neues-geraet.test.ts · anmelden-bremse.test.ts · pruefung/bausteine/kennwortbestaetigung.test.ts70 · 120 · 40 · 40 · 50 · 140 · 120 · 120 · 80H137 bis H141 (26.10.)
fachlich/konto/anlegen.ts · felder.ts · loeschen.ts · export.ts · einstellungen.ts · faktor.ts · token.ts140 · 60 · 120 · 110 · 70 · 140 · 60
fachlich/bewerbung/anlegen.ts · entwurf.ts · status.ts · liste.ts · notizen.ts · felder.ts · fachlich/einladung/anlegen.ts · antworten.ts · ics.ts · erinnerung.ts · fachlich/nachricht/senden.ts · lesen.ts · liste.ts160 · 80 · 200 · 140 · 60 · 70 · 110 · 90 · 90 · 50 · 110 · 60 · 80
fachlich/stelle/schreiben.ts · rechte.ts · vorschau.ts · ablauf.ts · fachlich/firma/registrieren.ts · profil-schreiben.ts · logo.ts · team.ts · loeschen.ts · fachlich/datei/hochladen.ts · pruefen.ts · ausliefern.ts · loeschen.ts · fachlich/zaehler/ungelesen.ts · fachlich/rechte.ts220 · 80 · 50 · 120 · 130 · 90 · 90 · 180 · 130 · 180 · 90 · 90 · 50 · 50 · 90 · 120rechte.ts enthält die Tabelle Rolle × Handlung als Daten
dienste/mail/vorlagen/b01, b05, b07–b14 · a01–a03, a05–a07, a09, a12, a13 · f01–f09, f18–f21 · versand-regel.tsje 40–90 · 8032 Vorlagen; Sammel-F04 100
hintergrund/aufgaben/konto-unbestaetigt.ts · stellen-ablauf.ts · bewerbungen-sammel.ts · einladung-erinnerung.ts · merkliste-ablauf.ts · fristen.ts · datenexport.ts · bewerbung-ohne-antwort.ts60 · 120 · 90 · 60 · 60 · 140 · 120 · 70bewerbung-ohne-antwort.ts: End-Check Befund 15 (offene Bewerbung ohne Handlung der Firma seit einstellungen.fristen.bewerbung_ohne_antwort_monate (6) → stelle_beendet-ähnlicher Abschluss ohne_antwort, B14 neutral; 14 Tage vorher Zeile firma.heute.bewerbungAbschluss)
app/api/live/route.ts · api/datei/[id]/route.ts · api/kalender/[id].ics/route.ts · api/auth/[...all]/route.ts110 · 80 · 50 · 20
dienste/db/schema/konten.ts · sitzungen.ts · faktor.ts · konto_tokens.ts · einwilligungen.ts · benachrichtigungen.ts · firmen_nutzer.ts · firmen_einladungen.ts · bewerbungs_entwuerfe.ts · bewerbungen.ts · bewerbung_dateien.ts · bewerbungs_antworten.ts · bewerbungs_notizen.ts · nachrichten.ts · einladungen.ts · dateien.ts · merkliste_konto.ts · konto_zugang.ts; firmen.ts (+5), stellen.ts (+7), einstellungen.ts (Typen)60 · 40 · 30 · 40 · 40 · 30 · 40 · 40 · 40 · 90 · 20 · 30 · 50 · 60 · 60 · 40 · 20
db/migrationen/0003_konten.sql · 0003_rueckweg.sql · 0003_rechte.sql · musterdaten/konten.ts · bewerbungen.ts · firmen-nutzer.ts · nachrichten.ts320 · 80 · 220 · 80 · 120 · 40 · 60Musterdaten: 3 Bewerber (einer mit Faktor), 2 Firmen mit Admin + Recruiter, 6 Bewerbungen in allen Zuständen, Einladung, Notizen
sprachen/{de,en,tr}/anmelden.json · bewerben.json · konto.json · firma.json · status.json · mail-bewerber.json · mail-konto.json · mail-firma.jsonje 40–200aus T 1.4, 1.6, 1.7 (ohne 2b-Schlüssel), 1.8, 2, 3, 4, 5, 6, 7.1, 7.2
pruefung/seiten/anmelden · firma-registrieren · konto-bestaetigt · bewerben · mein-bereich · bewerbungen · lebenslauf · job-alarme · merkliste-konto · einstellungen · firma-uebersicht · stellen · firma-bewerbungen · firmenprofil-bearbeiten · einladung (.test.ts)je 80–260
pruefung/fachlich/konto/ (6) · bewerbung/ (5) · einladung/ (2) · nachricht/ (1) · stelle/ (2) · firma/ (3) · datei/ (2) · pruefung/api/live · datei · pruefung/dienste/verzoegert · pruefung/rechte/fremde-firma · pruefung/hintergrund/ (8) · pruefung/mails/* (Stichproben b03, f03, b05 mit ICS, f18) · pruefung/bausteine/kontomenue · ablage · auswahlje 50–220fremde-firma.test.ts ~300 (alle Aktionen)
dienste/uebersetzung/azure.ts · stummel.ts · index.ts · hintergrund/aufgaben/stellen-uebersetzen.ts · bausteine/stellenkarte/UebersetzungUmschalter.tsx (Client, 1a-Seite Stelle) · pruefung/hintergrund/stellen-uebersetzen.test.ts · pruefung/dienste/uebersetzung.test.ts120 · 30 · 30 · 110 · 60 · 140 · 601.18, H143, H144; Schema-Ergänzung stellen_uebersetzungen in 0003_konten.sql
pruefung/waechter/bausteinliste.ts (+16 Seiten), links.test.ts (+2a-Adressen), aktionen-liste.ts (neu: jede exportierte Aktion braucht einen Rechte-Test)+120

Summe grob: ~210 neue Dateien, ~14.000 Zeilen inkl. Mails, Tests und Migrationen; keine Datei über 320 außer 0003_konten.sql. Bauzeit nach Zeitplan 2a (P): in Paketen von 30–45 Minuten, Reihenfolge: Konten und Anmelden → Bewerben-Fenster → Bewerberbereich → Firma registrieren und Stellen → Bewerbungen und Postfach → Team und Profil → Live → Hintergrund und Fristen.

6.2 Zeilen für ARCHITEKTUR.md

Seite → Dateien:

  • Anmelden = (oeffentlich)/anmelden/page.tsx + _formular/, kennwort/, kennwort-neu/, faktor/, (oeffentlich)/konto/sichern/ · Bausteine fenster, faktor, honigfeld · dienste/auth (auch anmeldungen, ip, faktorMail), dienste/sperrliste (Karte 3) · fachlich/konto · dienste/mail (B01, F01, A01, A02, A12, A13) · sprachen anmelden.json, bewerben.json (Felder) · Tests anmelden.test.ts, firma-registrieren.test.ts, pruefung/fachlich/konto/
  • Zielseiten Konto = (oeffentlich)/konto/bestaetigt/page.tsx, (oeffentlich)/einladung/page.tsx · fachlich/konto/anlegen, fachlich/firma/team · Tests konto-bestaetigt, einladung
  • Bewerben-Fenster = (oeffentlich)/stelle/[adresse]/_bewerben/, bewerben/page.tsx · Bausteine fenster, ablage, faktor, honigfeld · fachlich/bewerbung, fachlich/datei, fachlich/konto · dienste/mail (B01 bei Abbruch, B05, F03, F04), bremse · sprachen bewerben.json, fehler.json · Tests bewerben.test.ts, pruefung/fachlich/bewerbung/, datei/*
  • Bewerberbereich = (konto)/layout.tsx, mein-bereich/** · Bausteine bereich, jetztwichtig, statuschip, postfach, zeitstrahl, fenster, ablage, live, stellenkarte · fachlich/bewerbung, einladung, nachricht, konto, jobalarm (1b) · sprachen konto.json, status.json · Tests mein-bereich, bewerbungen, lebenslauf, job-alarme, merkliste-konto
  • Einstellungen = (konto)/konto/einstellungen/** · Bausteine faktor, fenster, kennwortbestaetigung · fachlich/konto/* · dienste/auth/geraete, faktorMail · dienste/mail (A02, A03, A05, A06, A09, A12) · Tests einstellungen, konto/loeschen, konto/export
  • Firmenbereich = (firma)/layout.tsx, firma/** · Bausteine bereich, jetztwichtig, statuschip, postfach, fenster, auswahl, listenfeld, ablage, live, stellenkarte (vorschau, firma), kontomenue · fachlich/stelle (schreiben, rechte, vorschau), bewerbung (status, liste, notizen), einladung, nachricht, firma (profil-schreiben, logo, team, loeschen), datei · dienste/mail (B07–B14, F02–F09, F18–F21) · sprachen firma.json, status.json · Tests firma-uebersicht, stellen, firma-bewerbungen, firmenprofil-bearbeiten, team, fremde-firma
  • Live = app/api/live/route.ts (Abfrage aus den Fachtabellen, 1.16) · bausteine/live · Test pruefung/api/live; SSE und ereignisse erst 2b.9
  • Übersetzung der Anzeigen = hintergrund/aufgaben/stellen-uebersetzen.ts · dienste/uebersetzung/* · Auslöser fachlich/stelle/schreiben.ts · Anzeige (oeffentlich)/stelle (1a) mit bausteine/stellenkarte/UebersetzungUmschalter · Tabelle stellen_uebersetzungen · Tests pruefung/hintergrund/stellen-uebersetzen, pruefung/dienste/uebersetzung
  • Dateien = app/api/datei/[id]/route.ts · fachlich/datei/ · Test pruefung/api/datei, fachlich/datei/
  • Kalender = app/api/kalender/[id].ics/route.ts · fachlich/einladung/ics · Test einladung/ics
  • Hintergrund 2a = hintergrund/aufgaben/{bewerbung-wartet-mail, konto-unbestaetigt, stellen-ablauf, bewerbungen-sammel, einladung-erinnerung, merkliste-ablauf, fristen, datenexport} · Tests pruefung/hintergrund/*
  • Rechte = fachlich/rechte.ts (Rolle × Handlung), fachlich/stelle/rechte.ts, fachlich/firma/rechte.ts, dienste/db/rls.ts, db/migrationen/0003_rechte.sql · Test pruefung/rechte/fremde-firma.test.ts, waechter/aktionen-liste.ts
  • Papierkorb = (konto)/konto/papierkorb/page.tsx, (firma)/firma/papierkorb/page.tsx · Bausteine papierkorb, auswahl, fenster · fachlich/papierkorb/ · dienste/verzoegert · Tests papierkorb.test.ts, pruefung/fachlich/papierkorb/, pruefung/hintergrund/papierkorb

Baustein → wo benutzt (Ergänzung zu 1a/1b):

  • kontomenue → Seitenrahmen (angemeldet, alle Seiten)
  • bereich (BereichKopf, Reiter, BestaetigenZeile) → (konto)/layout, (firma)/layout; die Verwaltung nutzt ihn nicht (Karte 3 D43: Menüleiste links, h1 der Seite)
  • jetztwichtig → Übersicht Bewerber, Übersicht Firma; ab 3 Verwaltung
  • ablage → Bewerben-Fenster, Lebenslauf, Firmenprofil (Logo), Postfach-Anhang; ab 2b Anlagen
  • statuschip → alle Listen und Details beider Bereiche; ab 3 Verwaltung
  • postfach/Verlauf → Bewerbung (Bewerber), Bewerbung (Firma)
  • fenster → Bewerben, Zurückziehen, Einladen/Zusage/Absage/Neuer Termin, Konto löschen, Firma löschen, Stelle löschen, Faktor; ab 3 Verwaltungs-Fenster
  • auswahl → Stellen (Firma), Bewerbungen (Firma), Papierkorb beider Bereiche; ab 3 Verwaltungslisten; Merkliste nur bei Bedarf (1b W1)
  • papierkorb → /firma/papierkorb, /konto/papierkorb; PapierkorbLink unter Stellen (Firma), Job-Alarme, Bewerbungen (Bewerber); Konto-Menü
  • listenfeld → Stellenformular
  • live → beide Bereiche; ab 3 Verwaltung („Heute zu tun“)
  • zeitstrahl → Bewerbung beide Sichten
  • faktor → Anmelden/faktor, Einstellungen, Bewerben-Fenster Schritt 1
  • honigfeld + bremse (1b) → zusätzlich Registrieren, Firma registrieren, Bewerben, Anmelden (Bremse), kontoStatus
  • dienste/mail (1a) → alle Konto-, Bewerber- und Firmen-Mails; ICS-Anhang neu
  • stellenkarte (1a) → zusätzlich Vorschau im Stellenformular, Stellenliste der Firma
7

Offene Punkte (Weichen), Annahmen, Textschlüssel

Getroffene Entscheidungen und Annahmen, etwa Bewerben ohne Kennwort, Rückgängig, Papierkorb und Übersetzung, sowie Ideen für später.

7.1 Weichen (A = mein Vorschlag)

NrWeicheAB
W1Bewerben-Fenster ohne JS: B und U kennen nur den Dialog. Ohne JS gibt es entweder eine eigene Seite mit denselben drei Schritten (mehr Dateien, aber vollständig bedienbar) oder nur einen Hinweis „Bitte JavaScript einschalten“.eigene Seite /stelle/[adresse]/bewerben als POST-Formulare (dieselben Server-Aktionen, Bausteine geteilt)nur Hinweis; Fenster braucht JS
W2Rückgängig 10 s (Zurückziehen, Absagen, Beenden, Entfernen): im Browser verzögert (einfach; bricht bei Tab-Wechsel/Netzabbruch ab und sendet dann nie) oder auf dem Server verzögert (pg-boss-Job, abbrechbar; wirkt immer).Server (dienste/verzoegert.ts): Aktion sofort als „ausstehend“ sichtbar, Job führt nach der festen Frist aus (10 s, einstellungen.fristen.rueckgaengig_sekunden, Karte 3 D23), Rückgängig löscht den Job; Mails erst bei AusführungBrowser-Timer
W3Ansprechperson der Stelle: FK auf konten (Konto ist rollenlos; 1a sah firmen_nutzer vor) oder FK auf firmen_nutzer (Mitgliedschaft; sauberer bei mehreren Firmen je Konto, aber beim Entfernen hängt die Zeile an einer entfernten Mitgliedschaft).FK konten + Prüfung „ist aktives Mitglied dieser Firma“ im Code; beim Entfernen Übernahme durch den Admin (P)FK firmen_nutzer
W4Zustand „Bewerbung wartet auf Mail-Bestätigung“: eigener Zustand (entfällt, C36) in bewerbungen (klar in Listen, Firma sieht sie nie) oder Zustand neu mit Prüfung über konten.bestaetigt_am (weniger Zustände, aber jede Firmen-Abfrage muss den Join prüfen).eigener Zustand (entfällt, C36); Übergang zu neu beim Bestätigen (eine Stelle, ein Test)neu + Join
W5„Gesichtet“ beim Öffnen: beim Laden der Detailseite (jedes Öffnen durch einen Firmennutzer, auch versehentlich aus der Live-Vorschau) oder erst beim Öffnen der Unterlagen. P sagt „Öffnen setzt Gesichtet“.Laden der Detailseite durch einen Firmennutzer (P wörtlich); Rolle Verwaltung ausgenommenerst Unterlagen
W6Live-Aktualisierung technisch: Server-Sent Events mit Tabelle ereignisse (einfach, Abfrage je Sekunde pro offener Verbindung gebündelt über LISTEN/NOTIFY) oder reine Abfrage alle 30 s (kein Strom, weniger Verbindungen, aber bis 30 s Verzögerung). P nennt SSE mit Rückfall.SSE über PostgreSQL LISTEN/NOTIFY (eine Verbindung je Tab, Rückfall Abfrage 30 s); Ereignisse 24 h in ereignisse für Wiederaufnahmenur Abfrage 30 s
W7Better Auth oder eigener Auth-Code: P Technik nennt Better Auth (Tabellen, Sitzungen, TOTP). Eigener Code wäre kleiner, aber Sicherheit selbst gebaut.Better Auth mit Drizzle-Adapter und TOTP-Plugin; eigene Tabellennamen über das Mapping; zusätzliche Felder (faktor_pflicht, geraet) in eigenen Spalteneigener Code
W8Kennung der Konto-Datei bei neuer Bewerbung: Datei wird je Bewerbung kopiert (Momentaufnahme, mehr Speicher) oder die Bewerbung zeigt auf dieselbe Datei und „Ersetzen“ im Lebenslauf legt eine neue Datei an, die alte bleibt für gesendete Bewerbungen (kein Kopieren, Löschung erst, wenn keine Bewerbung mehr darauf zeigt).Verweis ohne Kopie; Löschen der alten Datei erst, wenn keine Bewerbung sie nutzt (loeschen_ab)Kopie je Bewerbung

Entschieden am 22.10. als Annahme (jederzeit korrigierbar): W1 bis W8 je Spalte A.

7.2 Annahmen

NrAnnahme
C1Bewerben ohne JS über eigene Seite (W1 A).
C2Geräte-Liste zeigt Browser und Betriebssystem aus der Browser-Kennung, die letzte Nutzung und die gekürzte IP-Adresse der Anmeldung (aus anmeldungen, 30 Tage); kein Ort. Die Zählung bleibt ohne IP (1a); IP-Adressen liegen nur im Sicherheitsprotokoll und in der Sperrliste.
C3„Erneut schalten“ (nur beendet) legt eine Kopie als Entwurf an (neue Adresse, neue 30 Tage); die alte Stelle bleibt mit ihren Bewerbungen. Pausierte Stellen werden verlängert, nicht erneut geschaltet (C24).
C4Logos sind öffentlich, sobald die Virenprüfung bestanden ist (dateien.zustand geprueft); eine Freigabe durch die Verwaltung gibt es nicht, das Feld logo_freigegeben wird nicht angelegt (1a Teil 3). Missbrauch decken Melden und Sperren ab. Öffentliche Auslieferung über fachlich/datei/ausliefern.ts Fall „öffentlich“.
C5Ansprechperson des Betriebs (Firmenprofil) ist nur Vorbelegung für neue Stellen; das öffentliche Profil zeigt keine Person (1b 1.3 hat keine Zeile).
C6Rückgängig auf dem Server verzögert (W2 A), Frist fest aus einstellungen.fristen.rueckgaengig_sekunden; der Fokus landet auf dem Rückgängig-Knopf an der Stelle des gedrückten Knopfes (U A.6).
C7Better Auth (W7 A); seine Pflichtspalten bleiben neben den hier genannten.
C8stellen.ansprechperson_id zeigt auf konten (W3 A); die 1a-Felder ansprech_anrede/-vorname/-nachname/-telefon bleiben als Rückfall für Stellen ohne Konto-Ansprechperson (Schnittstelle, Import, Musterdaten; 1a A21). Stellen aus dem Formular haben immer ansprechperson_id.
C21Telefon-Freigabe der Ansprechperson liegt je Person und Firma in firmen_nutzer.telefon_in_anzeigen (Team), nicht je Stelle; es gibt kein stellen.ansprech_telefon_frei.
C22Eine Stelle im Zustand nachbessern (nach Ablehnen in der Prüfung oder Offline nehmen nach Meldung) geht bei „Veröffentlichen“ immer in pruefung mit erneut_eingereicht und neuer Prüfzeile, auch bei geprüfter Firma; Bearbeiten einer aktiven Stelle bleibt ohne Prüfung (C10).
C23Bewerben ist erlaubt, solange istOeffentlichSichtbar() ja sagt (aktiv oder pruefung, Firma nicht gesperrt); eine Stelle in Prüfung ist für Bewerber sichtbar und bewerbbar (P, 1a W5).
C9Zwei Tabs bearbeiten denselben Entwurf: letzter Schreibzugriff gewinnt, beim Speichern im anderen Tab prüft der Server den Stand (geaendert_am) und zeigt den Hinweis „Inzwischen geändert, bitte neu laden“, statt still zu überschreiben.
C10Bearbeiten einer aktiven Stelle geht sofort live, ohne neue Prüfung (Prüfung nur bei der ersten Stelle einer neuen Firma, P). Ausnahme ohne Sperre: Ändert eine Firma in den ersten 30 Tagen nach der Freigabe Stellentitel oder Firmennamen, entsteht eine Prüfzeile art aenderung in der Gruppe „nachprüfen“ (Karte 3 D27); die Stelle bleibt online.
C11Mail-Nummern nach T 6.2 bis 6.4 (am 22.10. abgeglichen): B01 Konto bestätigen, B02 bis B04 entfallen (C36), B05 Bewerbung angekommen, B06 keine Mail, B07 Einladung, B08 Neuer Termin, B09 Erinnerung Vortag, B10 Zusage, B11 Absage, B12 Neue Nachricht, B13 Merkliste läuft ab, B14 Stelle beendet, B15–B17 Job-Alarm (1b), B18/B19 Sperre (3); A01 Kennwort, A02 Kennwort geändert, A03 Faktor eingerichtet, A04/A08 Faktor-Rücksetzung (3), A05 Export, A06 Konto gelöscht, A07 lange nicht genutzt, A09 Faktor abgeschaltet; F01 Registrierung, F02 Team-Einladung, F03 neue Bewerbung, F04 täglich gesammelt, F05 Antwort auf Einladung, F06 zurückgezogen, F07 Nachricht, F08/F09 Ablauf, F10–F17 Verwaltung/Premium (3), F18 Firma gelöscht, F19 aus dem Team entfernt, F20 Faktor jetzt Pflicht, F21 Stelle wartet auf Prüfung. Codes mail.b., mail.a., mail.f.* wie T; Vorlagen heißen nach der Nummer.
C12Benachrichtigungs-Arten je Konto in einer Tabelle (fehlende Zeile = an); „immer“-Arten (Konto, Kennwort, Sicherheit) haben keine Zeile.
C13Firmen-Sitzung 14 Tage sobald eine Firma gewählt ist; Wechsel zurück zu „Bewerber“ setzt nicht auf 30 Tage zurück (kürzere Dauer bleibt).
C14Reiter sind Links mit eigener Adresse (kein JS-Tabpanel wie B), Optik unverändert; Konto-Menü ersetzt B-„…“-Menü.
C15Firma registrieren mit bestehendem Konto: angemeldet → nur Block „Ihr Betrieb“, Zugang entfällt; nicht angemeldet mit vergebener Mail → Hinweis „Bitte zuerst anmelden“ mit weiter=firma-registrieren.
C16Dateien liegen auf einem verschlüsselten Datenträger des Servers (P), Pfad in dateien.pfad, Auslieferung nur über /api/datei/[id] mit Rechte-Prüfung; Virenprüfung über ClamAV-Dienst, Konfiguration Abschnitt 4 (Betrieb); in der Testumgebung Stummel, der „geprueft“ setzt. Lesen und Schreiben von Dateien läuft nur über fachlich/datei/* mit einem Ablage-Dienst; kein anderer Teil kennt den Pfad, damit ein späterer Wechsel auf einen Objektspeicher nur diesen Dienst betrifft.
C17Live zum Livegang als Abfrage alle 60 s; LISTEN/NOTIFY mit SSE (W6 A) erst 2b.9.
C18Die Auswahl-Leiste (P Auswählen) wird hier für Stellen und Firmen-Bewerbungen gebaut; Merkliste bleibt wie 1b W1.
C19Einwilligung „nutzung“ (Datenschutz + Nutzungsbedingungen beim Konto) und „weitergabe“ (je Bewerbung) werden mit Textfassung gespeichert; die Sichtbarkeit für Betriebe ist keine Einwilligung, sondern ein Schalter.
C20Öffentlicher Stellen-Zustand pruefung (1a: sichtbar) bleibt; die Firma sieht Chip „Wartet auf Prüfung“ (T 5.4) und kann bearbeiten.
C24Eine abgelaufene Stelle ist pausiert: nicht öffentlich, für die Firma sichtbar, jederzeit ohne zeitliche Grenze verlängerbar, bis die Firma sie beendet oder löscht; der Nachtlauf fasst die Stelle nicht an (1a Enum stelle_zustand ohne archiviert). Datenschutz: offene Bewerbungen darauf werden 6 Monate nach dem Ablauf automatisch abgeschlossen (stelle_beendet, B14; Hinweis 14 Tage vorher in „Heute zu tun“), die Stelle bleibt pausiert.
C25Papierkorb für Firma und Bewerber: Löschen legt in den Papierkorb (geloescht_am), 30 Tage (einstellungen.fristen.papierkorb_tage, Karte 3), danach endgültig; Seiten /firma/papierkorb und /konto/papierkorb (1.17). Drin: Stellen und Entwürfe, Notizen (Firma); Job-Alarme, verworfene Bewerbungsentwürfe. Nicht drin: Merkliste (Rückgängig genügt, 1b W1), Konto und Firma löschen (eigene Abläufe mit Export und Fristen), Bewerbung zurückziehen (Zustand), Team-Mitglied entfernen und Einladung zurückziehen (Zustand mit Rückgängig und Übernahme der Stellen), Logo entfernen (eine Datei, neu wählen ist ein Klick), Nachrichten und Einwilligungen (werden nicht gelöscht), Geräte abmelden (Sitzung). Inhalte im Papierkorb zählen bei Export und Löschfristen mit; Konto- oder Firmenlöschung leert den Papierkorb sofort.
C26Quelle je Bewerbung (B4, 26.10.): nur aus dem Adress-Parameter von (Werte wie 1a stellen_aufrufe_tag), den das Bewerben-Fenster beim Öffnen übernimmt; kein Cookie, kein Referrer; fehlt er, „direkt“. Die Statistik dazu kommt nach dem Livegang (Kundenliste).
C27Vorab-Fragen des Betriebs (B1, 26.10.): FragenBlock.tsx in Schritt 2 und Tabelle bewerbungs_antworten sind zum Livegang leer; Stellenformular, Bewerbungsansicht und die AGG-Prüfung der erlaubten Fragen kommen erst mit der Freischaltung fragen nach dem Livegang.
C28Stellenformular (B5, B2, 26.10.): Beschäftigungsart als Pillen mit Mehrfachwahl (Vollzeit vorgewählt, mindestens eine), Befristung freiwillig als zwei Pillen plus Datumsfeld nach „Start“; beides ohne neues Element (Pillen und Datumsfeld gibt es im Formular schon).
C29Zweiter Faktor per E-Mail-Code: Bewerber und Firmennutzer wählen in den Einstellungen App oder E-Mail-Code; Code 6 Ziffern, 10 Minuten, einmalig, gehasht; höchstens 3 Codes je 15 Minuten; Wiederherstellungscodes nur bei der App; Firmen-Pflicht nimmt beide; die Verwaltung bleibt bei der App (Karte 3 D34). A12 geht über die Vorrang-Spur der Mail-Warteschlange (sofort, vor Massenmails).
C30Fehlversuche: keine dauerhafte Kontosperre; wachsende Wartezeit je Konto (ab 5 in 15 Minuten: 1, 2, 4, 8, 15 Minuten) und je IP erst ab 50 in 15 Minuten mit eigenem Satz, Hinweis „Kennwort vergessen?“ ab dem 3. Fehlversuch. Kennwort: 10 bis 128 Zeichen, lokale Liste häufiger Kennwörter, keine Sonderzeichen-Pflicht, kein Ablauf.
C31„Neues Gerät“ = Gerätekennung aus der Browser-Kennung: Browser-Name und Betriebssystem-Name, beide ohne Fassungsnummer (z. B. „Chrome · Android“; 26.10., Bewertung), ohne erfolgreiche Anmeldung dieses Kontos in den letzten 12 Monaten; keine Cookie-Marke, keine IP im Vergleich (Mobilfunk wechselt sie ständig). Ein Browser-Update löst darum keine A13 aus; ein anderer Browser auf demselben Gerät schon, das ist hinnehmbar, die Mail ist kurz und hat einen klaren Weg.
C32Erneute Kennworteingabe vor heiklen Aktionen gilt 5 Minuten je Sitzung (sitzungen.kennwort_bestaetigt_am) und ersetzt die bisherigen Kennwortfelder in den Fenstern „Konto löschen“ und „Firma löschen“ durch den einen Baustein kennwortbestaetigung/.
C34„Kennwort vergessen?“ im Bewerben-Fenster: sendet A01 sofort an die eingetippte Adresse, ohne eigene Seite; die neutrale Antwort und die Bremse (höchstens 3 Links je Adresse und Stunde) sind dieselben wie auf /anmelden/kennwort; der Token trägt weiter (konto_tokens.weiter, nur eigene Adressen), nach dem neuen Kennwort landet die Person angemeldet in der Stelle mit offenem Fenster in Schritt 2. Neue Schlüssel bewerben.kennwortLinkUnterwegs (T 7.9). Ohne JS (C1): der Link führt auf /anmelden/kennwort?weiter=…, die Seite übernimmt weiter genauso.
C35Bilder verkleinert der Browser, nicht der Server: bausteine/ablage/verkleinern.ts (createImageBitmap + Canvas, Zielmaße je Zweck: Lebenslauf-Foto 2.000 px JPG 0,85, Logo 800 px (PNG bleibt PNG), Werbemotiv in Originalmaßen neu kodiert (GIF unverändert, Animation), Ratgeber-Bild 1.600 px WebP), Metadaten fallen beim Kodieren weg. Der Server verlässt sich nicht darauf (_planung/sicherheit.md Nr. 16): Typ am Inhalt, Größe, Pixelmaße je Zweck (Lebenslauf höchstens 4.000 px, Logo 1.000 px, Ratgeber 2.400 px, Werbemotiv genau das Format), Viren, bei JPG Metadaten-Segmente ohne Neukodierung entfernen; zu große Maße → fehler.datei.bildZuGross mit Hinweis, ein kleineres Foto zu wählen (ohne JS oder bei alten Browsern). Einziger Server-Rückfall: HEIC → JPG für Lebenslauf-Fotos, wenn der Browser HEIC nicht dekodiert (außerhalb Safari), begrenzt auf 3 je Konto und Tag, sonst fehler.datei.heic.
C33Übersetzung der Anzeigen (26.10., Bewertung Runde 2; zugesagt in Kundenliste und Plan): Azure AI Translator im Europa-Rechenzentrum (Plan Schnittstellen „Anbieter“), nur en und tr zum Livegang (ar mit 2b.3), nur die sechs Textfelder der Stelle, maschinell ohne Gegenlesen (Hinweis an der Anzeige, 1b 1.12), Verzögerung 2 Minuten nach der letzten Änderung, 3 Versuche, dann Zeile „Heute zu tun“ beim Super Admin; Firmenprofile, Inhalte und Vorab-Fragen werden nicht übersetzt (Plan: Profile bleiben zum Start deutsch). Fällt der Dienst aus, zeigt die Seite den deutschen Text mit Hinweis; nichts blockiert das Veröffentlichen.
C36Bewerben mit Code statt Kennwort: Beim ersten Bewerben bestätigt ein 6-stelliger Code an die eingetippte Adresse (Mail A12, Zweck bewerben, Baustein faktor/CodeFeld, dieselbe Bremse wie der E-Mail-Faktor) die Adresse direkt in Schritt 1; das Konto entsteht erst nach richtigem Code, bestätigt und ohne Kennwort (kennwort_hash leer). Danach geht die Bewerbung sofort an die Firma. Die Zustände „wartet auf Bestätigung“ und „verfallen“, die Mails B02 bis B04, die Fassung „Adresse ändern“ nach dem Senden und bewerbung-wartet-mail.ts entfallen; Tippfehler fängt der Textlink „E-Mail ändern“ im Code-Schritt ab. Anmelden später per Code an die E-Mail oder mit einem Kennwort, das die Person in Einstellungen › Kennwort setzt (kennwortSetzen.ts, A02). Ein Konto von der Seite Registrieren bleibt beim Kennwort-Weg mit B01. Rechtsfrage R8 (Haken oder Satz) gilt unverändert.
C37Bedienungs-Nachprüfung 27.10. (Bericht BEDIENUNG-NACHCHECK-2026-10-27, P-5050-BN; Wege ohne Kennwort zu Ende gedacht): (1) jedes vorhandene Konto sieht beim Bewerben zuerst „Code an {mail} senden“, das Kennwort ist aufklappbar; (2) die Anmeldeseite hat für alle Konten den Rand-Knopf „Ohne Kennwort anmelden: Code per E-Mail“; (3) volle Adresse und „E-Mail ändern“ im Code-Schritt; (4) A12 je Zweck mit eigenem Betreff und Schlusssatz; (5) Kennwortbestätigung per Code für Konten ohne Kennwort; (6) eigener Fehlersatz für E-Mail-Codes; (7) Knopf „Mit dieser E-Mail weiter“ und Überschrift „Code aus Ihrer E-Mail“; (8) keine A13 nach Code-Anmeldung, nie zwei E-Mail-Codes hintereinander, E-Mail-Faktor erst mit Kennwort; (9) „Anmeldung zusätzlich schützen“ statt „zweiter Faktor“ in allen Oberflächen und Mails; (11) neue Zeilen nur auf Klick; (14) Bestätigungsseiten nennen den Fortschritt. Die Sicherheitslinie bleibt: kontoStatus verrät nur „neu“ oder „vorhanden“ (_planung/sicherheit.md Nr. 15).

7.3 Textschlüssel

Vorhanden und genutzt: T 1.4 (bewerben.), 1.6 (oeffentlich.anmelden., .registrieren., .firmaReg., .kennwort., .kennwortNeu., .faktor.), 1.7 (konto. ohne die 2b-Schlüssel konto.lebenslauf.erfahrung … .mappe, Deckblatt), 1.8 (firma.*), 2 (Leerzustände), 3.1 bis 3.3, 4.1 bis 4.4, 5.1 bis 5.5, 6.0 bis 6.4, 7.1, 7.2, 7.4.

Ergänzt am 22.10.: neue Schlüssel in T 7.6 (konto.uebersicht.lebenslaufBandTitel/-Text, konto.einst.bewegung, fehler.team.schonEingeladen, firma.profil.ansprechperson/-Satz, firma.stelle.kopieTitel, gemeinsam.live.neu; am 26.10. dazu fehler.anmelden.falsch, fehler.faktor.falsch, fehler.feld.webseite), neue Mails A09 mail.a.faktorAus (T 6.3) und F19 mail.f.teamEntfernt, F20 mail.f.faktorPflicht, F21 mail.f.stellePruefung (T 6.4). Mit vorhandenen Schlüsseln abgedeckt: Bestätigen-Zeile (konto.wichtig.kontoBestaetigen, firma.heute.mailBestaetigen), Geräte (konto.einst.geraete …), letzte Admin-Person (fehler.team.letzterAdmin), schon im Team (fehler.team.schonImTeam), Faktor-Pflicht (firma.team.faktorPflicht, .faktorStand), Termin in der Vergangenheit (fehler.feld.datumVergangen), Datei in Prüfung (fehler.datei.pruefungLaeuft: man kann weitermachen, kein „erneut versuchen“). Am 26.10. dazu T 7.8 (Papierkorb und pausierte Stellen: gemeinsam.papierkorb.*, fehler.papierkorb.weg, firma.stellen.gruppePausiert/.pilleBeendet, firma.heute.pausiert/.pausiertAbschluss, firma.rg.notizLoeschen, konto.rg.dateiErsetzt/.entwurfVerwerfen); firma.stellen.pilleArchiviert heißt jetzt .pillePausiert; fehler.stelle.verlaengernNichtMehr und status.stelle.archiviert sind gestrichen. Am 27.10. (C37, BN): neu bewerben.kontoGefundenAnsage, .kontoMitKennwort (ersetzt .kontoVorhandenCode), .mailAendern, .schritt1Code, .nameZeile; oeffentlich.anmelden.codeSenden, .codeHinweis, .codeFeld, .codeAnmelden; fehler.faktor.falschMail; konto.einst.faktorErstKennwort, .keinKennwort; gemeinsam.kennwortBestaetigen.titelCode, .textCode, .codeSenden; gemeinsam.datei.hochladen; Mail A12 in vier Fassungen; geändert bewerben.weiter1, .codeHinweis ({mail} statt {mailTeil}), gemeinsam.live.neu, die Faktor-Texte, A03, A09, F20.

Ergänzt am 26.10. (T 7.9): firma.neu.befristung, .befristungUnbefristet, .befristungBefristet, .befristetBis (Stellenformular); FragenBlock braucht zum Livegang keinen Schlüssel.

Ergänzt am 26.10. (T 7.10, Sicherheit): oeffentlich.faktor.mailTitel, .mailText, .mailErneut, .mailErneutGesendet, .mailErneutWarten, .mailZuOft; fehler.faktor.abgelaufen, fehler.faktor.mailZuOft; konto.einst.faktorArt, .faktorArtApp, .faktorArtAppSatz, .faktorArtMail, .faktorArtMailSatz, .faktorMailEinrichten, .faktorMailPruefen, .faktorAnApp, .faktorAnMail, .faktorUmstellen, .geraetIp; konto.sichern.titel, .text, .knopf, .fertig, .abgelaufen; fehler.anmelden.vergessenHinweis, fehler.feld.kennwortHaeufig, fehler.gesperrt.neutral, fehler.kennwortBestaetigen.noetig; gemeinsam.kennwortBestaetigen.titel, .text, .knopf; firma.team.faktorPflichtSatz; Text von fehler.versuche.anmelden (T 4.4) auf Wartezeit statt Sperre geändert; Mails A12 und A13 in T 6.3; A03 mit {faktorArt}.

Ergänzt am 26.10. (T 7.11, Übersetzung der Anzeigen, 1.18): vorhanden gemeinsam.sprache.maschinell, .deutschZeigen, .nochNichtUebersetzt (1a), verwaltung.heute.uebersetzung (T 7.3), verwaltung.einst.uebersetzung (T 1.9); neu gemeinsam.sprache.uebersetzungZeigen (Umschalter zurück, H144), verwaltung.einst.uebersetzungAuto, .uebersetzungStand, .uebersetzungErneut (Karte 3 1.11 Nr. 3, nur Deutsch).

7.4 Sonstiges, vor dem Bau zu klären (keine Weiche, aber Material)

  • AGB für Arbeitgeber: Text von Nomad (RECHTSTEXTE P-5050-RT Abschnitt 4), Link in oeffentlich.firmaReg.zustimmung zeigt auf /agb (1b 1.12).
  • ClamAV und verschlüsselter Datenträger: Betrieb (Abschnitt 4) muss sie vor dem Livegang bereitstellen; Testumgebung läuft mit Stummel (C16).
  • Fristen (P Sicherheit „bestätigt der Kunde, Mail Punkt 5“): Werte stehen in einstellungen.fristen und sind ohne Code änderbar.
  • Befund FC 15/16 (Recruiter-Rechte, Ansprechperson entfernt) sind in P nachgezogen und hier umgesetzt; FC 1, 2, 3, 9, 10, 11 betreffen Abschnitt 3 (Verwaltung) und sind hier nur als Zustände/Adressen vorbereitet (nachbessern, gesperrt, Sperre Bewerberkonto, faktor-reset).

7.5 Ideen (nicht geplant)

  • Browser-Push-Benachrichtigungen für neue Nachrichten (statt nur Mail und Live-Zahl).
  • „Angemeldet bleiben“ je Gerät benennen (eigener Name statt Browser-Kennung).
  • Bewerbung als Firma mit einem Klick an eine Kollegin weiterleiten („Bitte sieh dir das an“) als Notiz mit Erwähnung.
  • Kalender-Abo (ICS-Feed) für alle Einladungen einer Firma.
  • Entwurf der Bewerbung geräteübergreifend fortsetzen per Link in B01 („Bewerbung fortsetzen“).