docs: update group concept

This commit is contained in:
Simon 2026-01-19 11:53:14 +01:00
parent 1d1f3b16b1
commit 1c7c56130d
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2

View file

@ -117,10 +117,10 @@ CREATE TABLE groups (
description TEXT, description TEXT,
inserted_at TIMESTAMP NOT NULL, inserted_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL,
CONSTRAINT groups_name_unique UNIQUE (name) CONSTRAINT groups_name_unique UNIQUE (LOWER(name))
); );
CREATE INDEX groups_name_index ON groups(name); CREATE INDEX groups_name_index ON groups(LOWER(name));
``` ```
**Attributes:** **Attributes:**
@ -130,7 +130,7 @@ CREATE INDEX groups_name_index ON groups(name);
- `inserted_at` / `updated_at` - Timestamps - `inserted_at` / `updated_at` - Timestamps
**Constraints:** **Constraints:**
- `name` must be unique - `name` must be unique (case-insensitive, using LOWER(name))
- `name` cannot be null - `name` cannot be null
- `name` max length: 100 characters - `name` max length: 100 characters
- `description` max length: 500 characters - `description` max length: 500 characters
@ -194,7 +194,7 @@ end
- `destroy` - Delete group (with confirmation) - `destroy` - Delete group (with confirmation)
**Validations:** **Validations:**
- `name` required, unique, max 100 chars - `name` required, unique (case-insensitive), max 100 chars
- `description` optional, max 500 chars - `description` optional, max 500 chars
#### `Mv.Membership.MemberGroup` #### `Mv.Membership.MemberGroup`
@ -319,7 +319,7 @@ end
- Display group badges for each member - Display group badges for each member
- Badge shows group name - Badge shows group name
- Multiple badges if member in multiple groups - Multiple badges if member in multiple groups
- Click badge to filter by that group - *(Optional)* Click badge to filter by that group (enhanced UX, can be added later)
**Filtering:** **Filtering:**
- Dropdown/select to filter by group - Dropdown/select to filter by group
@ -374,7 +374,11 @@ end
</span> </span>
``` ```
**Clickable Group Badge (for filtering):** **Clickable Group Badge (for filtering) - Optional:**
**Note:** This is an optional enhancement. The dropdown filter provides the same functionality. The clickable badge improves UX by showing the active filter visually and allowing quick removal.
**Estimated effort:** 1.5-2.5 hours
```heex ```heex
<button <button
@ -712,13 +716,13 @@ Das MVP umfasst die **grundlegenden Funktionen**, die notwendig sind, um Gruppen
7. ✅ Nach Gruppen filtern 7. ✅ Nach Gruppen filtern
8. ✅ Nach Gruppen sortieren 8. ✅ Nach Gruppen sortieren
9. ✅ Gruppen in Mitgliederdetail anzeigen 9. ✅ Gruppen in Mitgliederdetail anzeigen
10. ✅ Gruppen in Mitgliedersuche (automatisch via search_vector)
**Nicht im MVP:** **Nicht im MVP:**
- ❌ Hierarchische Gruppen - ❌ Hierarchische Gruppen
- ❌ Rollen/Positionen in Gruppen - ❌ Rollen/Positionen in Gruppen
- ❌ Erweiterte Gruppenattribute (Datum, Status, etc.) - ❌ Erweiterte Gruppenattribute (Datum, Status, etc.)
- ❌ Gruppen-spezifische Berechtigungen - ❌ Gruppen-spezifische Berechtigungen
- ❌ Gruppen in Mitgliedersuche (kann später kommen)
### Fachliche Einheiten (Vertikale Slices) ### Fachliche Einheiten (Vertikale Slices)
@ -846,11 +850,9 @@ Das MVP umfasst die **grundlegenden Funktionen**, die notwendig sind, um Gruppen
- ✅ Einheit 3: Gruppen-Verwaltungs-UI - ✅ Einheit 3: Gruppen-Verwaltungs-UI
- ✅ Einheit 4: Gruppen in Mitgliederübersicht - ✅ Einheit 4: Gruppen in Mitgliederübersicht
- ✅ Einheit 5: Gruppen in Mitgliederdetail - ✅ Einheit 5: Gruppen in Mitgliederdetail
- ✅ Einheit 6: Gruppen in Mitgliedersuche (automatisch via search_vector)
- ✅ Einheit 7: Berechtigungen - ✅ Einheit 7: Berechtigungen
**Optional für MVP (kann später kommen):**
- ⏸️ Einheit 6: Gruppen in Mitgliedersuche (kann in Phase 2 kommen)
**Total MVP Estimation:** 13-15h **Total MVP Estimation:** 13-15h
### Implementierungsreihenfolge ### Implementierungsreihenfolge
@ -947,11 +949,13 @@ Jede fachliche Einheit kann als **separates Issue** umgesetzt werden:
3. Group filter dropdown 3. Group filter dropdown
4. Group sorting 4. Group sorting
5. URL query param persistence 5. URL query param persistence
6. *(Optional)* Clickable group badges for filtering (enhanced UX)
**Deliverables:** **Deliverables:**
- Groups visible in member overview - Groups visible in member overview
- Filter by group - Filter by group (via dropdown)
- Sort by group - Sort by group
- *(Optional)* Clickable badges for quick filtering
**Estimation:** 2-3h **Estimation:** 2-3h
@ -1046,12 +1050,14 @@ Jede fachliche Einheit kann als **separates Issue** umgesetzt werden:
- Group filter dropdown - Group filter dropdown
- Group sorting - Group sorting
- URL persistence - URL persistence
- *(Optional)* Clickable group badges for filtering
**Acceptance Criteria:** **Acceptance Criteria:**
- Groups visible in member overview - Groups visible in member overview
- Can filter by group - Can filter by group (via dropdown)
- Can sort by group - Can sort by group
- Filter persists in URL - Filter persists in URL
- *(Optional)* Can filter by clicking group badge
### Issue 4: Member Detail - Groups Display ### Issue 4: Member Detail - Groups Display
**Type:** Frontend **Type:** Frontend
@ -1069,13 +1075,16 @@ Jede fachliche Einheit kann als **separates Issue** umgesetzt werden:
**Type:** Backend **Type:** Backend
**Estimation:** 2h **Estimation:** 2h
**Tasks:** **Tasks:**
- Update search vector trigger - Update search vector trigger to include group names
- Extend fuzzy search - Extend fuzzy search to search group names
- Test search - Test search functionality
**Acceptance Criteria:** **Acceptance Criteria:**
- Group names searchable in member search - Group names searchable in member search (automatic via search_vector)
- Search finds members by group name - Search finds members by group name
- Search vector updates automatically when member-group associations change
**Note:** This is part of MVP as group names are automatically included in full-text search once the search_vector trigger is updated.
### Issue 6: Authorization ### Issue 6: Authorization
**Type:** Backend/Frontend **Type:** Backend/Frontend
@ -1132,11 +1141,12 @@ defmodule Mv.Membership.GroupTest do
assert %{name: ["has already been taken"]} = errors_on(changeset) assert %{name: ["has already been taken"]} = errors_on(changeset)
end end
test "name uniqueness is case-sensitive" do test "name uniqueness is case-insensitive" do
Group.create!(%{name: "Vorstand"}) Group.create!(%{name: "Vorstand"})
attrs = %{name: "VORSTAND"} attrs = %{name: "VORSTAND"}
# For MVP: case-sensitive uniqueness # Name uniqueness should be case-insensitive
assert {:ok, _} = Group.create(attrs) assert {:error, changeset} = Group.create(attrs)
assert %{name: ["has already been taken"]} = errors_on(changeset)
end end
test "allows description to be nil" do test "allows description to be nil" do
@ -1458,8 +1468,8 @@ create table(:groups, primary_key: false) do
add :updated_at, :utc_datetime_usec, null: false add :updated_at, :utc_datetime_usec, null: false
end end
create unique_index(:groups, [:name]) create unique_index(:groups, [fragment("LOWER(name)")], name: :groups_name_unique)
create index(:groups, [:name]) create index(:groups, [fragment("LOWER(name)")], name: :groups_name_index)
``` ```
**Migration 2: Create member_groups join table** **Migration 2: Create member_groups join table**