Implements support for both individual persons and organizations as members. Changes: - Added MemberType enum (INDIVIDUAL, ORGANIZATION) to distinguish member types - Added member_type column to database (defaults to INDIVIDUAL for backward compatibility) - Added company_name field for organizations - Made first_name nullable (required for individuals, optional for organizations) - Implemented conditional validation: - INDIVIDUAL members require first_name - ORGANIZATION members require company_name - Updated GraphQL schema with new memberType and companyName fields - Updated all resolvers to handle new fields and validation - Added comprehensive unit tests for validation logic - Updated existing tests to work with new fields - All 53 tests passing Technical notes: - Using memberType instead of 'kind' to avoid GraphQL introspection conflicts - Using native_enum=False for SQLite compatibility - Using batch_alter_table for SQLite ALTER COLUMN compatibility - Backward compatible: existing members automatically become INDIVIDUAL type 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1.4 KiB
1.4 KiB
Design: Organization Member Support
Data Model Changes
Member Table
- Add
member_typecolumn: Enum (INDIVIDUAL,ORGANIZATION). Default toINDIVIDUALfor existing records. - Add
company_namecolumn: String, nullable. - Alter
first_name: Change fromnullable=Falsetonullable=True.
Constraints
- Application Level:
- If
member_typeisINDIVIDUAL:first_namemust be present. - If
member_typeisORGANIZATION:company_namemust be present.
- If
- Database Level:
- We can't easily enforce conditional not-null constraints in standard SQL without triggers or check constraints. For simplicity and portability (SQLite/Postgres), we will enforce this at the application level (Pydantic/SQLAlchemy validators) and potentially add a CHECK constraint if supported by both dialects easily.
first_namewill become nullable in the DB schema.
API Changes
GraphQL Schema
- Update
Membertype to includememberTypeandcompanyName. - Update
createMemberandupdateMemberinputs. - Add validation logic in resolvers to enforce the conditional requirements.
Migration Strategy
- Add
member_typecolumn with default 'INDIVIDUAL'. - Add
company_namecolumn. - Alter
first_nameto be nullable.
Technical Note
- Using
memberTypeinstead ofkindto avoid conflicts with GraphQL introspection queries which usekindas a metadata field.