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

12 KiB
Raw Permalink Blame History

task, cycles, context, private, started, finished
task cycles context private started finished
Implement COOP_MEMBER and COOP_OFFICER account types with geographic chapter hierarchy 5 true false 2026-05-28T17:08:44Z 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:

case COOP_OFFICER = 'coop officer';
case COOP_MEMBER = 'coop member';

4. UserActions PHP enum — app/Enums/UserActions.php

Add after the last existing case:

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:

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:

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:

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:

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:

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:

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>:

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):

<!-- 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:

'/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_memberschapters 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:

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)

UserTypes::USER->value => [
    UserActions::JoinCooperative,
    UserActions::ViewUserInfo,
    UserActions::ManageUserInfo,
],

Insert COOP_MEMBER and COOP_OFFICER blocks immediately after this.

Home.vue fragment routing pattern

  • isCoordinatorHomeCooperative (already exists, used by COORDINATOR)
  • Insert isCoopOfficerHomeCoopOfficer BEFORE isUser check
  • Insert isCoopMemberHomeCoopMember 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.