Merge pull request 'Docs, Code Guidelines and Progress Log' (#193) from feature/guidelines_docs into main
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #193
This commit is contained in:
commit
a4ed2498e7
6 changed files with 5289 additions and 16 deletions
2576
CODE_GUIDELINES.md
Normal file
2576
CODE_GUIDELINES.md
Normal file
File diff suppressed because it is too large
Load diff
38
README.md
38
README.md
|
|
@ -161,27 +161,33 @@ Now you can log in to Mila via OIDC!
|
||||||
|
|
||||||
## 🏗️ Architecture
|
## 🏗️ Architecture
|
||||||
|
|
||||||
- **Backend:** Elixir, Phoenix, LiveView, Ash Framework
|
**Tech Stack Overview:**
|
||||||
- **Frontend:** Phoenix LiveView + DaisyUI + Heroicons
|
- **Backend:** Elixir + Phoenix + Ash Framework
|
||||||
- **Database:** PostgreSQL (via AshPostgres)
|
- **Frontend:** Phoenix LiveView + Tailwind CSS + DaisyUI
|
||||||
- **Auth:** AshAuthentication (OIDC + password strategy)
|
- **Database:** PostgreSQL
|
||||||
- **Mail:** Swoosh
|
- **Auth:** AshAuthentication (OIDC + password)
|
||||||
- **i18n:** Gettext
|
|
||||||
|
|
||||||
Code structure:
|
**Code Structure:**
|
||||||
- `lib/mv/` — core Ash resources/domains (`Accounts`, `Membership`)
|
- `lib/accounts/` & `lib/membership/` — Ash resources and domains
|
||||||
- `lib/mv_web/` — Phoenix controllers, LiveViews, components
|
- `lib/mv_web/` — Phoenix controllers, LiveViews, components
|
||||||
- `assets/` — frontend assets (Tailwind, JS, etc.)
|
- `assets/` — Tailwind, JavaScript, static files
|
||||||
|
|
||||||
|
📚 **Full tech stack details:** See [`CODE_GUIDELINES.md`](CODE_GUIDELINES.md)
|
||||||
|
📖 **Implementation history:** See [`docs/development-progress-log.md`](docs/development-progress-log.md)
|
||||||
|
🗄️ **Database schema:** See [`docs/database-schema-readme.md`](docs/database-schema-readme.md)
|
||||||
|
|
||||||
## 🧑💻 Development
|
## 🧑💻 Development
|
||||||
|
|
||||||
Useful `just` commands:
|
**Common commands:**
|
||||||
- `just run` — start DB, Mailcrab, Rauthy, app
|
```bash
|
||||||
- `just test` — run tests
|
just run # Start full dev environment
|
||||||
- `just lint` — run code style checks (credo, formatter)
|
just test # Run test suite
|
||||||
- `just audit` — run security audits
|
just lint # Code style checks
|
||||||
- `just reset-database` — reset local DB
|
just audit # Security audits
|
||||||
- `just regen-migrations <name>` — regenerate migrations
|
just reset-database # Reset local DB
|
||||||
|
```
|
||||||
|
|
||||||
|
📚 **Full development guidelines:** See [`CODE_GUIDELINES.md`](CODE_GUIDELINES.md)
|
||||||
|
|
||||||
## 📦 Production Deployment
|
## 📦 Production Deployment
|
||||||
|
|
||||||
|
|
|
||||||
392
docs/database-schema-readme.md
Normal file
392
docs/database-schema-readme.md
Normal file
|
|
@ -0,0 +1,392 @@
|
||||||
|
# Database Schema Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document provides a comprehensive overview of the Mila Membership Management System database schema.
|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
- **DBML File:** [`database_schema.dbml`](./database_schema.dbml)
|
||||||
|
- **Visualize Online:**
|
||||||
|
- [dbdiagram.io](https://dbdiagram.io) - Upload the DBML file
|
||||||
|
- [dbdocs.io](https://dbdocs.io) - Generate interactive documentation
|
||||||
|
|
||||||
|
## Schema Statistics
|
||||||
|
|
||||||
|
| Metric | Count |
|
||||||
|
|--------|-------|
|
||||||
|
| **Tables** | 5 |
|
||||||
|
| **Domains** | 2 (Accounts, Membership) |
|
||||||
|
| **Relationships** | 3 |
|
||||||
|
| **Indexes** | 15+ |
|
||||||
|
| **Triggers** | 1 (Full-text search) |
|
||||||
|
|
||||||
|
## Tables Overview
|
||||||
|
|
||||||
|
### Accounts Domain
|
||||||
|
|
||||||
|
#### `users`
|
||||||
|
- **Purpose:** User authentication and session management
|
||||||
|
- **Rows (Estimated):** Low to Medium (typically 10-50% of members)
|
||||||
|
- **Key Features:**
|
||||||
|
- Dual authentication (Password + OIDC)
|
||||||
|
- Optional 1:1 link to members
|
||||||
|
- Email as source of truth when linked
|
||||||
|
|
||||||
|
#### `tokens`
|
||||||
|
- **Purpose:** JWT token storage for AshAuthentication
|
||||||
|
- **Rows (Estimated):** Medium to High (multiple tokens per user)
|
||||||
|
- **Key Features:**
|
||||||
|
- Token lifecycle management
|
||||||
|
- Revocation support
|
||||||
|
- Multiple token purposes
|
||||||
|
|
||||||
|
### Membership Domain
|
||||||
|
|
||||||
|
#### `members`
|
||||||
|
- **Purpose:** Club member master data
|
||||||
|
- **Rows (Estimated):** High (core entity)
|
||||||
|
- **Key Features:**
|
||||||
|
- Complete member profile
|
||||||
|
- Full-text search via tsvector
|
||||||
|
- Bidirectional email sync with users
|
||||||
|
- Flexible address and contact data
|
||||||
|
|
||||||
|
#### `properties`
|
||||||
|
- **Purpose:** Dynamic custom member attributes
|
||||||
|
- **Rows (Estimated):** Variable (N per member)
|
||||||
|
- **Key Features:**
|
||||||
|
- Union type value storage (JSONB)
|
||||||
|
- Multiple data types supported
|
||||||
|
- One property per type per member
|
||||||
|
|
||||||
|
#### `property_types`
|
||||||
|
- **Purpose:** Schema definitions for custom properties
|
||||||
|
- **Rows (Estimated):** Low (admin-defined)
|
||||||
|
- **Key Features:**
|
||||||
|
- Type definitions
|
||||||
|
- Immutable and required flags
|
||||||
|
- Centralized property management
|
||||||
|
|
||||||
|
## Key Relationships
|
||||||
|
|
||||||
|
```
|
||||||
|
User (0..1) ←→ (0..1) Member
|
||||||
|
↓
|
||||||
|
Tokens (N)
|
||||||
|
|
||||||
|
Member (1) → (N) Properties
|
||||||
|
↓
|
||||||
|
PropertyType (1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Relationship Details
|
||||||
|
|
||||||
|
1. **User ↔ Member (Optional 1:1, both sides optional)**
|
||||||
|
- A User can have 0 or 1 Member (`user.member_id` can be NULL)
|
||||||
|
- A Member can have 0 or 1 User (optional `has_one` relationship)
|
||||||
|
- Both entities can exist independently
|
||||||
|
- Email synchronization when linked (User.email is source of truth)
|
||||||
|
- `ON DELETE SET NULL` on user side (User preserved when Member deleted)
|
||||||
|
|
||||||
|
2. **Member → Properties (1:N)**
|
||||||
|
- One member, many properties
|
||||||
|
- `ON DELETE CASCADE` - properties deleted with member
|
||||||
|
- Composite unique constraint (member_id, property_type_id)
|
||||||
|
|
||||||
|
3. **Property → PropertyType (N:1)**
|
||||||
|
- Properties reference type definition
|
||||||
|
- `ON DELETE RESTRICT` - cannot delete type if in use
|
||||||
|
- Type defines data structure
|
||||||
|
|
||||||
|
## Important Business Rules
|
||||||
|
|
||||||
|
### Email Synchronization
|
||||||
|
- **User.email** is the source of truth when linked
|
||||||
|
- On linking: Member.email ← User.email (overwrite)
|
||||||
|
- After linking: Changes sync bidirectionally
|
||||||
|
- Validation prevents email conflicts
|
||||||
|
|
||||||
|
### Authentication Strategies
|
||||||
|
- **Password:** Email + hashed_password
|
||||||
|
- **OIDC:** Email + oidc_id (Rauthy provider)
|
||||||
|
- At least one method required per user
|
||||||
|
|
||||||
|
### Member Constraints
|
||||||
|
- First name and last name required (min 1 char)
|
||||||
|
- Email unique, validated format (5-254 chars)
|
||||||
|
- Birth date cannot be in future
|
||||||
|
- Join date cannot be in future
|
||||||
|
- Exit date must be after join date
|
||||||
|
- Phone: `+?[0-9\- ]{6,20}`
|
||||||
|
- Postal code: 5 digits
|
||||||
|
|
||||||
|
### Property System
|
||||||
|
- Maximum one property per type per member
|
||||||
|
- Value stored as union type in JSONB
|
||||||
|
- Supported types: string, integer, boolean, date, email
|
||||||
|
- Types can be marked as immutable or required
|
||||||
|
|
||||||
|
## Indexes
|
||||||
|
|
||||||
|
### Performance Indexes
|
||||||
|
|
||||||
|
**members:**
|
||||||
|
- `search_vector` (GIN) - Full-text search
|
||||||
|
- `email` - Email lookups
|
||||||
|
- `last_name` - Name sorting
|
||||||
|
- `join_date` - Date filtering
|
||||||
|
- `paid` (partial) - Payment status queries
|
||||||
|
|
||||||
|
**properties:**
|
||||||
|
- `member_id` - Member property lookups
|
||||||
|
- `property_type_id` - Type-based queries
|
||||||
|
- Composite `(member_id, property_type_id)` - Uniqueness
|
||||||
|
|
||||||
|
**tokens:**
|
||||||
|
- `subject` - User token lookups
|
||||||
|
- `expires_at` - Token cleanup
|
||||||
|
- `purpose` - Purpose-based queries
|
||||||
|
|
||||||
|
**users:**
|
||||||
|
- `email` (unique) - Login lookups
|
||||||
|
- `oidc_id` (unique) - OIDC authentication
|
||||||
|
- `member_id` (unique) - Member linkage
|
||||||
|
|
||||||
|
## Full-Text Search
|
||||||
|
|
||||||
|
### Implementation
|
||||||
|
- **Trigger:** `members_search_vector_trigger()`
|
||||||
|
- **Function:** Automatically updates `search_vector` on INSERT/UPDATE
|
||||||
|
- **Index Type:** GIN (Generalized Inverted Index)
|
||||||
|
|
||||||
|
### Weighted Fields
|
||||||
|
- **Weight A (highest):** first_name, last_name
|
||||||
|
- **Weight B:** email, notes
|
||||||
|
- **Weight C:** birth_date, phone_number, city, street, house_number, postal_code
|
||||||
|
- **Weight D (lowest):** join_date, exit_date
|
||||||
|
|
||||||
|
### Usage Example
|
||||||
|
```sql
|
||||||
|
SELECT * FROM members
|
||||||
|
WHERE search_vector @@ to_tsquery('simple', 'john & doe');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database Extensions
|
||||||
|
|
||||||
|
### Required PostgreSQL Extensions
|
||||||
|
|
||||||
|
1. **uuid-ossp**
|
||||||
|
- Purpose: UUID generation functions
|
||||||
|
- Used for: `gen_random_uuid()`, `uuid_generate_v7()`
|
||||||
|
|
||||||
|
2. **citext**
|
||||||
|
- Purpose: Case-insensitive text type
|
||||||
|
- Used for: `users.email` (case-insensitive email matching)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
```sql
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "citext";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Strategy
|
||||||
|
|
||||||
|
### Ash Migrations
|
||||||
|
This project uses Ash Framework's migration system:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate new migration
|
||||||
|
mix ash.codegen --name add_new_feature
|
||||||
|
|
||||||
|
# Apply migrations
|
||||||
|
mix ash.setup
|
||||||
|
|
||||||
|
# Rollback migrations
|
||||||
|
mix ash_postgres.rollback -n 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migration Files Location
|
||||||
|
```
|
||||||
|
priv/repo/migrations/
|
||||||
|
├── 20250421101957_initialize_extensions_1.exs
|
||||||
|
├── 20250528163901_initial_migration.exs
|
||||||
|
├── 20250617090641_member_fields.exs
|
||||||
|
├── 20250620110850_add_accounts_domain.exs
|
||||||
|
├── 20250912085235_AddSearchVectorToMembers.exs
|
||||||
|
├── 20250926180341_add_unique_email_to_members.exs
|
||||||
|
└── 20251016130855_add_constraints_for_user_member_and_property.exs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Integrity
|
||||||
|
|
||||||
|
### Foreign Key Behaviors
|
||||||
|
|
||||||
|
| Relationship | On Delete | Rationale |
|
||||||
|
|--------------|-----------|-----------|
|
||||||
|
| `users.member_id → members.id` | SET NULL | Preserve user account when member deleted |
|
||||||
|
| `properties.member_id → members.id` | CASCADE | Delete properties with member |
|
||||||
|
| `properties.property_type_id → property_types.id` | RESTRICT | Prevent deletion of types in use |
|
||||||
|
|
||||||
|
### Validation Layers
|
||||||
|
|
||||||
|
1. **Database Level:**
|
||||||
|
- CHECK constraints
|
||||||
|
- NOT NULL constraints
|
||||||
|
- UNIQUE indexes
|
||||||
|
- Foreign key constraints
|
||||||
|
|
||||||
|
2. **Application Level (Ash):**
|
||||||
|
- Custom validators
|
||||||
|
- Email format validation (EctoCommons.EmailValidator)
|
||||||
|
- Business rule validation
|
||||||
|
- Cross-entity validation
|
||||||
|
|
||||||
|
3. **UI Level:**
|
||||||
|
- Client-side form validation
|
||||||
|
- Real-time feedback
|
||||||
|
- Error messages
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Query Patterns
|
||||||
|
|
||||||
|
**High Frequency:**
|
||||||
|
- Member search (uses GIN index on search_vector)
|
||||||
|
- Member list with filters (uses indexes on join_date, paid)
|
||||||
|
- User authentication (uses unique index on email/oidc_id)
|
||||||
|
- Property lookups by member (uses index on member_id)
|
||||||
|
|
||||||
|
**Medium Frequency:**
|
||||||
|
- Member CRUD operations
|
||||||
|
- Property updates
|
||||||
|
- Token validation
|
||||||
|
|
||||||
|
**Low Frequency:**
|
||||||
|
- PropertyType management
|
||||||
|
- User-Member linking
|
||||||
|
- Bulk operations
|
||||||
|
|
||||||
|
### Optimization Tips
|
||||||
|
|
||||||
|
1. **Use indexes:** All critical query paths have indexes
|
||||||
|
2. **Preload relationships:** Use Ash's `load` to avoid N+1
|
||||||
|
3. **Pagination:** Use keyset pagination (configured by default)
|
||||||
|
4. **Partial indexes:** `members.paid` index only non-NULL values
|
||||||
|
5. **Search optimization:** Full-text search via tsvector, not LIKE
|
||||||
|
|
||||||
|
## Visualization
|
||||||
|
|
||||||
|
### Using dbdiagram.io
|
||||||
|
|
||||||
|
1. Visit [https://dbdiagram.io](https://dbdiagram.io)
|
||||||
|
2. Click "Import" → "From file"
|
||||||
|
3. Upload `database_schema.dbml`
|
||||||
|
4. View interactive diagram with relationships
|
||||||
|
|
||||||
|
### Using dbdocs.io
|
||||||
|
|
||||||
|
1. Install dbdocs CLI: `npm install -g dbdocs`
|
||||||
|
2. Generate docs: `dbdocs build database_schema.dbml`
|
||||||
|
3. View generated documentation
|
||||||
|
|
||||||
|
### VS Code Extension
|
||||||
|
|
||||||
|
Install "DBML Language" extension to view/edit DBML files with:
|
||||||
|
- Syntax highlighting
|
||||||
|
- Inline documentation
|
||||||
|
- Error checking
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Sensitive Data
|
||||||
|
|
||||||
|
**Encrypted:**
|
||||||
|
- `users.hashed_password` (bcrypt)
|
||||||
|
|
||||||
|
**Should Not Log:**
|
||||||
|
- hashed_password
|
||||||
|
- tokens (jti, purpose, extra_data)
|
||||||
|
|
||||||
|
**Personal Data (GDPR):**
|
||||||
|
- All member fields (name, email, birth_date, address)
|
||||||
|
- User email
|
||||||
|
- Token subject
|
||||||
|
|
||||||
|
### Access Control
|
||||||
|
|
||||||
|
- Implement through Ash policies
|
||||||
|
- Row-level security considerations for future
|
||||||
|
- Audit logging for sensitive operations
|
||||||
|
|
||||||
|
## Backup Recommendations
|
||||||
|
|
||||||
|
### Critical Tables (Priority 1)
|
||||||
|
- `members` - Core business data
|
||||||
|
- `users` - Authentication data
|
||||||
|
- `property_types` - Schema definitions
|
||||||
|
|
||||||
|
### Important Tables (Priority 2)
|
||||||
|
- `properties` - Member custom data
|
||||||
|
- `tokens` - Can be regenerated but good to backup
|
||||||
|
|
||||||
|
### Backup Strategy
|
||||||
|
```bash
|
||||||
|
# Full database backup
|
||||||
|
pg_dump -Fc mv_prod > backup_$(date +%Y%m%d).dump
|
||||||
|
|
||||||
|
# Restore
|
||||||
|
pg_restore -d mv_prod backup_20251110.dump
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Test Database
|
||||||
|
- Separate test database: `mv_test`
|
||||||
|
- Sandbox mode via Ecto.Adapters.SQL.Sandbox
|
||||||
|
- Reset between tests
|
||||||
|
|
||||||
|
### Seed Data
|
||||||
|
```bash
|
||||||
|
# Load seed data
|
||||||
|
mix run priv/repo/seeds.exs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Future Considerations
|
||||||
|
|
||||||
|
### Potential Additions
|
||||||
|
|
||||||
|
1. **Audit Log Table**
|
||||||
|
- Track changes to members
|
||||||
|
- Compliance and history tracking
|
||||||
|
|
||||||
|
2. **Payment Tracking**
|
||||||
|
- Payment history table
|
||||||
|
- Transaction records
|
||||||
|
- Fee calculation
|
||||||
|
|
||||||
|
3. **Document Storage**
|
||||||
|
- Member documents/attachments
|
||||||
|
- File metadata table
|
||||||
|
|
||||||
|
4. **Email Queue**
|
||||||
|
- Outbound email tracking
|
||||||
|
- Delivery status
|
||||||
|
|
||||||
|
5. **Roles & Permissions**
|
||||||
|
- User roles (admin, treasurer, member)
|
||||||
|
- Permission management
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- **Ash Framework:** [https://hexdocs.pm/ash](https://hexdocs.pm/ash)
|
||||||
|
- **AshPostgres:** [https://hexdocs.pm/ash_postgres](https://hexdocs.pm/ash_postgres)
|
||||||
|
- **DBML Specification:** [https://dbml.dbdiagram.io](https://dbml.dbdiagram.io)
|
||||||
|
- **PostgreSQL Docs:** [https://www.postgresql.org/docs/](https://www.postgresql.org/docs/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** 2025-11-10
|
||||||
|
**Schema Version:** 1.0
|
||||||
|
**Database:** PostgreSQL 17.6 (dev) / 16 (prod)
|
||||||
|
|
||||||
329
docs/database_schema.dbml
Normal file
329
docs/database_schema.dbml
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
// Mila - Membership Management System
|
||||||
|
// Database Schema Documentation
|
||||||
|
//
|
||||||
|
// This file can be used with:
|
||||||
|
// - https://dbdiagram.io
|
||||||
|
// - https://dbdocs.io
|
||||||
|
// - VS Code Extensions: "DBML Language" or "dbdiagram.io"
|
||||||
|
//
|
||||||
|
// Version: 1.0
|
||||||
|
// Last Updated: 2025-11-10
|
||||||
|
|
||||||
|
Project mila_membership_management {
|
||||||
|
database_type: 'PostgreSQL'
|
||||||
|
Note: '''
|
||||||
|
# Mila Membership Management System
|
||||||
|
|
||||||
|
A membership management application for small to mid-sized clubs.
|
||||||
|
|
||||||
|
## Key Features:
|
||||||
|
- User authentication (OIDC + Password)
|
||||||
|
- Member management with flexible custom properties
|
||||||
|
- Bidirectional email synchronization between users and members
|
||||||
|
- Full-text search capabilities
|
||||||
|
- GDPR-compliant data management
|
||||||
|
|
||||||
|
## Domains:
|
||||||
|
- **Accounts**: User authentication and session management
|
||||||
|
- **Membership**: Club member data and custom properties
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// ACCOUNTS DOMAIN
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
Table users {
|
||||||
|
id uuid [pk, not null, default: `gen_random_uuid()`, note: 'Primary identifier']
|
||||||
|
email citext [not null, unique, note: 'Email address (case-insensitive) - source of truth when linked to member']
|
||||||
|
hashed_password text [null, note: 'Bcrypt-hashed password (null for OIDC-only users)']
|
||||||
|
oidc_id text [null, unique, note: 'External OIDC identifier from authentication provider (e.g., Rauthy)']
|
||||||
|
member_id uuid [null, unique, note: 'Optional 1:1 link to member record']
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
email [unique, name: 'users_unique_email_index']
|
||||||
|
oidc_id [unique, name: 'users_unique_oidc_id_index']
|
||||||
|
member_id [unique, name: 'users_unique_member_index']
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**User Authentication Table**
|
||||||
|
|
||||||
|
Handles user login accounts with two authentication strategies:
|
||||||
|
1. Password-based authentication (email + hashed_password)
|
||||||
|
2. OIDC/SSO authentication (email + oidc_id)
|
||||||
|
|
||||||
|
**Relationship with Members:**
|
||||||
|
- Optional 1:1 relationship with members table (0..1 ↔ 0..1)
|
||||||
|
- A user can have 0 or 1 member (user.member_id can be NULL)
|
||||||
|
- A member can have 0 or 1 user (optional has_one relationship)
|
||||||
|
- Both entities can exist independently
|
||||||
|
- When linked, user.email is the source of truth
|
||||||
|
- Email changes sync bidirectionally between user ↔ member
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- At least one auth method required (password OR oidc_id)
|
||||||
|
- Email must be unique across all users
|
||||||
|
- OIDC ID must be unique if present
|
||||||
|
- Member can only be linked to one user (enforced by unique index)
|
||||||
|
|
||||||
|
**Deletion Behavior:**
|
||||||
|
- When member is deleted → user.member_id set to NULL (user preserved)
|
||||||
|
- When user is deleted → member.user relationship cleared (member preserved)
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
Table tokens {
|
||||||
|
jti text [pk, not null, note: 'JWT ID - unique token identifier']
|
||||||
|
subject text [not null, note: 'Token subject (usually user ID)']
|
||||||
|
purpose text [not null, note: 'Token purpose (e.g., "access", "refresh", "password_reset")']
|
||||||
|
expires_at timestamp [not null, note: 'Token expiration timestamp (UTC)']
|
||||||
|
extra_data jsonb [null, note: 'Additional token metadata']
|
||||||
|
created_at timestamp [not null, default: `now() AT TIME ZONE 'utc'`, note: 'Creation timestamp (UTC)']
|
||||||
|
updated_at timestamp [not null, default: `now() AT TIME ZONE 'utc'`, note: 'Last update timestamp (UTC)']
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
subject [name: 'tokens_subject_idx', note: 'For user token lookups']
|
||||||
|
expires_at [name: 'tokens_expires_at_idx', note: 'For token cleanup queries']
|
||||||
|
purpose [name: 'tokens_purpose_idx', note: 'For purpose-based queries']
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**AshAuthentication Token Management**
|
||||||
|
|
||||||
|
Stores JWT tokens for authentication and authorization.
|
||||||
|
|
||||||
|
**Token Purposes:**
|
||||||
|
- `access`: Short-lived access tokens for API requests
|
||||||
|
- `refresh`: Long-lived tokens for obtaining new access tokens
|
||||||
|
- `password_reset`: Temporary tokens for password reset flow
|
||||||
|
- `email_confirmation`: Temporary tokens for email verification
|
||||||
|
|
||||||
|
**Token Lifecycle:**
|
||||||
|
- Tokens are created during login/registration
|
||||||
|
- Can be revoked by deleting the record
|
||||||
|
- Expired tokens should be cleaned up periodically
|
||||||
|
- `store_all_tokens? true` enables token tracking
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// MEMBERSHIP DOMAIN
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
Table members {
|
||||||
|
id uuid [pk, not null, default: `uuid_generate_v7()`, note: 'UUIDv7 primary key (sortable by creation time)']
|
||||||
|
first_name text [not null, note: 'Member first name (min length: 1)']
|
||||||
|
last_name text [not null, note: 'Member last name (min length: 1)']
|
||||||
|
email text [not null, unique, note: 'Member email address (5-254 chars, validated)']
|
||||||
|
birth_date date [null, note: 'Date of birth (cannot be in future)']
|
||||||
|
paid boolean [null, note: 'Payment status flag']
|
||||||
|
phone_number text [null, note: 'Contact phone number (format: +?[0-9\- ]{6,20})']
|
||||||
|
join_date date [null, note: 'Date when member joined club (cannot be in future)']
|
||||||
|
exit_date date [null, note: 'Date when member left club (must be after join_date)']
|
||||||
|
notes text [null, note: 'Additional notes about member']
|
||||||
|
city text [null, note: 'City of residence']
|
||||||
|
street text [null, note: 'Street name']
|
||||||
|
house_number text [null, note: 'House number']
|
||||||
|
postal_code text [null, note: '5-digit German postal code']
|
||||||
|
search_vector tsvector [null, note: 'Full-text search index (auto-generated)']
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
email [unique, name: 'members_unique_email_index']
|
||||||
|
search_vector [type: gin, name: 'members_search_vector_idx', note: 'GIN index for full-text search']
|
||||||
|
email [name: 'members_email_idx']
|
||||||
|
last_name [name: 'members_last_name_idx', note: 'For name sorting']
|
||||||
|
join_date [name: 'members_join_date_idx', note: 'For date filters']
|
||||||
|
(paid) [name: 'members_paid_idx', type: btree, note: 'Partial index WHERE paid IS NOT NULL']
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**Club Member Master Data**
|
||||||
|
|
||||||
|
Core entity for membership management containing:
|
||||||
|
- Personal information (name, birth date, email)
|
||||||
|
- Contact details (phone, address)
|
||||||
|
- Membership status (join/exit dates, payment status)
|
||||||
|
- Additional notes
|
||||||
|
|
||||||
|
**Email Synchronization:**
|
||||||
|
When a member is linked to a user:
|
||||||
|
- User.email is the source of truth (overwrites member.email on link)
|
||||||
|
- Subsequent changes to either email sync bidirectionally
|
||||||
|
- Validates that email is not already used by another unlinked user
|
||||||
|
|
||||||
|
**Full-Text Search:**
|
||||||
|
- `search_vector` is auto-updated via trigger
|
||||||
|
- Weighted fields: first_name (A), last_name (A), email (B), notes (B)
|
||||||
|
- Supports flexible member search across multiple fields
|
||||||
|
|
||||||
|
**Relationships:**
|
||||||
|
- Optional 1:1 with users (0..1 ↔ 0..1) - authentication account
|
||||||
|
- 1:N with properties (custom dynamic fields)
|
||||||
|
|
||||||
|
**Validation Rules:**
|
||||||
|
- first_name, last_name: min 1 character
|
||||||
|
- email: 5-254 characters, valid email format
|
||||||
|
- birth_date: cannot be in future
|
||||||
|
- join_date: cannot be in future
|
||||||
|
- exit_date: must be after join_date (if both present)
|
||||||
|
- phone_number: matches pattern ^\+?[0-9\- ]{6,20}$
|
||||||
|
- postal_code: exactly 5 digits
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
Table properties {
|
||||||
|
id uuid [pk, not null, default: `gen_random_uuid()`, note: 'Primary identifier']
|
||||||
|
value jsonb [null, note: 'Union type value storage (format: {type: "string", value: "example"})']
|
||||||
|
member_id uuid [not null, note: 'Link to member']
|
||||||
|
property_type_id uuid [not null, note: 'Link to property type definition']
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(member_id, property_type_id) [unique, name: 'properties_unique_property_per_member_index', note: 'One property per type per member']
|
||||||
|
member_id [name: 'properties_member_id_idx']
|
||||||
|
property_type_id [name: 'properties_property_type_id_idx']
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**Dynamic Custom Member Properties**
|
||||||
|
|
||||||
|
Provides flexible, extensible attributes for members beyond the fixed schema.
|
||||||
|
|
||||||
|
**Value Storage:**
|
||||||
|
- Stored as JSONB map with type discrimination
|
||||||
|
- Format: `{type: "string|integer|boolean|date|email", value: <actual_value>}`
|
||||||
|
- Allows multiple data types in single column
|
||||||
|
|
||||||
|
**Supported Types:**
|
||||||
|
- `string`: Text data
|
||||||
|
- `integer`: Numeric data
|
||||||
|
- `boolean`: True/False flags
|
||||||
|
- `date`: Date values
|
||||||
|
- `email`: Validated email addresses
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- Each member can have only ONE property per property_type
|
||||||
|
- Properties are deleted when member is deleted (CASCADE)
|
||||||
|
- Property type cannot be deleted if properties exist (RESTRICT)
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Custom membership numbers
|
||||||
|
- Additional contact methods
|
||||||
|
- Club-specific attributes
|
||||||
|
- Flexible data model without schema migrations
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
Table property_types {
|
||||||
|
id uuid [pk, not null, default: `gen_random_uuid()`, note: 'Primary identifier']
|
||||||
|
name text [not null, unique, note: 'Property name/identifier (e.g., "membership_number")']
|
||||||
|
value_type text [not null, note: 'Data type: string | integer | boolean | date | email']
|
||||||
|
description text [null, note: 'Human-readable description']
|
||||||
|
immutable boolean [not null, default: false, note: 'If true, value cannot be changed after creation']
|
||||||
|
required boolean [not null, default: false, note: 'If true, all members must have this property']
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
name [unique, name: 'property_types_unique_name_index']
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**Property Type Definitions**
|
||||||
|
|
||||||
|
Defines the schema and behavior for custom member properties.
|
||||||
|
|
||||||
|
**Attributes:**
|
||||||
|
- `name`: Unique identifier for the property type
|
||||||
|
- `value_type`: Enforces data type consistency
|
||||||
|
- `description`: Documentation for users/admins
|
||||||
|
- `immutable`: Prevents changes after initial creation (e.g., membership numbers)
|
||||||
|
- `required`: Enforces that all members must have this property
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- `value_type` must be one of: string, integer, boolean, date, email
|
||||||
|
- `name` must be unique across all property types
|
||||||
|
- Cannot be deleted if properties reference it (ON DELETE RESTRICT)
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
- Membership Number (string, immutable, required)
|
||||||
|
- Emergency Contact (string, mutable, optional)
|
||||||
|
- Certified Trainer (boolean, mutable, optional)
|
||||||
|
- Certification Date (date, immutable, optional)
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// RELATIONSHIPS
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
// Optional 1:1 User ↔ Member Link
|
||||||
|
// - A user can have 0 or 1 linked member (optional)
|
||||||
|
// - A member can have 0 or 1 linked user (optional)
|
||||||
|
// - Both can exist independently
|
||||||
|
// - ON DELETE SET NULL: User preserved when member deleted
|
||||||
|
// - Email Synchronization: When linking occurs, user.email becomes source of truth
|
||||||
|
Ref: users.member_id - members.id [delete: set null]
|
||||||
|
|
||||||
|
// Member → Properties (1:N)
|
||||||
|
// - One member can have multiple properties
|
||||||
|
// - Each property belongs to exactly one member
|
||||||
|
// - ON DELETE CASCADE: Properties deleted when member deleted
|
||||||
|
// - UNIQUE constraint: One property per type per member
|
||||||
|
Ref: properties.member_id > members.id [delete: cascade]
|
||||||
|
|
||||||
|
// Property → PropertyType (N:1)
|
||||||
|
// - Many properties can reference one property type
|
||||||
|
// - Property type defines the schema/behavior
|
||||||
|
// - ON DELETE RESTRICT: Cannot delete type if properties exist
|
||||||
|
Ref: properties.property_type_id > property_types.id [delete: restrict]
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// ENUMS
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
// Valid data types for property values
|
||||||
|
// Determines how Property.value is interpreted
|
||||||
|
Enum property_value_type {
|
||||||
|
string [note: 'Text data']
|
||||||
|
integer [note: 'Numeric data']
|
||||||
|
boolean [note: 'True/False flags']
|
||||||
|
date [note: 'Date values']
|
||||||
|
email [note: 'Validated email addresses']
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token purposes for different authentication flows
|
||||||
|
Enum token_purpose {
|
||||||
|
access [note: 'Short-lived access tokens']
|
||||||
|
refresh [note: 'Long-lived refresh tokens']
|
||||||
|
password_reset [note: 'Password reset tokens']
|
||||||
|
email_confirmation [note: 'Email verification tokens']
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// TABLE GROUPS
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
TableGroup accounts_domain {
|
||||||
|
users
|
||||||
|
tokens
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**Accounts Domain**
|
||||||
|
|
||||||
|
Handles user authentication and session management using AshAuthentication.
|
||||||
|
Supports multiple authentication strategies (Password, OIDC).
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
TableGroup membership_domain {
|
||||||
|
members
|
||||||
|
properties
|
||||||
|
property_types
|
||||||
|
|
||||||
|
Note: '''
|
||||||
|
**Membership Domain**
|
||||||
|
|
||||||
|
Core business logic for club membership management.
|
||||||
|
Supports flexible, extensible member data model.
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
1227
docs/development-progress-log.md
Normal file
1227
docs/development-progress-log.md
Normal file
File diff suppressed because it is too large
Load diff
743
docs/feature-roadmap.md
Normal file
743
docs/feature-roadmap.md
Normal file
|
|
@ -0,0 +1,743 @@
|
||||||
|
# Feature Roadmap & Implementation Plan
|
||||||
|
|
||||||
|
**Project:** Mila - Membership Management System
|
||||||
|
**Last Updated:** 2025-11-10
|
||||||
|
**Status:** Planning Phase
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Phase 1: Feature Area Breakdown](#phase-1-feature-area-breakdown)
|
||||||
|
2. [Phase 2: API Endpoint Definition](#phase-2-api-endpoint-definition)
|
||||||
|
3. [Phase 3: Implementation Task Creation](#phase-3-implementation-task-creation)
|
||||||
|
4. [Phase 4: Task Organization and Prioritization](#phase-4-task-organization-and-prioritization)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: Feature Area Breakdown
|
||||||
|
|
||||||
|
### Feature Areas
|
||||||
|
|
||||||
|
#### 1. **Authentication & Authorization** 🔐
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ OIDC authentication (Rauthy)
|
||||||
|
- ✅ Password-based authentication
|
||||||
|
- ✅ User sessions and tokens
|
||||||
|
- ✅ Basic authentication flows
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#171](https://git.local-it.org/local-it/mitgliederverwaltung/issues/171) - Ensure correct handling of Password login vs OIDC login (M)
|
||||||
|
- [#146](https://git.local-it.org/local-it/mitgliederverwaltung/issues/146) - Translate "or" in the login screen (Low)
|
||||||
|
- [#144](https://git.local-it.org/local-it/mitgliederverwaltung/issues/144) - Add language switch dropdown to login screen (Low)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Role-based access control (RBAC)
|
||||||
|
- ❌ Permission system
|
||||||
|
- ❌ Password reset flow
|
||||||
|
- ❌ Email verification
|
||||||
|
- ❌ Two-factor authentication (future)
|
||||||
|
|
||||||
|
**Related Issues:**
|
||||||
|
- [#191](https://git.local-it.org/local-it/mitgliederverwaltung/issues/191) - Implement Roles in Ash (M)
|
||||||
|
- [#190](https://git.local-it.org/local-it/mitgliederverwaltung/issues/190) - Implement Permissions in Ash (M)
|
||||||
|
- [#151](https://git.local-it.org/local-it/mitgliederverwaltung/issues/151) - Define implementation plan for roles and permissions (M) [3/7 tasks done]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 2. **Member Management** 👥
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Member CRUD operations
|
||||||
|
- ✅ Member profile with personal data
|
||||||
|
- ✅ Address management
|
||||||
|
- ✅ Membership status tracking
|
||||||
|
- ✅ Full-text search (PostgreSQL tsvector)
|
||||||
|
- ✅ Sorting by basic fields
|
||||||
|
- ✅ User-Member linking (optional 1:1)
|
||||||
|
- ✅ Email synchronization between User and Member
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#169](https://git.local-it.org/local-it/mitgliederverwaltung/issues/169) - Allow combined creation of Users/Members (M, Low priority)
|
||||||
|
- [#168](https://git.local-it.org/local-it/mitgliederverwaltung/issues/168) - Allow user-member association in edit/create views (M, High priority)
|
||||||
|
- [#165](https://git.local-it.org/local-it/mitgliederverwaltung/issues/165) - Pagination for list of members (S, Low priority)
|
||||||
|
- [#162](https://git.local-it.org/local-it/mitgliederverwaltung/issues/162) - Implement fuzzy and substring search (M, Medium priority)
|
||||||
|
- [#160](https://git.local-it.org/local-it/mitgliederverwaltung/issues/160) - Implement clear icon in searchbar (S, Low priority)
|
||||||
|
- [#154](https://git.local-it.org/local-it/mitgliederverwaltung/issues/154) - Concept advanced search (Low priority, needs refinement)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Fuzzy search
|
||||||
|
- ❌ Advanced filters (date ranges, multiple criteria)
|
||||||
|
- ❌ Pagination (currently all members loaded)
|
||||||
|
- ❌ Bulk operations (bulk delete, bulk update)
|
||||||
|
- ❌ Member import/export (CSV, Excel)
|
||||||
|
- ❌ Member profile photos/avatars
|
||||||
|
- ❌ Member history/audit log
|
||||||
|
- ❌ Duplicate detection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 3. **Custom Fields (Property System)** 🔧
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Property types (string, integer, boolean, date, email)
|
||||||
|
- ✅ Property type management
|
||||||
|
- ✅ Dynamic property assignment to members
|
||||||
|
- ✅ Union type storage (JSONB)
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#194](https://git.local-it.org/local-it/mitgliederverwaltung/issues/194) - Custom Fields: Harden implementation (S) [0/3 tasks]
|
||||||
|
- [#157](https://git.local-it.org/local-it/mitgliederverwaltung/issues/157) - Concept how custom fields are handled (M, High priority) [0/4 tasks]
|
||||||
|
- [#161](https://git.local-it.org/local-it/mitgliederverwaltung/issues/161) - Don't show birthday field for default configurations (S, Low priority)
|
||||||
|
- [#153](https://git.local-it.org/local-it/mitgliederverwaltung/issues/153) - Sorting functionalities for custom fields (M, Low priority)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Default field visibility configuration
|
||||||
|
- ❌ Field groups/categories
|
||||||
|
- ❌ Conditional fields (show field X if field Y = value)
|
||||||
|
- ❌ Field validation rules (min/max, regex patterns)
|
||||||
|
- ❌ Required custom fields
|
||||||
|
- ❌ Multi-select fields
|
||||||
|
- ❌ File upload fields
|
||||||
|
- ❌ Sorting by custom fields
|
||||||
|
- ❌ Searching by custom fields
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 4. **User Management** 👤
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ User CRUD operations
|
||||||
|
- ✅ User list view
|
||||||
|
- ✅ User profile view
|
||||||
|
- ✅ Admin password setting
|
||||||
|
- ✅ User-Member relationship
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ User roles assignment UI
|
||||||
|
- ❌ User permissions management
|
||||||
|
- ❌ User activity log
|
||||||
|
- ❌ User invitation system
|
||||||
|
- ❌ User onboarding flow
|
||||||
|
- ❌ Self-service profile editing
|
||||||
|
- ❌ Password change flow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 5. **Navigation & UX** 🧭
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Basic navigation structure
|
||||||
|
- ✅ Navbar with profile button
|
||||||
|
- ✅ Member list as landing page
|
||||||
|
- ✅ Breadcrumbs (basic)
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#188](https://git.local-it.org/local-it/mitgliederverwaltung/issues/188) - Check if searching just on typing is accessible (S, Low priority)
|
||||||
|
- [#174](https://git.local-it.org/local-it/mitgliederverwaltung/issues/174) - Accessibility - aria-sort in tables (S, Low priority)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Dashboard/Home page
|
||||||
|
- ❌ Quick actions menu
|
||||||
|
- ❌ Recent activity widget
|
||||||
|
- ❌ Keyboard shortcuts
|
||||||
|
- ❌ Mobile navigation
|
||||||
|
- ❌ Context-sensitive help
|
||||||
|
- ❌ Onboarding tooltips
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 6. **Internationalization (i18n)** 🌍
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Gettext integration
|
||||||
|
- ✅ German translations
|
||||||
|
- ✅ English translations
|
||||||
|
- ✅ Translation files for auth, errors, default
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#146](https://git.local-it.org/local-it/mitgliederverwaltung/issues/146) - Translate "or" in the login screen (Low)
|
||||||
|
- [#144](https://git.local-it.org/local-it/mitgliederverwaltung/issues/144) - Add language switch dropdown to login screen (Low)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Language switcher UI
|
||||||
|
- ❌ User-specific language preferences
|
||||||
|
- ❌ Date/time localization
|
||||||
|
- ❌ Number formatting (currency, decimals)
|
||||||
|
- ❌ Complete translation coverage
|
||||||
|
- ❌ RTL support (future)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 7. **Payment & Fees Management** 💰
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Basic "paid" boolean field on members
|
||||||
|
- ⚠️ No payment tracking
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#156](https://git.local-it.org/local-it/mitgliederverwaltung/issues/156) - Set up & document testing environment for vereinfacht.digital (L, Low priority)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Membership fee configuration
|
||||||
|
- ❌ Payment records/transactions
|
||||||
|
- ❌ Payment history per member
|
||||||
|
- ❌ Payment reminders
|
||||||
|
- ❌ Payment status tracking (pending, paid, overdue)
|
||||||
|
- ❌ Invoice generation
|
||||||
|
- ❌ vereinfacht.digital API integration
|
||||||
|
- ❌ SEPA direct debit support
|
||||||
|
- ❌ Payment reports
|
||||||
|
|
||||||
|
**Related Milestones:**
|
||||||
|
- Import transactions via vereinfacht API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 8. **Admin Panel & Configuration** ⚙️
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ AshAdmin integration (basic)
|
||||||
|
- ⚠️ No user-facing admin UI
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#186](https://git.local-it.org/local-it/mitgliederverwaltung/issues/186) - Create Architecture docs in Repo (S, Low priority)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Global settings management
|
||||||
|
- ❌ Club/Organization profile
|
||||||
|
- ❌ Email templates configuration
|
||||||
|
- ❌ Property type management UI (user-facing)
|
||||||
|
- ❌ Role and permission management UI
|
||||||
|
- ❌ System health dashboard
|
||||||
|
- ❌ Audit log viewer
|
||||||
|
- ❌ Backup/restore functionality
|
||||||
|
|
||||||
|
**Related Milestones:**
|
||||||
|
- As Admin I can configure settings globally
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 9. **Communication & Notifications** 📧
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Swoosh mailer integration
|
||||||
|
- ✅ Email confirmation (via AshAuthentication)
|
||||||
|
- ✅ Password reset emails (via AshAuthentication)
|
||||||
|
- ⚠️ No member communication features
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Email broadcast to members
|
||||||
|
- ❌ Email templates (customizable)
|
||||||
|
- ❌ Email to member groups/filters
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 10. **Reporting & Analytics** 📊
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ❌ No reporting features
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Member statistics dashboard
|
||||||
|
- ❌ Membership growth charts
|
||||||
|
- ❌ Payment reports
|
||||||
|
- ❌ Custom report builder
|
||||||
|
- ❌ Export to PDF/CSV/Excel
|
||||||
|
- ❌ Scheduled reports
|
||||||
|
- ❌ Data visualization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 11. **Data Import/Export** 📥📤
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Seed data script
|
||||||
|
- ⚠️ No user-facing import/export
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ CSV import for members
|
||||||
|
- ❌ Excel import for members
|
||||||
|
- ❌ Import validation and preview
|
||||||
|
- ❌ Import error handling
|
||||||
|
- ❌ Bulk data export
|
||||||
|
- ❌ Backup export
|
||||||
|
- ❌ Data migration tools
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 12. **Testing & Quality Assurance** 🧪
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ ExUnit test suite
|
||||||
|
- ✅ Unit tests for resources
|
||||||
|
- ✅ Integration tests for email sync
|
||||||
|
- ✅ LiveView tests
|
||||||
|
- ✅ Component tests
|
||||||
|
- ✅ CI/CD pipeline (Drone)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ E2E tests (browser automation)
|
||||||
|
- ❌ Performance testing
|
||||||
|
- ❌ Load testing
|
||||||
|
- ❌ Security penetration testing
|
||||||
|
- ❌ Accessibility testing automation
|
||||||
|
- ❌ Visual regression testing
|
||||||
|
- ❌ Test coverage reporting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 13. **Infrastructure & DevOps** 🚀
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Docker Compose for development
|
||||||
|
- ✅ Production Dockerfile
|
||||||
|
- ✅ Drone CI/CD pipeline
|
||||||
|
- ✅ Renovate for dependency updates
|
||||||
|
- ⚠️ No staging environment
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#186](https://git.local-it.org/local-it/mitgliederverwaltung/issues/186) - Create Architecture docs in Repo (S, Low priority)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Staging environment
|
||||||
|
- ❌ Automated deployment
|
||||||
|
- ❌ Database backup automation
|
||||||
|
- ❌ Monitoring and alerting
|
||||||
|
- ❌ Error tracking (Sentry, etc.)
|
||||||
|
- ❌ Log aggregation
|
||||||
|
- ❌ Health checks and uptime monitoring
|
||||||
|
|
||||||
|
**Related Milestones:**
|
||||||
|
- We have a staging environment
|
||||||
|
- We implement security measures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 14. **Security & Compliance** 🔒
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ OIDC authentication
|
||||||
|
- ✅ Password hashing (bcrypt)
|
||||||
|
- ✅ CSRF protection
|
||||||
|
- ✅ SQL injection prevention (Ecto)
|
||||||
|
- ✅ Sobelow security scans
|
||||||
|
- ✅ Dependency auditing
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Role-based access control (see #1)
|
||||||
|
- ❌ Audit logging
|
||||||
|
- ❌ GDPR compliance features (data export, deletion)
|
||||||
|
- ❌ Session management (timeout, concurrent sessions)
|
||||||
|
- ❌ Rate limiting
|
||||||
|
- ❌ IP whitelisting/blacklisting
|
||||||
|
- ❌ Security headers configuration
|
||||||
|
- ❌ Data retention policies
|
||||||
|
|
||||||
|
**Related Milestones:**
|
||||||
|
- We implement security measures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 15. **Accessibility & Usability** ♿
|
||||||
|
|
||||||
|
**Current State:**
|
||||||
|
- ✅ Semantic HTML
|
||||||
|
- ✅ Basic ARIA labels
|
||||||
|
- ⚠️ Needs comprehensive audit
|
||||||
|
|
||||||
|
**Open Issues:**
|
||||||
|
- [#188](https://git.local-it.org/local-it/mitgliederverwaltung/issues/188) - Check if searching just on typing is accessible (S, Low priority)
|
||||||
|
- [#174](https://git.local-it.org/local-it/mitgliederverwaltung/issues/174) - Accessibility - aria-sort in tables (S, Low priority)
|
||||||
|
|
||||||
|
**Missing Features:**
|
||||||
|
- ❌ Comprehensive accessibility audit (WCAG 2.1 Level AA)
|
||||||
|
- ❌ Keyboard navigation improvements
|
||||||
|
- ❌ Screen reader optimization
|
||||||
|
- ❌ High contrast mode
|
||||||
|
- ❌ Font size adjustments
|
||||||
|
- ❌ Focus management
|
||||||
|
- ❌ Skip links
|
||||||
|
- ❌ Error announcements
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Feature Area Summary
|
||||||
|
|
||||||
|
| Feature Area | Current Status | Priority | Complexity |
|
||||||
|
|--------------|----------------|----------|------------|
|
||||||
|
| **Authentication & Authorization** | 40% complete | **High** | Medium |
|
||||||
|
| **Member Management** | 70% complete | **High** | Low-Medium |
|
||||||
|
| **Custom Fields** | 50% complete | **High** | Medium |
|
||||||
|
| **User Management** | 60% complete | Medium | Low |
|
||||||
|
| **Navigation & UX** | 50% complete | Medium | Low |
|
||||||
|
| **Internationalization** | 70% complete | Low | Low |
|
||||||
|
| **Payment & Fees** | 5% complete | **High** | High |
|
||||||
|
| **Admin Panel** | 20% complete | Medium | Medium |
|
||||||
|
| **Communication** | 30% complete | Medium | Medium |
|
||||||
|
| **Reporting** | 0% complete | Medium | Medium-High |
|
||||||
|
| **Import/Export** | 10% complete | Low | Medium |
|
||||||
|
| **Testing & QA** | 60% complete | Medium | Low-Medium |
|
||||||
|
| **Infrastructure** | 70% complete | Medium | Medium |
|
||||||
|
| **Security** | 50% complete | **High** | Medium-High |
|
||||||
|
| **Accessibility** | 40% complete | Medium | Medium |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Open Milestones (From Issues)
|
||||||
|
|
||||||
|
1. ✅ **Ich kann einen neuen Kontakt anlegen** (Closed)
|
||||||
|
2. 🔄 **I can search through the list of members - fulltext** (Open) - Related: #162, #154
|
||||||
|
3. 🔄 **I can sort the list of members for specific fields** (Open) - Related: #153
|
||||||
|
4. 🔄 **We have a intuitive navigation structure** (Open)
|
||||||
|
5. 🔄 **We have different roles and permissions** (Open) - Related: #191, #190, #151
|
||||||
|
6. 🔄 **As Admin I can configure settings globally** (Open)
|
||||||
|
7. 🔄 **Accounts & Logins** (Open) - Related: #171, #169, #168
|
||||||
|
8. 🔄 **I can add custom fields** (Open) - Related: #194, #157, #161
|
||||||
|
9. 🔄 **Import transactions via vereinfacht API** (Open) - Related: #156
|
||||||
|
10. 🔄 **We have a staging environment** (Open)
|
||||||
|
11. 🔄 **We implement security measures** (Open)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: API Endpoint Definition
|
||||||
|
|
||||||
|
### Endpoint Types
|
||||||
|
|
||||||
|
Since this is a **Phoenix LiveView** application with **Ash Framework**, we have three types of endpoints:
|
||||||
|
|
||||||
|
1. **LiveView Endpoints** - Mount points and event handlers
|
||||||
|
2. **HTTP Controller Endpoints** - Traditional REST-style endpoints
|
||||||
|
3. **Ash Resource Actions** - Backend data layer API
|
||||||
|
|
||||||
|
### Authentication Requirements Legend
|
||||||
|
|
||||||
|
- 🔓 **Public** - No authentication required
|
||||||
|
- 🔐 **Authenticated** - Requires valid user session
|
||||||
|
- 👤 **User Role** - Requires specific user role
|
||||||
|
- 🛡️ **Admin Only** - Requires admin privileges
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1. Authentication & Authorization Endpoints
|
||||||
|
|
||||||
|
#### HTTP Controller Endpoints
|
||||||
|
|
||||||
|
| Method | Route | Purpose | Auth | Request | Response |
|
||||||
|
|--------|-------|---------|------|---------|----------|
|
||||||
|
| `GET` | `/auth/user/password/sign_in` | Show password login form | 🔓 | - | HTML form |
|
||||||
|
| `POST` | `/auth/user/password/sign_in` | Submit password login | 🔓 | `{email, password}` | Redirect + session cookie |
|
||||||
|
| `GET` | `/auth/user/rauthy` | Initiate OIDC flow | 🔓 | - | Redirect to Rauthy |
|
||||||
|
| `GET` | `/auth/user/rauthy/callback` | Handle OIDC callback | 🔓 | `{code, state}` | Redirect + session cookie |
|
||||||
|
| `POST` | `/auth/user/sign_out` | Sign out user | 🔐 | - | Redirect to login |
|
||||||
|
| `GET` | `/auth/user/password/reset` | Show password reset form | 🔓 | - | HTML form |
|
||||||
|
| `POST` | `/auth/user/password/reset` | Request password reset | 🔓 | `{email}` | Success message + email sent |
|
||||||
|
| `GET` | `/auth/user/password/reset/:token` | Show reset password form | 🔓 | - | HTML form |
|
||||||
|
| `POST` | `/auth/user/password/reset/:token` | Submit new password | 🔓 | `{password, password_confirmation}` | Redirect to login |
|
||||||
|
|
||||||
|
#### Ash Resource Actions
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `User` | `:sign_in_with_password` | Password authentication | 🔓 | `{email, password}` | `{:ok, user}` or `{:error, reason}` |
|
||||||
|
| `User` | `:sign_in_with_rauthy` | OIDC authentication | 🔓 | `{oidc_id, email, user_info}` | `{:ok, user}` or `{:error, reason}` |
|
||||||
|
| `User` | `:register_with_password` | Create user with password | 🔓 | `{email, password}` | `{:ok, user}` |
|
||||||
|
| `User` | `:register_with_rauthy` | Create user via OIDC | 🔓 | `{oidc_id, email}` | `{:ok, user}` |
|
||||||
|
| `User` | `:request_password_reset` | Generate reset token | 🔓 | `{email}` | `{:ok, token}` |
|
||||||
|
| `User` | `:reset_password` | Reset password with token | 🔓 | `{token, password}` | `{:ok, user}` |
|
||||||
|
| `Token` | `:revoke` | Revoke authentication token | 🔐 | `{jti}` | `{:ok, token}` |
|
||||||
|
|
||||||
|
#### **NEW: Role & Permission Actions** (Issue #191, #190, #151)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Role` | `:create` | Create new role | 🛡️ | `{name, description, permissions}` | `{:ok, role}` |
|
||||||
|
| `Role` | `:list` | List all roles | 🔐 | - | `[%Role{}]` |
|
||||||
|
| `Role` | `:update` | Update role | 🛡️ | `{id, name, permissions}` | `{:ok, role}` |
|
||||||
|
| `Role` | `:delete` | Delete role | 🛡️ | `{id}` | `{:ok, role}` |
|
||||||
|
| `User` | `:assign_role` | Assign role to user | 🛡️ | `{user_id, role_id}` | `{:ok, user}` |
|
||||||
|
| `User` | `:remove_role` | Remove role from user | 🛡️ | `{user_id, role_id}` | `{:ok, user}` |
|
||||||
|
| `Permission` | `:list` | List all permissions | 🔐 | - | `[%Permission{}]` |
|
||||||
|
| `Permission` | `:check` | Check user permission | 🔐 | `{user_id, resource, action}` | `{:ok, boolean}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Member Management Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Query Params | Events |
|
||||||
|
|-------|---------|------|--------------|--------|
|
||||||
|
| `/members` | Member list with search/sort | 🔐 | `?search=&sort_by=&sort_dir=` | `search`, `sort`, `delete`, `select` |
|
||||||
|
| `/members/new` | Create new member form | 🔐 | - | `save`, `cancel`, `add_property` |
|
||||||
|
| `/members/:id` | Member detail view | 🔐 | - | `edit`, `delete`, `link_user` |
|
||||||
|
| `/members/:id/edit` | Edit member form | 🔐 | - | `save`, `cancel`, `add_property`, `remove_property` |
|
||||||
|
|
||||||
|
#### LiveView Event Handlers
|
||||||
|
|
||||||
|
| Event | Purpose | Params | Response |
|
||||||
|
|-------|---------|--------|----------|
|
||||||
|
| `search` | Trigger search | `%{"search" => query}` | Update member list |
|
||||||
|
| `sort` | Sort member list | `%{"field" => field}` | Update sorted list |
|
||||||
|
| `delete` | Delete member | `%{"id" => id}` | Redirect to list |
|
||||||
|
| `save` | Create/update member | `%{"member" => attrs}` | Redirect or show errors |
|
||||||
|
| `link_user` | Link user to member | `%{"user_id" => id}` | Update member view |
|
||||||
|
| `unlink_user` | Unlink user from member | - | Update member view |
|
||||||
|
| `add_property` | Add custom property | `%{"property_type_id" => id, "value" => val}` | Update form |
|
||||||
|
| `remove_property` | Remove custom property | `%{"property_id" => id}` | Update form |
|
||||||
|
|
||||||
|
#### Ash Resource Actions
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Member` | `:create_member` | Create member | 🔐 | `{first_name, last_name, email, ...}` | `{:ok, member}` |
|
||||||
|
| `Member` | `:read` | List/search members | 🔐 | `{search, sort_by, limit, offset}` | `[%Member{}]` |
|
||||||
|
| `Member` | `:update_member` | Update member | 🔐 | `{id, attrs}` | `{:ok, member}` |
|
||||||
|
| `Member` | `:destroy` | Delete member | 🔐 | `{id}` | `{:ok, member}` |
|
||||||
|
| `Member` | `:search_fulltext` | Full-text search | 🔐 | `{query}` | `[%Member{}]` |
|
||||||
|
| `Member` | `:link_to_user` | Link member to user | 🔐 | `{member_id, user_id}` | `{:ok, member}` |
|
||||||
|
| `Member` | `:unlink_from_user` | Unlink from user | 🔐 | `{member_id}` | `{:ok, member}` |
|
||||||
|
|
||||||
|
#### **NEW: Enhanced Search & Filter Actions** (Issue #162, #154, #165)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Member` | `:fuzzy_search` | Fuzzy text search | 🔐 | `{query, threshold}` | `[%Member{}]` |
|
||||||
|
| `Member` | `:advanced_search` | Multi-criteria search | 🔐 | `{filters: [{field, op, value}]}` | `[%Member{}]` |
|
||||||
|
| `Member` | `:paginate` | Paginated member list | 🔐 | `{page, per_page, filters}` | `{members, total, page_info}` |
|
||||||
|
| `Member` | `:sort_by_custom_field` | Sort by property | 🔐 | `{property_type_id, direction}` | `[%Member{}]` |
|
||||||
|
| `Member` | `:bulk_delete` | Delete multiple members | 🛡️ | `{ids: [id1, id2, ...]}` | `{:ok, count}` |
|
||||||
|
| `Member` | `:bulk_update` | Update multiple members | 🛡️ | `{ids, attrs}` | `{:ok, count}` |
|
||||||
|
| `Member` | `:export` | Export to CSV/Excel | 🔐 | `{format, filters}` | File download |
|
||||||
|
| `Member` | `:import` | Import from CSV | 🛡️ | `{file, mapping}` | `{:ok, imported_count, errors}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Custom Fields (Property System) Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/property-types` | List property types | 🛡️ | `new`, `edit`, `delete` |
|
||||||
|
| `/property-types/new` | Create property type | 🛡️ | `save`, `cancel` |
|
||||||
|
| `/property-types/:id/edit` | Edit property type | 🛡️ | `save`, `cancel`, `delete` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `PropertyType` | `:create` | Create property type | 🛡️ | `{name, value_type, description, ...}` | `{:ok, property_type}` |
|
||||||
|
| `PropertyType` | `:read` | List property types | 🔐 | - | `[%PropertyType{}]` |
|
||||||
|
| `PropertyType` | `:update` | Update property type | 🛡️ | `{id, attrs}` | `{:ok, property_type}` |
|
||||||
|
| `PropertyType` | `:destroy` | Delete property type | 🛡️ | `{id}` | `{:ok, property_type}` |
|
||||||
|
| `Property` | `:create` | Add property to member | 🔐 | `{member_id, property_type_id, value}` | `{:ok, property}` |
|
||||||
|
| `Property` | `:update` | Update property value | 🔐 | `{id, value}` | `{:ok, property}` |
|
||||||
|
| `Property` | `:destroy` | Remove property | 🔐 | `{id}` | `{:ok, property}` |
|
||||||
|
|
||||||
|
#### **NEW: Enhanced Custom Fields** (Issue #194, #157, #161, #153)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `PropertyType` | `:set_default_visibility` | Show/hide by default | 🛡️ | `{id, visible}` | `{:ok, property_type}` |
|
||||||
|
| `PropertyType` | `:set_required` | Mark as required | 🛡️ | `{id, required}` | `{:ok, property_type}` |
|
||||||
|
| `PropertyType` | `:add_validation` | Add validation rule | 🛡️ | `{id, rule_type, params}` | `{:ok, property_type}` |
|
||||||
|
| `PropertyType` | `:create_group` | Create field group | 🛡️ | `{name, property_type_ids}` | `{:ok, group}` |
|
||||||
|
| `Property` | `:validate_value` | Validate property value | 🔐 | `{property_type_id, value}` | `{:ok, valid}` or `{:error, reason}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. User Management Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/users` | User list | 🛡️ | `new`, `edit`, `delete`, `assign_role` |
|
||||||
|
| `/users/new` | Create user form | 🛡️ | `save`, `cancel` |
|
||||||
|
| `/users/:id` | User detail view | 🔐 | `edit`, `delete`, `change_password` |
|
||||||
|
| `/users/:id/edit` | Edit user form | 🔐 | `save`, `cancel`, `link_member` |
|
||||||
|
| `/profile` | Current user profile | 🔐 | `edit`, `change_password` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `User` | `:create_user` | Create user (admin) | 🛡️ | `{email, member_id?}` | `{:ok, user}` |
|
||||||
|
| `User` | `:read` | List users | 🛡️ | - | `[%User{}]` |
|
||||||
|
| `User` | `:update_user` | Update user | 🔐 | `{id, email, member_id?}` | `{:ok, user}` |
|
||||||
|
| `User` | `:destroy` | Delete user | 🛡️ | `{id}` | `{:ok, user}` |
|
||||||
|
| `User` | `:admin_set_password` | Set password (admin) | 🛡️ | `{id, password}` | `{:ok, user}` |
|
||||||
|
| `User` | `:change_password` | Change own password | 🔐 | `{current_password, new_password}` | `{:ok, user}` |
|
||||||
|
|
||||||
|
#### **NEW: Combined User/Member Management** (Issue #169, #168)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `User` | `:create_with_member` | Create user + member together | 🛡️ | `{user: {...}, member: {...}}` | `{:ok, %{user, member}}` |
|
||||||
|
| `User` | `:invite_user` | Send invitation email | 🛡️ | `{email, role_id, member_id?}` | `{:ok, invitation}` |
|
||||||
|
| `User` | `:accept_invitation` | Accept invitation | 🔓 | `{token, password}` | `{:ok, user}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Navigation & UX Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/` | Dashboard/Home | 🔐 | - |
|
||||||
|
| `/dashboard` | Dashboard view | 🔐 | Contextual based on role |
|
||||||
|
|
||||||
|
#### HTTP Controller Endpoints
|
||||||
|
|
||||||
|
| Method | Route | Purpose | Auth | Request | Response |
|
||||||
|
|--------|-------|---------|------|---------|----------|
|
||||||
|
| `GET` | `/health` | Health check | 🔓 | - | `{"status": "ok"}` |
|
||||||
|
| `GET` | `/` | Root redirect | - | - | Redirect to dashboard or login |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. Internationalization Endpoints
|
||||||
|
|
||||||
|
#### HTTP Controller Endpoints
|
||||||
|
|
||||||
|
| Method | Route | Purpose | Auth | Request | Response |
|
||||||
|
|--------|-------|---------|------|---------|----------|
|
||||||
|
| `POST` | `/locale` | Set user locale | 🔐 | `{locale: "de"}` | Redirect with cookie |
|
||||||
|
| `GET` | `/locales` | List available locales | 🔓 | - | `["de", "en"]` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. Payment & Fees Management Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints (NEW - Issue #156)
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/payments` | Payment list | 🔐 | `new`, `record_payment`, `send_reminder` |
|
||||||
|
| `/payments/:id` | Payment detail | 🔐 | `edit`, `delete`, `mark_paid` |
|
||||||
|
| `/fees` | Fee configuration | 🛡️ | `create`, `edit`, `delete` |
|
||||||
|
| `/invoices` | Invoice list | 🔐 | `generate`, `download`, `send` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions (NEW)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Fee` | `:create` | Create fee type | 🛡️ | `{name, amount, frequency}` | `{:ok, fee}` |
|
||||||
|
| `Fee` | `:read` | List fees | 🔐 | - | `[%Fee{}]` |
|
||||||
|
| `Payment` | `:create` | Record payment | 🔐 | `{member_id, fee_id, amount, date}` | `{:ok, payment}` |
|
||||||
|
| `Payment` | `:list_by_member` | Member payment history | 🔐 | `{member_id}` | `[%Payment{}]` |
|
||||||
|
| `Payment` | `:mark_paid` | Mark as paid | 🔐 | `{id}` | `{:ok, payment}` |
|
||||||
|
| `Invoice` | `:generate` | Generate invoice | 🔐 | `{member_id, fee_id, period}` | `{:ok, invoice}` |
|
||||||
|
| `Invoice` | `:send` | Send invoice via email | 🔐 | `{id}` | `{:ok, sent}` |
|
||||||
|
| `Payment` | `:import_vereinfacht` | Import from vereinfacht.digital | 🛡️ | `{transactions}` | `{:ok, count}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. Admin Panel & Configuration Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints (NEW)
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/admin` | Admin dashboard | 🛡️ | - |
|
||||||
|
| `/admin/settings` | Global settings | 🛡️ | `save` |
|
||||||
|
| `/admin/organization` | Organization profile | 🛡️ | `save` |
|
||||||
|
| `/admin/email-templates` | Email template editor | 🛡️ | `create`, `edit`, `preview` |
|
||||||
|
| `/admin/audit-log` | System audit log | 🛡️ | `filter`, `export` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions (NEW)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Setting` | `:get` | Get setting value | 🔐 | `{key}` | `value` |
|
||||||
|
| `Setting` | `:set` | Set setting value | 🛡️ | `{key, value}` | `{:ok, setting}` |
|
||||||
|
| `Setting` | `:list` | List all settings | 🛡️ | - | `[%Setting{}]` |
|
||||||
|
| `Organization` | `:read` | Get organization info | 🔐 | - | `%Organization{}` |
|
||||||
|
| `Organization` | `:update` | Update organization | 🛡️ | `{name, logo, ...}` | `{:ok, org}` |
|
||||||
|
| `AuditLog` | `:list` | List audit entries | 🛡️ | `{filters, pagination}` | `[%AuditLog{}]` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. Communication & Notifications Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints (NEW)
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/communications` | Communication history | 🔐 | `new`, `view` |
|
||||||
|
| `/communications/new` | Create email broadcast | 🔐 | `select_recipients`, `preview`, `send` |
|
||||||
|
| `/notifications` | User notifications | 🔐 | `mark_read`, `mark_all_read` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions (NEW)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `EmailBroadcast` | `:create` | Create broadcast | 🔐 | `{subject, body, recipient_filter}` | `{:ok, broadcast}` |
|
||||||
|
| `EmailBroadcast` | `:send` | Send broadcast | 🔐 | `{id}` | `{:ok, sent_count}` |
|
||||||
|
| `EmailTemplate` | `:create` | Create template | 🛡️ | `{name, subject, body}` | `{:ok, template}` |
|
||||||
|
| `EmailTemplate` | `:render` | Render template | 🔐 | `{id, variables}` | `rendered_html` |
|
||||||
|
| `Notification` | `:create` | Create notification | System | `{user_id, type, message}` | `{:ok, notification}` |
|
||||||
|
| `Notification` | `:list_for_user` | Get user notifications | 🔐 | `{user_id}` | `[%Notification{}]` |
|
||||||
|
| `Notification` | `:mark_read` | Mark as read | 🔐 | `{id}` | `{:ok, notification}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. Reporting & Analytics Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints (NEW)
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/reports` | Reports dashboard | 🔐 | `generate`, `schedule` |
|
||||||
|
| `/reports/members` | Member statistics | 🔐 | `filter`, `export` |
|
||||||
|
| `/reports/payments` | Payment reports | 🔐 | `filter`, `export` |
|
||||||
|
| `/reports/custom` | Custom report builder | 🛡️ | `build`, `save`, `run` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions (NEW)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Report` | `:generate_member_stats` | Member statistics | 🔐 | `{date_range, filters}` | Statistics object |
|
||||||
|
| `Report` | `:generate_payment_stats` | Payment statistics | 🔐 | `{date_range}` | Statistics object |
|
||||||
|
| `Report` | `:export_to_csv` | Export report to CSV | 🔐 | `{report_type, filters}` | CSV file |
|
||||||
|
| `Report` | `:export_to_pdf` | Export report to PDF | 🔐 | `{report_type, filters}` | PDF file |
|
||||||
|
| `Report` | `:schedule` | Schedule recurring report | 🛡️ | `{report_type, frequency, recipients}` | `{:ok, schedule}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 11. Data Import/Export Endpoints
|
||||||
|
|
||||||
|
#### LiveView Endpoints (NEW)
|
||||||
|
|
||||||
|
| Mount | Purpose | Auth | Events |
|
||||||
|
|-------|---------|------|--------|
|
||||||
|
| `/import` | Data import wizard | 🛡️ | `upload`, `map_fields`, `preview`, `import` |
|
||||||
|
| `/export` | Data export tool | 🔐 | `select_data`, `configure`, `export` |
|
||||||
|
|
||||||
|
#### Ash Resource Actions (NEW)
|
||||||
|
|
||||||
|
| Resource | Action | Purpose | Auth | Input | Output |
|
||||||
|
|----------|--------|---------|------|-------|--------|
|
||||||
|
| `Member` | `:import_csv` | Import members from CSV | 🛡️ | `{file, field_mapping}` | `{:ok, imported, errors}` |
|
||||||
|
| `Member` | `:validate_import` | Validate import data | 🛡️ | `{file, field_mapping}` | `{:ok, validation_results}` |
|
||||||
|
| `Member` | `:export_csv` | Export members to CSV | 🔐 | `{filters}` | CSV file |
|
||||||
|
| `Member` | `:export_excel` | Export members to Excel | 🔐 | `{filters}` | Excel file |
|
||||||
|
| `Database` | `:export_backup` | Full database backup | 🛡️ | - | Backup file |
|
||||||
|
| `Database` | `:import_backup` | Restore from backup | 🛡️ | `{file}` | `{:ok, restored}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**References:**
|
||||||
|
- Open Issues: https://git.local-it.org/local-it/mitgliederverwaltung/issues
|
||||||
|
- Project Board: Sprint 8 (23.10 - 13.11)
|
||||||
|
- Architecture: See [`CODE_GUIDELINES.md`](../CODE_GUIDELINES.md)
|
||||||
|
- Database Schema: See [`database-schema-readme.md`](database-schema-readme.md)
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue