# Company Group Management — Design

## Overview

Add group-level management to `client_management.cgi` so admins can perform bulk operations on all accounts within a company group (the `career_center.company` table). Currently, groups exist (357 groups, 6,260 accounts) but there is no UI to manage a group as a unit — admins must visit each account individually.

## Entry Points

### 1. From Search Results (clickable group name)
When a client has a `company_id`, the group name in the results card becomes a link to `?group_id=N`. This is the primary entry point.

### 2. Groups List View (`?view=groups`)
A searchable, sortable table of all company groups. Columns: Group Name, Member Count, Active Services (yes/no). Clicking a group navigates to `?group_id=N`. No admin nav link — accessed via a button/link in the CMS search bar area.

## Group View Layout (`?group_id=N`)

```
[Admin Header + Nav]

[Breadcrumb: <- Back to Search  /  General Dynamics]

[HEADER]
  "General Dynamics" (211 members)
  Reference Invoice: #206645 - Dominique Forotti
  Active Services: Unlimited Jobs until 12/31/2026, Unlimited Resumes until 12/31/2026
  (or: amber warning "No active services found — Grant Access is disabled")

[BULK ACTIONS BAR]
  [Grant Access (Jobs/Resumes)]  [Toggle Email Subs (On/Off)]  [Ungroup All (RED)]
                                                                    [Export CSV]

[MEMBER ROSTER — read-only table]
  Invoiced accounts listed first (highlighted), all sorted by last_name, first_name

  Name          | Email         | Type     | Services   | Subscribed
  ------------- | ------------- | -------- | ---------- | ----------
  * Jamie Kelly | jk@gd.com    | Employer | Jobs, Res  | Yes
  * Drew Evans  | de@gd.com    | Employer | Jobs, Res  | Yes
  Lula Beyene   | lb@gd.com    | Lead     | —          | No
  ...
  Showing 1-50 of 211  [Load More]

[Admin Footer]
```

## Bulk Actions

### Grant Access
- **Enabled only** when a reference invoice with active services is found
- **Reference invoice detection:**
  1. Get all employer_ids in the group (`WHERE company_id = ?`)
  2. Get all invoices for those employer_ids, ordered by `invoice_creation_date DESC`
  3. For each invoice, check for `paid_services` rows with `product_id IN (6,7)` AND `expire_date >= CURDATE()`
  4. First match = reference invoice. Capture: employer_id (invoice holder), product_ids, expire_date, invoice_id
  5. No match = Grant Access button disabled
- **Behavior:** Updates ALL group members EXCEPT the invoice holder
  - If member already has a `paid_services` row for that product_id with the SAME `associated_invoice` → UPDATE the `expire_date`
  - If member has no row for that product_id, or has one with a DIFFERENT `associated_invoice` → INSERT new row
  - New/updated rows get: same `product_id`, `start_date`, `expire_date`, `associated_invoice` as reference
- **Confirmation dialog:** "Grant Unlimited Jobs + Unlimited Resumes (expires 12/31/2026) to 210 members? Reference: Invoice #206645 (Jamie Kelly)"
- **Logging:** `logEvent()` on each affected account with `$USER` as `contact`
- **Toast:** "Granted access to N members (X updated, Y new)"

### Toggle Email Subscriptions
- Two buttons: "Turn On for All" / "Turn Off for All"
- **Confirmation:** "Set email subscriptions to ON/OFF for all 211 group members?"
- Updates `employer_data.subscribed` for all group members
- **Logging:** `logEvent()` on each account with `$USER` as `contact`, summary like "Bulk: Email subscriptions turned ON (group: General Dynamics)"
- **Toast:** "Email subscriptions turned ON/OFF for N members"

### Ungroup All
- **Styled as danger** (red background, requires confirmation)
- **Confirmation:** "Remove all 211 accounts from the General Dynamics group? This cannot be undone."
- Sets `company_id = NULL` on all group members
- **Logging:** `logEvent()` on each account with `$USER` as contact
- Redirects to `?view=groups` after completion

### Export
- Downloads CSV with columns: Last Name, First Name, Email Address
- Sorted by last_name, first_name
- Filename: `general_dynamics_members.csv` (group name slugified)

## AJAX Endpoints (new)

| Action | Purpose |
|--------|---------|
| `get_groups` | List all groups with member count + active services flag, supports search/sort/pagination |
| `get_group_detail` | Group info + member roster + reference invoice detection |
| `grant_group_access` | Clone/update paid_services for all group members from reference invoice |
| `toggle_group_email` | Bulk update employer_data.subscribed for all group members |
| `ungroup_all` | Set company_id = NULL for all group members |
| `export_group_csv` | Return CSV download of group members |

## Database Tables Involved

| Table | Usage |
|-------|-------|
| `company` | Group name lookup (id, name) |
| `employer_data` | Member roster (company_id join), subscribed updates, company_id nulling |
| `employer_status` | Join for status info in roster display |
| `invoices` | Finding invoiced accounts, reference invoice detection |
| `paid_services` | Active services display, grant access inserts/updates |
| `proposal_options` | Service name labels (option_title) |
| `employer_history` | logEvent() calls for all bulk actions |

## File Changes

| File | Change |
|------|--------|
| `admin/client_management.cgi` | Add 6 new AJAX endpoints, `printGroupView()`, `printGroupsListView()`, JS functions for group UI |

## UI Details

- **Breadcrumb:** `<- Back to Search / Group Name` using the preferred sub-nav pattern (chevron-left back link)
- **Invoiced accounts:** Highlighted with a subtle left border or background tint, star/icon indicator
- **Ungroup All button:** `bg-red-600 text-white hover:bg-red-700` styling
- **Grant Access button:** Disabled state with tooltip when no active services found
- **Member roster:** Paginated (50 per load, "Load More" button), no individual click-through
- **Groups list view:** Simple searchable table, link/button accessible from main CMS search bar

## Verification

1. `perl -c client_management.cgi` — syntax check
2. Navigate to `?view=groups` — see all 357 groups, searchable
3. Click a group — see member roster with invoiced accounts on top sorted by last/first name
4. Reference invoice auto-detected and displayed
5. Grant Access — services cloned to all non-holder members, logged
6. Toggle Email — subscribed field updated for all, logged
7. Ungroup All — all members removed from group, redirects to groups list
8. Export — CSV downloads with correct columns and sort
9. `chown hbcuconnect:psacln client_management.cgi`
