docs: add @moduledoc to core membership resources
Add comprehensive module documentation to Member, Property, PropertyType, and Email. Improves code discoverability and enables ExDoc generation.
This commit is contained in:
parent
20af015da6
commit
409bc7bf2f
4 changed files with 141 additions and 0 deletions
|
|
@ -1,4 +1,37 @@
|
||||||
defmodule Mv.Membership.Email do
|
defmodule Mv.Membership.Email do
|
||||||
|
@moduledoc """
|
||||||
|
Custom Ash type for validated email addresses.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This type extends `:string` with email-specific validation constraints.
|
||||||
|
It ensures that email values stored in Property resources are valid email
|
||||||
|
addresses according to a standard regex pattern.
|
||||||
|
|
||||||
|
## Validation Rules
|
||||||
|
- Minimum length: 5 characters
|
||||||
|
- Maximum length: 254 characters (RFC 5321 maximum)
|
||||||
|
- Pattern: Standard email format (username@domain.tld)
|
||||||
|
- Automatic trimming of leading/trailing whitespace
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
This type is used in the Property union type for properties with
|
||||||
|
`value_type: :email` in PropertyType definitions.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
# In a property type definition
|
||||||
|
PropertyType.create!(%{
|
||||||
|
name: "work_email",
|
||||||
|
value_type: :email
|
||||||
|
})
|
||||||
|
|
||||||
|
# Valid values
|
||||||
|
"user@example.com"
|
||||||
|
"first.last@company.co.uk"
|
||||||
|
|
||||||
|
# Invalid values
|
||||||
|
"not-an-email" # Missing @ and domain
|
||||||
|
"a@b" # Too short
|
||||||
|
"""
|
||||||
@match_pattern ~S/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/
|
@match_pattern ~S/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/
|
||||||
@match_regex Regex.compile!(@match_pattern)
|
@match_regex Regex.compile!(@match_pattern)
|
||||||
@min_length 5
|
@min_length 5
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,36 @@
|
||||||
defmodule Mv.Membership.Member do
|
defmodule Mv.Membership.Member do
|
||||||
|
@moduledoc """
|
||||||
|
Ash resource representing a club member.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Members are the core entity in the membership management system. Each member
|
||||||
|
can have:
|
||||||
|
- Personal information (name, email, phone, address)
|
||||||
|
- Optional link to a User account (1:1 relationship)
|
||||||
|
- Dynamic custom properties via PropertyType system
|
||||||
|
- Full-text searchable profile
|
||||||
|
|
||||||
|
## Email Synchronization
|
||||||
|
When a member is linked to a user account, emails are automatically synchronized
|
||||||
|
bidirectionally. User.email is the source of truth on initial link.
|
||||||
|
See `Mv.EmailSync` for details.
|
||||||
|
|
||||||
|
## Relationships
|
||||||
|
- `has_many :properties` - Dynamic custom fields
|
||||||
|
- `has_one :user` - Optional authentication account link
|
||||||
|
|
||||||
|
## Validations
|
||||||
|
- Required: first_name, last_name, email
|
||||||
|
- Email format validation (using EctoCommons.EmailValidator)
|
||||||
|
- Phone number format: international format with 6-20 digits
|
||||||
|
- Postal code format: exactly 5 digits (German format)
|
||||||
|
- Date validations: birth_date and join_date not in future, exit_date after join_date
|
||||||
|
- Email uniqueness: prevents conflicts with unlinked users
|
||||||
|
|
||||||
|
## Full-Text Search
|
||||||
|
Members have a `search_vector` attribute (tsvector) that is automatically
|
||||||
|
updated via database trigger. Search includes name, email, notes, and contact fields.
|
||||||
|
"""
|
||||||
use Ash.Resource,
|
use Ash.Resource,
|
||||||
domain: Mv.Membership,
|
domain: Mv.Membership,
|
||||||
data_layer: AshPostgres.DataLayer
|
data_layer: AshPostgres.DataLayer
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,36 @@
|
||||||
defmodule Mv.Membership.Property do
|
defmodule Mv.Membership.Property do
|
||||||
|
@moduledoc """
|
||||||
|
Ash resource representing a custom property value for a member.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Properties implement the Entity-Attribute-Value (EAV) pattern, allowing
|
||||||
|
dynamic custom fields to be attached to members. Each property links a
|
||||||
|
member to a property type and stores the actual value.
|
||||||
|
|
||||||
|
## Value Storage
|
||||||
|
Values are stored using Ash's union type with JSONB storage format:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"value": "example"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported Types
|
||||||
|
- `:string` - Text data
|
||||||
|
- `:integer` - Numeric data
|
||||||
|
- `:boolean` - True/false flags
|
||||||
|
- `:date` - Date values
|
||||||
|
- `:email` - Validated email addresses (custom type)
|
||||||
|
|
||||||
|
## Relationships
|
||||||
|
- `belongs_to :member` - The member this property belongs to (CASCADE delete)
|
||||||
|
- `belongs_to :property_type` - The property type definition
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Each member can have only one property per property type (unique composite index)
|
||||||
|
- Properties are deleted when the associated member is deleted (CASCADE)
|
||||||
|
"""
|
||||||
use Ash.Resource,
|
use Ash.Resource,
|
||||||
domain: Mv.Membership,
|
domain: Mv.Membership,
|
||||||
data_layer: AshPostgres.DataLayer
|
data_layer: AshPostgres.DataLayer
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,48 @@
|
||||||
defmodule Mv.Membership.PropertyType do
|
defmodule Mv.Membership.PropertyType do
|
||||||
|
@moduledoc """
|
||||||
|
Ash resource defining the schema for custom member properties.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
PropertyTypes define the "schema" for custom fields in the membership system.
|
||||||
|
Each PropertyType specifies the name, data type, and behavior of a custom field
|
||||||
|
that can be attached to members via Property resources.
|
||||||
|
|
||||||
|
## Attributes
|
||||||
|
- `name` - Unique identifier for the property (e.g., "phone_mobile", "birthday")
|
||||||
|
- `value_type` - Data type constraint (`:string`, `:integer`, `:boolean`, `:date`, `:email`)
|
||||||
|
- `description` - Optional human-readable description
|
||||||
|
- `immutable` - If true, property values cannot be changed after creation
|
||||||
|
- `required` - If true, all members must have this property (future feature)
|
||||||
|
|
||||||
|
## Supported Value Types
|
||||||
|
- `:string` - Text data (unlimited length)
|
||||||
|
- `:integer` - Numeric data (64-bit integers)
|
||||||
|
- `:boolean` - True/false flags
|
||||||
|
- `:date` - Date values (no time component)
|
||||||
|
- `:email` - Validated email addresses
|
||||||
|
|
||||||
|
## Relationships
|
||||||
|
- `has_many :properties` - All property values of this type
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Name must be unique across all property types
|
||||||
|
- Cannot delete a property type that has existing property values (RESTRICT)
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
# Create a new property type
|
||||||
|
PropertyType.create!(%{
|
||||||
|
name: "phone_mobile",
|
||||||
|
value_type: :string,
|
||||||
|
description: "Mobile phone number"
|
||||||
|
})
|
||||||
|
|
||||||
|
# Create a required property type
|
||||||
|
PropertyType.create!(%{
|
||||||
|
name: "emergency_contact",
|
||||||
|
value_type: :string,
|
||||||
|
required: true
|
||||||
|
})
|
||||||
|
"""
|
||||||
use Ash.Resource,
|
use Ash.Resource,
|
||||||
domain: Mv.Membership,
|
domain: Mv.Membership,
|
||||||
data_layer: AshPostgres.DataLayer
|
data_layer: AshPostgres.DataLayer
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue