1123 lines
42 KiB
Markdown
1123 lines
42 KiB
Markdown
# Taiwan NPO Membership Management System
|
||
## Complete System Specification
|
||
|
||
**Version:** 1.0
|
||
**Last Updated:** 2025-11-20
|
||
**Technology Stack:** Laravel 11, PHP 8.x, MySQL, Spatie Permission
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Executive Summary](#1-executive-summary)
|
||
2. [System Architecture](#2-system-architecture)
|
||
3. [Database Schema](#3-database-schema)
|
||
4. [Core Features](#4-core-features)
|
||
5. [Workflows](#5-workflows)
|
||
6. [Security & Authorization](#6-security--authorization)
|
||
7. [Email Notifications](#7-email-notifications)
|
||
8. [File Structure](#8-file-structure)
|
||
9. [Configuration](#9-configuration)
|
||
|
||
---
|
||
|
||
## 1. Executive Summary
|
||
|
||
This system is a comprehensive membership management platform designed specifically for Taiwan NPOs (Non-Profit Organizations). It implements a complete lifecycle for member registration, payment verification, financial management, issue tracking, and budget management.
|
||
|
||
### Key Capabilities
|
||
|
||
- **Member Lifecycle Management:** Registration → Payment → 3-Tier Verification → Activation
|
||
- **Financial Management:** Budget planning, transaction tracking, finance document approval
|
||
- **Issue Tracking:** Complete work item management with time logging and collaboration
|
||
- **Multi-Tier Approval Workflows:** 3-tier verification for payments and finance documents
|
||
- **Audit Logging:** Complete audit trail for compliance and accountability
|
||
- **Role-Based Access Control:** Granular permissions using Spatie Permission package
|
||
|
||
### User Roles
|
||
|
||
1. **Public Users:** Can self-register as members
|
||
2. **Members:** Can submit payments, view membership status, request issues
|
||
3. **Cashier:** First-tier verification for payments and documents
|
||
4. **Accountant:** Second-tier verification
|
||
5. **Chair:** Third-tier final approval
|
||
6. **Membership Manager:** Activates memberships after approval
|
||
7. **Staff:** General administrative access
|
||
8. **Admin:** Full system access
|
||
|
||
---
|
||
|
||
## 2. System Architecture
|
||
|
||
### 2.1 Technology Stack
|
||
|
||
**Backend:**
|
||
- **Framework:** Laravel 11
|
||
- **PHP Version:** 8.x
|
||
- **Database:** MySQL 8.0+
|
||
- **Authentication:** Laravel Breeze
|
||
- **Authorization:** Spatie Laravel Permission
|
||
- **Queue System:** Database/Redis queue driver
|
||
|
||
**Frontend:**
|
||
- **Template Engine:** Blade
|
||
- **CSS Framework:** Tailwind CSS
|
||
- **JavaScript:** Alpine.js (via Breeze)
|
||
- **Dark Mode:** Supported
|
||
|
||
**Infrastructure:**
|
||
- **File Storage:** Laravel Storage (private disk)
|
||
- **Email:** Laravel Mail with queue support
|
||
- **Encryption:** AES-256 for sensitive data
|
||
|
||
### 2.2 Application Layers
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Web Interface (Blade) │
|
||
│ - Public Registration │
|
||
│ - Member Dashboard │
|
||
│ - Admin Panel │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ HTTP Layer (Controllers) │
|
||
│ - Request Validation │
|
||
│ - Business Logic Coordination │
|
||
│ - Response Formatting │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ Application Layer (Models) │
|
||
│ - Business Logic │
|
||
│ - Eloquent Relationships │
|
||
│ - Accessors & Mutators │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ Data Layer (Database) │
|
||
│ - MySQL Database │
|
||
│ - Migrations & Schema │
|
||
│ - Indexes & Constraints │
|
||
└─────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ Support Services (Cross-cutting) │
|
||
│ - AuditLogger │
|
||
│ - Email Notifications │
|
||
│ - File Storage │
|
||
│ - Encryption Services │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Database Schema
|
||
|
||
### 3.1 Core Tables
|
||
|
||
#### **users**
|
||
Primary authentication table.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| name | varchar(255) | NOT NULL | User's full name |
|
||
| email | varchar(255) | NOT NULL, UNIQUE | Email address |
|
||
| email_verified_at | timestamp | NULL | Email verification time |
|
||
| password | varchar(255) | NOT NULL | Bcrypt hashed password |
|
||
| is_admin | boolean | DEFAULT false | Legacy admin flag |
|
||
| profile_photo_path | varchar(2048) | NULL | Profile photo path |
|
||
| remember_token | varchar(100) | NULL | Remember me token |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Relationships:**
|
||
- HasOne: Member
|
||
- BelongsToMany: Role (via model_has_roles)
|
||
- BelongsToMany: Permission (via model_has_permissions)
|
||
|
||
---
|
||
|
||
#### **members**
|
||
Member profile information.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| user_id | bigint unsigned | FK(users), NULL, UNIQUE | Associated user account |
|
||
| full_name | varchar(255) | NOT NULL, INDEXED | Full name |
|
||
| email | varchar(255) | NOT NULL, INDEXED | Email (indexed for search) |
|
||
| phone | varchar(20) | NULL | Phone number |
|
||
| national_id_encrypted | text | NULL | AES-256 encrypted national ID |
|
||
| national_id_hash | varchar(64) | NULL, INDEXED | SHA256 hash for search |
|
||
| address_line_1 | varchar(255) | NULL | Address line 1 |
|
||
| address_line_2 | varchar(255) | NULL | Address line 2 |
|
||
| city | varchar(100) | NULL | City |
|
||
| postal_code | varchar(10) | NULL | Postal code |
|
||
| emergency_contact_name | varchar(255) | NULL | Emergency contact name |
|
||
| emergency_contact_phone | varchar(20) | NULL | Emergency contact phone |
|
||
| membership_started_at | date | NULL | Membership start date |
|
||
| membership_expires_at | date | NULL | Membership expiry date |
|
||
| membership_status | enum | DEFAULT 'pending' | Status: pending, active, expired, suspended |
|
||
| membership_type | enum | DEFAULT 'regular' | Type: regular, honorary, lifetime, student |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Relationships:**
|
||
- BelongsTo: User
|
||
- HasMany: MembershipPayment
|
||
- HasMany: FinanceDocument
|
||
- HasMany: Issue (for member requests)
|
||
|
||
**Key Methods:**
|
||
- `hasPaidMembership()` - Returns true if active with future expiry
|
||
- `canSubmitPayment()` - Returns true if pending and no pending payment
|
||
- `getPendingPayment()` - Gets payment awaiting verification
|
||
- `getMembershipStatusBadgeAttribute()` - CSS badge class
|
||
- `getMembershipStatusLabelAttribute()` - Chinese label
|
||
- `getMembershipTypeLabelAttribute()` - Chinese type label
|
||
|
||
---
|
||
|
||
#### **membership_payments**
|
||
Payment records with 3-tier verification workflow.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| member_id | bigint unsigned | FK(members), NOT NULL | Member who paid |
|
||
| paid_at | date | NOT NULL | Payment date |
|
||
| amount | decimal(10,2) | NOT NULL | Payment amount (TWD) |
|
||
| method | varchar(255) | NULL | Legacy payment method |
|
||
| reference | varchar(255) | NULL | Legacy reference |
|
||
| status | enum | DEFAULT 'pending' | Workflow status |
|
||
| payment_method | enum | NULL | Method: bank_transfer, convenience_store, cash, credit_card |
|
||
| receipt_path | varchar(255) | NULL | Receipt file path (private storage) |
|
||
| submitted_by_user_id | bigint unsigned | FK(users), NULL | User who submitted |
|
||
| verified_by_cashier_id | bigint unsigned | FK(users), NULL | Tier 1 verifier |
|
||
| cashier_verified_at | timestamp | NULL | Tier 1 timestamp |
|
||
| verified_by_accountant_id | bigint unsigned | FK(users), NULL | Tier 2 verifier |
|
||
| accountant_verified_at | timestamp | NULL | Tier 2 timestamp |
|
||
| verified_by_chair_id | bigint unsigned | FK(users), NULL | Tier 3 verifier |
|
||
| chair_verified_at | timestamp | NULL | Tier 3 timestamp |
|
||
| rejected_by_user_id | bigint unsigned | FK(users), NULL | Rejector |
|
||
| rejected_at | timestamp | NULL | Rejection timestamp |
|
||
| rejection_reason | text | NULL | Reason for rejection |
|
||
| notes | text | NULL | Admin notes |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Workflow States:**
|
||
1. `pending` - Awaiting Tier 1 verification
|
||
2. `approved_cashier` - Tier 1 approved, awaiting Tier 2
|
||
3. `approved_accountant` - Tier 2 approved, awaiting Tier 3
|
||
4. `approved_chair` - Fully approved (triggers activation)
|
||
5. `rejected` - Rejected at any tier
|
||
|
||
**Key Methods:**
|
||
- `canBeApprovedByCashier()` - Validates Tier 1 eligibility
|
||
- `canBeApprovedByAccountant()` - Validates Tier 2 eligibility
|
||
- `canBeApprovedByChair()` - Validates Tier 3 eligibility
|
||
- `getStatusLabelAttribute()` - Chinese status label
|
||
- `getPaymentMethodLabelAttribute()` - Chinese method label
|
||
|
||
---
|
||
|
||
#### **finance_documents**
|
||
Finance document approval workflow (3-tier).
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| member_id | bigint unsigned | FK(members), NULL | Related member |
|
||
| submitted_by_user_id | bigint unsigned | FK(users), NOT NULL | Submitter |
|
||
| title | varchar(255) | NOT NULL | Document title |
|
||
| amount | decimal(10,2) | NULL | Amount (if applicable) |
|
||
| status | varchar(255) | DEFAULT 'pending' | Workflow status |
|
||
| description | text | NULL | Description |
|
||
| attachment_path | varchar(255) | NULL | Attachment file path |
|
||
| approved_by_cashier_id | bigint unsigned | FK(users), NULL | Tier 1 approver |
|
||
| cashier_approved_at | timestamp | NULL | Tier 1 timestamp |
|
||
| approved_by_accountant_id | bigint unsigned | FK(users), NULL | Tier 2 approver |
|
||
| accountant_approved_at | timestamp | NULL | Tier 2 timestamp |
|
||
| approved_by_chair_id | bigint unsigned | FK(users), NULL | Tier 3 approver |
|
||
| chair_approved_at | timestamp | NULL | Tier 3 timestamp |
|
||
| rejected_by_user_id | bigint unsigned | FK(users), NULL | Rejector |
|
||
| rejected_at | timestamp | NULL | Rejection timestamp |
|
||
| rejection_reason | text | NULL | Reason for rejection |
|
||
| submitted_at | timestamp | NULL | Submission timestamp |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Same 3-tier workflow as membership_payments**
|
||
|
||
---
|
||
|
||
#### **issues**
|
||
Issue tracking system with comprehensive features.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| issue_number | varchar(50) | NOT NULL, UNIQUE | Auto: ISS-2025-001 |
|
||
| title | varchar(255) | NOT NULL | Issue title |
|
||
| description | text | NULL | Issue description |
|
||
| issue_type | enum | NOT NULL | Type: work_item, project_task, maintenance, member_request |
|
||
| status | enum | DEFAULT 'new', INDEXED | Status: new, assigned, in_progress, review, closed |
|
||
| priority | enum | DEFAULT 'medium', INDEXED | Priority: low, medium, high, urgent |
|
||
| created_by_user_id | bigint unsigned | FK(users), INDEXED | Creator |
|
||
| assigned_to_user_id | bigint unsigned | FK(users), NULL, INDEXED | Assignee |
|
||
| reviewer_id | bigint unsigned | FK(users), NULL | Reviewer |
|
||
| member_id | bigint unsigned | FK(members), NULL | Related member |
|
||
| parent_issue_id | bigint unsigned | FK(issues), NULL | Parent issue (for sub-tasks) |
|
||
| due_date | date | NULL, INDEXED | Due date |
|
||
| closed_at | timestamp | NULL | Closure timestamp |
|
||
| estimated_hours | decimal(8,2) | NULL | Estimated hours |
|
||
| actual_hours | decimal(8,2) | DEFAULT 0 | Actual hours (from time logs) |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
| deleted_at | timestamp | NULL | Soft delete timestamp |
|
||
|
||
**Relationships:**
|
||
- HasMany: IssueComment, IssueAttachment, IssueTimeLog
|
||
- BelongsToMany: IssueLabel, User (watchers)
|
||
- BelongsTo: User (creator, assignee, reviewer)
|
||
- BelongsTo: Issue (parent)
|
||
|
||
**Key Methods:**
|
||
- Status checks: `isNew()`, `isAssigned()`, `isInProgress()`, `inReview()`, `isClosed()`
|
||
- Workflow validation: `canBeAssigned()`, `canMoveToInProgress()`, `canMoveToReview()`, `canBeClosed()`
|
||
- Calculations: `getProgressPercentageAttribute()`, `getIsOverdueAttribute()`, `getTotalTimeLoggedAttribute()`
|
||
|
||
---
|
||
|
||
#### **budgets**
|
||
Budget management with lifecycle workflow.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| fiscal_year | integer | NOT NULL, INDEXED | Fiscal year (2000-2100) |
|
||
| name | varchar(255) | NOT NULL | Budget name |
|
||
| period_type | enum | NOT NULL | Type: annual, quarterly, monthly |
|
||
| period_start | date | NOT NULL | Period start date |
|
||
| period_end | date | NOT NULL | Period end date |
|
||
| status | enum | DEFAULT 'draft', INDEXED | Status: draft, submitted, approved, active, closed |
|
||
| created_by_user_id | bigint unsigned | FK(users), NOT NULL | Creator |
|
||
| approved_by_user_id | bigint unsigned | FK(users), NULL | Approver |
|
||
| approved_at | timestamp | NULL | Approval timestamp |
|
||
| notes | text | NULL | Notes |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Workflow:** draft → submitted → approved → active → closed
|
||
|
||
**Key Methods:**
|
||
- Status checks: `isDraft()`, `isApproved()`, `isActive()`, `isClosed()`
|
||
- Validation: `canBeEdited()`, `canBeApproved()`
|
||
- Calculations: `getTotalBudgetedIncomeAttribute()`, `getTotalActualExpenseAttribute()`, etc.
|
||
|
||
---
|
||
|
||
#### **budget_items**
|
||
Line items within budgets.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| budget_id | bigint unsigned | FK(budgets), NOT NULL, INDEXED | Parent budget |
|
||
| chart_of_account_id | bigint unsigned | FK(chart_of_accounts), NOT NULL | Account code |
|
||
| budgeted_amount | decimal(15,2) | NOT NULL | Planned amount |
|
||
| actual_amount | decimal(15,2) | NOT NULL, DEFAULT 0 | Actual amount spent |
|
||
| notes | text | NULL | Notes |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Composite Index:** (budget_id, chart_of_account_id)
|
||
|
||
**Key Methods:**
|
||
- `getVarianceAttribute()` - actual - budgeted
|
||
- `getVariancePercentageAttribute()` - (variance / budgeted) × 100
|
||
- `getRemainingBudgetAttribute()` - budgeted - actual
|
||
- `isOverBudget()` - Returns true if actual > budgeted
|
||
|
||
---
|
||
|
||
#### **transactions**
|
||
Financial transaction records.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| budget_item_id | bigint unsigned | FK(budget_items), NULL | Linked budget item |
|
||
| chart_of_account_id | bigint unsigned | FK(chart_of_accounts), NOT NULL | Account code |
|
||
| transaction_date | date | NOT NULL, INDEXED | Transaction date |
|
||
| amount | decimal(15,2) | NOT NULL | Amount |
|
||
| transaction_type | enum | NOT NULL, INDEXED | Type: income, expense |
|
||
| description | varchar(255) | NOT NULL | Description |
|
||
| reference_number | varchar(255) | NULL | Reference number |
|
||
| finance_document_id | bigint unsigned | FK(finance_documents), NULL | Linked document |
|
||
| membership_payment_id | bigint unsigned | FK(membership_payments), NULL | Linked payment |
|
||
| created_by_user_id | bigint unsigned | FK(users), NOT NULL | Creator |
|
||
| notes | text | NULL | Notes |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Indexes:** transaction_date, transaction_type, (budget_item_id, transaction_date)
|
||
|
||
---
|
||
|
||
#### **chart_of_accounts**
|
||
Hierarchical chart of accounts for financial tracking.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| account_code | varchar(50) | NOT NULL, UNIQUE | Account code (e.g., 4000) |
|
||
| account_name_zh | varchar(255) | NOT NULL | Chinese name |
|
||
| account_name_en | varchar(255) | NOT NULL | English name |
|
||
| account_type | enum | NOT NULL | Type: income, expense, asset, liability, net_asset |
|
||
| category | varchar(100) | NULL | Category grouping |
|
||
| parent_account_id | bigint unsigned | FK(chart_of_accounts), NULL | Parent account (hierarchy) |
|
||
| is_active | boolean | DEFAULT true | Active flag |
|
||
| display_order | integer | DEFAULT 0 | Sort order |
|
||
| description | text | NULL | Description |
|
||
| created_at | timestamp | NULL | Creation timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Hierarchical Structure:** Supports parent-child relationships for account grouping
|
||
|
||
---
|
||
|
||
#### **audit_logs**
|
||
Complete audit trail for compliance.
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| id | bigint unsigned | PK, AUTO_INCREMENT | Primary key |
|
||
| user_id | bigint unsigned | FK(users), NULL | User who performed action |
|
||
| action | varchar(255) | NOT NULL, INDEXED | Action name (e.g., member.created) |
|
||
| auditable_type | varchar(255) | NULL | Model class name |
|
||
| auditable_id | bigint unsigned | NULL | Model ID |
|
||
| metadata | json | NULL | Additional context |
|
||
| created_at | timestamp | NULL | Action timestamp |
|
||
| updated_at | timestamp | NULL | Last update timestamp |
|
||
|
||
**Common Actions:**
|
||
- member.self_registered, member.created, member.updated, member.activated
|
||
- payment.submitted, payment.approved_by_*, payment.rejected
|
||
- finance_document.*, issue.*, budget.*, transaction.*
|
||
|
||
---
|
||
|
||
### 3.2 Supporting Tables
|
||
|
||
#### **roles** (Spatie Permission)
|
||
- id, name, guard_name, description, timestamps
|
||
|
||
#### **permissions** (Spatie Permission)
|
||
- id, name, guard_name, timestamps
|
||
|
||
#### **model_has_roles** (Spatie Permission)
|
||
- role_id, model_type, model_id
|
||
|
||
#### **model_has_permissions** (Spatie Permission)
|
||
- permission_id, model_type, model_id
|
||
|
||
#### **role_has_permissions** (Spatie Permission)
|
||
- permission_id, role_id
|
||
|
||
#### **issue_comments**
|
||
- id, issue_id, user_id, comment_text, is_internal, timestamps
|
||
|
||
#### **issue_attachments**
|
||
- id, issue_id, user_id, file_path, file_name, file_size, mime_type, timestamps
|
||
|
||
#### **issue_labels**
|
||
- id, name (unique), color, description, timestamps
|
||
|
||
#### **issue_label_pivot**
|
||
- issue_id, issue_label_id
|
||
|
||
#### **issue_time_logs**
|
||
- id, issue_id, user_id, hours, work_date, description, timestamps
|
||
|
||
#### **issue_watchers**
|
||
- id, issue_id, user_id
|
||
|
||
#### **issue_relationships**
|
||
- id, issue_id, related_issue_id, relationship_type, timestamps
|
||
|
||
#### **custom_fields**
|
||
- id, name, field_type, options (JSON), is_required, timestamps
|
||
|
||
#### **custom_field_values**
|
||
- id, custom_field_id, customizable_type, customizable_id, value (JSON), timestamps
|
||
|
||
#### **financial_reports**
|
||
- id, budget_id, report_type, report_data (JSON), generated_by_user_id, generated_at, timestamps
|
||
|
||
---
|
||
|
||
## 4. Core Features
|
||
|
||
### 4.1 Member Registration & Lifecycle
|
||
|
||
**Public Self-Registration:**
|
||
- Route: `GET/POST /register/member`
|
||
- Controller: PublicMemberRegistrationController
|
||
- Creates User + Member records
|
||
- Sets initial status to 'pending'
|
||
- Sends welcome email with payment instructions
|
||
- Auto-login after registration
|
||
|
||
**Admin-Created Members:**
|
||
- Route: `POST /admin/members`
|
||
- Controller: AdminMemberController
|
||
- Can create member with or without user account
|
||
- Sets initial status to 'pending'
|
||
|
||
**Member States:**
|
||
1. **Pending:** Registered but not yet paid/verified
|
||
2. **Active:** Payment approved and membership activated
|
||
3. **Expired:** Membership expiry date has passed
|
||
4. **Suspended:** Admin-suspended
|
||
|
||
**Key Features:**
|
||
- National ID encryption (AES-256)
|
||
- National ID hash (SHA256) for searching without decryption
|
||
- Emergency contact information
|
||
- Address management
|
||
- Membership type management (regular, student, honorary, lifetime)
|
||
|
||
---
|
||
|
||
### 4.2 Payment Verification Workflow (3-Tier)
|
||
|
||
**Member Payment Submission:**
|
||
- Route: `POST /member/payments`
|
||
- Controller: MemberPaymentController
|
||
- Upload receipt (JPG, PNG, PDF, max 10MB)
|
||
- Specify payment method, amount, date, reference
|
||
- Creates payment with status='pending'
|
||
- Stored in private storage
|
||
- Emails sent to member (confirmation) and cashiers (notification)
|
||
|
||
**Tier 1: Cashier Verification**
|
||
- Route: `POST /admin/payment-verifications/{payment}/approve-cashier`
|
||
- Permission: `verify_payments_cashier`
|
||
- Verifies receipt legitimacy
|
||
- Updates: status=approved_cashier, cashier_verified_at, verified_by_cashier_id
|
||
- Sends email to member and accountants
|
||
|
||
**Tier 2: Accountant Verification**
|
||
- Route: `POST /admin/payment-verifications/{payment}/approve-accountant`
|
||
- Permission: `verify_payments_accountant`
|
||
- Reviews financial details
|
||
- Updates: status=approved_accountant, accountant_verified_at, verified_by_accountant_id
|
||
- Sends email to member and chairs
|
||
|
||
**Tier 3: Chair Approval**
|
||
- Route: `POST /admin/payment-verifications/{payment}/approve-chair`
|
||
- Permission: `verify_payments_chair`
|
||
- Final approval
|
||
- Updates: status=approved_chair, chair_verified_at, verified_by_chair_id
|
||
- **Automatically activates membership:**
|
||
- member.membership_status = 'active'
|
||
- member.membership_started_at = today
|
||
- member.membership_expires_at = today + 1 year (or lifetime)
|
||
- Sends activation email to member
|
||
|
||
**Rejection:**
|
||
- Route: `POST /admin/payment-verifications/{payment}/reject`
|
||
- Can be done at any tier
|
||
- Requires rejection reason
|
||
- Updates: status=rejected, rejected_by_user_id, rejected_at, rejection_reason
|
||
- Sends rejection email with reason
|
||
- Member can resubmit
|
||
|
||
**Dashboard:**
|
||
- Route: `GET /admin/payment-verifications`
|
||
- Tabbed interface: All, Cashier Queue, Accountant Queue, Chair Queue, Approved, Rejected
|
||
- Shows counts for each queue
|
||
- Search by member name, email, reference
|
||
- Permission-based filtering
|
||
|
||
---
|
||
|
||
### 4.3 Finance Document Approval
|
||
|
||
**Document Submission:**
|
||
- Route: `POST /admin/finance-documents`
|
||
- Controller: FinanceDocumentController
|
||
- Title, optional amount, optional attachment
|
||
- Status starts as 'pending'
|
||
|
||
**3-Tier Approval:**
|
||
Same workflow structure as payment verification:
|
||
1. Cashier approval (Tier 1)
|
||
2. Accountant approval (Tier 2)
|
||
3. Chair approval (Tier 3)
|
||
|
||
**Features:**
|
||
- File attachment support
|
||
- Amount tracking
|
||
- Rejection with reason
|
||
- Email notifications at each stage
|
||
|
||
---
|
||
|
||
### 4.4 Issue Tracking System
|
||
|
||
**Issue Creation:**
|
||
- Route: `POST /admin/issues`
|
||
- Controller: IssueController
|
||
- Auto-generates issue number: ISS-{YYYY}-{incrementing}
|
||
- Required: title, type, priority
|
||
- Optional: description, assignee, labels, due date, estimated hours
|
||
|
||
**Issue Types:**
|
||
- work_item: General work tasks
|
||
- project_task: Project-related tasks
|
||
- maintenance: System maintenance
|
||
- member_request: Member support requests
|
||
|
||
**Status Workflow:**
|
||
```
|
||
new → assigned → in_progress → review → closed
|
||
```
|
||
|
||
**Can reopen:** closed → assigned
|
||
|
||
**Priority Levels:**
|
||
- low (default background color: gray)
|
||
- medium (default background color: blue)
|
||
- high (default background color: orange)
|
||
- urgent (default background color: red)
|
||
|
||
**Collaboration Features:**
|
||
1. **Comments:**
|
||
- Add comments to issues
|
||
- is_internal flag hides comments from members
|
||
- Notifies watchers
|
||
|
||
2. **Attachments:**
|
||
- Upload files to issues
|
||
- Download attachments
|
||
- Delete attachments
|
||
|
||
3. **Time Logging:**
|
||
- Log hours worked on issues
|
||
- Specify work date
|
||
- Automatic summation
|
||
|
||
4. **Watchers:**
|
||
- Add users to watch issue updates
|
||
- Receive email notifications
|
||
|
||
5. **Labels:**
|
||
- Color-coded labels
|
||
- Filterable
|
||
- Multiple labels per issue
|
||
|
||
6. **Sub-tasks:**
|
||
- Create child issues via parent_issue_id
|
||
- Hierarchical structure
|
||
|
||
7. **Issue Relationships:**
|
||
- blocks, is_blocked_by
|
||
- relates_to
|
||
- duplicates, is_duplicated_by
|
||
|
||
**Automation:**
|
||
- Auto-calculation of progress percentage (0-100% based on status)
|
||
- Overdue detection (due_date < today and not closed)
|
||
- Days until due calculation
|
||
|
||
**Reports:**
|
||
- Route: `GET /admin/issue-reports`
|
||
- Status distribution
|
||
- Priority distribution
|
||
- Workload analysis
|
||
|
||
---
|
||
|
||
### 4.5 Budget Management
|
||
|
||
**Budget Creation:**
|
||
- Route: `POST /admin/budgets`
|
||
- Controller: BudgetController
|
||
- Fiscal year, period type, date range
|
||
- Status starts as 'draft'
|
||
|
||
**Budget Items:**
|
||
- Link to chart of accounts
|
||
- Set budgeted amounts
|
||
- Track actual amounts (updated via transactions)
|
||
- Calculate variances
|
||
|
||
**Workflow:**
|
||
```
|
||
draft → submitted → approved → active → closed
|
||
```
|
||
|
||
**Features:**
|
||
- Total budgeted income/expense calculation
|
||
- Total actual income/expense calculation
|
||
- Variance analysis (budgeted vs actual)
|
||
- Utilization percentage
|
||
- Over-budget detection
|
||
|
||
**Reporting:**
|
||
- Generate financial reports
|
||
- Store report snapshots (JSON)
|
||
- Historical tracking
|
||
|
||
---
|
||
|
||
### 4.6 Transaction Management
|
||
|
||
**Transaction Recording:**
|
||
- Route: `POST /admin/transactions`
|
||
- Controller: TransactionController
|
||
- Type: income or expense
|
||
- Link to budget item (optional)
|
||
- Link to chart of account (required)
|
||
- Link to finance document or membership payment (optional)
|
||
- Date, amount, description
|
||
|
||
**Features:**
|
||
- Search by date range, type, description
|
||
- Automatic budget item actual amount update
|
||
- Reference number tracking
|
||
- Notes support
|
||
|
||
---
|
||
|
||
## 5. Workflows
|
||
|
||
### 5.1 Complete Member Journey
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ STEP 1: REGISTRATION │
|
||
│ User fills public registration form │
|
||
│ → Creates User account (with password) │
|
||
│ → Creates Member record (status='pending') │
|
||
│ → Sends welcome email │
|
||
│ → Auto-login │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ STEP 2: PAYMENT SUBMISSION │
|
||
│ Member uploads receipt + payment details │
|
||
│ → Payment created (status='pending') │
|
||
│ → Receipt stored in private storage │
|
||
│ → Email to member (confirmation) │
|
||
│ → Email to cashiers (notification) │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ STEP 3: TIER 1 VERIFICATION (Cashier) │
|
||
│ Cashier reviews receipt and basic info │
|
||
│ → Approves or rejects │
|
||
│ IF APPROVED: │
|
||
│ → status='approved_cashier' │
|
||
│ → Email to member + accountants │
|
||
│ IF REJECTED: │
|
||
│ → status='rejected' │
|
||
│ → Email to member with reason │
|
||
│ → Member must resubmit │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
↓ (if approved)
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ STEP 4: TIER 2 VERIFICATION (Accountant) │
|
||
│ Accountant verifies financial details │
|
||
│ → Approves or rejects │
|
||
│ IF APPROVED: │
|
||
│ → status='approved_accountant' │
|
||
│ → Email to member + chairs │
|
||
│ IF REJECTED: (same as Tier 1) │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
↓ (if approved)
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ STEP 5: TIER 3 APPROVAL (Chair) │
|
||
│ Chair gives final approval │
|
||
│ → Approves or rejects │
|
||
│ IF APPROVED: │
|
||
│ → status='approved_chair' │
|
||
│ → AUTOMATIC ACTIVATION: │
|
||
│ ◦ member.membership_status = 'active' │
|
||
│ ◦ member.membership_started_at = today │
|
||
│ ◦ member.membership_expires_at = today + 1 year │
|
||
│ → Email to member (activation confirmation) │
|
||
│ → Email to membership managers (FYI) │
|
||
│ IF REJECTED: (same as Tier 1 & 2) │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
↓ (if approved)
|
||
┌─────────────────────────────────────────────────────────────┐
|
||
│ STEP 6: ACTIVE MEMBERSHIP │
|
||
│ Member now has: │
|
||
│ → Access to member-only resources │
|
||
│ → Active membership badge │
|
||
│ → Membership expiry date │
|
||
│ → Full dashboard access │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2 Issue Lifecycle
|
||
|
||
```
|
||
┌──────────┐
|
||
│ NEW │ ← Issue created
|
||
└────┬─────┘
|
||
│ assign user
|
||
↓
|
||
┌──────────┐
|
||
│ ASSIGNED │ ← User assigned
|
||
└────┬─────┘
|
||
│ start work
|
||
↓
|
||
┌──────────────┐
|
||
│ IN_PROGRESS │ ← Work started
|
||
└────┬─────────┘
|
||
│ ready for review
|
||
↓
|
||
┌──────────┐
|
||
│ REVIEW │ ← Reviewing
|
||
└────┬─────┘
|
||
│ approve
|
||
↓
|
||
┌──────────┐
|
||
│ CLOSED │ ← Done
|
||
└──────────┘
|
||
↑
|
||
│ can reopen
|
||
└──────────
|
||
```
|
||
|
||
### 5.3 Budget Lifecycle
|
||
|
||
```
|
||
┌────────┐
|
||
│ DRAFT │ ← Create budget, add items
|
||
└───┬────┘
|
||
│ submit for approval
|
||
↓
|
||
┌───────────┐
|
||
│ SUBMITTED │ ← Pending approval
|
||
└─────┬─────┘
|
||
│ approve
|
||
↓
|
||
┌───────────┐
|
||
│ APPROVED │ ← Approved but not yet active
|
||
└─────┬─────┘
|
||
│ activate
|
||
↓
|
||
┌────────┐
|
||
│ ACTIVE │ ← Currently in use, transactions linked
|
||
└───┬────┘
|
||
│ period ends
|
||
↓
|
||
┌────────┐
|
||
│ CLOSED │ ← Period ended, archived
|
||
└────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Security & Authorization
|
||
|
||
### 6.1 Authentication
|
||
|
||
**Method:** Session-based authentication via Laravel Breeze
|
||
**Features:**
|
||
- Password hashing (Bcrypt)
|
||
- Email verification (optional)
|
||
- Remember me functionality
|
||
- Password reset via email
|
||
|
||
### 6.2 Authorization (Spatie Permission)
|
||
|
||
**Roles:**
|
||
1. **admin** - Full system access
|
||
2. **staff** - Internal tools access
|
||
3. **cashier** - Payment Tier 1 verification
|
||
4. **accountant** - Payment Tier 2 verification
|
||
5. **chair** - Payment Tier 3 approval
|
||
6. **payment_cashier** - Dedicated cashier role
|
||
7. **payment_accountant** - Dedicated accountant role
|
||
8. **payment_chair** - Dedicated chair role
|
||
9. **membership_manager** - Membership activation
|
||
|
||
**Permissions:**
|
||
- `verify_payments_cashier` - Tier 1 approval
|
||
- `verify_payments_accountant` - Tier 2 approval
|
||
- `verify_payments_chair` - Tier 3 approval
|
||
- `activate_memberships` - Activate memberships
|
||
- `view_payment_verifications` - View dashboard
|
||
|
||
**Middleware:**
|
||
- `EnsureUserIsAdmin` - Protects `/admin` routes
|
||
- `CheckPaidMembership` - Verifies active paid membership
|
||
|
||
### 6.3 Data Security
|
||
|
||
**National ID Protection:**
|
||
- Stored encrypted (AES-256)
|
||
- Hashed with SHA256 for searching
|
||
- Never displayed in plain text
|
||
|
||
**Password Security:**
|
||
- Bcrypt hashing
|
||
- Minimum password requirements
|
||
- Password confirmation on sensitive actions
|
||
|
||
**CSRF Protection:**
|
||
- All POST/PATCH/DELETE requests protected
|
||
- Automatic token generation
|
||
|
||
**File Security:**
|
||
- Payment receipts stored in private disk
|
||
- Served only via authenticated controller methods
|
||
- File type validation on upload
|
||
|
||
**SQL Injection Prevention:**
|
||
- Eloquent ORM with parameter binding
|
||
- Never use raw queries without bindings
|
||
|
||
---
|
||
|
||
## 7. Email Notifications
|
||
|
||
### 7.1 Membership Emails
|
||
|
||
| Email | Trigger | Recipients |
|
||
|-------|---------|------------|
|
||
| MemberRegistrationWelcomeMail | After self-registration | New member |
|
||
| PaymentSubmittedMail | Payment submitted | Member + Cashiers |
|
||
| PaymentApprovedByCashierMail | Tier 1 approval | Member + Accountants |
|
||
| PaymentApprovedByAccountantMail | Tier 2 approval | Member + Chairs |
|
||
| PaymentFullyApprovedMail | Tier 3 approval | Member + Membership Managers |
|
||
| PaymentRejectedMail | Payment rejected | Member |
|
||
| MembershipActivatedMail | Membership activated | Member |
|
||
| MembershipExpiryReminderMail | X days before expiry | Member |
|
||
|
||
### 7.2 Finance Emails
|
||
|
||
| Email | Trigger | Recipients |
|
||
|-------|---------|------------|
|
||
| FinanceDocumentSubmitted | Document submitted | Cashiers |
|
||
| FinanceDocumentApprovedByCashier | Tier 1 approval | Submitter + Accountants |
|
||
| FinanceDocumentApprovedByAccountant | Tier 2 approval | Submitter + Chairs |
|
||
| FinanceDocumentFullyApproved | Tier 3 approval | Submitter |
|
||
| FinanceDocumentRejected | Document rejected | Submitter |
|
||
|
||
### 7.3 Issue Emails
|
||
|
||
| Email | Trigger | Recipients |
|
||
|-------|---------|------------|
|
||
| IssueAssignedMail | Issue assigned | Assignee |
|
||
| IssueStatusChangedMail | Status changed | Creator + Assignee + Watchers |
|
||
| IssueCommentedMail | New comment | Creator + Assignee + Watchers |
|
||
| IssueDueSoonMail | Due within X days | Assignee |
|
||
| IssueOverdueMail | Past due date | Assignee |
|
||
| IssueClosedMail | Issue closed | Creator + Watchers |
|
||
|
||
### 7.4 Queue Configuration
|
||
|
||
All emails implement `ShouldQueue` for async delivery:
|
||
- Queue driver: database/redis
|
||
- Failed jobs table for retry
|
||
- Queue workers handle delivery
|
||
|
||
---
|
||
|
||
## 8. File Structure
|
||
|
||
```
|
||
usher-manage-stack/
|
||
├── app/
|
||
│ ├── Http/
|
||
│ │ ├── Controllers/
|
||
│ │ │ ├── AdminMemberController.php
|
||
│ │ │ ├── AdminPaymentController.php
|
||
│ │ │ ├── PaymentVerificationController.php
|
||
│ │ │ ├── PublicMemberRegistrationController.php
|
||
│ │ │ ├── MemberPaymentController.php
|
||
│ │ │ ├── MemberDashboardController.php
|
||
│ │ │ ├── FinanceDocumentController.php
|
||
│ │ │ ├── IssueController.php
|
||
│ │ │ ├── IssueLabelController.php
|
||
│ │ │ ├── IssueReportsController.php
|
||
│ │ │ ├── BudgetController.php
|
||
│ │ │ ├── TransactionController.php
|
||
│ │ │ ├── AdminRoleController.php
|
||
│ │ │ ├── AdminAuditLogController.php
|
||
│ │ │ └── AdminDashboardController.php
|
||
│ │ └── Middleware/
|
||
│ │ ├── EnsureUserIsAdmin.php
|
||
│ │ └── CheckPaidMembership.php
|
||
│ ├── Mail/
|
||
│ │ ├── MemberRegistrationWelcomeMail.php
|
||
│ │ ├── PaymentSubmittedMail.php
|
||
│ │ ├── PaymentApprovedByCashierMail.php
|
||
│ │ ├── PaymentApprovedByAccountantMail.php
|
||
│ │ ├── PaymentFullyApprovedMail.php
|
||
│ │ ├── PaymentRejectedMail.php
|
||
│ │ ├── MembershipActivatedMail.php
|
||
│ │ ├── FinanceDocument*.php (5 files)
|
||
│ │ └── Issue*.php (6 files)
|
||
│ ├── Models/
|
||
│ │ ├── Member.php
|
||
│ │ ├── MembershipPayment.php
|
||
│ │ ├── User.php
|
||
│ │ ├── Role.php
|
||
│ │ ├── Permission.php
|
||
│ │ ├── Issue.php
|
||
│ │ ├── IssueComment.php
|
||
│ │ ├── IssueAttachment.php
|
||
│ │ ├── IssueLabel.php
|
||
│ │ ├── IssueTimeLog.php
|
||
│ │ ├── Budget.php
|
||
│ │ ├── BudgetItem.php
|
||
│ │ ├── Transaction.php
|
||
│ │ ├── ChartOfAccount.php
|
||
│ │ ├── FinanceDocument.php
|
||
│ │ └── AuditLog.php
|
||
│ └── Support/
|
||
│ └── AuditLogger.php
|
||
├── database/
|
||
│ ├── migrations/
|
||
│ │ ├── 2025_11_18_092000_create_audit_logs_table.php
|
||
│ │ ├── 2025_11_18_093000_create_finance_documents_table.php
|
||
│ │ ├── 2025_11_19_133732_create_budgets_table.php
|
||
│ │ ├── 2025_11_19_133802_create_transactions_table.php
|
||
│ │ ├── 2025_11_19_144027_create_issues_table.php
|
||
│ │ ├── 2025_11_19_155725_enhance_membership_payments_table_for_verification.php
|
||
│ │ └── 2025_11_19_155807_add_membership_status_to_members_table.php
|
||
│ └── seeders/
|
||
│ ├── RoleSeeder.php
|
||
│ ├── PaymentVerificationRolesSeeder.php
|
||
│ ├── ChartOfAccountSeeder.php
|
||
│ └── IssueLabelSeeder.php
|
||
├── resources/
|
||
│ └── views/
|
||
│ ├── admin/
|
||
│ │ ├── members/
|
||
│ │ │ ├── index.blade.php
|
||
│ │ │ ├── show.blade.php
|
||
│ │ │ ├── create.blade.php
|
||
│ │ │ ├── edit.blade.php
|
||
│ │ │ └── activate.blade.php
|
||
│ │ ├── payment-verifications/
|
||
│ │ │ ├── index.blade.php
|
||
│ │ │ └── show.blade.php
|
||
│ │ ├── issues/
|
||
│ │ ├── budgets/
|
||
│ │ └── finance-documents/
|
||
│ ├── member/
|
||
│ │ ├── dashboard.blade.php
|
||
│ │ └── submit-payment.blade.php
|
||
│ ├── register/
|
||
│ │ └── member.blade.php
|
||
│ └── emails/
|
||
│ ├── members/
|
||
│ ├── payments/
|
||
│ ├── finance-documents/
|
||
│ └── issues/
|
||
└── routes/
|
||
└── web.php
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Configuration
|
||
|
||
### 9.1 Environment Variables
|
||
|
||
```env
|
||
APP_NAME="Taiwan NPO Membership System"
|
||
APP_ENV=production
|
||
APP_KEY=base64:...
|
||
APP_DEBUG=false
|
||
APP_URL=https://your-domain.com
|
||
|
||
DB_CONNECTION=mysql
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=3306
|
||
DB_DATABASE=usher_manage
|
||
DB_USERNAME=root
|
||
DB_PASSWORD=
|
||
|
||
MAIL_MAILER=smtp
|
||
MAIL_HOST=smtp.mailtrap.io
|
||
MAIL_PORT=2525
|
||
MAIL_USERNAME=
|
||
MAIL_PASSWORD=
|
||
MAIL_ENCRYPTION=tls
|
||
MAIL_FROM_ADDRESS=noreply@your-domain.com
|
||
MAIL_FROM_NAME="${APP_NAME}"
|
||
|
||
QUEUE_CONNECTION=database
|
||
|
||
FILESYSTEM_DISK=local
|
||
```
|
||
|
||
### 9.2 Permissions Required
|
||
|
||
**Cashier:**
|
||
- verify_payments_cashier
|
||
- view_payment_verifications
|
||
|
||
**Accountant:**
|
||
- verify_payments_accountant
|
||
- view_payment_verifications
|
||
|
||
**Chair:**
|
||
- verify_payments_chair
|
||
- view_payment_verifications
|
||
|
||
**Membership Manager:**
|
||
- activate_memberships
|
||
- view_payment_verifications
|
||
|
||
**Admin:**
|
||
- All permissions (automatic grant)
|
||
|
||
---
|
||
|
||
## 10. Deployment Checklist
|
||
|
||
- [ ] Run migrations: `php artisan migrate`
|
||
- [ ] Seed roles & permissions: `php artisan db:seed --class=RoleSeeder`
|
||
- [ ] Seed payment roles: `php artisan db:seed --class=PaymentVerificationRolesSeeder`
|
||
- [ ] Seed chart of accounts: `php artisan db:seed --class=ChartOfAccountSeeder`
|
||
- [ ] Seed issue labels: `php artisan db:seed --class=IssueLabelSeeder`
|
||
- [ ] Configure mail settings
|
||
- [ ] Configure queue worker
|
||
- [ ] Set up file storage (private disk)
|
||
- [ ] Create admin user
|
||
- [ ] Assign admin role
|
||
- [ ] Test payment workflow end-to-end
|
||
- [ ] Test email delivery
|
||
- [ ] Set up SSL certificate
|
||
- [ ] Configure backup strategy
|
||
|
||
---
|
||
|
||
## Appendix A: Glossary
|
||
|
||
**Member:** A registered person in the NPO system
|
||
**Payment Verification:** 3-tier approval process for membership payments
|
||
**Tier 1/2/3:** Sequential approval levels (Cashier/Accountant/Chair)
|
||
**Issue:** Work item, task, or support request in the tracking system
|
||
**Budget:** Financial plan for a fiscal period
|
||
**Chart of Account:** Standardized account codes for financial tracking
|
||
**Audit Log:** Record of all significant system actions
|
||
|
||
---
|
||
|
||
**End of Specification Document**
|