Files
BarangaySystem/.claude/plans/4fc3b455fb62b15dfb06790a1f421c96-complete.md
2026-06-06 18:43:00 +08:00

265 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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 818838 — 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 217311 — 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 84133 — add isCoopMember, isCoopOfficer computed properties
- `resources/js/Pages/Home.vue` lines 73111 — 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.