Stand: v0.28.145 (2026-11-07) — alle fünf Etappen des Bauplans sind live: 1 «Fundament» v0.28.126, 2 «Verbraucher» v0.28.127, 3 «Wizard» + P32 v0.28.128 (5.11.), 4 «Danach» v0.28.129, 5 «Mitgliederportal für Haushalte» v0.28.130 (6.11.) · Konzept: docs/konzept-mitglieder-import.md und docs/bauplan-mitglieder-import.html im Repo (Kennungen D1–D95 sind Entscheide von Yves, K = Befunde im Code, P = Annahmen).
Diese Seite erklärt, wie CluHu Mitgliedschaften künftig denkt, was davon schon in der Datenbank steht und was erst in den nächsten Etappen sichtbar wird.
Seit Etappe 2 (v0.28.127) sichtbar:
?archived=1 zeigt sie in den Listen-APIs); endgültig gelöscht wird nur ohne Blocker über ?purge=1. Für beides und für das Wiederherstellen gibt es keine Oberfläche, nur die API bzw. den Dienst. Seit v0.28.145 gibt eine archivierte Mitgliedschaft ihre Mitgliedernummer frei (D94): Import-Spalte und Erfassungsmaske dürfen sie neu vergeben, die Datenbank prüft die Eindeutigkeit nur unter lebenden Mitgliedschaften; automatisch vergebene Nummern («hochzählen», Vorschlag der Maske) überspringen die Nummer einer ehemaligen Mitgliedschaft weiterhin. Wiederherstellen prüft vorher, ob die Nummer inzwischen neu vergeben ist, und blockiert dann. Warum: Nach «Alle Mitglieder löschen» (damals «archivieren») scheiterte das zweite Einspielen der Beispieldaten mit «Mitgliedernummer 3001 kommt doppelt vor»; E-Mails waren nie das Problem, weil Klasse C sie beim Archivieren räumt.apps/vorlagen/recipients.py) liest die Haken statt Rolle und Alter; Kalender, Antwort-Link, ICS, Portal-Startseite, Vorlagen, Newsletter, Geburtstagsmail und der Faktura-Zusteller folgen automatisch. Die Altersgrenze «Kinder» unter Mail › Anrede ist weg (D46). Details auf den Seiten Kalender, Faktura, Berechtigungen (Login-Härtung, Register «Mitgliederportal») und Import («Import nachbearbeiten», ToDo-Kacheln).Aus Etappe 1 (v0.28.126) blieb nach aussen wenig sichtbar, nämlich:
VOCAB_ROWS[...]['uses']): «Training» und «Auftritt» (je Einzahl und Mehrzahl) erscheinen, sobald das GV-Addon aktiv ist, weil die GV-Folien sie lesen (v0.28.136); der Kalender nennt die Terminart noch fest. Jeder Begriff trägt eine Erklärzeile statt einer Spalte «Wo es erscheint», am Handy stehen die Felder unter dem Begriff. Die Figur (Symbol der Spielfiguren) folgt fest der Vereinsart, ist nicht einstellbar und steht seit v0.28.134 nicht mehr auf der Seite — sichtbar ist sie nur im Import-Wizard. Das Onboarding fragt die Vereinsart neu beim Anlegen (D66, D83). Die Wörter erscheinen ab Etappe 3 im Import-Wizard und ab Etappe 4 in Kalender und Mitgliederportal (D48, D59c).Ein Verein hat eine Mitgliedschaftsform. Sie beschreibt, wie der Verein denkt, und ist eine Obergrenze je Zeile beim Import und je Maske beim Erfassen:
| Form | Kachel (Vereinssprache) | Was je Mitgliedschaft entsteht |
|---|---|---|
| E | Einzelmitglieder | eine Person. Weitere Namen in der Zeile sind Kontaktangaben, nie Personen. |
| V | «Turnende mit Erziehungsberechtigten» (Vereinswort) | genau eine Person, die mitmacht (Kind oder Erwachsener), dazu null bis zwei Erziehungsberechtigte für Post, Rechnung und Mitgliederportal. Erziehungsberechtigte werden über Zeilen hinweg wiederverwendet. |
| H | Familien & Haushalte | eine bis n Teilnehmende, null bis n Betreuende, optional Kinder ohne Teilnahme; Obergrenzen setzt der Verein mit Spielfiguren. Eine Rechnung je Mitgliedschaft. Bezeichnung «Familie Keller» (D55). |
Die Form steht in der Tabelle membership_settings (eine Zeile je Verein, Vorgabe E) und ist seit Etappe 2 unter Vereinsdaten › Mitgliedschaften sichtbar und wechselbar (Popup mit «Einverstanden», D49); der Wizard (Etappe 3) wird sie beim ersten Import abfragen. Dort liegt auch die Vorgabe beim Anlegen: Wer bekommt Mitgliederportal, Termine, Vereinsinfos und die Rechnung, wenn eine Mitgliedschaft neu entsteht (D56); services.apply_creation_defaults(member) schreibt sie einmalig auf die Links einer neuen Mitgliedschaft. Geburtstag hat keine Zeile: wer gefeiert wird, stellt das Geburtstags-Addon ein (D77). Dazu die Blocknamen der Positionen (block_labels, p1/p2/c1/c2, D47): Vorgabe aus dem Wortschatz der Vereinsart, umbenennbar im Register und unter «Import nachbearbeiten».
Bis v0.28.125 trug jede Verknüpfung Person ↔ Mitgliedschaft einen von zehn Rollencodes (Mitglied, Hauptkontakt, 2. Kontakt, Rechnungs-Empfänger, Erziehungsberechtigt, Kind, Notfallkontakt, Teilnehmende, Spieler/in, eigene Bezeichnung). Zwei Codes bedeuteten «Hauptkontakt», es gab keine Regel «genau einer», keine Dublettensperre, und wer Post oder Rechnung bekam, hing an der Rolle.
Neu stehen am Link:
| Feld | Bedeutung |
|---|---|
macht mit (participates) |
Vereinsangehörige: zählt, trägt einen Eintritt, sammelt Vereinsjahre (D3). |
betreut (caretaker) |
erscheint im Register «Mitglied-Empfänger» als Erziehungsberechtigte / Betreuende und pflegt im Mitgliederportal die Teilnehmenden derselben Mitgliedschaft (D80). |
Etikett (label) |
«Erziehungsberechtigte 1», «Mutter», «Grosi»; frei änderbar. |
| Portal, Termine, Infos, Geburtstag | je ja/nein: wer was bekommt (D28). |
Rechnung (receives_invoice) |
genau eine Person je Mitgliedschaft (Radio). |
Hauptperson (is_primary, intern, D53) |
genau eine je Mitgliedschaft; bestimmt den Namen in E und V, Rückfall für die Rechnung. |
Eintritt / Austritt (valid_from / valid_to) |
dieser Person in dieser Mitgliedschaft (D10, D25). |
Die vier Arten, die daraus entstehen: Teilnehmende (mit, nicht betreut), Betreuende (betreut, nicht mit), Betreuende die mitmachen (beides), Kind ohne Teilnahme (keines von beidem, nur in H).
Migration (v0.28.126, 0034): Jeder bestehende Link bekam die Haken aus seinem Rollencode (Mitglied/Hauptkontakt/2. Kontakt/Teilnehmende/Spieler/Kind → macht mit; Erziehungsberechtigt/Rechnungs-Empfänger/Notfallkontakt/eigene Bezeichnung → betreut), Mitgliedschaften ohne Hauptperson bekamen die älteste passende Person, doppelte Hauptpersonen und doppelte Links wurden bereinigt, die Rechnungsperson folgt der Rolle «Rechnungs-Empfänger», sonst der Hauptperson. Das Protokoll je Verein steht in der Migrate-Ausgabe (nur Zahlen). Der alte Code bleibt eine Version lang lesbar; die Verbraucher (Haushaltsindex, Faktura, Geburtstage, Ehrungen, Kalender) wechseln in Etappe 2.
Bisher gab es kein Eintrittsfeld: Jubiläen, Ehrungen und GV zeigten je auf eine frei gewählte Datumsspalte an der Mitgliedschaft, und alle verknüpften Personen erbten das Datum, Eltern eingeschlossen (K7). Der Austritt stand nur an der Mitgliedschaft.
Neu hängen Eintritt und Austritt je Person am Link:
Eintritt = valid_from der Person in dieser Mitgliedschaft. Nur Teilnehmende tragen einen Eintritt; Betreuende haben keinen und sammeln keine Vereinsjahre.
Vereinseintritt der Person = frühester Eintritt über alle ihre Mitgliedschaften.
Mitgliederliste (seit v0.28.127) zeigt je Mitgliedschaft ein Aggregat über die aktiven, teilnehmenden Links (Datenbank-Annotation Min/Max/Anzahl verschiedener Daten): bei einer Person das Datum 1:1 («01.08.2024»), bei mehreren «alle gleich · Start 01.01.2019» oder «mehrere Eintritte · ältester 01.08.2021», sortierbar nach dem ältesten Datum (sort=entry), filterbar nach «gemeinsamer Start ja/nein» (filter[entry_same]) und Datumsbereich. Die Spalte trägt ein Info-«i» mit dieser Rechenregel (D36). In Form E ist sie direkt editierbar und schreibt den Link-Eintritt (P25).
| Fall | Was die Liste zeigt | Sortierung | Filter «gemeinsamer Start» |
|---|---|---|---|
| eine teilnehmende Person mit Eintritt | das Datum 1:1 | nach diesem Datum | ja |
| mehrere Teilnehmende, alle gleich | «alle gleich · Start » | nach dem Datum | ja |
| mehrere Teilnehmende, verschieden | «mehrere Eintritte · ältester » | nach dem ältesten | nein |
| Betreuende ohne Teilnahme | zählen nicht; kein Eintritt, keine Vereinsjahre | — | — |
| kein Eintritt bekannt | leer, in der Sortierung zuletzt | — | — |
Austritt = valid_to. Ausgetretene Personen erscheinen in der Mitgliedschaft nicht mehr (in der Mitgliederliste wieder einblendbar über den Trichter der Spalte «Personen», Haken «ausgetretene Personen mit anzeigen», API filter[show_exited]=1 bzw. ?exited=1; im Personen-Popup über «ausgetretene anzeigen (n)»). Sind alle Teilnehmenden ausgetreten, setzt der Dienst services.sync_member_exit(member) das Austrittsdatum der Mitgliedschaft auf das späteste valid_to, exited=True und Status passiv; ein neuer aktiver Link hebt das auf. Tritt die Hauptperson aus, wandert die Markierung (und ein bei ihr liegendes Rechnungs-Radio) auf die nächste Teilnehmende. Austritt vor Eintritt wird abgelehnt. Ehrungen, Geburtstage und GV lesen Eintritt und Austritt vom Link (die alten Spalten-Zeiger sind nur noch Übergang für Links ohne Datum).
Wiedereintritt = neuer Link derselben Person; der alte bleibt beendet. Die Dublettensperre nimmt beendete Links aus (P26).
Migration: Die konfigurierte Eintrittsspalte (Ehrungen, sonst Geburtstage/Jubiläen, sonst GV) wurde als valid_from auf die Links mit «macht mit» übertragen; exit_date ausgetretener Mitgliedschaften als valid_to auf alle ihre Links.
gender w/m/x, gender_source erfasst/abgeleitet): aus Mail › Anrede (Spalte + Zuordnung) und der J+S-Zuordnung übernommen; Konflikte protokolliert, Anrede gewinnt. Die alten Zeiger bleiben eine Version als Rückfall.ahv_number): normalisiert, Prüfziffer über apps/columns/ahv.py. Genau eine AHV-Zusatzspalte je Verein wurde übertragen und gelöscht; bei mehreren oder nicht eindeutigen Zuordnungen bleibt die Spalte für das Werkzeug «Zusatzspalte in Systemfeld» (Etappe 2, D70). Sichtbar nur für Admins und J+S, beim Archivieren gelöscht (P18, Etappe 2).archived_at): Grundlage für Archiv statt Löschen (D16, Etappe 2).HouseholdIndex.allows/recipient_ids; nur der Index wechselte von Rolle + Alter auf die Haken. Darum war der Umbau tragbar. Betreuende handeln für Teilnehmende derselben Mitgliedschaft, nie füreinander (B2, D62).Was kann es: Unter Mitgliederportal › Meine Daten sieht eine eingeloggte Person Karten für sich («Anna Muster · Ich») und für jede Person, die sie in einer gemeinsamen Mitgliedschaft betreut («Lea Muster · du bist Erziehungsberechtigte 1»; nur wenn der Verein unter Berechtigungen › Mitgliederportal «Haushalt im Portal anzeigen» eingeschaltet hat; Partner ohne «betreut» sehen einander nicht, D62). Jede Zeile trägt eine Marke: grün direkt (Telefon, Adresse; leere Felder füllen), gelb mit Freigabe des Vereins (Vorname, Nachname, Geburtsdatum, Geschlecht → Aufgabe an die Freigabe-Personen «Anna Muster für Lea Muster — Vorname»), blau mit Bestätigungsmail (E-Mail einer Person mit Login), grau nur der Verein (Mitgliedschaft, Status, Eintritt, Beitragscode → «Korrektur melden»). Welche Marke gilt, bestimmen die Schalter des Vereins (C24). Der Jahrgang steht auf der Karte, solange kein Geburtsdatum da ist; abgeleitetes Geschlecht ist als solches markiert; der Geburtstagsgruss erscheint nur mit aktivem Addon und nur lesend (D77, D89).
Zugang fürs Kind (C21): «E-Mail für Lea eintragen» (Format, im Verein eindeutig: «Diese Adresse gehört bereits Anna Muster») löst keine Mail aus, weil Lea kein Login hat (D63); dann «Einladung an Lea senden» über denselben Dienst wie beim Admin (authorization.services.invite_person, Link 92 Tage), mit «ausgelöst von Anna Muster» im Protokoll und Meldung an die Admins nach dem Schalter (jede / erste je Haushalt / keine). Stellt der Verein «nur als Antrag», entsteht eine Aufgabe für die Admins statt der Einladung; bei «nein» gibt es den Knopf nicht. Nach dem Passwort-Setzen sieht Lea nur sich; Anna behält ihre Rechte, solange ihre Haken im Register stehen.
Warum so: Ein Login, ein Haushalt (B15): die Pflege folgt dem Haken «betreut» am Link, nicht dem Alter oder der Rolle (D80). Die Einladung ist die Einwilligung und zugleich die Bestätigung, dass die Adresse dem Kind gehört; darum keine Bestätigungsmail ins Leere. Die eigene Person behält die Selfservice-Regeln ihrer Rolle (Feld-Matrix). Technik: apps/portal/household.py (persons_for_user, may_edit, change_field, invite_cared), ChangeRequest.for_person (Zielperson, portal 0005), Routen portal/api/haushalt/<person>/feld/ und …/einladen/.
Startseite (C19, D58, D88): Chip-Leiste «Alle | Ich | Lea 2 | Tim 1» mit Zählern (offene Einladungen und Hinweise je Person). Standard-Chip «Ich», wenn die Login-Person selbst mitmacht; betreut sie nur, startet die Seite bei mehreren betreuten Personen in «Alle», bei genau einer direkt bei dieser ohne Leiste. Der Chip filtert Termine, Hinweise, Meine Daten, «Wer bekommt was» und den Rechnungen-Platzhalter; Vereinsinfos, Meldungen, Aufgaben, Geburtstage, Spesen, Dateien, Programm und Konto gehören zum Login und bleiben in «Alle» (die Seite sagt es). Terminkarten tragen Namensmarken («Ich» grün, Kinder blau), gemeinsame Termine («Chlausturnen, ganzer Verein») sind eine Karte mit Status je Person; «Für Lea zusagen / absagen» steht direkt im Portal (P16), die Antwort protokolliert, wer sie gegeben hat; der Stellvertreter-Link aus einer Mail führt eingeloggt ins Portal statt auf die öffentliche Seite. Hinweise je Person: «Lea hat kein Geburtsdatum · J+S braucht es → ergänzen» (springt in die Daten-Karte), «Tim hat keine E-Mail: kein eigenes Mitgliederportal · seine Termine laufen über dich → ok so» (Wegklick je Benutzer), «Einladung für Lea offen seit n Tagen → erneut senden». Zustand des Chips in der Sitzung gemerkt und per ?person= steuerbar; Technik apps/portal/haushalt_kontext.py, static/js/portal-haushalt.js, Partials _chips.html, _mod_hinweise.html.
Wer bekommt was (C22, D60, D77): Modul mit einer Zeilengruppe je Mitgliedschaft, in der die Person betreut oder mitmacht — Person × Portal / Termine / Infos als Haken, Rechnung als Radio nur lesend mit «Änderung anfragen» (Aufgabe beim Verein; der Verein bleibt zuständig). Leitplanken: der eigene Zugang lässt sich nicht entfernen, kein Portal ohne E-Mail, der letzte erreichbare Haken «Termine» bleibt («Trag eine E-Mail für Tim ein, eine zweite Erziehungsberechtigte, oder setze bei Tim den Haken ‹Termine›»), in Mitgliedschaften mit einer Person ist nur «Infos» wählbar, keine Spalte Geburtstag (D77). Was «direkt» und was «als Antrag» geht, bestimmen die Schalter unter Berechtigungen › Mitgliederportal («Haken direkt, Rechnung als Antrag» / «alles als Antrag» / «nein»). Jede Zelle schreibt dasselbe Link-Feld wie Register und Popup; Kalender-Stellvertretungen folgen sofort; das Protokoll unter Import nachbearbeiten zeigt «Anna Muster hat für Lea Muster ‹Termine› gesetzt». Der Abmeldelink im Newsletter nimmt den Haken «Infos» bei allen Mitgliedschaften der Person weg und nennt «Zustellung ändern: Mitgliederportal › Wer bekommt was»; Vereinsmails tragen diese Fusszeile für Personen mit Login (P14). Technik apps/portal/zustellung.py, Routen portal/api/haushalt/empfaenger/, …/set/, …/rechnung-anfragen/.
Zugang abschliessen (C21 Schritte 3–5, D61, D63): Setzt Lea ihr Passwort über den Einladungslink, bekommen ihre aktiven Links den Portal-Haken; kam die Einladung aus dem Portal, erhält die Betreuende die Meldung «Lea Muster hat ihren Zugang zum Mitgliederportal eingerichtet»; Lea sieht nur sich, Anna weiter beide; nimmt Anna später ihren Haken «Termine» bei Lea heraus, gehen Erinnerungen nur noch an Lea. Das Protokoll listet Einladung, Abschluss und Haken-Änderungen (letzte 7 Tage). Technik authorization.services.complete_portal_access, household.access_info mit «offen seit n Tagen».
Warum so: Ein Umschalter allein braucht drei Klicks für den Wochenüberblick, «alles gemischt» kennt kein «nur Tim»; die Kombination aus Standard-Chip und Marken nimmt von beidem das Brauchbare (D58, E6). Die Rechnungsperson wechselt nur der Verein, weil daran Geld hängt (D60). Keine Altersautomatik: Erwachsenwerden ist Umschalten von Hand (D29). Tests: «Haushalt mit zwei Kindern» Ende zu Ende, «Standard-Chip in drei Konstellationen», «gleiche E-Mail in zwei Vereinen» (D3).
services.form_change_plan(club, target) / apply_form_change(...); der Wizard wechselt weiterhin nur aufwärts. Seit v0.28.137: Solange keine (nicht archivierte) Mitgliedschaft existiert, ist die Form im Wizard frei wechselbar — auch nach «Einzeln erfassen» ohne erfasste Person (wizard_views.form_lock); die Sperre greift erst mit der ersten Mitgliedschaft. Warum: Ein Verein, der sich nur umentscheidet, soll nicht archivieren müssen. Ebenfalls v0.28.137: Die Seitenleiste zeigt «Personen», «Mail», «Berechtigungen» und «Addon» (seit v0.28.139 auch «Statistiken») erst ab drei Mitgliedschaften (menu.FOCUS_MIN_MEMBERS, Zustand menu.focus_state) — neue Vereine sollen zuerst Mitglieder erfassen; die Seiten bleiben per Adresse erreichbar. Seit v0.28.139 erklärt das ein Willkommens-Banner zuoberst auf der Übersicht (core/_fokus_banner.html): Gruss, die Drei-Mitgliedschaften-Regel, drei Figur-Plätze der Vereinsart als Fortschritt («2 von 3»), Knopf «Mitglieder erfassen» (nur Admins) und der Hinweis, zuerst mit einer fiktiven Mitgliederliste (Beispieldatei je Form) zu testen. Bewusst kein Pendenz-Stil und kein Wegklicken — er ersetzt die Hinweis-Kachel «Noch keine Mitglieder erfasst» und verschwindet mit der dritten Mitgliedschaft. Die ToDo-Kachel «Bezeichnungen der Personen-Positionen» erscheint seit v0.28.139 erst, wenn eine Mitgliedschaft existiert (vorher hing sie nur an der Form V/H). Seit v0.28.140 gilt der Fokus auch für die Zahlen-Kachel der Übersicht, die Einstellungen-Kacheln Mail/Logs/Backup (menu.FOCUS_HIDDEN_TILES) und das Register «Mitgliedschaften» der Vereinsdaten (club_focus aus dem Context-Processor). Und der Knopf «Beispieldaten für diese Form einspielen» in der Formwahl lädt keine Datei mehr herunter, sondern führt die Beispieldatei still durch den ganzen Wizard bis zur Ergebnis-Seite (wizard_views._sample_import: Analyse, alles Erkannte und Restspalten übernehmen, Vereinsvorgabe, Sammelentscheide, stiller Import), nur bei leerer Mitgliederliste; «Diesen Import rückgängig» räumt die Testdaten wieder weg. Warum: Ein neuer Verein soll CluHu in einem Klick mit Daten sehen, ohne Download und Upload. Seit v0.28.144 zeigt die Beispieldatei «Familien & Haushalte» die Rollen: je Zeile vier Blöcke « 1 … 4» für Personen, die mitmachen (beim Tennisclub «Spieler 1 …»), und zwei Blöcke «Erziehungsberechtigte 1 … 2» für Erwachsene, die nur betreuen; die 30 Haushalte sind absichtlich verschieden zusammengesetzt (allein, Paar, alle vier machen mit, zwei Kinder mit beiden Eltern als Erziehungsberechtigte, ein Elternteil macht mit und eines betreut, alleinerziehend). Das Einspielen setzt die Figuren passend (p1–p4 «macht mit», c1–c2 «betreut»), die Rollenwörter im Spaltentitel führen den Wizard sicher zum Block. Warum: Bis v0.28.142 waren alle vier Blöcke «macht mit» — im Register «Mitglied-Empfänger» blieb «Erziehungsberechtigte 1» leer, und der Verein sah nicht, wie Betreuende aussehen.data_type 'contact', Wert «Name · Telefon»), im Feld-Manager wählbar, in der Tabelle mit zwei Teilen editierbar, Konvertierung Text → Kontaktangabe mit Probelauf (Endpunkt), nie in Personenliste, Newsletter oder Kalender. Importer und Erfassungsmaske legen Notfallnummern in diesem Typ an; bestehende Spalten wurden migriert (columns 0013).apps/core/vocab_addons.py, Programm › Einstellungen behält nur Vorlage und Schalter). Warum so: ein Ort für den Verein, kein Datenumbau; warum nicht ein Speicher für alles: das Programm liest seine Begriffe an vielen Stellen, eine Migration brächte Risiko ohne sichtbaren Gewinn. Details auf Kalender.Was kann es (aus User-Sicht): Die Spalte allein entscheidet, was eine Person tut. Wer mitmacht und betreut, steht im Register «Mitglied-Empfänger» in zwei Spalten: als «Spieler 2» mit den Kästchen und als «Erziehungsberechtigte 1» mit Name und «macht selbst mit · siehe Spieler 2» (ein Datensatz, zwei Zellen, kein zweiter Link). In jeder Spieler-Zelle steht der Knopf «+ als Erziehungsberechtigte»: er kopiert die Person in die nächste freie Spalte Erziehungsberechtigte; ist die Person nachweislich unter 18 oder hat sie keine E-Mail, fragt das Register vorher («Noah Keller ist 14 Jahre alt. Noah Keller hat keine E-Mail, also kein Login fürs Mitgliederportal. Trotzdem eintragen?»); der Knopf fehlt nur, wenn die Person schon dort steht oder alle sechs Positionen belegt sind. «×» in der zweiten Zelle nimmt «betreut» wieder weg, die Teilnahme bleibt (Austritt bleibt Sache der Mitgliederliste). Neue Spalten «Kind ohne Teilnahme 1 bis 6» zeigen Kinder, die zum Haushalt gehören, aber nicht mitmachen (nur der Geburtstagsgruss ist wählbar); «+ macht neu mit» lässt ein Kind mit Eintritt heute mitmachen; «weitere Personen» bleibt nur als Überlauf ab der siebten Person. Der Dialog «hinzufügen» in einer leeren Zelle bietet zuerst die Personen dieser Mitgliedschaft an («als Erziehungsberechtigte dazu», «macht neu mit») und erst darunter die Suche nach anderen Personen. Ein ⓘ im Spaltenkopf erklärt jede Spaltenart in einem Satz.
Im Mitgliederportal gilt: Wer betreut, pflegt alle Personen der Mitgliedschaft, die nicht selbst betreuen — neu auch Kinder ohne Teilnahme (Daten-Karte «Kind ohne Teilnahme», im Modul «Wer bekommt was» gesperrte Zellen «macht nicht mit», keine Rechnungsauswahl, kein E-Mail-Hinweis). Betreuende sehen einander nie, auch wenn beide mitmachen. Unter Import nachbearbeiten zählt die Kachel «Erwachsene und Kinder machen mit, niemand betreut» Mitgliedschaften, in denen Erwachsene mit Kindern spielen und niemand betreut; Vorschau mit Namen, «Anwenden» setzt die Erwachsenen zusätzlich als Erziehungsberechtigte; Mitgliedschaften ohne Geburtsdaten stehen als «nicht entscheidbar» dabei.
Im Import gibt es im Schritt Spielfiguren sechs Vorlagen mit Zählern («Kinder spielen, Eltern betreuen», «Eltern spielen auch», «Eltern-Kind-Angebot», «Familienmitgliedschaft», «Paar und Erwachsenen-Haushalt», «Mitglied mit Kontakt- oder Zahlungsperson»; Wörter aus dem Wortschatz, bei Turnvereinen steht das Eltern-Kind-Angebot vorne); ein Klick setzt die Figuren für den ganzen Lauf, danach bleibt alles von Hand änderbar. Ist eine Figur «Erziehungsberechtigte, die auch spielen» gesetzt, fragt die Prüfung «Wer in diesen Blöcken betreut auch?» mit Zahlen aus der Datei (Personen, erwachsen, unter 18, ohne Geburtsdatum): «alle», «nur Erwachsene» (18 am Importtag; Vorgabe, sobald Minderjährige im Block stehen; ohne Alter gilt der Block) oder «Spalte mit Merkmal» (x, ja, ✓, 1 je Block im Schritt Zuordnen; die anderen «machen nur mit» oder «betreuen nur»). Die Beispieldaten «Familien & Haushalte» zeigen die Doppelplatzierung nach dem Einspielen. Dieselben Vorlagen stehen über der Erfassungsmaske «Mitglied hinzufügen» (Form Familien & Haushalte).
Warum so gebaut, und warum nicht anders: Ein Link je Person und Mitgliedschaft (Constraint, Haushaltsindex, Faktura) — darum ist die Doppelplatzierung eine Darstellung mit zwei Feldern am Link, nie ein zweiter Link, und ohne Migration. Die Felder «macht mit» und «betreut» bleiben systemintern (D107); der Admin sieht nur Spalten, Figuren und Knöpfe, und das Wort «Haken» kommt in den neuen Texten nicht vor (D108, Yves: «ein Ausdruck, den die User nicht kennen»). Keine vierte Mitgliedschaftsform «Familienforum» (D96): die Form verzweigt an rund 44 Stellen, die Vorlage «Familienmitgliedschaft» (zwei Erwachsene, die mitmachen und betreuen, Kinder ohne Teilnahme) deckt den Fall in Form H. Der «+»-Knopf steht bei allen Mitmachenden, nicht nur bei solchen mit E-Mail (D102): «betreut» wirkt auch ohne Login — die Faktura zählt Betreuende beim Geschwisterrabatt als Erwachsene, die Vorgaben beim Anlegen richten Post an Betreuende; darum Rückfrage statt Verstecken. Sechs Vorlagen mit Zählern statt 47 Knöpfen (D111): die Zahl der Kinder ist ein Zähler, kein Fall; Blocknamen setzt eine Vorlage nur auf der Seite «betreut», weil p1, p2, c1, c2 nach dem Import vereinsweit gelten. Alter zählt nur im Moment der Importfrage und der Kachel, nie als laufende Automatik (D46, R4).
Bewusst nicht gebaut (Grenzen des Modells, O17 a): Zuständigkeit je Kind (alle Betreuenden pflegen alle Nicht-Betreuenden), Status Aktiv/Passiv je Person (gilt je Mitgliedschaft), mehr als eine Rechnungsempfängerin je Mitgliedschaft, Begleitung je Termin, Institution als Bezugsperson, Pausieren je Person — der Wizard nennt die erste Grenze in einem Satz, wo sie greift. Entscheid über diese Punkte erst mit echten Vereinslisten und den gespeicherten Vorlagen-Schlüsseln (P46).
Was kann es (aus User-Sicht): Hat eine Mitgliedschaft schon zwei Erziehungsberechtigte, fragt «+ als Erziehungsberechtigte» immer nach: «Familie Keller» hat schon zwei Erziehungsberechtigte (mit Namen), und im Mitgliederportal pflegt die neue Person danach alle in dieser Mitgliedschaft, die nicht selbst betreuen. Erst «Eintragen» legt die dritte Spalte an. Dieselbe Frage kommt, wenn man über «hinzufügen» eine bestehende Person des Vereins als dritte verknüpft. Die Bezeichnung der Person (etwa «Erwachsene 2») bleibt bei «+» und bei «×» stehen; nur eine leere Bezeichnung bekommt den Spaltennamen, und «×» nimmt nur diesen wieder weg.
Warum so: Der Knopf überschreibt niemanden, er setzt «betreut» am selben Link. Eine dritte betreuende Person ist ein echter Fall (Patchwork, Grosseltern) und technisch überall getragen. Der versehentliche Klick aber hatte stille Folgen im Mitgliederportal, darum die Rückfrage mit der Wirkung im Text. Vorher schrieb «+» den Spaltennamen über die Bezeichnung und «×» leerte sie: Die ursprüngliche Bezeichnung war weg.
Warum nicht anders: Eine Sperre bei zwei hätte die echten Fälle ausgeschlossen, und die Höchstzahl der Vorlage ist nach dem Import nicht gespeichert. Ein Fenster «wen ersetzen?» wäre eine neue Funktion mit eigener Folge (die abgelöste Person verliert die Sicht auf die Kinder); heute geht das mit «×» und «+». Technik: plusWarnings(cell, row), caretakersOf, isCaretakerLabel in static/js/cluhu-komm-matrix.js; der Server prüft weiterhin keine Höchstzahl.
Was es kann: Im Schritt Spielfiguren hat jedes Feld seine eigene Höchstzahl, sichtbar als
«2 / 8» am Feld: 8 Teilnehmende, 2 Erziehungsberechtigte, 2 Erziehungsberechtigte, die auch
mitmachen, 8 Kinder ohne Teilnahme, eine Kontaktangabe. Die Zähler der Vorlagen haben eigene
Grenzen (Kinder 8, Erwachsene 10, Kontaktpersonen 1 …); das «+» ist an der Grenze aus. Ein
volles Feld nimmt keine weitere Figur an und sagt warum. Die Erfassungsmaske prüft dieselben
Grenzen, das Register «Mitglied-Empfänger» zeigt bis zwölf Spalten je Seite.
Warum so: Die alte Sechs (P29) galt für alles zusammen, war aber als «sechs Teilnehmende»
gemeint; eine Familienmitgliedschaft mit zehn Erwachsenen oder acht Kindern passte nicht.
Alle Zahlen stehen in einer Tabelle (apps/organization/haushalt_vorlagen.py: KIND_MAX,
max je Zähler, KIND_LIMIT, MAX_PERSONS, SIDE_MAX), damit eine Änderung an einer Stelle
Wizard, Maske und Register zugleich trifft.
Warum nicht anders: Eine Grenze je Art (statt je Feld und je Zähler) wäre einfacher,
hätte aber Yves' Liste nicht abgebildet: «Erwachsene» einer Familienmitgliedschaft (bis 10)
sind dieselbe Art wie «Erziehungsberechtigte, die auch mitmachen» (von Hand 2). Darum darf
eine Vorlage über die Handgrenze eines Feldes gehen; das Feld zeigt dann «10 · Vorlage».
Der Server prüft je Art die grösste Grenze (10/10/2/8) und alles zusammen (30).
Was der Admin sieht: Der zweite Schritt des Imports in der Form «Familien & Haushalte» heisst
«Vorlage». Oben die sechs Karten mit ihren Zählern (− / +), sonst nichts: keine Figuren zum Ziehen,
keine Ablage, kein globaler Zähler «Wie viele Personen …», keine Karte «selbst zusammenstellen»,
keine Checkbox «Kontaktangabe». «Weiter» bleibt gesperrt, bis eine Karte gewählt ist. Der
Hilfetext: «Mit − und + stellt ihr ein, wie viele Personen höchstens in einer Mitgliedschaft
stehen. Einzelne Mitgliedschaften dürfen weniger haben.» Darunter die Vorschau «Daraus entstehen
beim Zuordnen diese Blöcke» als Mini-Liste, die wie die eigene Excel-Datei aussieht: die Blöcke
als Spalten (mit Rollenzeile «turnt», «betreut», «turnt und betreut», «dabei, ohne Teilnahme»),
darunter bis zu sieben Beispielzeilen «Beispiel Mitgliedschaft 1…7» mit Figuren — die erste ist
die vollste, die anderen sind kleiner und alle verschieden, damit man sieht: die Zahl ist eine
Höchstzahl. Keine Beispielzeile unterschreitet die Mindestzahl eines Zählers (v0.28.154): ein
Eltern-Kind-Angebot zeigt immer Kind und Begleitperson, «Eltern turnen auch» immer einen Erwachsenen. Kinder sind kleine
Figuren, Erwachsene grosse; wer mitmacht, trägt die zweifarbige Vereinsfigur, wer nur betreut oder
nicht teilnimmt, die graue. Ein Kettenglied an der Figur, in der Rollenzeile und in der Legende
markiert Personen, die mitmachen und betreuen. Dasselbe Kettenglied steht im Register
«Mitglied-Empfänger» in beiden Zellen einer solchen Person. Die Karte «Kinder turnen, Eltern
betreuen» hat neu den Zähler «Kinder ohne Teilnahme» (Geschwister in der Liste, die nicht
turnen); die Karte «Eltern turnen auch» sagt: «Kinder und Eltern turnen. Jede Person hat eigene
Spalten in eurer Liste. Die Eltern betreuen zusätzlich die Kinder.» Die Kontaktangabe
(Notfallnummer) ist Sache des Zuordnen-Schritts: dort steht «Kontaktangabe» bei jeder Restspalte
im Menü, mit dem Satz «Notfallkontakt: nur Name und Telefonnummer. Für CluHu keine Person,
bekommt weder Newsletter noch Rechnung und hat kein Login.»
Warum so gebaut: Eine Figur hatte nur eine Eigenschaft, ihr Feld. Ziehen war dasselbe wie
Zählen, nur aufwändiger — und die Vorlagen stellten die Figuren in den Schatten, zwei Bedienarten
nebeneinander verwirrten (Yves). Die Figuren bleiben als Bild, weil sie etwas zeigen, das kein
Text schafft: wie eine Zeile der Liste aussieht, dass Zeilen unterschiedlich voll sein dürfen,
und wer Kind und wer erwachsen ist. Die Vorschau zeigt eine mitmachende und betreuende Person
bewusst nur einmal: In der Excel-Liste hat sie einen Spaltenblock, die zwei Zellen entstehen erst
nach dem Import im Register. Eine Geisterkopie in einer zweiten Zelle wurde verworfen, weil sie
Admins dazu brächte, die Eltern doppelt zu erfassen. Zwei Rollenbahnen unter der Tabelle wurden
verworfen (zwei Zeilen Höhe, ab sechs Blöcken unruhig). Die Vorlagen-Karte wird nicht vorgewählt,
sondern «Weiter» gesperrt, weil die bewusste Wahl der Sinn des Schritts ist; eine stille Vorwahl
importierte Listen in der falschen Form. Die Kontaktangabe-Checkbox entfiel (Option A), weil die
Vorlagen nichts von Zusatzspalten wissen müssen und der Zuordnen-Schritt Notfall-Spalten ohnehin
erkennt; Bedingung dafür war, dass «Kontaktangabe» bei jeder Restspalte wählbar ist, nicht nur
bei erkannten («Mami Handy» fiel vorher durch). Das Datenformat (Figuren-Slots p1…, c1…, k1…) ist
unverändert; der Rückbau war reine Oberfläche, Register, Maske und Server blieben gleich.
Bewusst nicht gebaut: keine siebte Vorlage für Listen ohne Rollen-Spalten («Person 1 … 4»),
solange keine echte Liste so aussieht; keine Zeilenzahl über sieben (es erscheinen so viele
Zeilen, wie es verschiedene gibt — Paar: zwei, Kinder/Eltern: sechs, Eltern turnen auch: sieben).
Was kann es (aus User-Sicht): Unter Einstellungen › Vereinsdaten › Mitgliedschaften stehen jetzt zwei Blöcke zum Anlegen.
Die vier Modi:
| Modus | Erfassungsmaske | Import (Spalte zugeordnet, Zelle leer) |
|---|---|---|
| abfragen | Feld steht leer in der Maske | bleibt leer |
| verbergen | Feld steht nicht in der Maske und bleibt leer | bleibt leer |
| mit Vorgabe abfragen | Feld steht mit dem Vorgabewert in der Maske, änderbar | bekommt den Vorgabewert |
| stumm befüllen | Feld steht nicht in der Maske und bekommt immer den Vorgabewert | bekommt den Vorgabewert |
Dieselbe Einstellung je Feld steht in der Feldverwaltung «eigene Felder» (Mitgliederliste oder Personenliste › Aktionen › eigene Felder) im Block «Beim Anlegen». Beide Orte schreiben dieselben zwei Angaben am Feld. Die Listen unter Vereinsdaten sind die Übersicht über alle Felder, der Block in der Feldverwaltung ist der Ort, an dem man ein einzelnes Feld samt Optionen pflegt. Details und Prüfregeln auf Mitglieder, Abschnitt «Custom-Felder».
Warum so gebaut: Bis v0.28.177 liessen sich Modus und Vorgabewert nur im Import-Schritt «Vorgabe» setzen. Wer nach dem Import merkte, dass ein Feld in der Maske stört, hatte keinen Ort dafür. Die Vorgabe «wer bekommt was» gab es dagegen doppelt, im Import und hier, und der Import überschrieb beim Durchführen die Einstellung des Vereins. Jetzt gilt eine Wahrheit: die Einstellung des Vereins, und der Import wendet sie an. Hintergrund auf Import, Abschnitt «Abschluss ohne den Schritt «Vorgabe»».
Warum zwei Orte für die Zusatzfelder und nicht einer: Yves hat beide gewählt (B1 und B2). Die Feldverwaltung ist der Ort, an dem Felder entstehen: wer ein Dropdown anlegt, will die Vorgabe gleich mitgeben. Die Vereinsdaten sind der Ort, an dem jemand die Frage stellt «was passiert, wenn eine Mitgliedschaft neu entsteht?» und alle Felder auf einen Blick braucht. Beide prüfen und speichern über dasselbe Modul (apps/columns/entry_defaults.py), es gibt also keine zwei Regelwerke.
Warum nicht anders:
Grenzen: Die Modi wirken in der Erfassungsmaske für neue Mitgliedschaften und im Import. Wird nur eine Person angelegt, liest sie niemand. Den Block gibt es nur für Feldarten, die die Maske als Zusatzfeld zeigt; E-Mail, Telefon, Adresse, AHV, Datei, verknüpfte Felder und die Kontaktangabe haben ihn nicht.
Technik: core/views.vereinsdaten_mitgliedschaften_view, Aktion fields → entry_defaults.submit(club, post); Template templates/core/vereinsdaten_mitgliedschaften.html (Abschnitt id="zusatzfelder", Bestätigung data-fields-saved); Tests apps/columns/tests_beim_anlegen.py::VereinsdatenTests.
Alle fünf Etappen sind ohne Zwischentests gebaut; die Prüfliste für den Abschlusstest (28 Punkte Etappen 1–4, 6 Punkte Etappe 5) steht im Changelog-Bericht an Yves (Session cluhu-5, 6.11.2026) und im Scratchpad der Session. Testvereine musiktest und ringer-veteranen, nie der Spiez-Mandant; Mails an cluhu.test landen gesperrt im Postausgang.
Browser-Sichtprüfung der Chip-Leiste; Modul «Rechnungen» im Portal (Platzhalter, bis es Rechnungen im Portal gibt); tote Helfer des alten Import-Motors in apps/importer/services.py; Konvertierungs-UI Text → Kontaktangabe im Feld-Manager; Mehrzahl von «Training»/«Auftritt» im Wortschatz; Newsletter-Kategorien (D90); Langformat-Import (E6).