mitgliederverwaltung/docs/groups-architecture.md

27 KiB

Groups - Technical Architecture

Project: Mila - Membership Management System
Feature: Groups Management
Version: 1.0
Last Updated: 2025-01-XX
Status: Architecture Design - Ready for Implementation


Purpose

This document defines the technical architecture for the Groups feature. It focuses on architectural decisions, patterns, module structure, and integration points without concrete implementation details.

Related Documents:


Table of Contents

  1. Architecture Principles
  2. Domain Structure
  3. Data Architecture
  4. Business Logic Architecture
  5. UI/UX Architecture
  6. Integration Points
  7. Authorization
  8. Performance Considerations
  9. Future Extensibility
  10. Implementation Phases

Architecture Principles

Core Design Decisions

  1. Many-to-Many Relationship:

    • Members can belong to multiple groups
    • Groups can contain multiple members
    • Implemented via join table (member_groups) as separate Ash resource
  2. Flat Structure (MVP):

    • Groups are initially flat (no hierarchy)
    • Architecture designed to allow hierarchical extension later
    • No parent/child relationships in MVP
  3. Minimal Attributes (MVP):

    • Only name and description in initial version
    • Extensible for future attributes (dates, status, etc.)
  4. Cascade Deletion:

    • Deleting a group removes all member-group associations
    • Members themselves are not deleted (CASCADE on join table only)
    • Requires explicit confirmation with group name input
  5. Search Integration:

    • Groups searchable within member search (not separate search)
    • Group names included in member search vector for full-text search

Domain Structure

Ash Domain: Mv.Membership

Purpose: Groups are part of the Membership domain, alongside Members and CustomFields

New Resources:

  • Group - Group definitions (name, description)
  • MemberGroup - Join table for many-to-many relationship between Members and Groups

Extended Resources:

  • Member - Extended with has_many :groups relationship (through MemberGroup)

Module Organization

lib/
├── membership/
│   ├── membership.ex              # Domain definition (extended)
│   ├── group.ex                   # Group resource
│   ├── member_group.ex            # MemberGroup join table resource
│   └── member.ex                  # Extended with groups relationship
├── mv_web/
│   └── live/
│       ├── group_live/
│       │   ├── index.ex           # Groups management page
│       │   ├── form.ex            # Create/edit group form
│       │   └── show.ex            # Group detail view
│       └── member_live/
│           ├── index.ex            # Extended with group filtering/sorting
│           └── show.ex            # Extended with group display
└── mv/
    └── membership/
        └── group/                 # Future: Group-specific business logic
            └── helpers.ex        # Group-related helper functions

Data Architecture

Database Schema

groups Table

CREATE TABLE groups (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
  name TEXT NOT NULL,
  description TEXT,
  inserted_at TIMESTAMP NOT NULL,
  updated_at TIMESTAMP NOT NULL,
  CONSTRAINT groups_name_unique UNIQUE (name)
);

CREATE INDEX groups_name_index ON groups(name);

Attributes:

  • id - UUID v7 primary key
  • name - Unique group name (required, max 100 chars)
  • description - Optional description (max 500 chars)
  • inserted_at / updated_at - Timestamps

Constraints:

  • name must be unique
  • name cannot be null
  • name max length: 100 characters
  • description max length: 500 characters

member_groups Table (Join Table)

CREATE TABLE member_groups (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
  member_id UUID NOT NULL REFERENCES members(id) ON DELETE CASCADE,
  group_id UUID NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
  inserted_at TIMESTAMP NOT NULL,
  updated_at TIMESTAMP NOT NULL,
  CONSTRAINT member_groups_unique_member_group UNIQUE (member_id, group_id)
);

CREATE INDEX member_groups_member_id_index ON member_groups(member_id);
CREATE INDEX member_groups_group_id_index ON member_groups(group_id);

Attributes:

  • id - UUID v7 primary key
  • member_id - Foreign key to members (CASCADE delete)
  • group_id - Foreign key to groups (CASCADE delete)
  • inserted_at / updated_at - Timestamps

Constraints:

  • Unique constraint on (member_id, group_id) - prevents duplicate memberships
  • CASCADE delete: Removing member removes all group associations
  • CASCADE delete: Removing group removes all member associations

Indexes:

  • Index on member_id for efficient member → groups queries
  • Index on group_id for efficient group → members queries

Ash Resources

Mv.Membership.Group

use Ash.Resource,
  domain: Mv.Membership,
  data_layer: AshPostgres.DataLayer

relationships do
  has_many :member_groups, Mv.Membership.MemberGroup
  many_to_many :members, Mv.Membership.Member,
    through: Mv.Membership.MemberGroup
end

calculations do
  calculate :member_count, :integer,
    expr(count(member_groups, :id))
end

Actions:

  • create - Create new group
  • read - List/search groups
  • update - Update group name/description
  • destroy - Delete group (with confirmation)

Validations:

  • name required, unique, max 100 chars
  • description optional, max 500 chars

Mv.Membership.MemberGroup

use Ash.Resource,
  domain: Mv.Membership,
  data_layer: AshPostgres.DataLayer

relationships do
  belongs_to :member, Mv.Membership.Member
  belongs_to :group, Mv.Membership.Group
end

Actions:

  • create - Add member to group
  • read - Query member-group associations
  • destroy - Remove member from group

Validations:

  • Unique constraint on (member_id, group_id)

Mv.Membership.Member (Extended)

relationships do
  # ... existing relationships ...
  
  has_many :member_groups, Mv.Membership.MemberGroup
  many_to_many :groups, Mv.Membership.Group,
    through: Mv.Membership.MemberGroup
end

New Actions:

  • add_to_groups - Add member to one or more groups
  • remove_from_groups - Remove member from one or more groups

Business Logic Architecture

Group Management

Create Group:

  • Validate name uniqueness
  • Generate slug (if needed for future URL-friendly identifiers)
  • Return created group

Update Group:

  • Validate name uniqueness (if name changed)
  • Update description
  • Return updated group

Delete Group:

  • Check if group has members (for warning display)
  • Require explicit confirmation (group name input)
  • Cascade delete all member_groups associations
  • Group itself deleted

Member-Group Association

Add Member to Group:

  • Validate member exists
  • Validate group exists
  • Check for duplicate association
  • Create MemberGroup record

Remove Member from Group:

  • Find MemberGroup record
  • Delete association
  • Member and group remain intact

Bulk Operations:

  • Add member to multiple groups in single transaction
  • Remove member from multiple groups in single transaction

Search Integration

Member Search Enhancement:

  • Include group names in member search vector
  • When searching for member, also search in associated group names
  • Example: Searching "Arbeitsgruppe" finds all members in groups with "Arbeitsgruppe" in name

Implementation:

  • Extend member.search_vector trigger to include group names
  • Update trigger on member_groups changes
  • Use PostgreSQL tsvector for full-text search

UI/UX Architecture

Groups Management Page (/groups)

Route: live "/groups", GroupLive.Index, :index

Features:

  • List all groups in table
  • Create new group button
  • Edit group (inline or modal)
  • Delete group with confirmation modal
  • Show member count per group

Table Columns:

  • Name (sortable, searchable)
  • Description
  • Member Count
  • Actions (Edit, Delete)

Delete Confirmation Modal:

  • Warning: "X members are in this group"
  • Confirmation: "All member-group associations will be permanently deleted"
  • Input field: Enter group name to confirm
  • Delete button disabled until name matches
  • Cancel button

Member Overview Integration

New Column: "Gruppen" (Groups)

  • Display group badges for each member
  • Badge shows group name
  • Multiple badges if member in multiple groups
  • Click badge to filter by that group

Filtering:

  • Dropdown/select to filter by group
  • "All groups" option (default)
  • Filter persists in URL query params
  • Works with existing search/sort

Sorting:

  • Sort by group name (members with groups first, then alphabetically)
  • Sort by number of groups (members with most groups first)

Search:

  • Group names included in member search
  • Searching group name shows all members in that group

Member Detail View Integration

New Section: "Gruppen" (Groups)

  • List all groups member belongs to
  • Display as badges or list
  • Add/remove groups inline
  • Link to group detail page

Group Detail View (/groups/:id)

Route: live "/groups/:id", GroupLive.Show, :show

Features:

  • Display group name and description
  • List all members in group
  • Link to member detail pages
  • Edit group button
  • Delete group button (with confirmation)

Integration Points

Member Search Vector

Trigger Update:

  • When member_groups record created/deleted
  • Update members.search_vector to include group names
  • Use PostgreSQL trigger for automatic updates

Search Query:

  • Extend existing fuzzy_search to include group names
  • Group names added with weight 'B' (same as city, etc.)

Member Form

Future Enhancement:

  • Add groups selection in member form
  • Multi-select dropdown for groups
  • Add/remove groups during member creation/edit

Authorization Integration

Current (MVP):

  • Only admins can manage groups
  • Uses existing Mv.Authorization.Checks.HasPermission
  • Permission: groups resource with :all scope

Future:

  • Group-specific permissions
  • Role-based group management
  • Member-level group assignment permissions

Authorization

Permission Model (MVP)

Resource: groups

Actions:

  • read - View groups (all users with member read permission)
  • create - Create groups (admin only)
  • update - Edit groups (admin only)
  • destroy - Delete groups (admin only)

Scopes:

  • :all - All groups (for admins)
  • :all - All groups (for read-only users, read permission only)

Permission Sets Update

Admin Permission Set:

%{
  resources: [
    # ... existing resources ...
    %{resource: "groups", action: :read, scope: :all, granted: true},
    %{resource: "groups", action: :create, scope: :all, granted: true},
    %{resource: "groups", action: :update, scope: :all, granted: true},
    %{resource: "groups", action: :destroy, scope: :all, granted: true}
  ]
}

Read-Only Permission Set:

%{
  resources: [
    # ... existing resources ...
    %{resource: "groups", action: :read, scope: :all, granted: true}
  ]
}

Member-Group Association Permissions

Current (MVP):

  • Adding/removing members from groups requires group update permission
  • Managed through group edit interface

Future:

  • Separate permission for member-group management
  • Member-level permissions for self-assignment

Performance Considerations

Database Indexes

Critical Indexes:

  • groups.name - For uniqueness and search
  • member_groups.member_id - For member → groups queries
  • member_groups.group_id - For group → members queries
  • Composite index on (member_id, group_id) - For uniqueness check

Query Optimization

Member Overview:

  • Load groups with members in single query (using load)
  • Use Ash.Query.load(groups: [:id, :name]) to minimize data transfer
  • Filter groups at database level when filtering by group

Group Detail:

  • Paginate member list for large groups
  • Load member count via calculation (not separate query)

Search Performance

Search Vector:

  • Group names included in search_vector (tsvector)
  • GIN index on search_vector for fast full-text search
  • Trigger updates on member_groups changes

Filtering:

  • Use database-level filtering (not in-memory)
  • Leverage indexes for group filtering

Future Extensibility

Hierarchical Groups

Design for Future:

  • Add parent_group_id to groups table (nullable)
  • Add parent_group relationship (self-referential)
  • Add validation to prevent circular references
  • Add calculation for path (e.g., "Parent > Child > Grandchild")

Migration Path:

  • Add column with NULL default (all groups initially root-level)
  • Add foreign key constraint
  • Add validation logic
  • Update UI to show hierarchy

Group Attributes

Future Attributes:

  • created_at / founded_date - Group creation date
  • dissolved_at - Group dissolution date
  • status - Active/inactive/suspended
  • color - UI color for badges
  • icon - Icon identifier

Migration Path:

  • Add nullable columns
  • Set defaults for existing groups
  • Update UI to display new attributes

Roles/Positions in Groups

Future Feature:

  • Add member_group_roles table
  • Link MemberGroup to Role (e.g., "Leiter", "Mitglied")
  • Extend MemberGroup with role_id foreign key
  • Display role in member detail and group detail views

Group Permissions

Future Feature:

  • Group-specific permission sets
  • Role-based group access
  • Member-level group management permissions

Feature Breakdown: Fachliche Einheiten und MVP

Strategie: Vertikaler Schnitt

Das Groups-Feature wird in fachlich abgeschlossene, vertikale Einheiten aufgeteilt. Jede Einheit liefert einen vollständigen, nutzbaren Funktionsbereich, der unabhängig getestet und ausgeliefert werden kann.

MVP Definition

Minimal Viable Product (MVP): Das MVP umfasst die grundlegenden Funktionen, die notwendig sind, um Gruppen zu verwalten und Mitgliedern zuzuordnen:

  1. Gruppen anlegen (Name + Beschreibung)
  2. Gruppen bearbeiten
  3. Gruppen löschen (mit Bestätigung)
  4. Mitglieder zu Gruppen zuordnen
  5. Mitglieder aus Gruppen entfernen
  6. Gruppen in Mitgliederübersicht anzeigen
  7. Nach Gruppen filtern
  8. Nach Gruppen sortieren
  9. Gruppen in Mitgliederdetail anzeigen

Nicht im MVP:

  • Hierarchische Gruppen
  • Rollen/Positionen in Gruppen
  • Erweiterte Gruppenattribute (Datum, Status, etc.)
  • Gruppen-spezifische Berechtigungen
  • Gruppen in Mitgliedersuche (kann später kommen)

Fachliche Einheiten (Vertikale Slices)

Einheit 1: Gruppen-Verwaltung (Backend)

Fachlicher Scope: Administratoren können Gruppen im System verwalten

Umfang:

  • Gruppen-Ressource (Name, Beschreibung)
  • CRUD-Operationen für Gruppen
  • Validierungen (Name eindeutig, Längenlimits)
  • Lösch-Logik mit Cascade-Verhalten

Deliverable: Gruppen können über Ash API erstellt, bearbeitet und gelöscht werden

Abhängigkeiten: Keine

Estimation: 4-5h


Einheit 2: Mitglieder-Gruppen-Zuordnung (Backend)

Fachlicher Scope: Mitglieder können Gruppen zugeordnet werden

Umfang:

  • MemberGroup Join-Tabelle
  • Many-to-Many Relationship
  • Add/Remove Member-Group Assoziationen
  • Cascade Delete Verhalten

Deliverable: Mitglieder können Gruppen zugeordnet und entfernt werden

Abhängigkeiten: Einheit 1 (Gruppen müssen existieren)

Estimation: 2-3h (kann mit Einheit 1 kombiniert werden)


Einheit 3: Gruppen-Verwaltungs-UI

Fachlicher Scope: Administratoren können Gruppen über die Weboberfläche verwalten

Umfang:

  • Gruppen-Übersichtsseite (/groups)
  • Gruppen-Formular (Anlegen/Bearbeiten)
  • Gruppen-Detailseite (Mitgliederliste)
  • Lösch-Bestätigungs-Modal (mit Name-Eingabe)

Deliverable: Vollständige Gruppen-Verwaltung über UI möglich

Abhängigkeiten: Einheit 1 + 2 (Backend muss funktionieren)

Estimation: 3-4h


Einheit 4: Gruppen in Mitgliederübersicht

Fachlicher Scope: Gruppen werden in der Mitgliederübersicht angezeigt und können gefiltert/sortiert werden

Umfang:

  • "Gruppen"-Spalte mit Badges
  • Filter-Dropdown für Gruppen
  • Sortierung nach Gruppen
  • URL-Parameter-Persistenz

Deliverable: Gruppen sichtbar, filterbar und sortierbar in Mitgliederübersicht

Abhängigkeiten: Einheit 1 + 2 (Gruppen und Zuordnungen müssen existieren)

Estimation: 2-3h


Einheit 5: Gruppen in Mitgliederdetail

Fachlicher Scope: Gruppen werden in der Mitgliederdetail-Ansicht angezeigt

Umfang:

  • "Gruppen"-Sektion in Member Show
  • Badge-Anzeige
  • Links zu Gruppendetail-Seiten

Deliverable: Gruppen sichtbar in Mitgliederdetail

Abhängigkeiten: Einheit 3 (Gruppendetail-Seite muss existieren)

Estimation: 1-2h


Einheit 6: Gruppen in Mitgliedersuche

Fachlicher Scope: Gruppen-Namen sind in der Mitgliedersuche durchsuchbar

Umfang:

  • Search Vector Update (Trigger)
  • Fuzzy Search Erweiterung
  • Test der Suchfunktionalität

Deliverable: Suche nach Gruppennamen findet zugehörige Mitglieder

Abhängigkeiten: Einheit 1 + 2 (Gruppen und Zuordnungen müssen existieren)

Estimation: 2h


Einheit 7: Berechtigungen

Fachlicher Scope: Nur Administratoren können Gruppen verwalten

Umfang:

  • Gruppen zu Permission Sets hinzufügen
  • Authorization Policies implementieren
  • UI-Berechtigungsprüfungen

Deliverable: Berechtigungen korrekt implementiert

Abhängigkeiten: Alle vorherigen Einheiten (Feature muss funktionieren)

Estimation: 1-2h


MVP-Zusammensetzung

MVP besteht aus:

  • Einheit 1: Gruppen-Verwaltung (Backend)
  • Einheit 2: Mitglieder-Gruppen-Zuordnung (Backend)
  • Einheit 3: Gruppen-Verwaltungs-UI
  • Einheit 4: Gruppen in Mitgliederübersicht
  • Einheit 5: Gruppen in Mitgliederdetail
  • 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

Implementierungsreihenfolge

Empfohlene Reihenfolge:

  1. Phase 1: Backend Foundation (Einheit 1 + 2)

    • Gruppen-Ressource
    • MemberGroup Join-Tabelle
    • CRUD-Operationen
    • Ergebnis: Gruppen können über API verwaltet werden
  2. Phase 2: Verwaltungs-UI (Einheit 3)

    • Gruppen-Übersicht
    • Gruppen-Formular
    • Gruppen-Detail
    • Ergebnis: Gruppen können über UI verwaltet werden
  3. Phase 3: Mitglieder-Integration (Einheit 4 + 5)

    • Gruppen in Übersicht
    • Gruppen in Detail
    • Ergebnis: Gruppen sichtbar in Mitglieder-Ansichten
  4. Phase 4: Such-Integration (Einheit 6)

    • Search Vector Update
    • Ergebnis: Gruppen durchsuchbar
  5. Phase 5: Berechtigungen (Einheit 7)

    • Permission Sets
    • Policies
    • Ergebnis: Berechtigungen korrekt

Issue-Struktur

Jede fachliche Einheit kann als separates Issue umgesetzt werden:

  • Issue 1: Gruppen-Ressource & Datenbank-Schema (Einheit 1 + 2)
  • Issue 2: Gruppen-Verwaltungs-UI (Einheit 3)
  • Issue 3: Gruppen in Mitgliederübersicht (Einheit 4)
  • Issue 4: Gruppen in Mitgliederdetail (Einheit 5)
  • Issue 5: Gruppen in Mitgliedersuche (Einheit 6)
  • Issue 6: Berechtigungen (Einheit 7)

Alternative: Issue 3 und 4 können kombiniert werden, da sie beide die Anzeige von Gruppen betreffen.


Implementation Phases

Phase 1: MVP Core (Foundation)

Goal: Basic group management and member assignment

Tasks:

  1. Create Group resource (name, description)
  2. Create MemberGroup join table resource
  3. Extend Member with groups relationship
  4. Database migrations
  5. Basic CRUD actions for groups
  6. Add/remove members from groups (via group management)

Deliverables:

  • Groups can be created, edited, deleted
  • Members can be added/removed from groups
  • Basic validation and constraints

Estimation: 4-5h

Phase 2: UI - Groups Management

Goal: Complete groups management interface

Tasks:

  1. Groups index page (/groups)
  2. Group form (create/edit)
  3. Group show page (list members)
  4. Delete confirmation modal (with name input)
  5. Member count display

Deliverables:

  • Full groups management UI
  • Delete confirmation workflow
  • Group detail view

Estimation: 3-4h

Phase 3: Member Overview Integration

Goal: Display and filter groups in member overview

Tasks:

  1. Add "Gruppen" column to member overview table
  2. Display group badges
  3. Group filter dropdown
  4. Group sorting
  5. URL query param persistence

Deliverables:

  • Groups visible in member overview
  • Filter by group
  • Sort by group

Estimation: 2-3h

Phase 4: Member Detail Integration

Goal: Display groups in member detail view

Tasks:

  1. Add "Gruppen" section to member show page
  2. Display group badges
  3. Link to group detail pages

Deliverables:

  • Groups visible in member detail
  • Navigation to group pages

Estimation: 1-2h

Phase 5: Search Integration

Goal: Include groups in member search

Tasks:

  1. Update search_vector trigger to include group names
  2. Extend fuzzy_search to search group names
  3. Test search functionality

Deliverables:

  • Group names searchable in member search
  • Search finds members by group name

Estimation: 2h

Phase 6: Authorization

Goal: Implement permission-based access control

Tasks:

  1. Add groups to permission sets
  2. Implement authorization policies
  3. Test permission enforcement
  4. Update UI to respect permissions

Deliverables:

  • Only admins can manage groups
  • All users can view groups (if they can view members)

Estimation: 1-2h

Total Estimation: 13-18h

Note: This aligns with the issue estimation of 15h.


Issue Breakdown

Issue 1: Groups Resource & Database Schema

Type: Backend
Estimation: 4-5h
Tasks:

  • Create Group resource
  • Create MemberGroup join table resource
  • Extend Member resource
  • Database migrations
  • Basic validations

Acceptance Criteria:

  • Groups can be created via Ash API
  • Members can be associated with groups
  • Database constraints enforced

Issue 2: Groups Management UI

Type: Frontend
Estimation: 3-4h
Tasks:

  • Groups index page
  • Group form (create/edit)
  • Group show page
  • Delete confirmation modal

Acceptance Criteria:

  • Groups can be created/edited/deleted via UI
  • Delete requires name confirmation
  • Member count displayed

Issue 3: Member Overview - Groups Integration

Type: Frontend
Estimation: 2-3h
Tasks:

  • Add groups column with badges
  • Group filter dropdown
  • Group sorting
  • URL persistence

Acceptance Criteria:

  • Groups visible in member overview
  • Can filter by group
  • Can sort by group
  • Filter persists in URL

Issue 4: Member Detail - Groups Display

Type: Frontend
Estimation: 1-2h
Tasks:

  • Add groups section to member show
  • Display group badges
  • Link to group pages

Acceptance Criteria:

  • Groups visible in member detail
  • Links to group pages work

Issue 5: Search Integration

Type: Backend
Estimation: 2h
Tasks:

  • Update search vector trigger
  • Extend fuzzy search
  • Test search

Acceptance Criteria:

  • Group names searchable in member search
  • Search finds members by group name

Issue 6: Authorization

Type: Backend/Frontend
Estimation: 1-2h
Tasks:

  • Add groups to permission sets
  • Implement policies
  • Test permissions

Acceptance Criteria:

  • Only admins can manage groups
  • All users can view groups (if they can view members)

Testing Strategy

Unit Tests

Group Resource:

  • Name uniqueness validation
  • Name/description length constraints
  • Member count calculation

MemberGroup Resource:

  • Unique constraint on (member_id, group_id)
  • Cascade delete behavior

Integration Tests

Group Management:

  • Create group
  • Update group
  • Delete group with confirmation
  • Add member to group
  • Remove member from group

Member-Group Relationships:

  • Member can belong to multiple groups
  • Group can contain multiple members
  • Cascade delete when member deleted
  • Cascade delete when group deleted

UI Tests

Groups Management:

  • Groups index page loads
  • Create group form works
  • Edit group form works
  • Delete confirmation modal works
  • Name confirmation required for delete

Member Overview:

  • Groups column displays correctly
  • Group filter works
  • Group sorting works
  • URL params persist

Member Detail:

  • Groups section displays
  • Links to group pages work

Migration Strategy

Database Migrations

Migration 1: Create groups table

create table(:groups, primary_key: false) do
  add :id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true
  add :name, :text, null: false
  add :description, :text
  add :inserted_at, :utc_datetime_usec, null: false
  add :updated_at, :utc_datetime_usec, null: false
end

create unique_index(:groups, [:name])
create index(:groups, [:name])

Migration 2: Create member_groups join table

create table(:member_groups, primary_key: false) do
  add :id, :uuid, null: false, default: fragment("uuid_generate_v7()"), primary_key: true
  add :member_id, :uuid, null: false
  add :group_id, :uuid, null: false
  add :inserted_at, :utc_datetime_usec, null: false
  add :updated_at, :utc_datetime_usec, null: false
end

create unique_index(:member_groups, [:member_id, :group_id])
create index(:member_groups, [:member_id])
create index(:member_groups, [:group_id])

alter table(:member_groups) do
  modify :member_id, references(:members, on_delete: :delete_all, type: :uuid)
  modify :group_id, references(:groups, on_delete: :delete_all, type: :uuid)
end

Migration 3: Update search_vector trigger (if needed)

  • Extend trigger to include group names
  • Update trigger function

Code Migration

Ash Resources:

  • Use mix ash.codegen to generate migrations
  • Manually adjust if needed

Domain Updates:

  • Add groups resources to Mv.Membership domain
  • Define domain actions

Summary

This architecture provides a solid foundation for the Groups feature while maintaining flexibility for future enhancements. The many-to-many relationship is implemented via a join table, following existing patterns in the codebase. The MVP focuses on core functionality (create, edit, delete groups, assign members) with clear extension points for hierarchical groups, roles, and advanced permissions.

The implementation is split into 6 manageable issues, totaling approximately 15 hours of work, aligning with the original estimation. Each phase builds on the previous one, allowing for incremental development and testing.