Build CRM · high-level scoping document
The federated CRM that holds each professional service provider's "telephone book" as a private database, then exposes consented contacts to other providers via an opt-in/opt-out fabric, feeding the flip 360 referral and commission engine. Same breed as Air BnB / Afterpay / Uber / Airtasker: the protocol is the moat.
1 · Business problem · verbatim brief
Two stakeholders briefed the CRM requirement on Sat 21 Jun 2026. Their verbatim words are quoted below — the scoping is anchored on what they actually said, not a reinterpretation.
"The participants of the flip360 business eg a financial planner, an accountant, a mortage broker and so on have a 'telephone book' of clients (a client database) that they can park onto the flip360 business as contactable by other flip360 professional service providers with an opt in/opt out filter for would you like to be connected with. But each of this business providers dont want another business provider being able to direct access their telephone book. Do you follow this data protection legislation and the business offering that matt wants to set up under CRM that feeds the flip360 referral/commission engine?"
"The workstream lead Corrina wants to be able to warm up a database that has opted in and be able to have full utilisation of the CRM."
Carla's read-back (WS2 Lead interpretation)
flip 360 is a federated trust marketplace: each provider brings their own book; the platform's value is the consent-gated cross-referral fabric between books. Three non-negotiables:
- Provider A's book is provider A's IP. Provider B cannot see names, counts, or any PII of A's contacts without a consent grant.
- Consent is the protocol. A client opts in to be discoverable by category. Their data, their choice, one-click opt-out.
- Conversions fire commission. An introduction that converts triggers the existing commission engine, governed by a signed Introducer Agreement at /legal/introducer/F360-LEG-####.
Corrina's warm-up CRM is a layered capability on top: once a client has opted in, the owning provider can segment, nurture, campaign, and track lifecycle — full Notion-equivalent CRM utilisation, scoped to that provider's tenant.
2 · RACI matrix
Per Carla's instruction: Corrina and Matt for consult on what this CRM needs to do; Carla responsible for elicitation of user requirements mapping to functional spec and UAT.
3 · Functional requirements register
15 requirements — architectural/platform baseline (FR-CRM-001 to 015) elicited from the briefs in §1 plus Carla's WS2 Lead architectural foundation. Every requirement traces to a verbatim source, maps to a proposed surface, and carries an acceptance test that UAT will execute against.
4 · Privacy compliance scaffolding
flip 360 will (at scale) be an APP entity under the Privacy Act 1988 holding personal information of tens of thousands of Australians, plus a sender under the Spam Act 2003. Compliance is not a phase 2 feature; it is the foundation.
5 · Data model proposal
The CRM extends the existing live schema; it does not fork. The existing contacts / deals / commission_rules / legal_agreements tables continue to be the source of truth. New tables overlay consent, disclosure audit, introductions, campaigns.
Schema overlay (migration 0011_crm_overlay.sql)
-- EXTEND existing contacts table (no breaking changes) ALTER TABLE contacts ADD COLUMN owner_provider_id INTEGER REFERENCES providers(id); ALTER TABLE contacts ADD COLUMN owner_visibility TEXT DEFAULT 'PRIVATE'; -- 'PRIVATE' (default, owner-only) | 'DISCOVERABLE' (consent granted) ALTER TABLE contacts ADD COLUMN discoverable_categories TEXT; -- JSON array ALTER TABLE contacts ADD COLUMN collection_purpose TEXT; ALTER TABLE contacts ADD COLUMN collection_source TEXT; ALTER TABLE contacts ADD COLUMN collected_at DATETIME; ALTER TABLE contacts ADD COLUMN consent_version TEXT; ALTER TABLE contacts ADD COLUMN lifecycle_stage TEXT DEFAULT 'cold'; -- 'cold' | 'warming' | 'engaged' | 'active' | 'lapsed' ALTER TABLE contacts ADD COLUMN self_service_token TEXT UNIQUE; -- NEW · providers (the tenants) CREATE TABLE providers ( id INTEGER PRIMARY KEY AUTOINCREMENT, business_name TEXT NOT NULL, professional_category TEXT NOT NULL, -- 'financial-planner' | 'broker' | ... afsl_acl_number TEXT, pi_insurance_cert_url TEXT, kyc_completed_at DATETIME, provider_agreement_execution_id INTEGER REFERENCES agreement_executions(id), webauthn_credential_id TEXT, status TEXT DEFAULT 'PENDING', -- 'PENDING' | 'ACTIVE' | 'SUSPENDED' created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- NEW · consent_grants (the consent ledger, hash-anchored) CREATE TABLE consent_grants ( id INTEGER PRIMARY KEY AUTOINCREMENT, contact_id INTEGER NOT NULL REFERENCES contacts(id), owner_provider_id INTEGER NOT NULL REFERENCES providers(id), granted_at DATETIME NOT NULL, consent_version TEXT NOT NULL, categories TEXT NOT NULL, -- JSON array marketing_opt_in INTEGER DEFAULT 0, -- Spam Act separation introduction_opt_in INTEGER DEFAULT 0, ip_address TEXT, user_agent TEXT, withdrawn_at DATETIME, payload_hash TEXT NOT NULL -- sha-256 ); -- NEW · disclosure_log (APP 6 + APP 11.2 audit) CREATE TABLE disclosure_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, query_provider_id INTEGER NOT NULL REFERENCES providers(id), target_contact_id INTEGER NOT NULL REFERENCES contacts(id), query_type TEXT NOT NULL, -- 'discovery-count' | 'intro-request' | 'intro-made' occurred_at DATETIME DEFAULT CURRENT_TIMESTAMP, request_id TEXT -- correlates with introductions.id where applicable ); -- NEW · introductions (feeds commission engine) CREATE TABLE introductions ( id INTEGER PRIMARY KEY AUTOINCREMENT, introducer_provider_id INTEGER NOT NULL REFERENCES providers(id), target_provider_id INTEGER NOT NULL REFERENCES providers(id), contact_id INTEGER NOT NULL REFERENCES contacts(id), status TEXT NOT NULL, -- 'REQUESTED' | 'APPROVED' | 'DECLINED' | 'MADE' | 'CONVERTED' governing_agreement_execution_id INTEGER REFERENCES agreement_executions(id), commission_rule_id INTEGER REFERENCES commission_rules(id), requested_at DATETIME DEFAULT CURRENT_TIMESTAMP, converted_at DATETIME ); -- NEW · campaigns (Corrina's warm-up) CREATE TABLE campaigns ( id INTEGER PRIMARY KEY AUTOINCREMENT, owner_provider_id INTEGER NOT NULL REFERENCES providers(id), name TEXT NOT NULL, segment_definition TEXT NOT NULL, -- JSON query spec status TEXT DEFAULT 'DRAFT', marketing_consent_gate INTEGER DEFAULT 1, -- hard requirement created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- NEW · campaign_sends (per-recipient event log) CREATE TABLE campaign_sends ( id INTEGER PRIMARY KEY AUTOINCREMENT, campaign_id INTEGER NOT NULL REFERENCES campaigns(id), contact_id INTEGER NOT NULL REFERENCES contacts(id), sent_at DATETIME, opened_at DATETIME, clicked_at DATETIME, unsubscribed_at DATETIME, converted_at DATETIME ); -- INDICES for tenant isolation enforcement CREATE INDEX idx_contacts_owner ON contacts(owner_provider_id); CREATE INDEX idx_consent_grants_contact ON consent_grants(contact_id); CREATE INDEX idx_disclosure_log_query ON disclosure_log(query_provider_id, occurred_at); CREATE INDEX idx_introductions_status ON introductions(status);
Tenant isolation enforcement
Tenant isolation is enforced at the middleware layer, not in business logic. Every Hono route handler that reads contact data is wrapped:
// src/middleware/tenantScope.ts (proposed)
export const tenantScope: MiddlewareHandler = async (c, next) => {
const session = await getSession(c)
if (!session?.providerId) return c.json({ error: 'unauthenticated' }, 401)
c.set('providerId', session.providerId)
// EVERY downstream SELECT on contacts MUST include owner_provider_id = ?
// Linter enforces; PR review enforces; runtime assertion enforces.
await next()
}
There is no "admin view" that bypasses tenant scope except a single named privacy-officer route under /crm/admin/audit with every access written to disclosure_log.
6 · UAT plan
UAT executes after build, before cutover. Named testers, scripted scenarios, acceptance criteria all gated. Sign-off card on /engagement/pmo/scoping/crm at completion.
Testers
- Matt Punter (CEO & Founder) — federated business model end-to-end. Tests provider-to-provider introduction → commission firing.
- Corrina McGowan — warm-up campaigns + segment + lifecycle. Tests campaign send to opted-in segment with full event tracking.
- Carla Oliver — defect triage + technical sign-off. Runs the privacy + tenant isolation tests.
- Test data subject — a Carla-controlled test contact who exercises the /me/{token} self-service portal end-to-end (view, edit, export, opt-out, delete).
- Pine Lawyers (review only) — reviews the privacy policy + collection notice + Provider Agreement before go-live sign-off.
UAT scenarios (one per P0 requirement minimum)
7 · Risk + dependency register
Risks
Dependencies
8 · Sequencing options for Steerco #2 decision
Three viable paths through the build. Steerco #2 (Mon 29 Jun 2026) approves one. This scoping document is the evidence base for that decision.
Owner-private first, federate later
Ship the owner-private CRM in fortnight 1 (each provider runs their own book, no cross-provider visibility). Layer consent fabric + introductions + commissions in fortnight 2-3 once Pine Lawyers signs off.
Cons: Federated trust marketplace (the actual product) ships in fortnight 3, not fortnight 1.
Effort: ~25 days across 3 fortnights.
Carla recommendation: RECOMMENDED
Full federated CRM end-to-end day 1
Build the full consent fabric + introductions + campaigns + commissions concurrently. Pine Lawyers engaged in parallel from day 1. Ship as a single coherent product in fortnight 3.
Cons: Hard dependency on Pine Lawyers timing. Corrina waits 3 fortnights for usable surface. WS2 capacity stretched.
Effort: ~30 days across 3 fortnights.
Carla view: Acceptable if Pine Lawyers engagement letter is signed by Wed 24 Jun.
Defer to Phase 2
Hold the CRM build until Phase 2. Use a third-party CRM (HubSpot, Pipedrive) for WS6 partner activation in the interim.
Cons: flip 360 is not "the project management tool" — narrative collapses. Federated trust marketplace deferred. Marketing copy on /architecture mismatches reality.
Effort: 0 days now · ~40 days in Phase 2 (more expensive — context switch + migration from third-party CRM).
Carla view: Not recommended. Compromises Q3 thought-leadership standard.
Recommendation to Steerco #2
Option A (Owner-private first, federate later) · with Pine Lawyers engagement initiated this week so the federated layer can ship in fortnight 2-3 without slip.
This is the same-breed-as-IPO-comps play: ship the foundation now, prove tenant isolation under real load, layer the federated trust fabric on a hardened base. Air BnB shipped accommodation listings before they shipped Experiences. Afterpay shipped pay-in-four before they shipped business-tier features. Same discipline.
Sign-off path
- Mon 22 Jun — Carla publishes v1 of this document (today) · WS2-S003 in sprint
- Tue 23 Jun — Carla schedules consult sessions with Matt (commission/legal wiring) + Corrina (warm-up campaigns)
- Wed 24 Jun — Pine Lawyers engagement letter signed (dependency D-01)
- Thu 25 Jun — Matt and Corrina review the requirements register (§3) and confirm or amend
- Fri 26 Jun 17:00 AEST — Scoping document v1.0 locked. Acceptance card signed by Matt + Corrina + Carla. Posted to Steerco #2 papers.
- Mon 29 Jun — Steerco #2 approves sequencing option (A / B / C). Build sprint begins same day.