Skip to content

Sequence 3: Engagement & Consent

Status: Complete Depends On: Sequence 2 (Client Identity) Last Updated: 2024-12-23


Overview

This sequence implements the engagement letter and consent management workflow. Once a client's identity is verified, they must sign an engagement letter before tax work begins. This sequence also covers Form 7216 consent for client data disclosure.

Stories in This Sequence

Story Title Status Priority
S3-001 Engagement Letter Generation Done P0
S3-002 Engagement Letter Signature Done P0
S3-003 Form 7216 Consent Management Done P0

S3-001: Engagement Letter Generation

Story: As an admin, I want to generate engagement letters from templates, so that clients can be onboarded efficiently.

Acceptance Criteria

  • Templates stored and versioned in database
  • Client data auto-populated (name, address, tax year, services)
  • Fee schedule included based on return type
  • Multiple service types supported (tax prep, planning, representation)
  • Preview before sending
  • Version tracking on templates

Technical Design

Domain Model

# src/domain/engagement.py

class EngagementTemplate:
    """Template for engagement letters."""
    id: UUID
    name: str                    # e.g., "Individual Tax Preparation 2024"
    template_type: EngagementType  # TAX_PREP, TAX_PLANNING, REPRESENTATION
    content_template: str        # Markdown/HTML with placeholders
    fee_schedule_id: Optional[UUID]
    version: int
    is_active: bool
    created_at: datetime
    updated_at: datetime

class Engagement:
    """Generated engagement letter for a client."""
    id: UUID
    client_id: UUID
    template_id: UUID
    template_version: int
    tax_year: int
    services: List[ServiceType]   # List of services included
    fee_amount: Decimal
    fee_schedule_details: dict    # Breakdown of fees
    content_html: str             # Rendered letter content
    status: EngagementStatus      # DRAFT, PENDING_SIGNATURE, SIGNED, EXPIRED
    generated_at: datetime
    sent_at: Optional[datetime]
    signed_at: Optional[datetime]
    signature_request_id: Optional[str]  # Google signature request ID
    created_at: datetime
    updated_at: datetime

class FeeSchedule:
    """Fee schedule for services."""
    id: UUID
    name: str
    tax_year: int
    base_fees: dict              # {service_type: amount}
    complexity_multipliers: dict  # {complexity_level: multiplier}
    is_active: bool
    created_at: datetime

Database Tables

-- engagement_template table
CREATE TABLE engagement_template (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    name VARCHAR(255) NOT NULL,
    template_type engagement_type_enum NOT NULL,
    content_template TEXT NOT NULL,
    fee_schedule_id UUID REFERENCES fee_schedule(id),
    version INTEGER NOT NULL DEFAULT 1,
    is_active BOOLEAN NOT NULL DEFAULT true,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

-- fee_schedule table
CREATE TABLE fee_schedule (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    name VARCHAR(255) NOT NULL,
    tax_year INTEGER NOT NULL,
    base_fees JSONB NOT NULL DEFAULT '{}',
    complexity_multipliers JSONB NOT NULL DEFAULT '{}',
    is_active BOOLEAN NOT NULL DEFAULT true,
    created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

-- engagement table
CREATE TABLE engagement (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    client_id UUID NOT NULL REFERENCES client(id),
    template_id UUID NOT NULL REFERENCES engagement_template(id),
    template_version INTEGER NOT NULL,
    tax_year INTEGER NOT NULL,
    services JSONB NOT NULL DEFAULT '[]',
    fee_amount DECIMAL(10,2) NOT NULL,
    fee_schedule_details JSONB NOT NULL DEFAULT '{}',
    content_html TEXT NOT NULL,
    status engagement_status_enum NOT NULL DEFAULT 'draft',
    generated_at TIMESTAMP NOT NULL DEFAULT NOW(),
    sent_at TIMESTAMP,
    signed_at TIMESTAMP,
    signature_request_id VARCHAR(255),
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

API Endpoints

Endpoint Method Description
/v1/engagement/templates GET List active templates
/v1/engagement/templates/{id} GET Get template details
/v1/engagement/generate POST Generate engagement for client
/v1/engagement/{id} GET Get engagement details
/v1/engagement/{id}/preview GET Preview rendered letter
/v1/engagement/{id}/send POST Send for signature

Files to Create/Modify

File Action Description
src/domain/engagement.py Create Domain entities
src/repositories/engagement_repository.py Create Data access
src/services/template_service.py Create Template rendering
src/workflows/intake/engagement_workflow.py Create Business logic
src/api/routes/engagement.py Create API endpoints
src/api/schemas/engagement_schemas.py Create Pydantic models
tests/integration/conftest.py Modify Add test schema
tests/e2e/conftest.py Modify Add test schema

S3-002: Engagement Letter Signature

Story: As a client, I want to sign my engagement letter electronically, so that I can engage the firm without mailing documents.

Acceptance Criteria

  • Google Workspace signature request sent
  • Signing order enforced (if multiple signers)
  • Reminder emails sent for unsigned documents
  • Signed document retrieved and stored
  • Engagement status updated upon signature
  • Tax work blocked until signed

Technical Design

Google Workspace Integration

# src/services/google_service.py

class GoogleService(BaseService):
    """
    Google Workspace integration for signatures, calendar, and Meet.

    Supports:
    - Document signatures via Google Docs/Drive
    - Calendar event creation
    - Meet scheduling for video verification

    Note: Uses service account with domain-wide delegation.
    """

    async def create_signature_request(
        self,
        document_content: bytes,
        document_name: str,
        signers: List[SignerInfo],
        callback_url: str,
    ) -> SignatureRequest:
        """Create a signature request for a document."""
        ...

    async def get_signature_status(
        self,
        request_id: str,
    ) -> SignatureStatus:
        """Get status of a signature request."""
        ...

    async def download_signed_document(
        self,
        request_id: str,
    ) -> bytes:
        """Download the signed document."""
        ...

Webhook Handler

# src/api/routes/webhooks.py

@router.post("/v1/webhooks/google/signature")
async def google_signature_webhook(
    request: Request,
    background_tasks: BackgroundTasks,
):
    """
    Handle Google Workspace signature completion webhook.

    Updates engagement status and stores signed document.
    """
    ...

Files to Create/Modify

File Action Description
src/services/google_service.py Create Google Workspace integration
src/api/routes/webhooks.py Modify Add signature webhook handler
src/workflows/intake/engagement_workflow.py Modify Add signature handling

Story: As a preparer, I want to track Form 7216 consent, so that we never disclose client information without proper authorization.

Acceptance Criteria

  • Consent form generated when disclosure needed
  • Consent types tracked (disclosure to third party, use for other services)
  • Expiration date tracked
  • Renewal reminders sent before expiration
  • Disclosure blocked if no valid consent
  • Consent history maintained for audit

Technical Design

Domain Model

# src/domain/consent.py

class ConsentType(str, Enum):
    """Types of Form 7216 consent."""
    DISCLOSURE_THIRD_PARTY = "disclosure_third_party"  # Sharing with third party
    USE_OTHER_SERVICES = "use_other_services"          # Using data for other services
    DISCLOSURE_SPOUSE = "disclosure_spouse"            # Sharing with spouse (if separate)
    DISCLOSURE_REPRESENTATIVE = "disclosure_representative"  # Sharing with POA

class Consent:
    """Client consent record (Form 7216)."""
    id: UUID
    client_id: UUID
    consent_type: ConsentType
    description: str              # What is being consented to
    third_party_name: Optional[str]  # Who data is disclosed to
    tax_years: List[int]          # Tax years covered
    granted_at: datetime
    expires_at: Optional[datetime]
    revoked_at: Optional[datetime]
    signature_request_id: Optional[str]
    document_s3_key: Optional[str]  # Signed consent form
    created_at: datetime

Database Tables

-- consent table
CREATE TABLE consent (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    client_id UUID NOT NULL REFERENCES client(id),
    consent_type consent_type_enum NOT NULL,
    description TEXT NOT NULL,
    third_party_name VARCHAR(255),
    tax_years JSONB NOT NULL DEFAULT '[]',
    granted_at TIMESTAMP NOT NULL,
    expires_at TIMESTAMP,
    revoked_at TIMESTAMP,
    signature_request_id VARCHAR(255),
    document_s3_key VARCHAR(500),
    created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_consent_client_id ON consent(client_id);
CREATE INDEX idx_consent_type ON consent(consent_type);
CREATE INDEX idx_consent_expires_at ON consent(expires_at) WHERE revoked_at IS NULL;

API Endpoints

Endpoint Method Description
/v1/consent POST Create consent request
/v1/consent/{id} GET Get consent details
/v1/consent/client/{client_id} GET Get all consents for client
/v1/consent/{id}/revoke POST Revoke consent
/v1/consent/check POST Check if valid consent exists

Files to Create/Modify

File Action Description
src/domain/consent.py Create Domain entities
src/repositories/consent_repository.py Create Data access
src/workflows/consent_workflow.py Create Business logic
src/api/routes/consent.py Create API endpoints
src/api/schemas/consent_schemas.py Create Pydantic models

Implementation Order

  1. S3-001: Engagement Letter Generation
  2. Domain models (engagement, template, fee schedule)
  3. Repository layer
  4. Template rendering service
  5. API endpoints
  6. Unit and integration tests

  7. S3-002: Engagement Letter Signature

  8. Google Workspace service (signatures)
  9. Signature workflow integration
  10. Webhook handler
  11. Integration tests with mock Google API

  12. S3-003: Form 7216 Consent Management

  13. Consent domain model
  14. Repository and workflow
  15. API endpoints
  16. Consent validation in disclosure workflows

Test Coverage Requirements

Component Unit Tests Integration Tests E2E Tests
Engagement domain 10+ - -
Engagement repository - 15+ -
Template service 10+ - -
Engagement workflow 15+ - -
Engagement API - - 10+
Google service 10+ - -
Consent domain 5+ - -
Consent repository - 10+ -
Consent API - - 5+

Dependencies

External Services

Service Purpose Config Key
Google Workspace Document signatures config.google
S3 Signed document storage config.s3

Internal Dependencies

Component Dependency
EngagementWorkflow AuroraService, GoogleService, S3Service, EmailService
ConsentWorkflow AuroraService, GoogleService, S3Service

Completion Checklist

  • S3-001 implemented and tested
  • S3-002 implemented and tested
  • S3-003 implemented and tested
  • All tests passing (unit, integration, e2e)
  • ARCHITECTURE.md updated
  • This document updated with completion status