Loan Agreement Generation
Overview
The LOC Service generates loan agreement PDFs using LaTeX templates. The agreements are generated when a loan application is approved and include all required disclosures, loan terms, and installment schedules.
Architecture
Loan Application Approved
│
▼
┌─────────────────────────┐
│ API Lambda │
│ (generates event) │
└───────────┬─────────────┘
│
▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ SQS Queue │ OR │ Direct Invoke │
│ (async generation) │ │ (sync generation) │
└───────────┬─────────────┘ └───────────┬─────────────┘
│ │
└────────────┬───────────────────┘
│
▼
┌─────────────────────────┐
│ Agreements Generator │
│ Lambda │
└───────────┬─────────────┘
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────┐ ┌────────────┐
│ LaTeX │ │Tectonic│ │ S3 │
│ Template │ │ Render │ │ Upload │
└────────────┘ └────────┘ └────────────┘
Components
Agreements Generator Lambda (cmd/agreements-generator)
The Lambda function handles both SQS and direct invocation:
-
SQS Mode: Processes batch messages from the queue
-
Direct Invoke Mode: Returns the S3 key immediately for synchronous workflows
Template System
Template Files
The templates are embedded in the binary using Go’s embed package:
| File | Purpose |
|---|---|
|
Main LaTeX template with placeholders |
|
Primary font |
|
Bold font variant |
|
Company logo for header |
|
Tectonic binary for PDF rendering |
Template Delimiters
The template uses custom delimiters to avoid conflicts with LaTeX syntax:
|@ .FieldName @|
Example in the template:
\newcommand{\BorrowerName}{|@ .Name @|}
\newcommand{\LoanNumber}{|@ .LoanNumber @|}
\newcommand{\PrincipalAmount}{\$|@ .LoanAmount @|}
Template Data Structure
The AgreementGenerateEvent struct defines all available template fields:
type AgreementGenerateEvent struct {
UserID string `json:"user_id"`
LoanApplicationID string `json:"loan_application_id"`
// Borrower Information
Name string `json:"name"`
Address string `json:"address"`
CityStateZip string `json:"city_state_zip"`
PhoneNumber string `json:"phone_number"`
// Loan Identification
LoanNumber string `json:"loan_number"`
LoanDate string `json:"loan_date"`
// Loan Amounts
LoanAmount string `json:"loan_amount"` // Principal
TotalAmount string `json:"total_amount"` // Total to repay
AmountDisbursed string `json:"amount_disbursed"` // Net to borrower
// Fee Information
APR string `json:"apr"`
AdminFee string `json:"admin_fee"`
OriginationFee string `json:"origination_fee"`
OriginationFeePercent string `json:"origination_fee_percent"`
// Installment Information
NumInstallments int `json:"num_installments"`
InstallmentSummary string `json:"installment_summary"`
InstallmentStart string `json:"installment_start"`
InstallmentEnd string `json:"installment_end"`
Installments []LoanInstallments `json:"installments"`
}
type LoanInstallments struct {
Amount string `json:"amount"`
Due string `json:"due"`
}
LaTeX Escaping
User-provided data must be escaped to prevent LaTeX injection and rendering errors. The Escape function handles special characters:
var replacements = []string{
"&", `\&`,
"%", `\%`,
"$", `\$`,
"#", `\#`,
"_", `\_`,
"{", `\{`,
"}", `\}`,
"~", `\textasciitilde`,
"^", `\textasciicircum`,
`\`, `\textbackslash`,
}
All string fields in the event are automatically escaped before template evaluation.
Rendering Process
Step 1: Prepare Temp Directory
tmp, err := os.MkdirTemp("", "*-loan-agreement")
defer os.RemoveAll(tmp)
Step 2: Copy Embedded Files
All template files are copied from the embedded filesystem to the temp directory:
-
LaTeX source files
-
Font files
-
Logo image
-
Tectonic binary
Step 3: Inject Data
The template is evaluated with the escaped data:
tmpl, err := template.New(fileName).Delims("|@", "@|").Parse(string(templateData))
err = tmpl.Execute(writer, data)
Error Handling
Updating the Template
To modify the loan agreement template:
-
Edit
pkg/latex/templates/loan_agreement.tex -
Un-skip the
TestRenderLoanAgreementunit test and run the unit test -
Ensure all placeholders use
|@ .FieldName @|format -
Verify special characters are properly escaped
Testing
Dependencies
Tectonic
Tectonic is a modernized TeX/LaTeX engine that:
-
Self-contained (no external TeX installation needed)
-
Caches packages locally
-
Produces consistent output
The binary is embedded in the Lambda deployment package.
Code Location
| Component | Path |
|---|---|
Lambda Handler |
|
Renderer |
|
Worker |
|
Escaping |
|
LaTeX Template |
|
Fonts |
|
Logo |
|