Gap 1: Withdrawal (ACHD) for AV Channel
ScaAchService already handles ACHD. The gap is AvAchService which currently only processes ACHC (contributions). The OLZ BetaRequestFactory, RttRequestFactory, and WwsInstruction all have dormant ACHD logic that was never exposed via a handler.
flowchart TD
REQ(["POST /ach/transaction
TransactionType = ACHD"])
R{"Route by OriginId"}
SCA["ScaAchService
Already handles ACHD ✓"]
AV["AvAchService
Currently ACHC only ✗"]
GAP["GAP: AvAchService needs
1. ACHD routing
2. Distribution PECO code
3. Tax withholding calc
4. Net vs Gross distribution
5. IRA-specific eligibility rules"]
OLZ["OLZ Reference:
BetaRequestFactory has ACHD PECO codes
RttRequestFactory has ACHD SLA logic
WwsInstruction infers ACHD type"]
REUSE["Reuse NLZ pattern:
Add ACHD branches to
EligibilityService + ComplianceService"]
REQ --> R
R -->|SCA| SCA
R -->|AccountView| AV --> GAP
GAP --> OLZ
OLZ --> REUSE
style SCA fill:#e6faf5,stroke:#00b894
style GAP fill:#fde8e6,stroke:#e74c3c
style OLZ fill:#fff8ec,stroke:#f39c12
style REUSE fill:#e3f0ff,stroke:#1e88e5
OLZ Dormant Withdrawal Code
| File (investor-ach-api) | ACHD Logic |
BetaRequestFactory.cs | AchType hardcoded to "ACHD". GetIrasPecoCode: ACHD → "Net Distribution PECO Code", ACHC → "Contribution PECO Code". Handles INS_PER_U/INS_PER_C with inner ACHD/ACHC switch. |
RttRequestFactory.cs | SLA routing: margin+ACHD = SLA 2, managed+INS_PER = SLA 3, IRA (ZH/ZE/ZG) = SLA 3, advisory ops = SLA 1 |
WwsInstruction.cs | InferTransactionType(): ManualCreditIndicator=true + ManualDebitIndicator=false → "ACHD" |
RulesRequestFactory.cs | SelectedNetGrossDistribution, FullDistribution balance. Recognizes INS_PER_C/R/U, INS_STD_C/U |
CmRequestFactory.cs | DistributionDay and TotalWithdrawalAmt fields exist but set to null (never populated) |
Gap 2: Recurring/Periodic ACH
Must be built from scratch. OLZ has the DB schema (CmPeriodicInstruction) and request type codes (INS_PER_C/R/U) but zero handler code. NLZ has nothing for recurring.
flowchart TD
subgraph OLZ_Schema["OLZ: Schema exists but unused"]
DB1["CmPeriodicInstruction table
FrequencyCode · CycleBeginDate · CycleEndDate"]
DB2["CmRequestAggregate
PeriodicFrequencyCode · BETAPeriodicInstructionId"]
DB3["Stored procs support CmPeriodicInstructionId"]
DB4["Request type codes
INS_PER_C · INS_PER_R · INS_PER_U"]
DB5["Zero handler code ✗"]
end
subgraph NLZ_Gap["NLZ: Must build in cam repos"]
N1["New endpoint: POST /ach/periodic-instruction"]
N2["PeriodicInstructionService
Frequency calc: W · BW · M · Q · A"]
N3["EligibilityService: pre-validation at setup"]
N4["cam-system-api: new periodic DB schema"]
N5["cam-mm-backgroundservice-api:
ProcessPeriodicTransactionRequestsService"]
N6["RTT: INS_PER_C + INS_PER_R SLA routing"]
N7["Kafka: periodic lifecycle events"]
end
DB1 -.->|Reference| N4
DB4 -.->|Reference| N6
DB5 -.->|Must build| N1
DB5 -.->|Must build| N2
DB5 -.->|Must build| N5
style OLZ_Schema fill:#fff8ec,stroke:#f39c12,color:#1a1d2e
style NLZ_Gap fill:#fde8e6,stroke:#e74c3c,color:#1a1d2e
Gap 3: Future-Dated Deposits
OLZ bug: ProcessRequestsHandler.cs lines 161-170 explicitly cancel FutureDate requests — only AfterHours type is processed. NLZ's CheckBetaOffHours handles off-hours queueing, but explicit future-date support in AvAchService needs verification.
Request Type Code Reference
| Code | Meaning | OLZ Usage | NLZ Status |
ACHC | One-time ACH Contribution (deposit) | PostAchContributionsHandler | Built |
ACHD | One-time ACH Distribution (withdrawal) | BetaRequestFactory, RttRequestFactory — no handler | Partial SCA has it, AV gap |
INS_PER_C | Periodic Instruction Create | RTT SLA only, no handler | Not built |
INS_PER_R | Periodic Instruction Recurring | RTT SLA only, no handler | Not built |
INS_PER_U | Periodic Instruction Update | BetaRequestFactory PECO code only | Not built |
Risk Register
| Risk | Severity | Mitigation |
| EligibilityService has no ACHD-specific rules (IRA limits, margin checks) | High | Port OLZ FICO ACHD rules into NLZ inline EligibilityService. Reference RttRequestFactory IRA/margin/managed-account SLA logic. |
| Periodic scheduler double-execution across multiple backgroundservice pods | High | Add distributed lock (Redis or DB advisory) to ProcessPeriodicTransactionRequestsService |
| cam-system-api BETA payload may not support distribution PECO codes | Medium | Verify cam-system-api BETA request builder handles ACHD. Reference OLZ BetaRequestFactory.GetIrasPecoCode() |
| Tax withholding logic not in any NLZ service | Medium | Build TaxWithholdingService in cam-movemoney-process-api. OLZ CmRequest has FedTax/StateTax fields but never populated. |
| No periodic instruction DB schema in cam-system-api | Medium | Design new table based on OLZ CmPeriodicInstruction (FrequencyCode, CycleBeginDate, CycleEndDate, AmountType) |
| OLZ FutureDate requests canceled in ProcessRequestsHandler | Low | NLZ handles off-hours queueing. Verify explicit future-date support in AvAchService. |
POC Deliverables
| # | Item | NLZ Repo | Owner | Target |
| 1 | Add ACHD handling to AvAchService (distribution PECO, tax withholding, IRA rules) | cam-movemoney-process-api | Dev | Sprint +1 |
| 2 | Add ACHD-specific eligibility rules to inline EligibilityService | cam-movemoney-process-api | Dev | Sprint +1 |
| 3 | Design periodic instruction DB schema | cam-movemoney-system-api | Kaushik | Sprint +1 |
| 4 | Build POST /ach/periodic-instruction endpoint (create/modify/cancel) | cam-movemoney-process-api | Dev | Sprint +2 |
| 5 | Build ProcessPeriodicTransactionRequestsService | cam-mm-backgroundservice-api | Dev | Sprint +2 |
| 6 | Verify cam-system-api BETA request supports ACHD PECO codes | cam-movemoney-system-api | Kaushik + BETA team | Sprint +1 |
| 7 | Integration test: ACHD via NLZ path (flag ON, AV channel) | cam-movemoney-process-api | QE | Sprint +2 |
| 8 | Add Kafka events for periodic transaction lifecycle | cam-movemoney-process-api | Dev | Sprint +2 |