Product2 weeks \u2014 idea to production

Eternal Portraits

A premium AI-generated pet portrait e-commerce platform with print-on-demand fulfillment. Pet owners upload a photo and receive a Renaissance-style classical oil painting portrait as a digital download or fine art print shipped globally.

Built using an AI-powered development workflow with Lovable as the primary IDE, Shopify for commerce, Gelato for fulfillment, and Supabase for backend orchestration. ChatGPT and Claude served as strategic partners throughout development. This project represents a new capability: full-stack e-commerce with AI generation, print-on-demand integration, and operational automation.

Digital Download $29Fine Art Print 8×10 $59Fine Art Print 12×16 $89

Tech Stack

LayerTechnology
Frontend + AI generationLovable (Gemini-based)
CommerceShopify Basic
PaymentsShopify Payments (Stripe)
BackendSupabase
Print fulfillmentGelato API v4
Image upscalingReplicate — clarity-upscaler
NotificationsTelegram Bot API
AnalyticsPostHog

Core Order Flow

1

User uploads pet photo (private bucket)

2

Client-side pre-crop to 4:5 vertical (Canvas API + react-image-crop)

3

Lovable AI (Gemini) generates classical portrait preview

4

Preview saved to public bucket (832×1040px)

5

User approves → selects product → adds to Shopify cart with portrait URL as line item property

6

Shopify checkout → payment via Shopify Payments / Stripe

7

Shopify fires orders/paid webhook

8

Supabase Edge Function: verify HMAC, respond 200 immediately, then background pipeline via EdgeRuntime.waitUntil()

9

Background: insert order → call Replicate upscaler (30–90s) → save final PNG → create Gelato print order → update status

10

Gelato prints and ships → tracking synced to Shopify


Key Engineering Decisions

Each decision includes the approaches evaluated and why they were discarded.

01

Gelato Integration — Custom API Over Native App

The Problem

Gelato’s native Shopify app auto-imports orders but has no concept of a dynamically generated image. Every order would require manual artwork upload, defeating the entire value proposition.

Approaches Discarded

Gelato native app only: Sees “Fine Art Print 8×10” with no artwork — creates blank orders.
Gelato app with Personalization Studio: Dynamic artwork feature is designed for user-uploaded files within Shopify’s product page, not externally generated URLs.

Chosen Approach

Custom Gelato API v4: image URL travels as a cart attribute through checkout. After payment, a Supabase Edge Function reads the URL and calls Gelato directly. Full control, fully automated.

Lesson learned: The native app was kept installed solely for its shipping rate profiles. Uninstalling it removes the fulfillment location from products, breaking shipping rate calculation at checkout — Shopify shows “Shipping not available” for all addresses.


02

Shopify Webhook Timeout — Background Processing

The Problem

Shopify webhooks have a 5-second response timeout. The post-payment pipeline (upscaling + Gelato order) takes 30–120 seconds.

Approaches Discarded

Synchronous processing: Shopify marks webhook as failed after 5s and retries — causes duplicate Gelato orders.
External queue (Redis/Upstash): Adds infrastructure complexity and cost for an early-stage product.

Chosen Approach

EdgeRuntime.waitUntil(): respond 200 to Shopify immediately after HMAC verification, run the entire pipeline as a non-blocking background promise. Zero additional infrastructure. 150s free plan limit is well within upscaler runtime.


03

Image Upscaler — Preserving Painterly Aesthetic

The Problem

AI generates ~1024×1536px previews (~102 DPI). Gelato requires 300 DPI for fine art prints. Standard upscalers destroy the oil painting texture.

Approaches Discarded

Real-ESRGAN: Over-smooths the image — craquelure, brushstrokes, and aged-canvas texture get eliminated. Result looks like clean digital art.
Sharp/bicubic upscaling in Edge Function: Purely geometric — same quality problem, no texture preservation.

Chosen Approach

philz1337x/clarity-upscaler on Replicate: accepts a text prompt during upscaling. Prompting for craquelure, aged canvas, brushstrokes preserves the painterly aesthetic. Cost ~$0.05/image. creativity: 0 + resemblance: 1 prevents hallucinations that alter the pet’s likeness.

Lesson learned: Originally triggered at cart-add time (charged per abandoner). Moved to post-payment only — ~$0.05 per order = 0.06% of Fine Art Print revenue.


04

Portrait Orientation — Two-Layer Solution

The Problem

AI generates portraits matching input orientation. Landscape input → landscape output → aggressive 4:5 center-crop → degraded composition.

Approaches Discarded

Post-generation crop only: Works for vertical inputs but causes severe composition issues for landscape — pets get cut off at head or body.
Server-side pre-crop: Adds latency and a round-trip. Frontend already has the image.

Chosen Approach

Client-side pre-crop using Canvas API + react-image-crop when landscape photo is detected. User can adjust the crop area. Post-generation server-side crop kept as safety net.


05

Payments — Unlocking Shopify Payments

The Problem

Shopify Payments not available for stores registered in Colombia. Alternative providers (Mercado Pago, dLocal) have poor UX recognition for US/Canada customers.

Approaches Discarded

Mercado Pago: 3.49%+ fees, poor brand recognition for US/Canada market.
dLocal / ONERWAY / Tilopay: Unknown brands create checkout friction and abandonment.

Chosen Approach

Configured the store through a US-eligible business setup so Shopify Payments could be enabled for the target market. This reduced checkout friction by using a familiar payment flow and accelerated payment methods such as Apple Pay and Google Pay.


06

Operational Monitoring — Telegram Over Email

The Problem

Solo-founder product needs immediate, mobile-first, actionable alerts — not email.

Approaches Discarded

Email (Resend/SendGrid): Easy to miss, no interactivity for triggering backend actions.
Slack/Discord webhook: Requires another app open, no native interactive buttons.

Chosen Approach

Telegram Bot with inline keyboard buttons. Three Edge Functions: telegram-notify (sends alerts), telegram-callback (handles button presses), retry-order-upscale (re-runs failed pipeline for a specific order). Failed orders can be retried from the phone without any dashboard.


Security Issues Found Pre-Launch

IDOR on generate-signed-url

Root cause: Function accepted any order_id without verifying caller ownership

Fix: Added email/order_id ownership check before generating download URL

Privilege escalation on admin_users

Root cause: INSERT RLS policy was WITH CHECK (true) — any authenticated user could self-promote to admin

Fix: Restricted to service role only

Digital downloads exposed via public bucket

Root cause: Public final-assets bucket + readable generation_requests table = enumerable download paths

Fix: Restricted generation_request_id visibility in public queries. Bucket stays public because Gelato needs direct download access.

What Was Intentionally Not Built

Scope discipline is part of the engineering. These were evaluated and deferred.

Custom order tracking dashboard — Shopify + Gelato cover this natively
Canvas or framed product variants — kept catalog minimal for launch
Human/couple/family portraits — pets only, brand focus
Custom email system — Shopify handles transactional emails
External AI provider migration — Lovable’s Gemini kept to avoid destabilizing proven generation quality
fal.ai integration — prototyped and rolled back; quality and reliability did not justify added complexity

Why this project matters

Eternal Portraits demonstrates what I can ship: a complete, revenue-ready product from idea to production in two weeks using an AI-powered development workflow. It combines:

Need a product built fast without cutting corners?

I build production-ready products using AI-native workflows, real integrations, and disciplined engineering.