Implementation Portal Troubleshooting Runbook
Operational runbook for diagnosing backend issues in apps/backend/src/implementation-portal/.
Use this when team users or portal clients report OTP failures, blocked step actions, invoice issues, or attachment problems.
Scope
Primary codepaths:
interfaces/http/*.controller.tsinterfaces/guards/portal-session.guard.tsapplication/use-cases/*domain/entities/*domain/services/*
1) Symptom triage
| Symptom | Likely layer |
|---|---|
| Client cannot request OTP | RequestPortalOtpUseCase + email adapter |
| OTP verification fails | VerifyPortalOtpUseCase + portal session repository |
401 Portal session token is required | PortalSessionGuard header/cookie mismatch |
| Client cannot complete a document step | CompleteClientStepUseCase attachment precondition |
| Team cannot log time | LogTimeEntryUseCase + TimeEntry minimum-hours rule |
| Time entry edit/delete blocked | BoardStepController invoice guard (invoiceDraftId) |
| Invoice send fails | SendInvoiceDraftUseCase + payment adapter |
| Attachments fail upload | UploadStepAttachmentUseCase + storage adapter + MIME/size constraints |
| Board health unexpectedly red | OverdueCheckerService stale/overdue thresholds |
2) OTP and portal session flow checks
Expected flow:
POST /portal/:shareToken/auth/request-otpPOST /portal/:shareToken/auth/verify-otp- guarded portal write endpoint with session token
Validated rules from code:
- OTP request is intentionally non-enumerating from controller perspective (
204response path). - OTP TTL is 15 minutes.
- session TTL is 24 hours.
- session token can be provided by:
x-portal-session-tokenheaderflowpos-portal-sessioncookie
If clients still fail after OTP verify:
- confirm token is sent on write request
- confirm token is not stale (>24h)
- confirm
shareTokenpoints to expected board
3) Step-status failures
Team-side completion (board-steps endpoints)
Common blockers:
- document step has zero attachments (
Document steps require at least one attachment...) - invalid state transition (for example completing from
pendinginstead ofin_progress) - approval flow misuse (
approve/rejectrequired for approval step types)
Client-side completion (portal endpoints)
Common blockers:
- step is not client-assigned
- document step has no attachments
- client approval called before step reached
completed|approved
4) Time-entry failures
From LogTimeEntryUseCase and TimeEntry entity:
- step must be hourly billed (
billableType=hourly) - minimum entry is
0.25hours
From BoardStepController:
- edit/delete of time entries is blocked once step has
invoiceDraftIdset
When users report "time log won't save":
- verify step billing type
- verify
hours >= 0.25 - verify step has not already been linked to an invoice draft
5) Attachment failures
From UploadStepAttachmentUseCase and StepAttachment entity:
- max file size: 50 MB (
STEP_ATTACHMENT_MAX_BYTES) - MIME type must be in the domain allowlist
- storage key format:
portal/{boardId}/steps/{stepId}/{timestamp}-{sanitizedFilename}
From GcsStorageAdapter:
- requires
GCS_PUBLIC_BUCKET - signed URLs are generated on read endpoints
Failure patterns:
Unsupported file type-> MIME not allowedFile size exceeds the 50 MB limit-> too large- storage configuration errors -> bucket missing or GCS credentials issue
6) Invoice failures
Draft generation
GenerateInvoiceDraftUseCase only includes unbilled steps and uses InvoiceCalculatorService.
Frequent causes of empty/low totals:
- steps are
non_billable - step statuses are not in billable completion states
- hourly steps have no time entries
- steps were already linked to another invoice draft (
invoiceDraftId)
Send flow
SendInvoiceDraftUseCase sequence:
- load draft + board
- create invoice in payment adapter
- add line items
- finalize
- mark sent
- send notification (best-effort)
If send fails:
- verify draft exists and belongs to business
- verify draft is still in
draftstatus - inspect payment adapter integration logs
7) Board health anomalies
OverdueCheckerService rules:
- green: 0 overdue
- yellow: 1-2 overdue
- red: 3+ overdue OR stale board (>7 days without step updates)
Terminal statuses excluded from overdue counting:
completedapprovedclient_approvedrejected
If board health appears too severe, confirm stale condition before changing overdue logic.
8) Safe recovery actions
- Re-issue OTP and retry portal session flow.
- Re-upload required document attachment before step completion.
- Regenerate invoice draft after resolving step/time-entry eligibility.
- Re-run send action once payment adapter dependency is healthy.
- Regenerate board share token for compromised or misrouted links.