← Back to list

member-workflow
by markus41
⭐ 0🍴 0📅 Nov 15, 2025
SKILL.md
name: member-workflow description: Guides implementation of member lifecycle workflows including registration, renewal, engagement tracking, and duplicate detection for 20,000+ members across national, state, and local NABIP chapters. Use when working on member onboarding, status changes, tier upgrades, or automated renewal processes.
Member Workflow
Establish scalable member management processes to streamline operations across the NABIP association's multi-tier structure.
When to Use
Activate this skill when:
- Implementing member registration workflows
- Building automated renewal reminder systems
- Creating duplicate member detection logic
- Designing member status change workflows (active → inactive, etc.)
- Implementing engagement scoring algorithms
- Building self-service member portals
- Working on membership tier transitions (Local → State → National)
Member Lifecycle States
Status Workflow
pending → active → inactive
↓ ↓ ↓
cancelled suspended expired
State Transition Rules
-
pending → active
- Payment confirmed
- Profile completed
- Email verified
- Chapter assignment confirmed
-
active → suspended
- Payment failure (grace period: 30 days)
- Policy violation flagged
- Admin action required
-
active → inactive
- Membership not renewed after expiration
- Member requested pause
- Chapter transfer in progress
-
inactive → active
- Renewal payment processed
- Reactivation request approved
- Chapter transfer completed
-
Any → cancelled
- Member requested cancellation
- Refund processed
- Data retention policy applied
Registration Workflow
// Example: Member registration with validation
interface MemberRegistration {
personalInfo: {
firstName: string
lastName: string
email: string
phone: string
}
membershipInfo: {
memberType: "national" | "state" | "local"
chapterId: string
referralSource?: string
}
paymentInfo: {
amount: number
paymentMethod: string
transactionId: string
}
}
async function registerMember(data: MemberRegistration) {
// Step 1: Validate against duplicate detection
const duplicateCheck = await checkDuplicateMember(data.personalInfo.email)
if (duplicateCheck.exists) {
return { success: false, error: "Member already exists", existingId: duplicateCheck.id }
}
// Step 2: Validate chapter hierarchy (local must have state parent, etc.)
const chapterValid = await validateChapterAssignment(
data.membershipInfo.chapterId,
data.membershipInfo.memberType
)
if (!chapterValid) {
return { success: false, error: "Invalid chapter assignment for member type" }
}
// Step 3: Create member record with 'pending' status
const member = await createMemberRecord({
...data.personalInfo,
...data.membershipInfo,
status: "pending",
engagementScore: 0,
joinedDate: new Date()
})
// Step 4: Process payment
const payment = await processPayment(data.paymentInfo)
if (!payment.success) {
// Rollback member creation or mark as payment_failed
await updateMemberStatus(member.id, "cancelled")
return { success: false, error: "Payment failed" }
}
// Step 5: Send welcome email sequence
await sendWelcomeEmail(member.email, {
memberType: data.membershipInfo.memberType,
chapterName: await getChapterName(data.membershipInfo.chapterId)
})
// Step 6: Activate membership
await updateMemberStatus(member.id, "active")
// Step 7: Calculate initial engagement score
await calculateEngagementScore(member.id)
return { success: true, memberId: member.id }
}
Renewal Workflow
Automated Renewal Reminders
// Trigger points for renewal reminders
const RENEWAL_REMINDER_SCHEDULE = {
firstReminder: 60, // days before expiration
secondReminder: 30,
thirdReminder: 14,
finalReminder: 7,
gracePeriodEnd: 30 // days after expiration
}
async function processRenewalReminders() {
const today = new Date()
// Find members approaching renewal
const membersNeedingReminder = await db
.select()
.from(members)
.where(
and(
eq(members.status, "active"),
sql`DATE(renewal_date) - DATE(${today}) IN (60, 30, 14, 7)`
)
)
for (const member of membersNeedingReminder) {
const daysUntilRenewal = calculateDays(member.renewalDate, today)
await sendRenewalEmail(member.email, {
daysRemaining: daysUntilRenewal,
renewalFee: calculateRenewalFee(member.memberType),
renewalLink: generateRenewalLink(member.id)
})
// Log reminder sent
await createActivityLog({
memberId: member.id,
action: "renewal_reminder_sent",
metadata: { daysUntilRenewal }
})
}
// Handle expired memberships
const expiredMembers = await db
.select()
.from(members)
.where(
and(
eq(members.status, "active"),
sql`DATE(renewal_date) < DATE(${today})`
)
)
for (const member of expiredMembers) {
const daysExpired = calculateDays(today, member.renewalDate)
if (daysExpired > RENEWAL_REMINDER_SCHEDULE.gracePeriodEnd) {
// Move to inactive
await updateMemberStatus(member.id, "inactive")
await sendGracePeriodExpiredEmail(member.email)
}
}
}
Duplicate Detection
Smart Matching Algorithm
interface DuplicateCheckResult {
exists: boolean
confidence: "high" | "medium" | "low"
matchedRecords: Array<{
id: string
matchReason: string[]
similarity: number
}>
}
async function checkDuplicateMember(email: string, name?: string): Promise<DuplicateCheckResult> {
const matches: any[] = []
// Exact email match (highest confidence)
const emailMatch = await db
.select()
.from(members)
.where(eq(members.email, email.toLowerCase()))
.limit(1)
if (emailMatch.length > 0) {
return {
exists: true,
confidence: "high",
matchedRecords: [{
id: emailMatch[0].id,
matchReason: ["exact_email_match"],
similarity: 1.0
}]
}
}
// Fuzzy name matching if provided
if (name) {
const nameMatches = await db
.select()
.from(members)
.where(sql`SIMILARITY(${members.name}, ${name}) > 0.7`)
.limit(5)
for (const match of nameMatches) {
matches.push({
id: match.id,
matchReason: ["similar_name"],
similarity: calculateStringSimilarity(name, match.name)
})
}
}
// Phone number matching (if available in future)
// Additional matching logic...
return {
exists: matches.length > 0,
confidence: matches.length > 0 ? "medium" : "low",
matchedRecords: matches
}
}
Engagement Scoring
Scoring Algorithm
interface EngagementFactors {
eventAttendance: number // 0-30 points
emailInteraction: number // 0-20 points
courseCompletion: number // 0-25 points
communityParticipation: number // 0-15 points
paymentHistory: number // 0-10 points
}
async function calculateEngagementScore(memberId: string): Promise<number> {
const factors = await gatherEngagementData(memberId)
const score = {
events: Math.min(factors.eventsAttended * 5, 30),
emails: Math.min(factors.emailClickRate * 20, 20),
courses: Math.min(factors.coursesCompleted * 12.5, 25),
community: Math.min(factors.forumPosts * 3, 15),
payment: factors.onTimePayments ? 10 : 0
}
const totalScore = Object.values(score).reduce((sum, val) => sum + val, 0)
// Update member record
await db
.update(members)
.set({
engagementScore: Math.round(totalScore),
lastEngagementCalculation: new Date()
})
.where(eq(members.id, memberId))
return totalScore
}
// Run engagement calculation weekly
async function scheduleEngagementUpdates() {
const activeMembers = await db
.select({ id: members.id })
.from(members)
.where(eq(members.status, "active"))
for (const member of activeMembers) {
await calculateEngagementScore(member.id)
}
}
Self-Service Portal Features
Member Portal Capabilities
- Profile Management: Update contact info, preferences
- Renewal Management: View renewal date, process payment
- Event Registration: Browse and register for events
- Course Enrollment: Access learning management
- Chapter Transfer: Request chapter changes
- Communication Preferences: Email/notification settings
- Engagement Dashboard: View personal engagement score
Common Workflows
Tier Upgrade (Local → State)
async function upgradeMemberTier(memberId: string, newTier: "state" | "national") {
// Validate upgrade eligibility
const member = await getMember(memberId)
if (member.memberType === newTier) {
throw new Error("Already at requested tier")
}
// Calculate price difference
const upgradeFeeDiff = calculateTierUpgradeFee(member.memberType, newTier)
// Process additional payment if needed
if (upgradeFeeDiff > 0) {
const payment = await processUpgradePayment(memberId, upgradeFeeDiff)
if (!payment.success) {
throw new Error("Upgrade payment failed")
}
}
// Update member tier
await db
.update(members)
.set({
memberType: newTier,
tierUpgradeDate: new Date()
})
.where(eq(members.id, memberId))
// Send confirmation email
await sendTierUpgradeEmail(member.email, newTier)
// Log activity
await createActivityLog({
memberId,
action: "tier_upgraded",
metadata: { fromTier: member.memberType, toTier: newTier }
})
}
Integration with Other Skills
- Use with
supabase-schema-validatorfor database design - Combine with
component-generatorfor member portal UI - Works with
analytics-helperfor engagement reports
Best for: Developers implementing member lifecycle management, automated workflows, and self-service features for the NABIP AMS.
Score
Total Score
60/100
Based on repository quality metrics
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
Reviews
💬
Reviews coming soon