12
🪷

Members Suite — Forms

Founders · Donors · Volunteers · Staff — one segmented registry

Forms — Members Suite

UX / forms specification · slug members · 2026-05-02 Companion to docs/blueprints/members.md. Reading order: Categorize → Founder → Substantial Donor → Recurring Donor → Volunteer Skills → Volunteer Availability → Communication Preferences → Mailing List → Tag/Segment → Donor History → Volunteer Match.

This document specifies every screen-level form in the Members Suite — the CRM face of the seven-category model (Founders, Substantial Donors, Recurring Donors, Service Recipients, Casual Associates, Volunteers, Staff Index). The single canonical members table remains the source of truth for biographical fields; the forms below operate on the categorization layer (member_categorizations), the donor aggregate denormalisation (member_donor_aggregates), the volunteer skill inventory (volunteer_skills), and the communication-preferences / subscription tables. A person can hold multiple active categorizations simultaneously — donor and volunteer and parent of a student — and every form respects that multiplicity.


Section 1 — Categorization

Workflow note: Every member starts life in casual_associate on first creation (DB-level default). Categorization is then a combination of automatic and manual workflows. Substantial-donor and recurring-donor categorizations are computed nightly from member_donor_aggregates and live Razorpay subscription state; service-recipient is derived from active sevas; volunteer and founder are manual; staff_index is auto-set by Staff Details onboarding. The Categorize Member form lets an admin override or supplement these — for example, recognising a long-serving sevadar as a Founder, or pre-categorizing a substantial donor before the nightly aggregate refresh has caught up.

Form 1.1 — Categorize Member

Purpose: Add or update a member's category memberships. Multi-category allowed. Who fills: Tenant-admin or module-admin; ad-hoc.

Field Type Required Options / Validation Default Help
Member Display locked from URL context current Subject of categorization
Categories to add Multi-select chips Yes founder / substantial_donor / recurring_donor / service_recipient / casual_associate / volunteer / staff_index Existing active categories greyed and pre-checked
Categories to remove Multi-select chips No only currently-active categories Triggers decategorize for each
Since date (per added category) Date Yes <= today today When this categorization began
Recognition level Select No Bronze / Silver / Gold / Platinum / Founder / (free text) Ranks a donor or founder; visible on donor wall
Source Radio Yes Manual / Imported / Automatic-override Manual "Automatic-override" forces a re-eval against nightly job
Threshold evidence (JSON) Textarea No valid JSON e.g. {"trigger":"manual","fy":"FY2025-26","note":"endowment of ₹5L"}
Notes Textarea No max 1000 Internal context
Reason for change Text Yes max 255 Written to audit_event
Effective date Date No <= today + 30 today Override since_date if needed

Submit action: POST /api/members/{member_id}/categorize for adds; DELETE /api/members/{member_id}/categorize/{category} for removes — both wrapped server-side in one transaction with a single audit event member.recategorized. Refreshes category-filter chips on the member detail page. Related forms: Form 2.1 (Founder Recognition) for additional founder fields; Form 3.1 (Substantial Donor Override) for threshold tuning.


Section 2 — Founders

Workflow note: Founders are a small, deliberately curated set — original trustees, founding archakas, primary land-donors, and equivalents. The category is rarely auto-set; it is recorded once at institutional setup (or backfilled from awardees legacy data) and rarely changed thereafter. The Founder Recognition Entry form captures the public-facing founding role, the since-date, and a recognition tier rendered on the donor wall and on annual report covers.

Form 2.1 — Founder Recognition Entry

Purpose: Record the founding role and recognition level. Augments the base categorization. Who fills: Tenant-admin or chairperson; once at recognition.

Field Type Required Options / Validation Default Help
Member Display locked current
Founding role Text Yes max 127 e.g. Founder Trustee, Pratisthapaka Acharya, Mula Bhumi Daanam
Since date Date Yes <= today Date of original contribution / installation
Recognition level Select Yes Bronze / Silver / Gold / Platinum / Founder / Maha-Founder Founder Drives wall and report rendering
Citation (display text) Textarea Yes max 1000 Shown on donor wall under name
Public consent Checkbox Yes false Required to display on public wall
Photo for wall File upload No jpg/png, square, max 2 MB from members.photo Override default photo
Founding contribution summary Textarea No max 2000 Land donated, capital seed, building sponsored
Anniversary date (commemoration) Date No day-and-month only used Drives anniversary Comms
Trustee number / serial Text No max 32 If on registered trust deed
Notes Textarea No max 2000 Internal

Submit action: POST /api/members/{member_id}/categorize with category=founder + recognition_level + threshold_data carrying citation and role. Audit event member.founder.recognized. Related forms: Form 1.1 (Categorize) is the underlying primitive; donor wall rendering is Vitta-side.


Section 3 — Donors

Workflow note: Donor categorization runs primarily off member_donor_aggregates, refreshed nightly (and on every confirmed payment event for low-latency recategorization). Two distinct workflows: Substantial Donor Threshold Override lets an admin manually set or revoke this category in advance of or against the automatic rule; Recurring Donor Setup links a member to a Razorpay subscription and pins the auto-categorization to that subscription's lifecycle. Both forms write to audit_events and trigger an immediate compute_substantial_donor_status re-evaluation.

Form 3.1 — Substantial Donor Threshold Override

Purpose: Manually set, revoke, or pin a substantial-donor categorization against the auto rule. Who fills: Tenant-admin or module-admin; case-by-case.

Field Type Required Options / Validation Default Help
Member Display locked current
Current auto-status Display computed from aggregates Shows lifetime_total vs threshold
Action Radio Yes Set as substantial donor / Revoke substantial donor / Pin (do not auto-recompute) "Pin" prevents nightly job from changing this row
Override reason Textarea Yes max 1000 e.g. anonymous bulk donor, related-party adjustment, KYC mismatch
Recognition level Select No Bronze / Silver / Gold / Platinum derived from amount Override if needed
Threshold evidence Textarea No JSON auto-prefilled with aggregate snapshot Captures the moment-in-time numbers
Effective from Date Yes <= today + 30 today
Pin until Date No required if Action=Pin Pin auto-releases after this date
Approver (second-eye) Select No (Yes for revoke) other tenant-admin Required for Revoke
Notes Textarea No max 2000

Submit action: POST /api/members/{member_id}/categorize (or DELETE) with source='manual' and threshold_met carrying the override evidence. Audit event member.substantial_donor.overridden. If Pin, the nightly compute_substantial_donor_status job skips this member until pin_until. Related forms: Form 3.2 (Recurring Donor) for subscription-linked donors; Form 9.1 (Donor History) shows the underlying transactions.

Form 3.2 — Recurring Donor Setup

Purpose: Link a member to a Razorpay subscription so recurring-donor status auto-tracks subscription state. Who fills: Tenant-admin or self-service via donation flow.

Field Type Required Options / Validation Default Help
Member Display locked current
Razorpay subscription ID Text Yes regex sub_[A-Za-z0-9]{14} From Razorpay dashboard or webhook
Plan Select Yes active Razorpay plans for this tenant Loaded via Razorpay API
Amount (INR) Number Yes matches plan amount from plan Display only, locked to plan
Frequency Display Monthly / Quarterly / Annual from plan
Fund allocation Select Yes general / annadana / building / fcra / endowment general Routes to fund accounting
Start date Date Yes >= today today First charge date
End date Date No > start Blank for open-ended
80G eligible Checkbox No true Drives certificate generation
Send acknowledgement on each charge Checkbox No true Triggers Comms
Anniversary card Checkbox No true Annual thank-you Comms
Lapse handling Radio No Auto-decategorize after 90 days / Wait for explicit cancel Auto-90d Per Open Q #5 in blueprint
Notes Textarea No max 1000

Submit action: POST /api/members/{member_id}/categorize with category=recurring_donor + razorpay_subscription_id stored in threshold_met. Razorpay webhook will subsequently keep state in sync. Audit event member.recurring_donor.set. Related forms: Form 3.1 (Substantial) — recurring donors often qualify as substantial after 12 months; Form 9.1 (Donor History).


Section 4 — Volunteers

Workflow note: Volunteers are members with the volunteer categorization plus rows in volunteer_skills. The Skill Inventory and Availability forms together populate the matrix that the Volunteer-Match Tool (Form 11.1) reads. Skills are tenant-extensible — a Sangita-focused tenant adds vocal_carnatic and tabla; a Vedapathashala adds chandas_recitation. The default seed catalog covers ten common skills and matches the reference HTML.

Form 4.1 — Volunteer Skill Inventory

Purpose: Capture what services a volunteer can offer and at what proficiency. Who fills: Volunteer self-service (during sign-up) or volunteer coordinator.

Field Type Required Options / Validation Default Help
Member Display locked current
Skills (multi-select with proficiency) Each skill: tick + 1–5 stars + certified flag
Driving Checkbox + Stars No proficiency 1–5 unchecked Two-wheeler / Four-wheeler / Heavy in notes
Cooking Checkbox + Stars No 1–5 unchecked Vegetarian satvik / Annadana scale
Accounting Checkbox + Stars No 1–5 unchecked Tally / book-keeping / GST returns
Physical service (kayaka seva) Checkbox + Stars No 1–5 unchecked Cleaning / setup / heavy lifting
IT / digital Checkbox + Stars No 1–5 unchecked Web, sound, projection, livestream
Language translation Checkbox + Stars No 1–5 unchecked Pair captured below
Music (vocal / instrumental) Checkbox + Stars No 1–5 unchecked Specify instrument in notes
Dance (classical) Checkbox + Stars No 1–5 unchecked Bharatanatyam / Kuchipudi / etc
Pravachana Checkbox + Stars No 1–5 unchecked Public discourse / kathakalakshepa
Sanskrit typing Checkbox + Stars No 1–5 unchecked VijayaDV-aware preferred
Photography Checkbox + Stars No 1–5 unchecked Stills / video / drone
Sound engineering Checkbox + Stars No 1–5 unchecked Live mixing / recording
Samagri setup Checkbox + Stars No 1–5 unchecked Ritual material preparation
Manuscript work Checkbox + Stars No 1–5 unchecked Transcription / proofing
Chandas recitation Checkbox + Stars No 1–5 unchecked Veda-recitation by chandas
Other skills (free) Multi-tag No tenant-extensible Auto-suggests existing tenant skills
Languages known Multi-select No Sanskrit / Kannada / Tamil / Telugu / Hindi / English / Marathi / Malayalam / Other Pairs with translation skill
Certifications Multi-tag No free text First-aid, food-safety, driving licence class

Submit action: POST /api/members/{member_id}/volunteer-skills per skill (server runs upsert on (member_id, skill_code)). If member is not yet categorized as volunteer, the form silently calls Form 1.1 to add the volunteer category. Related forms: Form 4.2 (Availability), Form 11.1 (Match Tool).

Form 4.2 — Volunteer Availability Form

Purpose: Capture when a volunteer is available, so Match-Tool can avoid impossible assignments. Who fills: Volunteer self-service or coordinator.

Field Type Required Options / Validation Default Help
Member Display locked current
Availability pattern Radio Yes Weekends only / Weekdays / Full time / Events only / Online only / Custom Events only
Days of week Multi-checkbox No Mon–Sun Shown only if Custom
Time-of-day windows Multi-checkbox No Pratahkal (5–9am) / Morning (9–12) / Afternoon (12–4) / Sayamkal (4–8) / Night (8pm onward) Maps to ritual time-slots
Travel radius (km) Number No 0–500 25 From their address — used for branch matching
Can travel to other branches Checkbox No false If true, available for any branch
Out-of-station dates Date range repeater No up to 12 ranges Blackout dates
Annual leave declared Number (days) No 0–365 Cumulative
Festival-only mode Checkbox No false Match tool only suggests during marked festivals
Lead-time required (days) Number No 0–60 3 Minimum notice
Languages willing to serve in Multi-select No inherits from skill form Translation / pravachana audiences
Notes Textarea No max 1000

Submit action: PATCH /api/members/{member_id}/volunteer-skills writes a single availability row keyed off the volunteer's primary skill row, or a dedicated volunteer_availability JSON column on member_categorizations (the categorization row's notes/threshold_data when category=volunteer). Audit event member.volunteer.availability_updated. Related forms: Form 11.1 (Match Tool) consumes this directly.


Section 5 — Communication & Subscriptions

Workflow note: Communication preferences are a 1:1 per-member record consulted by Comms (Agent 5) before every send. The form distinguishes campaign Comms (newsletters, festival greetings, fund-raising appeals) from transactional Comms (donation receipts, 80G certificates) — the receipt_only flag opts out of the former while preserving the legally-required latter. Mailing-list subscriptions are layered on top: a member can be on the "Annadana donors" list but off the "Festival announcements" list. Double-opt-in is the default; lists can disable it for in-person sign-ups (a tablet at the donation desk).

Form 5.1 — Communication Preferences

Purpose: Per-channel opt-ins and language preferences. The single source-of-truth Comms reads. Who fills: Member self-service preferred; admin can edit on member's behalf.

Field Type Required Options / Validation Default Help
Member Display locked current
Email opt-in Toggle No true Master switch for email
WhatsApp opt-in Toggle No false Requires WhatsApp Business consent
SMS opt-in Toggle No false High-cost channel; sparingly
Postal opt-in Toggle No true Annual report, festival prasadam
Receipt-only mode Toggle No false If true, only transactional Comms — donation receipts, 80G — sent regardless of channel switches
Preferred language Select No Sanskrit / Kannada / Tamil / Telugu / Hindi / English / Marathi / Malayalam English Sets template variant
Quiet hours start Time No 21:00 No non-urgent Comms after this
Quiet hours end Time No 07:00 No non-urgent Comms before this
Quiet days Multi-checkbox No Mon–Sun e.g. observing maunam on Saturdays
Festival-only mode Checkbox No false Only festival greetings + receipts
Frequency cap (per week) Number No 0–14 3 Max non-urgent messages per channel per week
Anniversary greetings Checkbox No true Birth-star, jubilee
80G certificate delivery Radio No Email / Postal / Both Email Per FY
Newsletter HTML or plain text Radio No HTML / Plain text HTML Accessibility option
Notes Textarea No max 500

Submit action: PUT /api/members/{member_id}/communication-preferences. If actor is the member themselves, sets last_updated_by_member_at. Audit event member.comm_prefs.changed. Related forms: Form 5.2 (Mailing Lists) for list-level granularity.

Form 5.2 — Mailing List Subscription

Purpose: Subscribe a member to one or more named mailing lists with double-opt-in. Who fills: Member self-service via public form, or admin during in-person sign-up.

Field Type Required Options / Validation Default Help
Member Display locked current
Available lists Multi-checkbox No Monthly Newsletter / Annadana Donors / FCRA Donors / Festival Devotees / Vedapathashala Parents / Pravachana Updates / Tenant-defined… Loaded from member_subscription_lists
Primary channel per list Auto-display from list config Email / Postal / WhatsApp / Multi
Force-active (skip double-opt-in) Checkbox No (admin only) false Use only when in-person consent is clear
Consent captured by Select No Self / Admin assist / Donation desk / Festival booth Self Recorded for audit
Consent timestamp Auto server-set now
Notes Textarea No max 500

Submit action: POST /api/members/{member_id}/subscriptions per list. If requires_double_optin (per list config), status=pending_optin and Comms sends confirmation email with token. Member's click on /api/subscriptions/confirm/{token} flips status=active. Audit event member.subscription.requested then member.subscription.confirmed. Related forms: Form 5.1 (Comm Prefs) is global; Form 5.2 is per-list.


Section 6 — Tags & Segments

Workflow note: Tags are a complement to categories — flat strings with no schema, used for ad-hoc segmentation that doesn't justify a category row. A tenant might tag members with mysuru-camp-2025, prasadam-volunteer, kishori-program, chaturmasya-2026. Tags are consumed by Comms audience builders alongside categories. The Tag/Segment Editor lets an admin create, rename, and bulk-apply tags.

Form 6.1 — Member Tag/Segment Editor

Purpose: Create, rename, and bulk-apply tags to members. Who fills: Tenant-admin or module-admin.

Field Type Required Options / Validation Default Help
Mode Radio Yes Create new tag / Rename existing / Bulk apply / Bulk remove Bulk apply
Tag name Combo (typeahead) Yes matches existing or creates new; max 63 Use snake_case or hyphen-case
Tag description Text No max 255 Internal context
Tag colour Select No 12-swatch palette grey Used in chip rendering
Target members Multi-select / saved-segment Yes typeahead by name / phone / email; or saved segment Up to 10000 in one batch
Filter (advanced) Builder No category / fund / FY / branch / age range Composes a server-side query
Apply mode Radio Yes (for bulk) Add to selection / Replace tags on selection / Remove from selection Add
Audit reason Textarea Yes max 500 Goes into audit_event for each affected member
Preview count Display live count of impacted rows
Confirm Checkbox Yes false Required to enable Apply

Submit action: Server runs the bulk operation in batched transactions (chunks of 500). One audit_event per batch with affected_count + tag + reason. Tag library exposed via existing Tag model — no new table. Related forms: Comms audience builder consumes tags + categories together.


Section 7 — Donor History & Volunteer Match (Tools)

Workflow note: Two read-mostly tools complete the suite. Donor History merges three underlying tables (transactions, payment_events, member_donor_aggregates) into a single timeline view — useful for personalised stewardship calls and 80G certificate generation. Volunteer-Match takes an event's required skills and date and returns ranked candidates. Both are surfaced from the member detail page and from the segment dashboards.

Form 7.1 — Donor History Merged View (read-only display spec)

Purpose: Display all donation activity for one member in one place. No write operations. Who fills: No fill — admin / treasurer reads.

Field Type Required Options / Validation Default Help
Member Display locked current Header with photo + name + categories
FY filter Select No All / Specific FY (FY2020-21 onward) All Limits the timeline
Fund filter Multi-select No general / annadana / building / fcra / endowment All
Channel filter Multi-select No Razorpay / Cheque / Cash / NEFT / UPI / In-kind All
Display columns (timeline) One row per transaction or event
Date Display from transactions.tx_date Sortable
Amount (INR) Display from transactions.amount
Fund Display from transactions.fund_code Coloured chip
Mode Display from transactions.mode
Receipt no Display from transactions.receipt_no Click to download PDF
80G eligible Display boolean Tick / cross
Razorpay event Display from payment_events Linked when matched
Aggregate cards (top of view)
Lifetime total Display from member_donor_aggregates All funds combined
Current FY total Display from member_donor_aggregates
Donation count Display from member_donor_aggregates
Last donation date Display from member_donor_aggregates
Recurring subscription Display active / paused / cancelled
Generate 80G certificate (action) Button per FY Deep-link to Vitta certificate generator
Recompute aggregates (action) Button admin only Calls POST /api/members/recompute-substantial-donor/{id}

Submit action: None — read-only. Action buttons open downstream forms (80G in Vitta, Recompute API call). Related forms: Form 3.1 (Threshold Override), Form 3.2 (Recurring Setup).

Form 7.2 — Volunteer-Match Tool

Purpose: Find available volunteers whose skills match an event's requirements. Who fills: Event coordinator or volunteer coordinator.

Field Type Required Options / Validation Default Help
Event Select (typeahead) Yes active events from Events Planner Loads event date + branch
Event date Date Yes from event from event Editable for what-if
Event branch Select Yes from event from event Editable
Skills required Multi-select chips Yes catalog from volunteer_skills skill_code All required skills must match
Minimum proficiency Slider No 1–5 3 Per-skill threshold
Volunteers needed Number Yes 1–500 5 Caps the candidate list
Travel radius cap (km) Number No 0–500 event branch radius Filters by volunteer travel_radius
Languages required Multi-select No inherits skill catalog Pairs with translation / pravachana
Exclude already-rostered today Checkbox No true Filters by volunteer_event_participations
Sort by Radio No Best match / Highest rating / Recently active / Distance Best match "Best match" weights skill fit + rating + distance
Notify selected Checkbox No true Sends Comms invite on commit
Invite message Textarea No max 1000 template Pre-filled with event context
Result table (display, with row actions) Ranked candidates
Volunteer name Display Click → member detail
Photo Display from members.photo
Skill match Display matched/total e.g. 3/3
Average rating Display from past participations
Distance (km) Display from address geocoding
Last served Display from volunteer_event_participations
Action Button Invite / Skip Click writes invite

Submit action: POST /api/volunteers/match returns ranked list. Per-row Invite calls POST /api/volunteers/{member_id}/event-participation with status=invited and triggers Comms. Related forms: Form 4.1 (Skill Inventory) and Form 4.2 (Availability) feed this; post-event rating closes the loop on volunteer_event_participations.