Project

General

Profile

Feature #151 » README.md

README: NSDL SEZ BOE/DTA Lambda pipeline: Phase A (fetch, QC, stage) and Phase B (deliver to Frappe) - Akshath Shettigara, 10/15/2026 04:35 PM

 

type: redmine-readme
project: Canofy Process Standardization
subject: NSDL SEZ BOE/DTA Lambda pipeline: Phase A (fetch, QC, stage) and Phase B (deliver to Frappe)
story_key: nsdl-lambda-core-pipeline
generated_at: 2026-10-15T16:16:51+05:30
story_type: feature
attachments:

  • file: nsdl-lambda-core-pipeline_20261015-1616__NSDL_SEZ_BOE_Automation_Blueprint.md.attach
    description: Architecture and design rationale this build followed (Blueprint)
  • file: nsdl-lambda-core-pipeline_20261015-1616__NSDL_SEZ_BOE_Automation_BuildSpec_ClaudeCode.md.attach
    description: Phase-by-phase build specification (Phases 0-11)

NSDL SEZ BOE/DTA Lambda pipeline: Phase A (fetch, QC, stage) and Phase B (deliver to Frappe)

An AWS Lambda pipeline that downloads SEZ trade data from the NSDL portal, validates it per client, and creates the matching BOE / DTA documents with PDF attachments in each client's Frappe/Canofy site.

1. Summary

The existing fw_verify script did this for one client from a developer machine. This story turns it into a multi-client, scheduled AWS service. Phase A logs in to NSDL, exports the Bill of Entry (BE) and DTA Sale reports, routes each row to a client by IEC code, runs six QC checks per client and stages the records in DynamoDB. Phase B delivers one client's staged records to that client's Frappe site and attaches the NSDL print PDF. It lives in the repo canofy-NSDL-data-extraction (app/phase_a_fetch, app/phase_b_deliver, shared, template.yaml) and is deployed to the TEST stack nsdl-sez-boe-automation-test in ap-south-1. PROD is not deployed.

2. Requirement

# Requirement Source Status
R1 Port the proven fw_verify logic instead of rewriting it user (first message) Done
R2 Several clients from one NSDL export, routed by IEC; an IEC under two clients is a hard error Blueprint Done
R3 Rolling date window computed from the run date, not from config Build Spec Done (later changed, see Decisions)
R4 Per-client QC (six checks) and gating before anything is delivered Build Spec Done
R5 Phase A stages into DynamoDB and never talks to Frappe Build Spec Done
R6 Phase B pushes with each client's own scoped Frappe credentials Build Spec Done
R7 Credentials only in AWS Secrets Manager; non-secret constants as Lambda env vars user Done
R8 Monitoring: alert topic, dead-letter queue, alarms, stuck-record watchdog Build Spec Phase 8 Done (one alert not built, see section 8)
R9 Never invent values the spec marks as human-confirmed (retention days, cron time, credentials) user Done

Requirement that changed: R3 started as a 7-day window ending on the run date; the window later ended the day before the run date (NSDL data lags a day). That change is recorded in nsdl-aws-deploy-lambda-hardening.

3. Decisions

Decision Options considered Why this one Date
Config strategy Config file, Secrets Manager for everything, env vars Credentials in Secrets Manager; tuning constants as env vars in template.yaml 2026-09-12
Shared code packaging Lambda Layer, Docker context at repo root DockerContext: . with the Dockerfile in each app folder; no layer to publish 2026-09-13
Required deploy parameters Invent defaults, require a value S3RetentionDays and the cron expression are required with no default 2026-09-13
Secret name Unsuffixed (spec), suffixed nsdl-boe-automation-secrets-<Environment> so TEST and PROD can coexist 2026-09-13
Phase B runtime Spec's 300 s zip function, container image with Playwright Image with a 900 s timeout, because Phase B performs a real NSDL login and print-to-PDF 2026-09-13
Phase B query scope STAGED only (spec), STAGED and PUSHED A record that is pushed but fails its PDF attach must be retried 2026-09-13
Phase B trigger Synchronous API Gateway call, asynchronous API Gateway REST caps synchronous calls at 29 s; asynchronous returns 202 and Phase B updates the audit record itself 2026-09-13
Testing Local only, real AWS Test against deployed Lambdas and real AWS resources; no dry-run mode exists 2026-09-13

4. Logic & Workflow

Phase A (daily, EventBridge): run_date (default today UTC) -> window -> NSDL login -> export BE and DTA -> validate files -> store in S3 + run control -> parse -> route rows by IEC -> six QC checks per client -> stage as STAGED

  1. The event may carry run_date and force_refresh; a same-day re-run reuses the stored export unless force_refresh is set.
  2. Both exports are checked: file exists, is readable as NSDL's tab-delimited text, and has the columns the parser needs.
  3. Each row's IEC is normalised (stripped, zero-padded to 10 digits if numeric) and mapped to a client through the reverse map built from the secret. Unmapped IECs are logged and skipped.
  4. Records already in a terminal status in DynamoDB are excluded, then six QC checks run per client and pipeline: header count, invoice count, item count, shipment count, sum checks (quantity, duty, assessable value) and IEC consistency within a request.
  5. A passing client's records are staged as STAGED; strict mode withholds a client whose QC fails.

Phase B (per client, started by an API call or an invoke with client_name): read secret -> query STAGED/PUSHED -> create in Frappe (skip if exists) -> NSDL login -> fetch print PDF -> attach -> mark ATTACHED

  1. Look up the client's Frappe URL and API credentials in the secret.
  2. For each record, check Frappe by request_id first and create it only if missing; mark the record PUSHED.
  3. Log in to NSDL once, fetch each pending record's print PDF, attach it, mark ATTACHED (a TTL is set only at this terminal status).
  4. A failed push or attach leaves the status unchanged, so the next run retries it; there is no permanent-failure state.
  5. If a sync_run_name was given, update that audit document with the result.

5. Files & Components Changed

File / resource Type Change Purpose
app/phase_a_fetch/* Lambda code New Phase A: download, parse, route, QC, stage
app/phase_b_deliver/* Lambda code New Phase B: deliver and attach
app/watchdog/lambda_handler.py Lambda code New Hourly scan for records stuck in STAGED over 24 h
shared/ (iec, secrets_loader, json_utils, logger, frappe_client) Shared code New IEC routing, secret loading, Frappe REST client
template.yaml SAM template New S3, three DynamoDB tables, three functions, API Gateway, SNS, SQS, alarms, secret
events/*.json Test events New Payloads for manual invokes
README.md Docs New Secret shape, deploy parameters, testing, monitoring

6. Configuration & Deployment

  • Secret nsdl-boe-automation-secrets-<ENV>: NSDL_ACCOUNTS.<account> (username, password, entity id) and CLIENTS.<client> (IEC codes, Frappe URL, API key and secret). Values are entered by a human, never committed.
  • Env vars (names only): RAW_FILES_BUCKET, RUN_CONTROL_TABLE, STAGED_RECORDS_TABLE, RUN_GATE_TABLE, NSDL_BOE_SECRET_NAME, NSDL_BASE_URL, NSDL_MODULE_BE, NSDL_MODULE_DTA, NSDL_ACCOUNT_KEY, STEP2_QC_STRICT, STAGED_TTL_DAYS, PDF pause settings.
  • Parameters with no default: S3RetentionDays, DailyScheduleCronExpression.
  • Deploy: sam build then sam deploy (container images). After deploy, populate the secret and subscribe a real endpoint to the alerts topic.

7. Testing

Test Data / Site Expected Actual Status
Phase A real run Live NSDL, run date 2026-09-13 Records staged, QC pass 64 eap records staged: BE 31 requests / 161 invoices / 227 items; DTA 33 / 140 / 210; all QC checks passed Pass
Phase B real run eap TEST Frappe site All staged records delivered 64 of 64 delivered; 31 BE PDFs attached Pass
Idempotency stress test All 64 reset to STAGED, Frappe emptied No duplicates after a timeout and retry One Frappe document per request after the first run timed out at 900 s and was retried Pass

8. Known Limitations & Open Items

  • No dry-run mode: any invoke of Phase A logs in to the real NSDL portal, and any Phase B invoke writes to the Frappe site in the secret.
  • Blueprint's per-client "Phase B gate fails" alert has no infrastructure; the alerts topic has no subscribers until someone subscribes.
  • DynamoDB status is treated as the truth: a Frappe document deleted by hand is not re-created unless its record is reset.
  • A full-size batch can exceed the 900 s limit; the batch cap is in nsdl-pdf-attachment-be-dta.
  • Not confirmed: PROD deployment and the production Frappe deployment of the audit doctype.

9. Status

Item Value
Branch main (initial commit)
Commits 2e9ba74 Initial commit: NSDL SEZ BOE/DTA automation Lambda pipeline (2026-09-15)
PR None (direct initial push)
Version VERSION file added later (see nsdl-github-actions-deployment)
Deployed to TEST stack nsdl-sez-boe-automation-test, ap-south-1

10. References

Related stories: nsdl-aws-deploy-lambda-hardening, nsdl-pdf-attachment-be-dta, nsdl-frappe-trigger-sync-run, nsdl-architecture-documentation, nsdl-github-actions-deployment. Attachments: Blueprint and Build Spec (see front matter).

(1-1/3)