<aside>

Goal

Automate the ingestion of POS customer exports from S3 into Supabase (CRM), with validation, rejection logging for audit, and Slack notifications.

Solution

Steps

1. Receive the S3 Event

Node: Receive S3 Event (Webhook)

Purpose: Triggers when the POS places a file in S3. Carries bucket, key, etag, presignedUrl, etc.

Configuration:

2. Download CSV from S3

Node: S3: Download CSV

Purpose: Uses the bucket and key from the webhook to fetch the file.

Configuration:

3. Parse CSV into Items

Node: Parse CSV to Items (Extract From CSV)

Purpose: Converts the CSV to an array of JSON items.

Configuration:

4. (Test Only) Limit

Node: Limit to 100 Items

Purpose: Keeps the workflow quick and safe while testing.

Configuration:

5. Validate Contact

Node: Valid Contact? (Email / Phone)

Purpose: Expression checks: Email || Phone.

Configuration:

6. Valid Branch

Loop Over Items

Node: Loop Over items

Purpose: Processes each valid record individually for better error handling.

Configuration:

Format for Supabase

Node: Format for Supabase (single Code node)

Purpose: Normalizes fields for database insertion.

Configuration:

javascript

return { json: { contact_key: $json.CustomerID || $json.Email || $json.Phone, email: $json.Email, phone: $json.Phone, first_name: $json.FirstName, last_name: $json.LastName, address: $json.Address, postal_code: $json.PostalCode, date_of_birth: $json.DateOfBirth, gender: $json.Gender, s3_key: $('Receive S3 Event').first().json.Records[0].s3.object.key, etag: $('Receive S3 Event').first().json.Records[0].s3.object.eTag } };

Supabase: Create Row

Node: Supabase: Create Row

Purpose: Inserts valid records into the main customers table.

Configuration:

Send Valid Records Message

Node: Send a message (Slack)

Purpose: Notifies about successfully processed records.

Configuration:

7. Rejections Branch

Loop Over Rejections

Node: Loop over rejections

Purpose: Processes each rejected record for audit logging.

Configuration:

Format for Supabase (Rejects)

Node: Format for Supabase (Rejects)

Purpose: Builds rejection records with full audit trail.

Configuration:

javascript

return { json: { contact_key: $json.CustomerID || 'unknown', first_name: $json.FirstName, last_name: $json.LastName, address: $json.Address, postal_code: $json.PostalCode, gender: $json.Gender, reason: (!$json.CustomerID && !$json.Email && !$json.Phone) ? 'missing_id_email_phone' : (!$json.CustomerID) ? 'missing_customer_id' : (!$json.Email && !$json.Phone) ? 'missing_email_phone' : 'validation_failed', raw: JSON.stringify($json) } };

Supabase: Create Row โ€“ Rejections

Node: Supabase: Create Row โ€“ Rejections

Purpose: Inserts rejected records into audit table.

Configuration:

Send Rejections Message

</aside>


Screenshot 2025-09-11 210247.png

๐Ÿ“‚ Download & Explore the Workflow:

S3-Supabase Import Automation (JSON_file).json

View GitHub Repository :

S3-Supabase/S3-Supabase Import Automation (JSON_file).json at main ยท AlvLeoAI/S3-Supabase