Bilingual Bakery CMS Template

Full-Stack
2026-05-10T18:51:45Z
SvelteKitSvelte 5TypeScriptTailwind 4Convex

A bilingual (SV / EN) bakery website template, designed from day one as a generic template a bakery owner could pick up and customise without a developer in the loop. The public side covers a hero with seasonal banner and a live 'open now' status pill, a product gallery filterable by category (Tårtor, Kakor, Bröd, Bakverk, Övrigt) and dietary tag (Glutenfri, Laktosfri, Vegansk, Nötfri), a custom-order form with eight fields (name, phone, email, pickup date, portions, occasion, description, allergies), an opening-hours widget that respects holiday closures rendered as 'Kommande avvikelser', a Google Places reviews carousel cached server-side for an hour, a pinnable news banner, and bilingual copy via a no-build-step i18n helper. The admin side is a login-protected dashboard with full CRUD over Sortiment, Beställningar, Öppettider, Nyheter, and Inställningar, including a kanban-style status flow over incoming orders (new, seen, accepted, declined). All brand details are placeholder lorem ipsum so the template stays neutral.

The stack is SvelteKit 2 + Svelte 5 (runes mode) + TypeScript on the front, Tailwind v4 via @tailwindcss/vite for styles, Convex for the database and file storage, Clerk for auth, Resend for transactional email, and the Google Places API for live reviews. Deploys to Vercel + Convex Cloud, runs on Bun.

The design choice that makes it interesting is the demo mode. The site runs with no API keys at all. When env vars are missing, src/lib/server/source.ts falls back to in-memory dummy data from src/lib/server/dummy.ts: ten sample products, five sample reviews, console-logged emails. Three auth modes toggle by env var. Bypass is the default, /admin is open with a visible 'DEMO BYPASS' banner. Password mode kicks in when OWNER_DEMO_PASSWORD is set, gating /admin/login behind a 30-day cookie session. Live mode kicks in when PUBLIC_CLERK_PUBLISHABLE_KEY is set, swapping in real Clerk auth flow. Every Convex-bound function in source.ts is shaped as a swap-in for the dummy version, so going to production is adding env vars and replacing call sites, not rewriting the data layer.

The owner-facing UX is the second deliberate choice. The admin routes use bakery vocabulary (Tårtor, Beställningar, Öppettider, Nyheter, Inställningar), not engineering terms. The Översikt dashboard surfaces three counters at a glance (Nya beställningar, Sortiment, Nyheter) and a Senaste beställningar feed. Featured products auto-promote to the homepage. JSON-LD LocalBusiness markup is rendered on every page for SEO without the owner ever touching it.

  • Filterable product gallery (/sortiment) with five categories (Tårtor, Kakor, Bröd, Bakverk, Övrigt) and four dietary tags (Glutenfri, Laktosfri, Vegansk, Nötfri), plus live availability badges (Slut just nu)
  • Custom-order form (/bestall) with eight fields: name, phone, email, pickup date, portions, occasion, description, and allergies
  • Live opening-hours widget with 'Stängt just nu' / 'Öppet' status pill, seven-day grid, and Kommande avvikelser list for holiday closures
  • Google Places reviews carousel cached server-side for one hour, with placeholder dummy reviews until a Place ID is configured
  • Bilingual SV and EN via a no-build-step i18n helper, with per-page lang query toggle
  • Three-mode auth toggle (bypass, password, Clerk) gated by env vars, with a visible 'DEMO BYPASS' banner when running keyless
  • Login-protected admin CRUD over Sortiment, Beställningar, Öppettider, Nyheter, and Inställningar, in bakery vocabulary rather than engineering terms
  • Översikt dashboard with three counters (Nya beställningar, Sortiment, Nyheter) and a Senaste beställningar feed flowing through new, seen, accepted, declined
  • Demo mode with zero API keys: src/lib/server/source.ts falls back to in-memory dummy data (ten products, five reviews, console-logged emails) when env vars are missing
  • Source.ts swap-in pattern: every Convex function shaped as a drop-in for the dummy version, so production rollout is env vars plus call-site replacement, not a rewrite
  • JSON-LD LocalBusiness markup rendered on every page for SEO with no owner touch points
  • Resend transactional email with a console-fallback when keys are missing