Implementation Portal Module
Technical module reference for apps/backend/src/implementation-portal/.
This page is focused on architecture and backend behavior. For operations and incident handling, use:
dev/runbooks/implementation-portal-troubleshooting
Module purpose
Implementation Portal models delivery work as tenant-scoped boards with:
- reusable templates (phases/steps)
- execution workflows for team and client participants
- billable tracking and invoice drafting
- portal-facing collaboration (attachments/comments) with OTP-secured write access
Hexagonal architecture mapping
Domain layer
Key entities:
ImplementationBoardBoardPhaseBoardStepTimeEntryStepAttachmentStepCommentInvoiceDraftGuideTemplate+ guide phase/step/resource entities
Key services:
BoardFactoryService(template -> board tree)InvoiceCalculatorService(billable line-item rules)OverdueCheckerService(board health scoring)
Ports:
- repositories for templates/boards/steps/invoices/client sessions
STORAGE_PORT,PAYMENT_PORT,NOTIFICATION_PORT
Application layer
Use-case orchestration under application/use-cases/*, including:
- template CRUD/clone/resource use cases
- board create/update/status lifecycle
- step completion/assignment/time/attachment/comment operations
- client OTP/session and portal step actions
- invoice draft generation and send flow
Infrastructure layer
- Kysely repositories (
infrastructure/persistence/kysely/*) - storage adapter:
gcs-storage.adapter.ts - payment adapter:
stripe-invoice.adapter.ts - notification adapter:
sendgrid-notification.adapter.ts - overdue queue processor:
overdue-notification.processor.ts
Interfaces layer
- staff-facing controllers:
guide-template.controller.tsimplementation-board.controller.tsboard-step.controller.tsinvoice-draft.controller.ts
- client-facing controller:
client-portal.controller.ts
- guard:
portal-session.guard.ts
Infrastructure concerns (HTTP/DB/GCS/Stripe/SendGrid) remain outside domain behavior.
Primary workflows
1) Guide template -> implementation board
- Team creates guide template.
- Team creates board with optional
templateId. BoardFactoryServiceclones template phases/steps and applies due offsets from board start date.
2) Team step execution
Team endpoints allow:
- step status transitions
- assignment and due-date updates
- time-entry logging on hourly steps
- step attachments and comments
3) Client portal flow
- Client reads board via
GET /portal/:shareToken. - Client requests OTP.
- Client verifies OTP and receives session token.
- Client uses guarded write endpoints (complete/approve step, upload, comment).
4) Invoicing
GenerateInvoiceDraftUseCasecomputes line items from eligible unbilled steps.- Team can edit line-item descriptions.
SendInvoiceDraftUseCasepushes invoice and items through payment adapter, finalizes, marks sent, then emits best-effort notification.
Step and billing rules
Step transitions
From BoardStep domain behavior and completion use cases:
pending -> in_progressin_progress -> completed(non-approval steps)in_progress -> approved|rejected(approval steps)rejected -> in_progress(rework)completed|approved -> client_approved
Completion constraints
- document steps require at least one attachment before completion (team + client paths)
- client completion is limited to client-assigned steps
- client approval requires current status
completedorapproved
Time-entry constraints
From LogTimeEntryUseCase and TimeEntry:
- allowed only when
billableType=hourly - minimum entry:
0.25hours
From step controller write guards:
- time entries cannot be edited/deleted once step is linked to an invoice draft
Invoice calculator rules
From InvoiceCalculatorService:
non_billable: excludedfixed: bill whencompleted|approved|client_approvedmilestone: only approval steps inapproved|client_approvedhourly:sum(hours) * hourlyRateonly whencompleted|approved|client_approved
File and comment behavior
Step attachments
From StepAttachment + upload use case:
- max size: 50 MB (
STEP_ATTACHMENT_MAX_BYTES) - MIME type must be in allowlist
- key pattern:
portal/{boardId}/steps/{stepId}/{timestamp}-{sanitizedFilename}
Storage adapter behavior:
- requires
GCS_PUBLIC_BUCKET - signed URLs generated for read actions in listing endpoints
Comments
From PostStepCommentUseCase:
- client-authored comments are always persisted as
client_visible - team comments can use internal/client visibility via team endpoints
Health and notification model
Health scoring
OverdueCheckerService:
- green: 0 overdue
- yellow: 1-2 overdue
- red: 3+ overdue OR stale board (>7 days without step updates)
Notification events
Notification port events currently include:
BOARD_ACTIVATEDCLIENT_STEP_READYIMPLEMENTER_STEP_DONESTEP_OVERDUEPHASE_COMPLETEDBOARD_COMPLETEDINVOICE_SENTFILE_SHARED
Emission points are use-case driven and mostly best-effort (non-blocking for main workflow).
Client session model
From OTP/session use cases and guard:
- OTP TTL: 15 minutes
- portal session TTL: 24 hours
- guard token sources:
x-portal-session-tokenheaderflowpos-portal-sessioncookie
Client portal read payload intentionally excludes billing-sensitive fields.
High-level endpoint groups
Team APIs
/businesses/:businessId/guide-templates/*/businesses/:businessId/implementation-boards/*/businesses/:businessId/board-steps/*/businesses/:businessId/invoice-drafts/*
Client portal APIs
/portal/:shareToken/portal/:shareToken/auth/request-otp/portal/:shareToken/auth/verify-otp- guarded portal write routes under
/portal/:shareToken/steps/*