Fresh Onam flowers delivered across Kannur, Kerala — a seasonal e-commerce site for selling pookalam flowers during Onam. Bilingual (English + മലയാളം), with a full admin/CRM backend for running the shop day-to-day.
- Storefront: https://onapookkal.store
- Admin: https://onapookkal.store/admin (username
admin) - Workers.dev fallback: https://onapookkal.aanandab44.workers.dev
- Bilingual UI — English by default, Malayalam toggle (top-right); persisted in localStorage.
- Animated pookalam hero with a live countdown to Thiruvonam (Onam 2026: Atham 17 Aug → Thiruvonam 26 Aug).
- Announcement bar — admin-editable top banner (English + Malayalam).
- Ordering window — customers can browse anytime, but ordering is gated until a configurable date (default 21 Aug 2026); until then the shop shows "ordering opens …" instead of Add-to-cart.
- Catalog — category filter pills + a search box (matches name & colour in English and Malayalam); featured products sort first.
- Product cards — image, unit price, strike-through compare-at price with a −% badge, "★" featured mark, "Only N left" low-stock warning, and a sold-out overlay.
- Dynamic kg pricing — for kg products, a live line total updates as the customer types grams (e.g. "500 g = ₹170"), and a "Spend ₹" box reverse-calculates grams from a budget amount (₹100 → ~294 g on a ₹340/kg flower). Two-way: type grams → ₹ updates, type ₹ → grams update.
- Product detail — gallery, pricing, stock status, add-to-cart.
- Cart — slide-in drawer, persisted to localStorage, mobile "view cart" bar + bottom nav, quantity controls.
- Smooth scroll + motion — Lenis smooth scrolling (anchor-aware), GSAP ScrollTrigger, scroll-reveal animations, scroll-progress bar, Onam motif decorations.
- Distance-based delivery charge — Haversine from the store origin (
11.8314722, 75.5517778): free ≤ 7 km, then ₹20 base + ₹5/extra km; free on orders over ₹2,000; ₹30 flat fallback when no location. Computed server-side (never trusts the client). - Delivery or store pickup — pickup skips the delivery charge and uses the store address.
- "Share my location" — used for home delivery so the delivery map gets exact pins instead of pincode guesses.
- Payment methods — Cash on Delivery, Pay-on-WhatsApp, and Razorpay online (auto-hidden until API keys are set).
- Pincode lookup — auto-fills district/area from the pincode.
- Orders save to D1 and simultaneously open a pre-filled WhatsApp message to the shop (+91 70340 26295).
- Order tracking (
/track) — customer enters order number + phone → live status timeline + a printable receipt. - Server-side re-pricing — item prices, delivery charge and stock are re-validated from the DB at order time (client values are never trusted).
- Privacy policy (
/privacy) — Indian IT Act 2000 + DPDP Act 2023 compliant, with Grievance Officer details.
- Three coupon types: percentage, flat ₹, and free delivery.
- Single-use and bound to a phone number (validated server-side; flat discounts capped at the subtotal).
- Applied at checkout with a live preview API (
/api/coupon); the discount line always shows when applied. - Two generators — in the admin panel (
/admin/coupons) and a standalone Python GUI (py -3.12 coupon_generator.py).
- Login — username
admin; password stored in the D1adminstable (not in the repo). - Products — manage names (EN/ML), price, cost price, compare-at price, stock, featured status, hidden (show/hide from store), sorting, unit, and images (URL or browser-compressed base64 upload — no R2 needed).
- Offers — percentage / flat site offers.
- Coupons — list, view used/unused, delete, and the in-page generator.
- Orders (CRM) — full order list with status filters + search; order status workflow (new → confirmed → packed → out for delivery → delivered / cancelled) with automatic restock on cancel; per-order WhatsApp button, "Send receipt on WhatsApp" (pre-filled itemized message) and "PDF bill" (printable receipt at
/admin/orders/[id]/receipt); CSV export; manual order entry for walk-in / phone orders. - Delivery map (
/admin/map) — Leaflet + OpenStreetMap plotting all pending delivery orders (exact pin from shared location, else pincode geocoded via Nominatim). - Reports (
/admin/reports) — total & today's revenue, order-status breakdown, a 14-day revenue chart, top products, and payment / delivery-method breakdowns. - Profit & Loss (
/admin/profit) — revenue, discounts given (coupons), COGS, gross profit, expenses and net profit with animated count-up cards, a per-day bar chart and a cumulative line chart. Cost price is snapshotted per order, so profit is frozen at order time. - Vendors & purchases — track suppliers and log stock purchases (feeds the P&L).
- Expenses tracker — log extra overhead (transport, packing, etc.) that feeds the P&L report.
- Inventory — server-side stock check + decrement on order; restock automatically on cancel.
- Next.js 16 (App Router) + React 19 + TypeScript + Tailwind CSS 4
- @opennextjs/cloudflare — deploys to Cloudflare Workers (edge)
- Cloudflare D1 (SQLite) via Drizzle ORM
- GSAP + Lenis (smooth scroll/animation), lucide-react, Leaflet (map)
- jsPDF + html2canvas-pro (client-side PDF receipts)
- Fonts bundled locally (Playfair Display, Plus Jakarta Sans, JetBrains Mono) — no runtime Google Fonts
- Product images — self-hosted in
/public/images/flowers/*.jpgor base64 data URLs in D1 (R2 is disabled)
npm install
npm run db:generate # create D1 migration from schema
npm run db:migrate:local # apply migration to local D1
npm run db:seed:local # seed categories, products, admin, settings
npm run dev # http://localhost:3000Admin username is
admin. The password is set in the D1adminstable — it is not in the repo.
Deploy is manual (no CI/CD — git push does not deploy):
npm run build # next build (Turbopack)
npm run deploy # opennextjs-cloudflare build + deploy to CloudflareKill any running next dev first (it locks .open-next with EPERM).
| Secret | Purpose |
|---|---|
AUTH_SECRET |
Session-signing secret (set via wrangler secret put AUTH_SECRET) |
RAZORPAY_KEY_ID / RAZORPAY_KEY_SECRET |
Optional — enable online payments |
This is a public repository (https://github.com/AanandAB/Onapoo). Never commit
secrets, tokens, password hashes, or the admin password. workers_dev: true must stay
in wrangler.jsonc to keep the workers.dev fallback URL.
src/
app/
(site)/ # storefront pages (home, shop, checkout, track, about, contact, faq, delivery, privacy)
admin/ # admin panel (login, dashboard, products, offers, coupons, orders, map, reports, vendors, purchases, profit, settings)
api/ # route handlers (coupon, pincode, upload, health, export-orders)
components/ # UI components (catalog, checkout, cart, admin, receipt, map, report…)
db/ # Drizzle schema + client
lib/ # business logic (site constants, coupons, orders, admin, geocode, auth, i18n, receipt)
scripts/ # seed + D1 migration/utility scripts
coupon_generator.py # standalone Python GUI coupon generator (writes to D1 via wrangler)