← Back to prototype
BBpillow · Platform documentation

Wireframes, database schema & tech stack.

Supporting documentation for the BBpillow e-commerce platform — website & LINE Mini-App. Built to serve B2C direct sales and B2B lead generation from a single unified backend.

Contents
  1. Wireframe outline — Homepage & Shop
  2. Database schema — B2C members & B2B leads
  3. Recommended tech stack
  4. LINE ecosystem integrations

1. Wireframe outline

Mobile-first, structural breakdown. Both pages designed to flex from a 360px viewport up to a 1180px content max.

Homepage

bbpillow ●EN · TH · 🛒 · 👤
HERO
Eyebrow · 100-year brand
H1: "Quality sleep at flea-market prices"
Sub-copy · CTA primary (Shop) · CTA secondary (Bulk inquiry)
Stats: 22M฿ · 100K+ customers · 4.8★
[product imagery composition / right]
Free
ship
1-yr
warranty
7-day
returns
100-yr
brand
CATEGORIES (5 tiles · image + label)
BEST SELLERS
carousel/grid · 4 product cards · "View all" link
BRAND STORY (dark band)
Portrait of founder · pull quote · CTA "Read story"
B2B strip (conditional) — Wholesale inquiry
LINE OA · "Add friend, get ฿100 off + points"
Footer · 4 columns© 2026

Structural notes

  • Sticky chrome: mode toggle (web ↔ mini-app) + lang switch · always on top.
  • Hero: headline split — Thai-first; CTA pair guides B2C left, B2B right.
  • Value props strip: light tinted band — reduces purchase anxiety up front.
  • Categories: 5 photo tiles. Tap routes to filtered Shop.
  • Best sellers: 4 cards. Server-driven from products.sold ranking.
  • Brand story band: dark soil background — visual rhythm break. Encapsulates Rinen philosophy.
  • LINE CTA: green-on-cream block — frictionless entry to LOA / Mini-App.

Hierarchy of intent

P1 Shop CTA (B2C) · P2 Bulk inquiry (B2B) · P3 LINE add-friend · P4 Brand story

Shop / Catalog

← Breadcrumb · Home / Shop120 items
H1 · "All products" + count
All
Pillow
Mattress
Topper
Sheet
FILTERS
▢ Material
▢ Price (range)
◯ Sort by
Product card
Product card
Product card
Product card
Product card
Product card
FooterPagination

Product card anatomy

  • Square image · -% badge top-left · "new" badge top-right
  • Bilingual product name (clamp 2 lines)
  • Stars · rating · review count
  • Price (Clay, large) · compare price (strike)
  • Inline "Add to cart" pill on hover/tap

Filter logic

Client-side filter for hi-fi feel; server-driven in production via:
GET /products?cat=pillow&mat=microfiber&p_max=300&sort=popular

Mobile behavior

Filters collapse into a bottom sheet · category chips remain horizontal scroll · grid drops to 2 columns at <860px.

2. Database schema

PostgreSQL recommended. Schema supports both B2C consumer accounts and B2B lead/quote workflow, plus unified inventory shared by Web + LINE Mini-App.

Core entities

  • users — B2C customers (LINE-linked)
  • addresses — shipping addresses, 1:N to users
  • products — master catalog (shared)
  • product_variants — size, color, SKU
  • inventory — single-source stock per variant
  • orders + order_items — B2C transactions
  • reviews — UGC, moderated
  • loyalty_ledger — point credits/debits

B2B lead-gen entities

  • b2b_leads — quote requests from Wholesale form
  • b2b_accounts — converted companies (post-sales contact)
  • price_tiers — quantity bands → unit price
  • quotes — generated PDFs, lifecycle states

Schema definition

-- ───── B2C members + auth ───── CREATE TABLE users ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), line_user_id text UNIQUE, -- LIFF sub claim email text UNIQUE, phone text, display_name text, avatar_url text, tier text DEFAULT 'soft', -- soft|warm|gold points integer DEFAULT 0, locale text DEFAULT 'th', created_at timestamptz DEFAULT now(), last_login timestamptz ); CREATE TABLE addresses ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid REFERENCES users(id) ON DELETE CASCADE, label text, -- home, office recipient text, phone text, line1 text, district text, city text, zip text, is_default boolean DEFAULT false ); -- ───── catalog (shared by web + mini-app) ───── CREATE TABLE products ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), slug text UNIQUE, name_th text NOT NULL, name_en text NOT NULL, desc_th text, desc_en text, category text, -- pillow|mattress|sheet|blanket|topper material text, base_price integer, -- THB compare_at integer, active boolean DEFAULT true, created_at timestamptz DEFAULT now() ); CREATE TABLE product_variants ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), product_id uuid REFERENCES products(id) ON DELETE CASCADE, sku text UNIQUE, size text, color text, price integer -- override base if set ); CREATE TABLE inventory ( variant_id uuid PRIMARY KEY REFERENCES product_variants(id), stock integer DEFAULT 0, -- single source of truth reserved integer DEFAULT 0, -- in-flight orders updated_at timestamptz DEFAULT now() ); -- ───── B2C orders ───── CREATE TABLE orders ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), order_no text UNIQUE NOT NULL, -- BB-XXXXXX user_id uuid REFERENCES users(id), channel text, -- web | line_mini status text DEFAULT 'pending', -- pending|paid|shipped|delivered|refunded subtotal integer, shipping integer, total integer, payment text, -- cod|promptpay|card|line_pay address_id uuid REFERENCES addresses(id), notes text, created_at timestamptz DEFAULT now() ); CREATE TABLE order_items ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), order_id uuid REFERENCES orders(id) ON DELETE CASCADE, variant_id uuid REFERENCES product_variants(id), qty integer, unit_price integer ); -- ───── loyalty + reviews ───── CREATE TABLE loyalty_ledger ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), user_id uuid REFERENCES users(id), delta integer, -- + earn / - redeem reason text, -- order:BB-... / reward:R-... ref_id uuid, created_at timestamptz DEFAULT now() ); CREATE TABLE reviews ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), product_id uuid REFERENCES products(id), user_id uuid REFERENCES users(id), order_id uuid REFERENCES orders(id), -- verified purchase stars smallint CHECK (stars BETWEEN 1 AND 5), body_th text, body_en text, photos text[], -- UGC image URLs status text DEFAULT 'pending', -- pending|approved|rejected created_at timestamptz DEFAULT now() ); -- ───── B2B lead gen ───── CREATE TABLE b2b_leads ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), company text NOT NULL, contact text, email text, phone text, biz_type text, -- hotel|dorm|retail|other qty_band text, -- 50-99|100-499|... products uuid[], -- product IDs of interest message text, status text DEFAULT 'new', -- new|contacted|quoted|won|lost assigned_to uuid, -- sales rep id source text, -- web|line|referral created_at timestamptz DEFAULT now() ); CREATE TABLE b2b_accounts ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), lead_id uuid REFERENCES b2b_leads(id), company text NOT NULL, tax_id text, credit_terms text, -- net30, prepaid primary_rep uuid, active boolean DEFAULT true ); CREATE TABLE price_tiers ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), product_id uuid REFERENCES products(id), min_qty integer, max_qty integer, unit_price integer ); CREATE TABLE quotes ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), quote_no text UNIQUE, lead_id uuid REFERENCES b2b_leads(id), account_id uuid REFERENCES b2b_accounts(id), total integer, pdf_url text, valid_until date, status text DEFAULT 'draft', -- draft|sent|accepted|expired created_at timestamptz DEFAULT now() );

Key relationships & choices

3. Recommended tech stack

Optimized for speed of delivery, LINE-first user base, and ability to scale from 100K to 1M users without a rewrite.

Frontend

Next.js 14 (App Router) Server components for SEO on shop/PDP, edge runtime for the Thai market. Shared component library between web and LIFF view.
TypeScript + Tailwind Type-safe data layer end-to-end. Tailwind tokens map directly to the Paper/Soil/Sky/Clay palette in this prototype.
@line/liff SDK LIFF v2 for the Mini-App. Wraps LINE Login, profile, message-sharing, and payment intents.
next-intl Bilingual TH/EN out of the box, persistent locale via cookie + LINE profile language.

Backend

NestJS or tRPC + Hono REST + typed RPC. tRPC is faster to ship since web and mini-app share the call signatures. NestJS is the safer pick if a separate B2B admin team will use the API.
PostgreSQL (Supabase / Neon) Managed Postgres + row-level security. Auth, storage, realtime in one. Schema above runs as-is.
Redis (Upstash) Cart sessions, rate limits, hot product cache. Edge-replicated for SE-Asia latency.
BullMQ workers Background jobs — order confirmations, LINE OA broadcast, low-stock alerts, weekly B2B digest.

Payments & logistics

Omise / 2C2P Cards + PromptPay + bank QR. Best Thai-market payment processors.
LINE Pay Direct LINE Pay integration for Mini-App orders — 1-tap checkout, native UX.
Flash Express / Kerry / Thailand Post APIs Programmatic label generation, tracking webhooks → order status updates.

Ops & analytics

Vercel Hosting for Next.js · edge functions · preview deploys.
Sentry + PostHog Errors + product analytics. PostHog session replay reveals where B2B leads abandon the quote form.
Cloudinary Product image CDN, auto-format (WebP/AVIF), on-the-fly transforms — keeps the visual quality at the price-point promise.
Resend + LINE Notify Transactional email + LINE-channel notifications for orders, B2B quotes, stock alerts.

4. LINE ecosystem integrations

LINE Login (SSO)

Both web and mini-app authenticate via LINE OAuth. Server verifies the ID token, looks up or creates a row in users keyed by line_user_id, auto-fills profile fields. One identity, two channels.

LIFF / Mini-App

Mini-App is a LIFF page deployed at liff.bbpillow.co.th. Uses liff.getProfile() for instant identity, liff.sendMessages() to share products to friends, liff.scanCode() for store QR pickup orders.

LINE OA + Notify

Order updates, shipment tracking, and B2B quote PDFs sent via LINE Messaging API. Promotional broadcast for new product drops; "buy in LINE" deep-link returns to the Mini-App.

Unified inventory

Web and Mini-App both call GET /api/inventory/:variant. Reservation happens at order placement against inventory.reserved with a 15-minute TTL. Stock can never be oversold across channels.

Next steps

1. Validate wireframes with the founder · 2. Lock palette + type pair via the prototype's Tweaks panel · 3. Spike LIFF + LINE Login on a throwaway branch · 4. Migrate the 8 sample products into the real schema · 5. Soft-launch to existing LINE OA followers.