DEV Community

Cover image for CraftscapeHK: Building an AI + AR Platform for Cultural Heritage on Google Cloud Run
Grace Yuen
Grace Yuen Subscriber

Posted on

CraftscapeHK: Building an AI + AR Platform for Cultural Heritage on Google Cloud Run

Try Our App

I'm writing this blog as a participant in Cloud Run Hackathon by Google Cloud

Throughout this month, we have built our project, CraftscapeHK, for the Google Cloud Run Hackathon. Here's how we leveraged Cloud Run to create a scalable, cost-effective solution for preserving Hong Kong's endangered traditional crafts.

Introduction

Hong Kong's traditional crafts—hand-carved mahjong tiles, painted porcelain, cheonsgam, and neon signs—are disappearing. More than 70% of craft shops have closed in recent years, typical revenues have fallen 30–50%, and 80% of artisans say their children won't continue the trade. The solution isn't nostalgic preservation—it's economic viability.

CraftscapeHK (藝守) is an AI + AR e-commerce platform that bridges cultural heritage with modern technology. We built it on Google Cloud Run, and in this post, I'll share how we leveraged Cloud Run's serverless architecture to create a scalable, cost-effective solution for preserving endangered crafts while connecting artisans with global audiences.


What is CraftscapeHK?

Users can:

  • Explore craft stories through an engaging Tinder-like interface
  • Design custom pieces using our AI Creation Studio and commission artisans directly
  • Experience AR exhibitions with 360° product views and immersive storytelling
  • Discover local events through a cultural events calendar
  • Support artisans by purchasing products and attending workshops

The platform integrates Google Gemini API for AI-powered design generation and uses AR for immersive 3D experiences.


Why Cloud Run?

We chose Cloud Run for three key reasons:

  1. Containerization-Native: Ship code in containers; Cloud Run handles the rest
  2. Cost-Effective: Pay only for actual request processing, perfect for unpredictable hackathon traffic
  3. Minimal Ops Overhead: No Kubernetes clusters to manage, no node pools to configure

Our architecture consists of:

  • Frontend Service: React 19 + Vite, served via Nginx on Cloud Run
  • Backend Service: NestJS + SQLite, running on Cloud Run
  • Container Registry (GCR): Image storage and versioning
  • Cloud Build: Automated CI/CD pipeline
  • Cloud Scheduler: Scheduled maintenance tasks

Architecture Overview

Architecture Diagram

1. Container Design & Optimization

Frontend Container

We built the frontend using a multi-stage Docker build approach. The builder stage compiles our React 19 + TypeScript code with Vite, while the production stage uses Nginx Alpine to serve the compiled assets. This drastically reduces the final image size to just ~15MB compared to ~400MB if we included the builder.

Key optimizations:

  • Multi-stage builds reduce final image size and attack surface
  • Alpine Linux base image minimizes container overhead
  • Nginx as reverse proxy handles static assets efficiently

Resource allocation:

  • Memory: 256Mi (sufficient for serving static assets)
  • CPU: 1 vCPU (adequate for request handling)
  • Timeout: 60 seconds (reasonable for frontend logic)
  • Max instances: 10 (prevents runaway scaling costs)

Backend Container

The backend uses a single-stage Docker build because we need TypeScript compilation and canvas dependencies at runtime for flexibility. This results in a ~250MB image, which is still lean for Cloud Run's container standards.

Why single-stage? We need build tools available in the production image for runtime operations and ensuring all dependencies are present.

Resource allocation:

  • Memory: 512Mi (handles NestJS runtime + database operations)
  • CPU: 1 vCPU (sufficient for API processing)
  • Timeout: 300 seconds (allows longer-running AI generation requests)
  • Max instances: 10 (prevents cascading failures)

2. Automatic Scaling

Cloud Run's built-in autoscaling is powerful:

Request arrives → Cold start (scale-to-zero)
   ↓
Container boots (2-3 seconds for backend, 1-2 for frontend)
   ↓
Request processes
   ↓
No traffic for 15 minutes → Scales down to 0 (no cost!)
   ↓
Next request triggers cold start again
Enter fullscreen mode Exit fullscreen mode

Why this matters for hackathons:

  • No cost during idle time: Perfect for projects with sporadic traffic
  • Automatic horizontal scaling: 5 concurrent requests? Spin up 5 instances automatically
  • Predictable billing: Only pay for CPU/memory while handling requests

3. CI/CD Pipeline with Cloud Build

Cloud Build orchestrates our entire deployment pipeline automatically on each GitHub push. The pipeline has several key steps:

Build Phase: Frontend and backend Docker images are built in parallel, tagged with both the commit SHA and latest tag for easy rollbacks.

Push Phase: Both images are pushed to Google Container Registry (GCR) with commit SHA tags and updated latest tags.

Deploy Phase: The backend service is deployed to Cloud Run first with environment variables like GEMINI_API_KEY injected at runtime, followed by the frontend deployment.

Initialization Phase: The pipeline waits for the backend service to be healthy, then seeds the SQLite database via an admin endpoint to ensure initial data is loaded.

Key benefits:

  • Automated on push: Every GitHub commit triggers a complete build and deployment
  • Commit SHA tagging: Easy rollbacks—just deploy a previous image version
  • Parallel builds: Frontend and backend build simultaneously for speed
  • Health checks: Database seeding only happens after backend is confirmed ready

4. Networking & Routing

Nginx acts as a reverse proxy on the frontend, routing requests intelligently between static content and backend APIs. Static assets like HTML, CSS, and JavaScript files are served directly from Nginx with minimal latency, while API requests are proxied to the backend Cloud Run service.

This design:

  • Serves static assets (React bundle) directly from Nginx with near-zero latency
  • Routes API calls to the backend service transparently
  • Reduces backend load and improves perceived application performance
  • Enables caching strategies at the proxy level

5. Database Strategy: SQLite in Container

We bundled SQLite directly in the backend container, seeding the database on deployment with craft data and artisan information. The database file persists within the container instance, surviving restarts within that instance's lifetime.

Why SQLite on Cloud Run?

  • No external database dependency: Simpler deployments with fewer failure points
  • Data persistence: The database survives within an instance and is restored across scale-ups
  • Cost: Zero database infrastructure costs—no Cloud SQL instances to maintain
  • Seeding on deploy: An admin endpoint initializes the database automatically on first deployment

Trade-offs:

  • ❌ Not suitable for multi-instance concurrent writes (SQLite has write-locking)
  • ✅ Perfect for read-heavy, artisan-focused platforms
  • ✅ Great for hackathon MVPs and proof-of-concepts

Data Flow: How Requests Travel Through Cloud Run

User Request
    ↓
[Frontend Cloud Run] (Nginx on port 8080)
    ├─ Static Assets (/index.html, /css/...) → Served directly from /usr/share/nginx/html
    └─ API Requests (/api/*) → Proxied to backend
         ↓
      [Backend Cloud Run] (NestJS on port 3000)
         ├─ API Processing
         ├─ SQLite Query
         └─ Gemini API Call (for AI image generation)
             ↓
             [Google Gemini API]
             ↓
    Response with generated image
             ↓
    JSON response
             ↓
    Frontend Renders UI
Enter fullscreen mode Exit fullscreen mode

Performance characteristics:

  • Cold start (first request in 15+ minutes): 2-5 seconds total
  • Warm start (subsequent requests): <100ms API latency
  • Static asset serving: <50ms (CDN-like caching via Nginx)

Cost Analysis: Why Cloud Run is Ideal for Hackathons

Compared to alternatives, Cloud Run shines for hackathon projects:

Cost Factor Cloud Run App Engine Kubernetes
Idle time cost $0 $10+/month $30+/month
Cold start 2-5s 3-8s 10+s
Billing granularity Per 100ms Per instance/month Per node/month
Ops complexity None Low High
Cost for 100K req/month ~$2 ~$15 ~$50+

Our actual estimate (assuming 100K requests/month with 2s avg processing):

  • Frontend: ~$0.30/month
  • Backend: ~$2-4/month (depends on Gemini API calls)
  • Total: ~$3-5/month

Key Features Leveraging Cloud Run

1. AI Image Generation

The backend integrates with Google Gemini API to generate custom craft designs based on user prompts. Users describe their vision, and the AI generates unique personalized craft designs that can be commissioned from artisans.

Cloud Run's 300-second timeout is crucial here, as AI model inference can take significant time. This generous timeout prevents requests from being cut off mid-processing, unlike traditional API Gateways with stricter limits.

2. Real-Time Artisan Messaging

Users can message artisans directly through the platform for custom orders and inquiries. These messages are stored in SQLite and retrieved instantly, enabling seamless communication between craftspeople and customers.

SQLite's reliability ensures messages aren't lost during container operations or scaling events.

3. AR Asset Serving

USDZ files (3D model format for augmented reality) are served as static assets from Nginx. These 3D craft models enable immersive AR experiences where users can visualize products in their own space before purchasing.

Cloud Run's efficient static file serving means AR assets load quickly and reliably across different network conditions.


Deployment Command: From Zero to Live

We simplified deployment to a single npm command that handles the entire process:

Within 3-5 minutes, the deployment pipeline:

  1. ✅ Builds the frontend Docker image with Vite
  2. ✅ Builds the backend Docker image with NestJS compiled
  3. ✅ Pushes both images to Google Container Registry
  4. ✅ Deploys backend to Cloud Run with environment variables
  5. ✅ Deploys frontend to Cloud Run with backend URL configured
  6. ✅ Seeds the SQLite database with craft and artisan data
  7. ✅ Service is live and accessible globally

Lessons Learned: Building on Cloud Run

1. Cold Starts Matter

For user-facing services, 2-5 second cold starts are acceptable when the service starts from scratch after being idle. However, if cold starts become problematic, you can configure minimum instances to keep at least one warm. This trades off cost for guaranteed fast response times. We didn't use minimum instances to stay within tight hackathon budgets.

2. SQLite Write Limitations

SQLite's write-locking mechanism isn't ideal for high-concurrency scenarios. For production systems with multiple writers, consider alternatives like Cloud SQL (PostgreSQL/MySQL), Firestore for real-time databases, or BigTable for large-scale analytics. For CraftscapeHK, our write volume is low (artisan edits, user orders), making SQLite a perfect fit.

3. Secrets Management

Never hardcode API keys directly into containers. Instead, use Cloud Secret Manager or pass sensitive values as environment variables during deployment. This keeps secrets out of version control and audit logs, and enables easy rotation without rebuilding images.

4. Monitoring is Critical

Observability is key to understanding performance. Monitor request latency to identify cold start impact, track error rates to catch issues early, track memory usage to right-size resource allocation, and monitor billing to understand actual costs versus estimates. Cloud Logging provides comprehensive access to all service logs.

5. Container Image Size

Smaller images pull faster, resulting in quicker cold starts. Our frontend at 15MB starts in ~1-2 seconds, while our 250MB backend takes 3-5 seconds. Every 100MB of image size adds approximately 500ms to cold start time. Techniques like Alpine Linux base images, multi-stage builds, and minimal dependencies compound these savings.


Future Improvements

If we were to scale CraftscapeHK beyond a hackathon project:

  1. Move to Cloud SQL for reliable multi-instance database access
  2. Add Cloud CDN for global asset distribution (AR models, craft images)
  3. Implement Pub/Sub for asynchronous AI processing (image generation can take 10+ seconds)
  4. Use Cloud Tasks for reliable artisan notifications
  5. Deploy to multiple regions with Cloud Load Balancing for global latency

Conclusion

Cloud Run proves that you don't need Kubernetes expertise to run production workloads. CraftscapeHK demonstrates how Cloud Run's serverless architecture enables small teams to:

Ship fast: From code to deployed in minutes

Scale automatically: Handle traffic spikes without manual intervention

Pay fairly: Only for resources consumed, $0 during idle time

Focus on product: Not infrastructure

For cultural heritage preservation or any hackathon project, Cloud Run is definitely a game-changer!


Check out our GitHub repo:

GitHub logo gracetyy / CraftscapeHK

AI-powered platform preserving Hong Kong's disappearing traditional crafts through AR experiences, and AI-assisted custom design creation with real-world artisans to bring ideas to life.

Craftscape HK (藝守)

Thumbnail

Live Demo

Important

Try our app here!

Table of Contents

Inspiration

Hong Kong’s traditional crafts—such as hand-carved mahjong tiles, painted porcelain, cheongsam, and neon sign—are fading due to shrinking markets and an aging artisan community.

More than 70% of craft shops have shut in recent years as demand wanes and rents spike, typical revenues have fallen 30–50% amid mass-produced competition, and 80% of artisans say their children won’t continue the trade because of long hours, low pay, and little recognition.

We wanted to build a bridge between the past and the future, enabling young people and global visitors to not only appreciate but also interact with these disappearing arts, and translating the appreciation into tangible support…




Top comments (0)