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 |
S3-003: Form 7216 Consent Management¶
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¶
- S3-001: Engagement Letter Generation
- Domain models (engagement, template, fee schedule)
- Repository layer
- Template rendering service
- API endpoints
-
Unit and integration tests
-
S3-002: Engagement Letter Signature
- Google Workspace service (signatures)
- Signature workflow integration
- Webhook handler
-
Integration tests with mock Google API
-
S3-003: Form 7216 Consent Management
- Consent domain model
- Repository and workflow
- API endpoints
- 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