# Annotation catalog — Whitespace module (ClientVerse Modules 0.4.0)
# Structural facts are authoritative in ../catalog.json. See ../README.md, ../../_conventions.md.
module: whitespace
package: modules
applies_to: [modules]
summary: >
  Whitespace identifies untapped revenue opportunities by scoring each account against practice
  areas the firm could serve but doesn't yet. A batch scores account/practice combinations on
  configurable factors (client tier, peer coverage, relationship strength, revenue potential),
  surfaces the top opportunities in a digest, and lets users act on coverage gaps.
extends:
  - api_name: CampaignMember
    note: >
      Whitespace adds fields to the standard CampaignMember object (new in 0.4.0). It is extended,
      not owned — the object itself is standard Salesforce.
annotation_status: drafted

objects:
  - api_name: WhiteSpace_Opportunity__c
    label: Whitespace Opportunity
    kind: custom_object
    data_source: Calculated (scoring batch)
    audience: [bd, attorneys, executives]
    description: >
      A scored account/practice-area coverage gap. One record per opportunity, holding the overall
      score, the per-factor component scores, the coverage status, and a recommended action. These
      are what the Whitespace dashboard and digest present.
    key_fields:
      - {api_name: Account__c, purpose: "The account the opportunity is for."}
      - {api_name: Practice_Area__c, purpose: "The practice area representing the gap."}
      - {api_name: Opportunity_Score__c, purpose: "Overall composite score."}
      - {api_name: Score_Client_Tier__c, purpose: "Component: how strategic the client is."}
      - {api_name: Score_Peer_Coverage__c, purpose: "Component: how well peers serve this area."}
      - {api_name: Score_Relationship_Strength__c, purpose: "Component: strength of the firm relationship."}
      - {api_name: Score_Revenue_Potential__c, purpose: "Component: estimated revenue upside."}
      - {api_name: Coverage_Status__c, purpose: "Current coverage classification (e.g. none/partial/active)."}
      - {api_name: Coverage_Lapse__c, purpose: "Whether previously-active coverage has lapsed."}
      - {api_name: Recommended_Action__c, purpose: "Suggested next step."}
      - {api_name: RM_Owner__c, purpose: "Relationship manager who owns follow-up."}
      - {api_name: Last_Scored_Date__c, purpose: "When the batch last scored this record."}

  - api_name: Whitespace_Scoring_Config__mdt
    label: Whitespace Scoring Config
    kind: custom_metadata
    data_source: Configuration (custom metadata)
    audience: [admins]
    description: >
      The Whitespace scoring run's settings: batch size, whether/when to send the digest (day + hour),
      and how many top opportunities to surface.
    key_fields:
      - {api_name: Active__c, purpose: "Whether scoring is enabled."}
      - {api_name: Batch_Size__c, purpose: "Records per scoring batch."}
      - {api_name: Send_Digest__c, purpose: "Whether to email the opportunity digest."}
      - {api_name: Digest_Day_Of_Week__c, purpose: "Digest schedule day."}
      - {api_name: Digest_Hour__c, purpose: "Digest schedule hour."}
      - {api_name: Top_Opportunity_Count__c, purpose: "How many opportunities the digest highlights."}

  - api_name: Whitespace_Score_Weight__mdt
    label: Whitespace Score Weight
    kind: custom_metadata
    data_source: Configuration (custom metadata)
    audience: [admins]
    description: >
      The weight (max points) each scoring factor contributes to the composite Opportunity Score.
      Tuning these reweights how opportunities rank.
    key_fields:
      - {api_name: Factor_Name__c, purpose: "Which scoring factor this weight applies to."}
      - {api_name: Max_Points__c, purpose: "Maximum points the factor can contribute."}
      - {api_name: Active__c, purpose: "Whether the factor is included."}

  - api_name: Whitespace_Threshold__mdt
    label: Whitespace Threshold
    kind: custom_metadata
    data_source: Configuration (custom metadata)
    audience: [admins]
    description: >
      Hours thresholds, per practice, that classify coverage as active vs partial. Drives the
      Coverage Status on each opportunity.
    key_fields:
      - {api_name: Practice_API_Name__c, purpose: "Practice the threshold applies to."}
      - {api_name: Active_Hours_Threshold__c, purpose: "Hours above which coverage counts as active."}
      - {api_name: Partial_Hours_Threshold__c, purpose: "Hours above which coverage counts as partial."}
