minhvo.vercel.app
Mon May 25 2026

Hoa Tươi Đà Nẵng — hoatuoidanangnhanhi.com
Astro
React 19
TypeScript
Cloudflare Pages
D1
R2
Workers AI
Vectorize
RAG
TailwindCSS
E-commerce
Vietnamese flower-shop storefront on Astro 6 + React 19 islands, deployed to Cloudflare Pages with D1, R2, Workers AI + Vectorize RAG, and Cloudflare Email Routing.
Overview
A Vietnamese flower-shop e-commerce storefront for Hoa Tươi Đà Nẵng, built on Astro 6 with React 19 islands and shipped end-to-end on the Cloudflare edge — D1 for the catalog, R2 for images, KV for chat caching, Workers AI + Vectorize for the RAG chatbot, and Cloudflare Email Routing for transactional mail.
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Astro 6 (static + per-page SSR via prerender = false), React 19 islands, TypeScript 5.9 |
| Styling | Tailwind CSS v4 (Vite plugin), Lucide icons |
| Editor | TipTap 3 (rich-text + tables + image extension) |
| Carousel / Charts | Embla / Recharts |
| Runtime | Cloudflare Pages with a _worker.js/ wrapper bundling Pages Functions + Astro SSR |
| Storage | Cloudflare D1 (flower-catalog), R2 (flower-images), KV (CHAT_CACHE) |
| AI | Cloudflare Workers AI + Vectorize (RAG), Vercel AI SDK, Google Gemini (primary) + OpenRouter (fallback) via Cloudflare AI Gateway |
Cloudflare Email Routing send_email binding (Resend retained as fallback) | |
| Auth | PBKDF2 password hashing, sliding 1-day session cookies, optional X-Admin-Key for CI |
| Analytics | GA4 (gtag.js), GTM, Facebook Pixel — loaded through Partytown |
| Payment | VietQR generator (src/lib/vietqr.ts) for bank-transfer instructions |
| Search | D1 with diacritic-stripped search_name column + JS-side diacritic fallback |
| Tooling | Wrangler 4, Playwright (audit harness), npm in CI |
Key Features
- Vietnamese-slugged routes (
/san-pham,/danh-muc,/gio-hang,/thanh-toan, …) and full SEO meta on every page - Live catalog snapshot —
npm run fetch:catalogpulls D1 →src/data/*.generated.tsso the static build always carries the latest catalog - RAG chatbot grounded on Workers AI + Vectorize, with Gemini primary and OpenRouter fallback through Cloudflare AI Gateway
- VietQR bank-transfer checkout generated server-side for every order
- React 19 admin SPA mounted at
/adminfor catalog + order management - GA4 + GTM + Facebook Pixel all loaded through Partytown so analytics never block the main thread
- Diacritic-tolerant product search — store both the original Vietnamese name and a stripped
search_name, plus a JS fallback for partial matches - Daily crons for Vectorize embedding rebuilds and Google Merchant Center catalog sync
Architecture
src/
pages/ Vietnamese-slugged routes
components/admin/ React 19 SPA mounted at /admin
components/cart/ cart + checkout islands
data/ *.generated.ts (live D1 snapshot) + *.fallback.ts
lib/ catalog domain, view-models, sitemaps, VietQR, theme
functions/
api/ Cloudflare Pages Functions (admin, auth, products, orders, chat …)
_shared/ csrf, session, rate-limit, sanitize, email, chat tools
_middleware.ts auth + rate-limit + security headers + CSP for /api/*
db/ schema.sql + migration-*.sql + seed-*.sql
scripts/
fetch-catalog.mjs pull D1 → src/data/*.generated.ts
build-embeddings.mjs rebuild Vectorize index (cron)
sync-merchant-center.mjs push catalog to Google Merchant Center (cron)
cloudflare/worker-wrapper.js Pages _worker.js entry
.github/workflows/ deploy.yml, preview.yml, embedding-cron.yml, gmc-sync.yml, backup-d1.yml
Implementation Highlights
_worker.js/wrapper stitches Pages Functions (/api/*), the SSR worker, and R2-served media (/media/*) into a single Cloudflare Pages deployment- Smoke-test gate:
npm run test:smokerunsastro check+astro build+verify-routes.mjsso any drift between generated routes and the expectedsmoke-routes.tsfails CI before deploy - Anonymous auth POSTs — kept auth endpoints out of the CDN cache key so a single authed POST can't poison the public response
- Image pipeline locked to WebP for catalog + content images; the audit harness flags any non-webp asset before merge
- Backup-D1 cron snapshots the production database to R2 nightly so we can roll back catalog or order tables independently
Role & Responsibilities
- Full-stack ownership — Astro/React UI, Pages Functions, D1 schema + migrations, R2 media pipeline
- Built the RAG chatbot (Workers AI + Vectorize + Gemini/OpenRouter via AI Gateway)
- Authored the cron pipelines (catalog snapshot, embeddings rebuild, Google Merchant Center sync, D1 backup)
- Owns deployment on Cloudflare Pages + Wrangler