Planning material — fictional examples, no production behavior

Client Portal Domain Model

Status

Current design direction — not approved for implementation. This document extends the architecture in the revised client portal plan. It defines the portal’s business concepts and boundaries. Authentication, session, credential, and identity-verification mechanics are defined in the authentication design.

The model is intentionally forward-looking. It is not a database migration, API contract, production-readiness claim, or record of a real client.

Purpose and boundary

The client portal is a collaboration surface for moving a prospective client from an initial inquiry to an approved agreement and deposit. It preserves the commercial discussion and human decisions that lead to an engagement. After a deposit is confirmed, delivery conversation moves primarily to Slack while the portal remains available for commercial context.

The portal is not the authoritative system for:

Stripe remains authoritative for invoices and payments. A selected external signature provider will remain authoritative for any legally binding signing ceremony.

Model overview

erDiagram
    USER ||--o| STAFF_USER : "may be"
    USER ||--o| CLIENT_PROFILE : "may be"
    USER ||--o{ ORGANIZATION_MEMBERSHIP : holds
    ORGANIZATION ||--o{ ORGANIZATION_MEMBERSHIP : grants
    ORGANIZATION ||--o{ ENGAGEMENT : owns
    ENGAGEMENT ||--|| INQUIRY : begins_with
    ENGAGEMENT ||--o{ MESSAGE : contains
    ENGAGEMENT ||--o{ STAFF_NOTE : contains
    ENGAGEMENT ||--o{ PROPOSAL : contains
    ENGAGEMENT ||--o{ AGREEMENT : contains
    ENGAGEMENT ||--o| DEPOSIT_REFERENCE : may_require
    ENGAGEMENT ||--o| DELIVERY_HANDOFF : may_reach
    PROPOSAL ||--o{ DOCUMENT_VERSION : publishes
    AGREEMENT ||--o{ DOCUMENT_VERSION : publishes
    DOCUMENT_VERSION ||--o{ REVIEW_DECISION : receives
    USER ||--o{ REVIEW_DECISION : makes
    USER ||--o{ ENGAGEMENT_READ_STATE : tracks
    AGENT_INTEGRATION ||--o{ AGENT_GRANT : receives
    AGENT_GRANT }o--|| ENGAGEMENT : permits
    ENGAGEMENT ||--o{ DRAFT_WORKSPACE : prepares
    DRAFT_WORKSPACE ||--o{ DRAFT_REVISION : records
    AGENT_INTEGRATION ||--o{ DRAFT_REVISION : may_create
    USER ||--o{ CONTACT_POINT : owns
    USER ||--o{ COMMUNICATION_CONSENT : grants
    USER ||--o{ NOTIFICATION_PREFERENCE : configures
    NOTIFICATION_INTENT ||--o{ DELIVERY_ATTEMPT : produces

The diagram shows the important conceptual relationships, not a required physical schema. Shared concepts may be represented by separate tables or typed records when implementation evidence justifies that choice.

Identity and tenancy

User

User is the stable application identity. Its identifier is an immutable UUID; email addresses and phone numbers are attributes, not foreign keys or durable identifiers. A user may be a staff user, a client profile, or both if a future use case requires it.

Staff user

StaffUser represents an authorized member of the consulting practice. Staff authority is independent of client organization membership. Todd initially holds the administrative staff role and may qualify inquiries, create or link organizations, invite clients, publish documents, designate approvers, record external payment observations, and manage agent integrations.

Client profile

ClientProfile holds client-facing profile information and references the user’s verified contact points. It does not determine access by itself. Access comes from active organization membership.

Organization and membership

Organization is the tenant boundary for authenticated client access. An OrganizationMembership links a user to an organization with an explicit client role and lifecycle state. An active member may view and discuss the organization’s engagements. Structured proposal or agreement approval also requires designation as the approver for the applicable document.

An organization may have multiple members and engagements. Membership never grants access to another organization, and interface filtering is not an authorization control.

Invitation

Invitation records Todd’s intent to add a particular email address to an organization. It has an expiry and can be accepted, revoked, or replaced. The invitation process and account proof are described in the authentication design; accepting an invitation activates the corresponding membership.

Commercial engagement

Inquiry

Inquiry is untrusted information submitted by an unauthenticated prospective client through the public consulting site. It preserves the structured form fields, submitter contact snapshot, receipt time, source, idempotency key, and qualification outcome. It does not grant portal access. Its detailed states, transition rules, consultant review experience, and notifications are defined in the inquiry onboarding workflow.

A public submission creates only the durable inquiry and the staff-owned review context needed to assess it. It never creates an account, organization, membership, or invitation. Todd may mark the inquiry as qualified, declined, or spam. After qualification, a separate, deliberate provisioning action creates or links an organization, creates the prequalification engagement and pending membership, and preserves the original inquiry history. Invitation sending remains another explicit consultant action.

Engagement

Engagement is the durable container for inquiry context, conversation, commercial documents, review decisions, deposit observation, and delivery handoff. Its normal lifecycle is:

prospect -> negotiating -> awaiting_deposit -> delivery -> closed

Declined and spam inquiries end before negotiation. The normal commercial path is flexible: Todd may publish multiple proposals, skip a proposal when it is unnecessary, or withdraw an obsolete document.

Before qualification and provisioning, the inquiry review context is visible only to staff. Once its engagement is created and linked to an organization, only active members receive access through that organization boundary.

Proposal and agreement

Proposal and Agreement are distinct commercial document types with shared review behavior. Each has:

Published versions contain an immutable native-content snapshot, content hash, version number, publisher, and publication time. A PDF export or external canonical-document reference is an optional derivative, not the identity of the version.

The review lifecycle is:

draft -> in_review -> changes_requested | approved
                    -> superseded | withdrawn

An active organization member may discuss a version. Only its designated approver may request changes or approve it. Publishing a replacement closes outstanding review requests and supersedes the previous current version. Historical comments and decisions remain attached to their original version and never transfer to a replacement.

Agreement approval is authenticated business approval of the displayed version. It must not be described as an electronic signature. If legal signing is required, the portal links the approved version to an external provider’s authoritative process.

Draft workspace and AI assistance

DraftWorkspace is private to staff and exists separately from published versions. DraftRevision preserves the content, creator, creation time, and available workflow or model provenance. It supports comparison and recovery without presenting internal generation attempts to clients.

AI output is always a draft. An agent cannot publish it, send it to a client, make a review decision, or cause an external action. A staff user must select and publish the client-visible content.

Conversation and activity

Messages and notes

Message is an authored, client-visible contribution to an engagement. It may be general discussion or reference exactly one immutable proposal or agreement version. A formal change request remains a review decision even when it also contains explanatory text.

StaffNote is a separately authorized internal record. It must not be exposed by client queries, serialization, search, or timeline projection. Per-item UI hiding is not an authorization boundary.

Timeline projection

The chat-like timeline is a read model rather than the source of business truth. It merges client-visible messages and append-only domain activity such as document publication, review decisions, agreement approval, deposit confirmation, and Slack handoff.

Items sort by occurrence time and then a stable unique identifier, oldest at the top and newest at the bottom. Internal views may additionally merge staff notes, inquiry qualification events, agent activity, and draft events.

EngagementReadState stores each member’s last observed position. It supports unread counts, suppresses notifications for already-viewed activity, and does not alter the timeline records.

External handoffs

Deposit reference

DepositReference is a synchronized observation, not a financial ledger. It references the approved agreement version, Stripe invoice identifier and hosted link, observed deposit state, observation source, recorder, and timestamp. Initial operation is manual; a later verified webhook may provide the same domain observation idempotently.

Recording a received deposit moves the engagement to delivery. The portal does not duplicate invoice line items, numbering, payment methods, receipts, taxes, disputes, or reconciliation.

Delivery handoff

DeliveryHandoff records when and by whom the primary interaction moved to Slack, with an optional stable destination reference. After handoff, the portal remains readable and supports secondary commercial discussion, but Slack owns the delivery conversation.

Notifications and contact preferences

ContactPoint represents a verified email address or E.164 mobile number. Authentication proves or changes contact points as described in the authentication design.

CommunicationConsent records the channel, consent state, wording version, collection source, timestamp, and available evidence. A verified mobile number is required for a client account, but SMS activity notifications require a separate, optional, revocable consent.

NotificationPreference records SMS eligibility, recipient timezone, and quiet-hour behavior. SMS is the primary portal-activity channel when consented; email is the fallback and remains the required channel for invitations, recovery, email changes, and security notices.

NotificationIntent is generated from a committed domain event. It identifies the recipient, category, safe deep-link destination, aggregation key, and delivery policy. DeliveryAttempt records provider identifiers, status, timestamps, and sanitized errors. Delivery failure never reverses the business action that produced the notification.

Initial client notification categories are:

The system suppresses self-notifications and activity the recipient has already viewed. Ordinary message bursts are coalesced for five minutes. Non-security SMS waits until 8:00 a.m.–8:00 p.m. in the recipient’s timezone. Messages identify the consultancy, describe only the activity category, and link to the portal without including client content, terms, or amounts.

SMS initially provides notifications only. Standard opt-in, opt-out, and help keywords update consent through verified, idempotent provider events. Other replies direct the client to continue in the portal and do not become timeline messages.

AI agent integration

AgentIntegration is a named, Todd-owned machine principal. It never impersonates a human user. AgentGrant combines explicit capabilities with an allowlist of organizations or individual engagements.

Within an allowed engagement, a granted agent may read inquiry content, client-visible activity, published documents, staff notes, and existing drafts. Draft-write access permits new private draft artifacts and attributed draft revisions. It does not permit deletion of history.

Agents cannot:

The portal exposes agent capabilities through the same versioned JSON:API boundary used by the application. Credential authentication and lifecycle are defined in the authentication design.

Invariants and validation scenarios

Deferred decisions

Physical tables, JSON:API resource shapes, retention periods, production rate limits, provider reconciliation schedules, signature-provider selection, and international messaging policy require separately reviewed implementation plans.