---
task: Implement COOP_MEMBER and COOP_OFFICER account types with geographic chapter hierarchy
cycles: 5
context: true
private: false
started: 2026-05-28T17:08:44Z
finished: 2026-05-28T17:09:30Z
---

## files
- `app/Enums/UserTypes.php` — add COOP_MEMBER and COOP_OFFICER cases
- `app/Enums/UserActions.php` — add ViewChapterOrgChart, ManageChapterMembers, ViewScopedMemberReports, AssignChapterOfficer
- `app/Http/Controllers/Helpers/Permissions/UserPermissions.php` lines 818–838 — add permission sets for new types; update UserTypeService::getAllowedUserTypes
- `app/Models/Chapter.php` — add cooperative_id to fillable; add cooperative() relationship
- `app/Models/ChapterMember.php` — add role field to fillable; add isOfficer() helper
- `database/migrations/2026_04_19_100001_create_chapters_table.php` — reference only, do NOT modify; write new migration instead
- `database/migrations/2026_04_19_100002_create_chapter_members_table.php` — reference only; write new migration for role column
- `app/Http/Controllers/Market/CooperativeController.php` — update registerMember to set acct_type=COOP_MEMBER if user is currently USER
- `app/Http/Controllers/Support/VueRouteMap.php` lines 217–311 — add new chapter pages; update existing coop pages to allow new types
- `resources/js/utils/UserTypes.js` — add COOP_MEMBER and COOP_OFFICER constants
- `resources/js/composables/Core/useAuth.js` lines 84–133 — add isCoopMember, isCoopOfficer computed properties
- `resources/js/Pages/Home.vue` lines 73–111 — add v-else-if blocks for COOP_OFFICER and COOP_MEMBER before the User fallback
- `resources/js/Pages/Fragments/Home/HomeCoopOfficer.vue` — NEW: officer dashboard showing chapter org chart + scoped member stats
- `resources/js/Pages/Fragments/Home/HomeCoopMember.vue` — NEW: member dashboard showing membership card, chapter info, wallet, marketplace
- `resources/js/Pages/ChapterOrgChart.vue` — NEW: org chart page filtered by officer's chapter level/geographic scope
- `resources/js/composables/useChapters.js` — may need fetchOfficerScope() method

## steps

### 1. New migration — add cooperative_id to chapters
Create `database/migrations/2026_05_28_000001_add_cooperative_id_to_chapters.php`:
- `$table->unsignedBigInteger('cooperative_id')->nullable()->after('name');`
- `$table->foreign('cooperative_id')->references('id')->on('organizations')->nullOnDelete();`
- Add `$table->index('cooperative_id');`
- Use Hypervel imports (NOT Illuminate): `use Hyperf\Database\Schema\Blueprint; use Hypervel\Database\Migrations\Migration; use Hypervel\Support\Facades\Schema;`

### 2. New migration — add role to chapter_members
Create `database/migrations/2026_05_28_000002_add_role_to_chapter_members.php`:
- `$table->string('role')->nullable()->after('position')->comment('Officer role: PRESIDENT, VICE_PRESIDENT, SECRETARY, TREASURER, AUDITOR, BOARD_MEMBER, MEMBER');`
- The existing `position` field remains for free-text title; `role` is the canonical enum-like string
- Use Hypervel imports

### 3. UserTypes PHP enum — app/Enums/UserTypes.php
After `case COORDINATOR = 'coordinator';`, add:
```php
case COOP_OFFICER = 'coop officer';
case COOP_MEMBER = 'coop member';
```

### 4. UserActions PHP enum — app/Enums/UserActions.php
Add after the last existing case:
```php
case ViewChapterOrgChart = 'viewchapterorgchart';
case ManageChapterMembers = 'managechaptermembers';
case ViewScopedMemberReports = 'viewscopedmemberreports';
case AssignChapterOfficer = 'assignchapterofficer';
```

### 5. UserPermissions — add new type permission sets
In `UserPermissions::roles()` after the `UserTypes::USER->value` block (line 818), add:

```php
UserTypes::COOP_MEMBER->value => [
    UserActions::JoinCooperative,
    UserActions::ViewUserInfo,
    UserActions::ManageUserInfo,
    UserActions::ViewChapterOrgChart,
],

UserTypes::COOP_OFFICER->value => [
    UserActions::JoinCooperative,
    UserActions::ViewUserInfo,
    UserActions::ManageUserInfo,
    UserActions::ViewOrganizations,
    UserActions::ViewChapterOrgChart,
    UserActions::ManageChapterMembers,
    UserActions::ViewScopedMemberReports,
    UserActions::AssignChapterOfficer,
    UserActions::ViewAccountingReports,
    UserActions::CheckifMobileNumberExists,
    UserActions::CheckifUsernameExists,
],
```

Also add ViewChapterOrgChart, ManageChapterMembers, ViewScopedMemberReports, AssignChapterOfficer to `$RoleswithNoTargetUser` array.

### 6. UserPermissions — getAllowedUserTypes
In `UserTypeService::getAllowedUserTypes()`, add COOP_OFFICER and COOP_MEMBER:
- COORDINATOR can create COOP_OFFICER and COOP_MEMBER
- COOP_OFFICER can create COOP_MEMBER
- ULTIMATE/SUPER_OPERATOR/OPERATOR can create both (already implied by wildcard but add explicitly)

### 7. Chapter model — add cooperative_id
In `app/Models/Chapter.php`, add `'cooperative_id'` to `$fillable` and add relationship:
```php
public function cooperative() {
    return $this->belongsTo(\App\Models\Market\Organization::class, 'cooperative_id');
}
```

### 8. ChapterMember model — add role to fillable
In `app/Models/ChapterMember.php`, add `'role'` to `$fillable`.
Add helper:
```php
public function isOfficer(): bool {
    return !empty($this->role) && $this->role !== 'MEMBER';
}
```

### 9. CooperativeController — update registerMember to set acct_type
In `CooperativeController@registerMember` (and `publicRegisterMember`), after successfully creating/confirming the `cooperative_members` row, check:
```php
if ($user->acct_type === UserTypes::USER) {
    $user->acct_type = UserTypes::COOP_MEMBER;
    $user->save();
}
```
This upgrades plain USER accounts to COOP_MEMBER on cooperative registration. Do not downgrade any existing type that is higher (COORDINATOR, OPERATOR, etc.).

### 10. Frontend UserTypes.js
In `resources/js/utils/UserTypes.js`, add:
```js
COOP_OFFICER: 'coop officer',
COOP_MEMBER: 'coop member',
```

### 11. useAuth.js — add computed helpers
In `resources/js/composables/Core/useAuth.js`, after `isUser` (line 113), add:
```js
const isCoopOfficer = computed(() => role.value === UserTypes.COOP_OFFICER);
const isCoopMember = computed(() => role.value === UserTypes.COOP_MEMBER);
```
Export both from the return object.

### 12. Home.vue — add dashboard fragments for new types
Import two new components at top of `<script setup>`:
```js
import HomeCoopOfficer from './Fragments/Home/HomeCoopOfficer.vue';
import HomeCoopMember from './Fragments/Home/HomeCoopMember.vue';
```
Add to destructured `useAuth()`: `isCoopOfficer, isCoopMember`.

In the template, insert BEFORE the `v-else-if="isUser"` block (line 109):
```html
<!-- Coop Officer -->
<template v-else-if="isCoopOfficer">
  <HomeCoopOfficer />
</template>

<!-- Coop Member -->
<template v-else-if="isCoopMember">
  <HomeCoopMember />
</template>
```

### 13. HomeCoopOfficer.vue — NEW officer dashboard
`resources/js/Pages/Fragments/Home/HomeCoopOfficer.vue`

Key elements:
- Stats card: member count in officer's chapter scope, sub-chapter count, new members (7d)
- Officer's chapter badge showing their level (BARANGAY / MUNICIPAL / PROVINCIAL / etc.) and geographic name
- ServiceButtonGrid with: Chapter Org Chart (`ChapterOrgChart`), Members, Reports, My Profile, Cooperative Detail
- SideTextButtonList with: Assign Officer, Add Member, Member Ledger
- Fetch data from `/home-data` (reuse existing endpoint; add coop_officer branch on backend if stats differ)
- The officer's chapter info comes from `user.value?.chapter_membership` (add to home-data response or fetch separately via `/Chapters/MyChapters`)

### 14. HomeCoopMember.vue — NEW member dashboard
`resources/js/Pages/Fragments/Home/HomeCoopMember.vue`

Key elements:
- Membership card: user name, membership type, chapter name (their barangay/municipal chapter), member since
- Stats: wallet balance (if applicable), chapter contact officer name
- ServiceButtonGrid with: Cooperative Detail, My Profile, Marketplace, My Wallet
- SideTextButtonList with: Member Ledger, View Chapter
- Fetch stats from `/home-data` (add member branch)

### 15. ChapterOrgChart.vue — NEW page
`resources/js/Pages/ChapterOrgChart.vue`

- Fetches chapter hierarchy from `/Chapters/OrgChart` (new backend endpoint)
- Backend scopes response by caller's `acct_type`:
  - COOP_OFFICER: return the subtree rooted at their highest chapter
  - COORDINATOR/OPERATOR/Big3: return full tree or coop-scoped tree
  - COOP_MEMBER: return their barangay chapter and its officers only (read-only)
- Renders a tree: collapsible nodes per level, each showing chapter name, officer names + roles
- Route: `/chapter-org-chart` (no hash needed unless scoped to a specific coop)

### 16. VueRouteMap.php — register new pages
Add entries:
```php
'/chapter-org-chart' => [
    'component' => 'ChapterOrgChart',
    'loginRequired' => true,
    'allowedUserTypes' => ['ult', 'super operator', 'operator', 'coordinator', 'coop officer', 'coop member'],
    'module' => 'cooperatives',
],
```
Update existing cooperative pages (cooperative-list, cooperative-detail, cooperative-member-register) to also allow `'coop officer'` and `'coop member'` in `allowedUserTypes`.

### 17. Backend: /Chapters/OrgChart endpoint
In `ChapterController.php`, add method `getOrgChart`:
- Auth: `auth` middleware
- Logic: determine caller's chapter scope (join `chapter_members` → `chapters` for the caller user)
- For COOP_OFFICER: find their chapter_members rows, get the highest-level chapter they are in, return full subtree via recursive children() eager load
- For COOP_MEMBER: return just their barangay chapter + officers
- For Big3/COORDINATOR: accept optional `?cooperative_id=` param, return that coop's full chapter tree
- Response: nested JSON `{ id, hashkey, name, level, location_key, children: [...], officers: [{user_id, name, role, position}] }`
- Register route in `routes/web.php`: `POST /Chapters/OrgChart` with `auth` middleware

### 18. Backend: /home-data — add COOP_OFFICER and COOP_MEMBER branches
In the controller that handles `GET /home-data`, add:
```php
if ($user->acct_type === UserTypes::COOP_OFFICER) {
    // count members in scope, sub-chapters, new members (7d)
    // attach chapter info (name, level, location_key) from chapter_members join
}
if ($user->acct_type === UserTypes::COOP_MEMBER) {
    // attach membership info: chapter name, officer contact, member since
}
```

## context

### Existing chapters migration (canonical)
```
level enum: ['national', 'region', 'province', 'city', 'barangay']
parent_id → chapters.id (nullOnDelete — chapter survives parent deletion)
location_key — normalized slug for address matching
```
NOTE: schema uses 'city' not 'municipal'. In PH context a city/municipality are different — if 'municipal' level is required, add it to the enum in migration step 1 or handle in the plan as a separate sub-step.

### chapter_members.position
Free-text string from `chapter_positions` system setting. The new `role` field (step 2) is the canonical enum: PRESIDENT, VICE_PRESIDENT, SECRETARY, TREASURER, AUDITOR, BOARD_MEMBER, MEMBER.

### UserPermissions::roles() — existing USER block (line 818)
```php
UserTypes::USER->value => [
    UserActions::JoinCooperative,
    UserActions::ViewUserInfo,
    UserActions::ManageUserInfo,
],
```
Insert COOP_MEMBER and COOP_OFFICER blocks immediately after this.

### Home.vue fragment routing pattern
- `isCoordinator` → `HomeCooperative` (already exists, used by COORDINATOR)
- Insert `isCoopOfficer` → `HomeCoopOfficer` BEFORE `isUser` check
- Insert `isCoopMember` → `HomeCoopMember` BEFORE `isUser` check

### CooperativeController::registerMember acct_type upgrade rule
Only upgrade USER → COOP_MEMBER. Never downgrade COORDINATOR, OPERATOR, STORE_OWNER, etc. Check: `$user->acct_type === UserTypes::USER`.

### Definition of Done checklist reminder
- [ ] UserActions::ViewChapterOrgChart etc. added to UserActions.php
- [ ] UserPermissions::roles() entries for COOP_MEMBER and COOP_OFFICER
- [ ] VueRouteMap allowedUserTypes updated for /chapter-org-chart and existing coop pages
- [ ] Direct URL access tested for /chapter-org-chart
- [ ] No bg-white/bg-light hardcoded in new Vue fragments
- [ ] New raw DB queries (if any) include created_by/updated_by

## notes
- dictionary: ai-docs/dictionary.md
- linters: none detected
- constraints: Use Hypervel imports (NOT Illuminate) in all migrations. chapters.level enum uses 'city' not 'municipal' — discuss with user before changing enum or treat city=municipal for now. The chapter auto-assignment (Chapter::autoAssignUser) already runs on UserInfo save and covers COOP_MEMBER address-based assignment. COOP_OFFICER chapter assignment is manual/administrative only.
