14
🪷

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.