> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Nonprofit Governance Controls — Integration Document

> Feature ID: GR-15 Version: 1.0 Status: 📋 Planned Created: 2026-03-07 Owner: GR (Governance & Compliance) Based On: specs/gr/specs/GR-15-nonprofit-governance-c…

**Feature ID:** GR-15\
**Version:** 1.0\
**Status:** 📋 Planned\
**Created:** 2026-03-07\
**Owner:** GR (Governance & Compliance)\
**Based On:** `specs/gr/specs/GR-15-nonprofit-governance-controls.md`

> **Cross-Reference:** See `docs/architecture/integrations/CROSS_CORE_INTEGRATIONS.md` for matrix entry.

***

## Summary

GR-15 integrates the Governance Controls module with HR-01 (employee roster for COI participants), FA (related-party transaction cross-reference), PF-10 (notifications for reminders and alerts), PF-46 (document retention and legal holds), GR-01 (linked governance policies), and GR-03 (compliance tracking of annual COI completion).

GR-15 uses multiple integration patterns: Platform Integration Layer for PF-10 and PF-46, shared-table lookups for `pf_profiles` (HR-01 employee data), explicit manual UUID cross-reference for FA related-party transactions, and intra-core references for GR-01 (policies) and GR-03 (compliance tracking). No direct core-to-core imports.

***

## Integration Points

### 1. HR-01 (Employee Directory) → GR-15 COI Attestation

**Pattern:** Data lookup via shared PF table\
**Direction:** GR-15 reads from HR-01 via `pf_profiles` (shared PF table)\
**Purpose:** Seed COI attestation participant roster from active employees with designated roles (board\_member, executive, staff)

**Integration Method:**

```typescript theme={null}
// GR reads profile data from shared pf_profiles table (PF layer)
// No direct import from @/cores/hr/
import { supabase } from '@/integrations/supabase/client';

// Query pf_profiles for active org members by role
const { data: eligibleProfiles } = await supabase
  .from('pf_profiles')
  .select('id, full_name, email')
  .eq('organization_id', orgId)
  .in('role_category', ['board_member', 'executive', 'staff']);
```

**Data Accessed:**

* `pf_profiles.id` — Profile UUID for FK in `gr_coi_attestations.profile_id`
* `pf_profiles.full_name` — Display name in COI dashboard
* `pf_profiles.email` — Notification delivery via PF-10

**Tenant Isolation:** All queries filtered by `organization_id`. No cross-org data access.

**RLS Impact:** `gr_coi_attestations.profile_id` references `pf_profiles(id)` — PF table; no direct HR table FK.

***

### 2. FA (Finance & Accounting) → GR-15 COI Attestation

**Pattern:** UUID cross-reference (no FK)\
**Direction:** GR-15 COI disclosures cross-reference FA vendor/payee data for related-party transaction identification\
**Purpose:** Compliance officers can identify when a disclosed COI party (vendor, contractor) matches a known FA payee for Form 990 Schedule L disclosure amounts

**Integration Method:**

* GR-15 stores the disclosed interest description in `gr_coi_attestations.conflict_description` (text field)
* Compliance officer cross-references manually with FA vendor records during Form 990 preparation
* **No automated FA query from GR-15 in Phase 1** (manual cross-reference; automated matching is a deferred enhancement)
* When automated matching is needed in future: use Platform Integration Layer or read-only API contract

**Data Cross-Referenced:**

* FA vendor name / payee name (manual matching against `conflict_description` text)
* FA transaction amounts (for Schedule L "Amount Involved" column)

**Note:** No database FK from GR to FA tables. Cross-reference is organizational/compliance workflow, not automated data join.

***

### 3. PF-10 (Notifications) ← GR-15

**Pattern:** Platform Integration Layer\
**Direction:** GR-15 triggers PF-10 notifications\
**Import:** `@/platform/notifications` / edge function notification utilities

**Events Triggering Notifications:**

| Event                                         | Recipient                         | Channel        | Template                        |
| --------------------------------------------- | --------------------------------- | -------------- | ------------------------------- |
| COI attestation cycle launched                | All invited participants          | In-app + email | `gr_coi_invitation`             |
| COI reminder (D-30, D-14, D-7, D-1)           | Pending attestors                 | In-app + email | `gr_coi_reminder`               |
| Whistleblower report received                 | Assigned compliance officer       | In-app + email | `gr_whistleblower_new`          |
| Whistleblower status changed                  | Assigned compliance officer       | In-app         | `gr_whistleblower_status`       |
| Board minutes approved                        | Minutes creator (board secretary) | In-app         | `gr_board_minutes_approved`     |
| Governance document approaching retention end | Compliance officer                | In-app + email | `gr_document_retention_warning` |

**Implementation:**

```typescript theme={null}
// In edge functions: use _shared/notification-utils.ts
import { createNotificationIfNew } from '../_shared/notification-utils.ts';

// Deduplication prevents duplicate reminders
await createNotificationIfNew({
  organizationId,
  userId: attendeeProfileId,
  type: 'gr_coi_reminder',
  title: 'COI Attestation Due',
  message: `Your conflict of interest attestation for ${year} is due in ${daysRemaining} days.`,
  metadata: { coiYear: year, dueDate },
});
```

***

### 4. PF-46 (Data Retention) ← GR-15

**Pattern:** Platform Integration Layer\
**Direction:** GR-15 registers governance document types with PF-46 retention engine\
**Import:** `@/platform/data-retention`

**Retention Entity Types Registered:**

| Entity Type               | Min Retention | Notes                              |
| ------------------------- | ------------- | ---------------------------------- |
| `gr_coi_attestation`      | 7 years       | IRS 990 record-keeping; IRC § 6033 |
| `gr_whistleblower_report` | 7 years       | SOX §802 record retention          |
| `gr_board_minutes`        | Permanent     | Best practice; state nonprofit law |
| `gr_board_resolution`     | Permanent     | Best practice; state nonprofit law |

**Integration:**

* `RETENTION_ENTITY_TYPES` in PF-46 must include the above types (PF-46 team to extend if needed)
* GR-15 Phase 4 creates `pf_retention_policies` rows for each entity type via admin UI + migration seed
* Legal holds: GR-15 reads `pf_legal_holds` to check for active holds before flagging document for destruction
* Pre-destruction notification: PF-46 cron triggers PF-10 notification; GR-15 configures warning threshold via `gr_module_settings.retention_warning_days`

***

### 5. GR-01 (Policy Management) ← GR-15

**Pattern:** Internal GR cross-reference (data lookup via shared GR module)\
**Direction:** GR-15 links COI Policy, Whistleblower Policy, Document Retention Policy to `gr_policies` records\
**Purpose:** Compliance controls linked to governing organizational policies

**Integration:**

* COI attestation cycle references the organization's COI Policy (`gr_policies.category = 'conflict_of_interest'`)
* Whistleblower intake form references Whistleblower Policy (`gr_policies.category = 'whistleblower'`)
* Document retention configuration references Document Retention Policy (`gr_policies.category = 'document_retention'`)
* Links stored as optional `policy_id UUID REFERENCES gr_policies(id)` on `gr_module_settings` or as JSONB metadata

***

### 6. GR-03 (Compliance Tracking) ← GR-15

**Pattern:** Internal GR event / data reference\
**Direction:** GR-15 COI completion drives GR-03 compliance requirement status\
**Purpose:** Annual COI attestation completion is a tracked compliance requirement in GR-03

**Integration:**

* GR-03 tracks "Annual COI Attestations" as a compliance requirement with a due date
* GR-15 COI attestation completion percentage can be surfaced in GR-03 compliance dashboard
* Integration is read-only from GR-03 perspective; GR-15 provides completion data via shared module query
* No direct FK; compliance officer views GR-15 dashboard from GR-03 via navigation link

***

## Event Contracts

### `gr_coi_cycle_launched` (Planned)

**Publisher:** GR-15 (compliance officer action)\
**Subscribers:** PF-10 (notifications), GR-03 (compliance tracking update)\
**Channel:** pg\_notify / Supabase realtime\
**Status:** 📋 Planned (Phase 1)

```typescript theme={null}
type GrCoiCycleLaunchedPayload = {
  event: 'gr_coi_cycle_launched';
  organizationId: string;
  attestationYear: number;
  dueDate: string; // ISO date
  participantCount: number;
  launchedBy: string; // profile_id
};
```

### `gr_whistleblower_report_submitted` (Planned)

**Publisher:** GR-15 (anonymous or authenticated submission)\
**Subscribers:** PF-10 (notify compliance officer)\
**Channel:** pg\_notify / edge function trigger\
**Status:** 📋 Planned (Phase 2)

```typescript theme={null}
type GrWhistleblowerReportSubmittedPayload = {
  event: 'gr_whistleblower_report_submitted';
  organizationId: string;
  reportId: string;
  isAnonymous: boolean;
  category: 'financial_fraud' | 'discrimination' | 'safety' | 'policy_violation' | 'other';
  // NOTE: Never include description or reporter identity in event payload
};
```

***

## API Contracts

### Public Edge Function: `gr-whistleblower-submit`

**Endpoint:** `POST /functions/v1/gr-whistleblower-submit`\
**Auth:** `verify_jwt: false` — Public endpoint (no authentication required for anonymous submission)\
**Purpose:** Accept anonymous whistleblower reports without requiring user authentication

**Request:**

```typescript theme={null}
type WhistleblowerSubmitRequest = {
  organizationId: string;         // Required: org scope
  category: 'financial_fraud' | 'discrimination' | 'safety' | 'policy_violation' | 'other';
  description: string;            // Required: 10-10000 chars
  isAnonymous: boolean;
  reporterProfileId?: string;     // Optional: provided when isAnonymous = false
};
```

**Response (200 OK):**

```typescript theme={null}
type WhistleblowerSubmitResponse = {
  success: true;
  reportToken: string;            // UUID v4: use for anonymous follow-up
  message: string;                // "Your report has been submitted."
};
```

**Response (400 Bad Request):**

```typescript theme={null}
type WhistleblowerSubmitError = {
  success: false;
  error: string;                  // Sanitized error message (no internal details)
};
```

**Security:**

* Uses `service_role` key server-side to bypass RLS
* `created_by = NULL` enforced when `isAnonymous = true`
* `reporter_profile_id = NULL` enforced when `isAnonymous = true`
* Input validation: description length 10–10000 chars; category enum validation
* Rate limiting: max 5 reports per IP per hour (via PF-42 rate limiting)
* CORS: `getCorsHeaders(req.headers.get('origin'))` from `_shared/cors.ts`

### Internal Edge Function: `gr-coi-attestation-reminders`

**Endpoint:** Cron-triggered (no HTTP endpoint)\
**Auth:** Service role\
**Schedule:** Daily at 08:00 UTC (configured via pg\_cron or Supabase dashboard)\
**Purpose:** Send escalating COI attestation reminders to pending attestors

**Cron Logic:**

1. Find all active COI cycles (`status != 'closed'`, `due_date > now()`)
2. For each cycle, find `pending` attestations
3. Calculate days until due date
4. Send reminder if today is D-30, D-14, D-7, or D-1
5. Use `createNotificationIfNew()` to prevent duplicates

***

## Platform Layer Usage

| Platform Layer              | Usage                                              | Import                                                        |
| --------------------------- | -------------------------------------------------- | ------------------------------------------------------------- |
| `@/platform/notifications`  | Sending COI reminders + whistleblower alerts       | `import { sendNotification } from '@/platform/notifications'` |
| `@/platform/data-retention` | Checking legal holds; registration of entity types | `import { useLegalHolds } from '@/platform/data-retention'`   |
| `@/platform/documents`      | Board minutes document attachment                  | `import { useDocuments } from '@/platform/documents'`         |
| `@/platform/forms`          | COI attestation form + Tiptap rich text            | `import { RichTextField } from '@/platform/forms'`            |
| `@/platform/table-v2`       | All list/table views                               | `import { DataTable } from '@/platform/table-v2'`             |

***

## Integration Matrix Entry

> This entry should be added to `docs/architecture/integrations/CROSS_CORE_INTEGRATIONS.md`.

| From Core | To Core | Integration Pattern                             | Status     | Documentation |
| --------- | ------- | ----------------------------------------------- | ---------- | ------------- |
| GR-15     | PF-10   | Platform Layer (notifications)                  | 📋 Planned | This doc      |
| GR-15     | PF-46   | Platform Layer (data retention)                 | 📋 Planned | This doc      |
| GR-15     | HR-01   | Data lookup via `pf_profiles` (PF shared table) | 📋 Planned | This doc      |
| GR-15     | FA      | UUID cross-reference (manual workflow)          | 📋 Planned | This doc      |
| GR-15     | GR-01   | Internal GR (policy link)                       | 📋 Planned | This doc      |
| GR-15     | GR-03   | Internal GR (compliance completion)             | 📋 Planned | This doc      |

***

## Validation Checklist

Based on `docs/architecture/integrations/CONTRACT_VALIDATION_CHECKLIST.md`:

* [x] Integration doc created at canonical path
* [x] All Integration Points from spec covered
* [x] API contracts documented (gr-whistleblower-submit, gr-coi-attestation-reminders)
* [x] Event contract stubs defined (gr\_coi\_cycle\_launched, gr\_whistleblower\_report\_submitted)
* [x] Platform layer usage documented
* [x] Tenant isolation documented for all integrations
* [x] Auth/security documented for public edge function
* [x] CORS pattern documented (uses `getCorsHeaders`)
* [x] HR exclusion from whistleblower explicitly documented
* [x] Integration matrix entry added to CROSS\_CORE\_INTEGRATIONS.md
* [x] Event contracts added to EVENT\_CONTRACTS.md (✅ Added in PR #1002 remediation)
* [x] KnownEventName updated in `src/platform/events/types.ts` (✅ Added in PR #1002 remediation)

***

## References

* **Spec:** `specs/gr/specs/GR-15-nonprofit-governance-controls.md`
* **Plan:** `specs/gr/plans/GR-15-nonprofit-governance-controls-PLAN.md`
* **PF-10:** `@/platform/notifications`
* **PF-46:** `docs/architecture/integrations/PF-46-data-retention-lifecycle-INTEGRATION.md`
* **Contract Template:** `specs/_templates/INTEGRATION_CONTRACT_TEMPLATE.md`
* **Cross-Core Matrix:** `docs/architecture/integrations/CROSS_CORE_INTEGRATIONS.md`
* **Event Contracts:** `docs/architecture/integrations/EVENT_CONTRACTS.md`
