Informational site with two auto-priced menus:
- Guadalajara (+20%)
- Colima (+30%)
- Next.js 15 (App Router) + TypeScript + Tailwind
- Firebase (Auth + Storage). Firestore optional.
- Local JSON fallback (already included).
pnpm i
cp .env.example .env
pnpm dev/data contains JSON generated from LISTA 2 (wholesale) with markups applied.
menu_guadalajara_list2.jsonmenu_colima_list2.json
- Create a Firebase project; enable Email/Password Auth and Storage.
- Fill
.envwith your Firebase Web config and setNEXT_PUBLIC_ADMIN_KEY. - Deploy (Vercel/Netlify). Visit
/adminto login and upload a new distributor PDF. - After upload, the page calls
/api/parse-menuwhich parses the PDF (requires that the Storage URL is signed/public). In this MVP the API returns counts; extend it to write the generated JSON to Firestore/Storage and update your menus.
If you prefer automation, use the local script:
# Put distributor PDF at ./input/LISTA2.pdf
pnpm parse:localThis will print JSON to stdout; adapt to save into /data if needed.
Palette:
- Dark Purple
#0D0221 - Federal Blue
#0F084B - Light Blue
#A6CFD5 - UCLA Blue
#467599 - Mint Green
#C2E7D9 - Cream (background)
#F2E9DF
- Vercel or Netlify. No DB required; the menus ship as static JSON.
- When ready, you can store versions under Firebase Storage and read via
/api/menurouted to Firestore/Storage.
The admin flow now persists parsed menus to Firestore:
- Admin uploads PDF → Firebase Storage → calls
/api/parse-menu - API parses PDF, computes base/gdl/col pricing, writes to:
menus/latest(current active menu)menus_history/{timestamp}(historical record)
/api/menu?region={guadalajara|colima}reads from Firestore first, falls back to local JSON if unavailable
Add to Netlify/Vercel:
| Variable | Description |
|---|---|
NEXT_PUBLIC_ADMIN_KEY |
Auth key for admin API routes |
NEXT_PUBLIC_FIREBASE_* |
Firebase web config (apiKey, authDomain, etc.) |
FIREBASE_SERVICE_ACCOUNT_JSON |
Full Firebase service account JSON from Firebase Console → Project Settings → Service Accounts → Generate New Private Key |
Security Note: Never commit FIREBASE_SERVICE_ACCOUNT_JSON to git. Only set via hosting platform environment variables.
For the admin back-office system (user management, content editor, supplier management, etc.):
| Variable | Description | Required |
|---|---|---|
NETLIFY_BUILD_HOOK_URL |
Auto-triggers deployment when site config changes. Get from: Netlify Dashboard → Site Settings → Build & deploy → Build hooks | Optional |
Example: https://api.netlify.com/build_hooks/691fce8f068766b564170395
The site includes a comprehensive admin back-office at /admin with:
- User Management: Role-based access control (Owner/Manager/Staff)
- Content Editor: Edit hero, about, CTA sections without code changes
- Theme Manager: Choose color palettes with WCAG contrast validation
- Font Selector: Pick Google Fonts with live preview
- Supplier Management: Track wholesale suppliers and default markups
- Manual Menu Items: Add custom items with profit margin validation
- Audit Logging: Track all admin actions with user/IP/timestamp
-
Create the owner account:
node scripts/create-owner.mjs
Enter email and password when prompted.
-
Seed initial supplier data:
node scripts/seed-suppliers.mjs
-
Initialize site configuration:
node scripts/init-site-config.mjs
-
Visit
/adminand log in with your owner credentials
/admin- Login dashboard/admin/users- User management (owner only)/admin/content- Site content/theme/font editor/admin/suppliers- Supplier management/admin/menu- Manual menu items with profit validation
All admin actions are logged to Firestore audit_log collection.
Our pricing system supports per-unit pricing to distinguish between items sold by kilo (kg) and items sold by pieza (piece).
- Source of Truth: Wholesale prices come from LISTA 2 (our distributor's price list).
- Regional Markups:
- Guadalajara: +20% markup on our base (wholesale) price
- Colima: +30% markup on our base (wholesale) price
- Unit Configuration: The file
data/overrides.units.jsondefines which units are available for specific items:{ "Cerdo::Manteca": { "units": ["kg"] }, "Res::Arrachera marinada": { "units": ["kg", "pieza"] } } - Automatic Inference: If an item is not in the overrides file, the parser uses heuristics:
- Items with keywords like
pieza,entero,media, or½are tagged as["pieza"] - All other items default to
["kg"]
- Items with keywords like
The system includes safeguards to prevent absurd prices from being displayed:
- Minimum: 10 MXN (items below this are auto-hidden)
- Maximum: 2,000 MXN (items above this are auto-hidden)
- When a price is hidden, a note is added to the item's metadata (visible in build logs)
- These thresholds are configurable in
lib/menu/validate.ts
- Product Cards: Display unit chips (e.g.,
$189/kg,$49/pieza) for each available unit - Unit Filtering: Users can filter products by unit type (Kilo or Pieza) in the filter panel
- Cart & WhatsApp: Unit labels are included in cart summaries and WhatsApp order messages
When the distributor updates LISTA 2:
-
Local Development:
pnpm parse:local ./input/LISTA2.pdf
This regenerates
data/menu_{guadalajara|colima}_list2.json -
Production (Admin Upload):
- Upload PDF via
/adminpage - API route
/api/parse-menuprocesses it and writes to Firestore - Both methods apply the same unit inference and validation logic
- Upload PDF via
To override unit availability for specific items, edit data/overrides.units.json:
{
"Category::Item Name": { "units": ["kg"] },
"Category::Item Name 2": { "units": ["kg", "pieza"] }
}Keys are case-sensitive and must match the exact category and item name from the PDF.
tresraices.com) for business verification. The Netlify subdomain tresraices.netlify.app will not be accepted.
📖 Quick Start: See docs/CUSTOM_DOMAIN_SETUP.md to purchase and connect a custom domain ($10-30/year).
📖 Complete Verification Guide: See docs/FACEBOOK_VERIFICATION.md for full setup instructions.
What's Already Done:
- ✅ Open Graph meta tags configured
- ✅ JSON-LD structured data for business verification
- ✅ Business contact information visible to crawlers
- ✅ Netlify SPA routing for Facebook crawler
What You Need to Do:
- Purchase a custom domain (
tresraices.comrecommended, ~$10-15/year) - Connect domain to Netlify (instructions in guide)
- Update code with new domain using
./scripts/update-domain.sh - Verify domain with Meta Business Suite
- Complete business identity verification
Result: Access to WhatsApp Business API, Instagram API, and Facebook Business features.