Automated rental invoice pipeline
This pipeline runs fully automatically every weekday morning without any user interaction.EventBridge fires the scheduled rule
fetch_latest_invoice Lambda function.fetch_latest_invoice searches Gmail
fetch_latest_invoice retrieves the user’s OAuth 2.0 tokens from AWS Secrets Manager, creates a Gmail API client, and searches the inbox for the current month’s rental invoice email. If a matching invoice is found and no record exists in the RentalInvoices DynamoDB table for that month, the PDF attachment is uploaded to S3.S3 triggers parse_invoice
s3:ObjectCreated:* event on the rental-invoices-bucket (prefix invoices/, suffix .pdf) automatically invokes the parse_invoice Lambda function with the bucket name and object key.parse_invoice parses the PDF and writes to DynamoDB
parse_invoice downloads the PDF from S3, extracts the user ID from the object key path (invoices/{user_id}/rental/...), and calls HyresaviParser to extract structured invoice data. The parsed record — including InvoiceID, UserID, total amount, and due date — is written to the RentalInvoices DynamoDB table.DynamoDB stream triggers send_invoice_notification
RentalInvoices table has stream_view_type = NEW_AND_OLD_IMAGES. When a new record is inserted, the stream event source mapping delivers the record to send_invoice_notification with batch_size = 1 and starting_position = LATEST.send_invoice_notification publishes to SNS
send_invoice_notification reads the INSERT record from the stream, extracts Due Date and Total Amount from the new image, and publishes a message to the NewInvoiceTopicNotification SNS topic.SNS delivers to email and iOS
Manual rental invoice ingestion
This flow is triggered by the iOS app when the user explicitly requests a full sync of all rental invoices.iOS app calls the ingest endpoint
API Gateway routes to fetch_invoices
fetch_invoices Lambda function via AWS_PROXY integration.fetch_invoices queries Gmail and uploads PDFs
fetch_invoices authenticates with the Gmail API using stored OAuth tokens, searches for all rental invoice emails matching the configured sender and subject, and for each email whose invoice month is not yet in DynamoDB, downloads the PDF attachment and uploads it to S3.parse_invoice → DynamoDB → stream → notification).Response returned to iOS app
fetch_invoices returns the number of new invoices ingested, or a message indicating none were found.fetch_invoices chains into the same parse → notification pipeline as the automated flow. Each uploaded PDF fires a separate s3:ObjectCreated event.Retail invoice ingestion
Retail invoice ingestion is triggered either by the iOS app on demand or by a weekly EventBridge schedule.Trigger: API call or EventBridge schedule
fetch_retail_invoices uses the last_retail_invoice_fetch timestamp stored in the Users table for incremental fetching.Separately, a weekly EventBridge rule invokes fetch_retail_invoices automatically.fetch_retail_invoices reads VendorConfig
VendorConfig DynamoDB table for all active vendor entries. Each entry contains email_patterns and subject_keywords used to construct Gmail API search queries.Gmail API search per vendor
fetch_retail_invoices authenticates with the Gmail API and runs a targeted search. Duplicate detection prevents re-processing emails that have already been ingested.HTML attachments uploaded to S3
s3:ObjectCreated:* event on .html files triggers the parse_retail_invoice Lambda function.last_retail_invoice_fetch updated
fetch_retail_invoices updates the last_retail_invoice_fetch field in the Users table so the next run only fetches newer invoices.parse_retail_invoice) is triggered by S3 HTML uploads in the same way that parse_invoice is triggered by PDF uploads. HTML parsers per sub-type are planned — see the project roadmap in the README.