Prompt file imported from SpaceTrev/tresraices (
.github/prompts/copilot-admin-firestore.prompt.md). Copyright stays with the author.
Copilot Admin Firestore Prompt
Goal
Finish admin functionality for Tres Raíces MVP.
Context
- Next.js 15 App Router (TypeScript), Tailwind.
- Firebase client (Auth + Storage) already used in
/admin. /app/api/parse-menu/route.tscurrently parses a PDF and returns counts only./app/api/menu/route.tsserves local JSON from/data.- We want: upload PDF → parse → compute markups (+20% GDL, +30% Colima) → save to Firestore as
menus/latestand a historical doc →/api/menushould read Firestore first, fallback to bundled JSON. - Security: route requires header
x-admin-keymatchingNEXT_PUBLIC_ADMIN_KEY(already set in Netlify). - We will provide a service account via env var:
FIREBASE_SERVICE_ACCOUNT_JSON.
Deliverables
-
Create
lib/firebaseAdmin.ts- Initializes
firebase-adminfromFIREBASE_SERVICE_ACCOUNT_JSON.
- Initializes
-
Update
/app/api/parse-menu/route.ts- Authorize via
x-admin-key. - Accept
{storageUrl}(public/signed Firebase Storage URL). - Download PDF, parse text (reuse existing parser), compute grouped JSON objects:
gdl(prices with +20%)col(prices with +30%)base(unmarked base prices)
- Write to Firestore:
menus/latest→{ gdl, col, base, updatedAt: serverTimestamp() }menus_history/{timestamp}→ same payload plussourceUrl
- Return
{ status: "ok", parsedCount, categoriesCount, wroteLatest: true }
- Authorize via
-
Update
/app/api/menu/route.ts- Try Firestore first:
- If Firestore available and
menus/latestexists, returngdlorcolbased onregionquery. - Else fallback to local JSON files in
/data.
- If Firestore available and
- Keep everything ESM and typed.
- Add minimal error handling and clear 401/400/500 responses.
- Try Firestore first:
-
Do not change the admin UI — it already uploads to Storage and calls
/api/parse-menu. -
Add a quick note to
README.mdunder “Phase 2” describing the new env var and Firestore behavior.
Environment Variables
Already in Netlify or to be added:
| Variable | Description |
|---|---|
NEXT_PUBLIC_ADMIN_KEY |
Auth key used by admin routes |
NEXT_PUBLIC_FIREBASE_* |
Existing Firebase web config vars |
FIREBASE_SERVICE_ACCOUNT_JSON |
🔸 New — paste full JSON from Firebase → Service accounts |
Code Constraints
- Use
admin.firestore().collection('menus')(Native mode). - Avoid new dependencies beyond what’s already in
package.json. - Keep the existing regex-based parser logic.
- Must compile on Next.js 15.
🧩 Files to Add / Modify
lib/firebaseAdmin.ts
import admin from "firebase-admin";
let app: admin.app.App | undefined;
export function getAdminApp() {
if (app) return app;
const raw = process.env.FIREBASE_SERVICE_ACCOUNT_JSON;
if (!raw) throw new Error("FIREBASE_SERVICE_ACCOUNT_JSON not set");
const creds = JSON.parse(raw);
app = admin.initializeApp({
credential: admin.credential.cert(creds),
});
return app;
}
export function getDb() {
return getAdminApp().firestore();
}
app/api/parse-menu/route.ts
(Replace with full implementation)
- Authorize via header.
- Fetch PDF from Firebase Storage.
- Parse text to extract items/prices.
- Compute
base,gdl,colgrouped JSON. - Save both to Firestore (
menus/latest,menus_history/{timestamp}). - Return
{ status: "ok", parsedCount, categoriesCount, wroteLatest: true }.
app/api/menu/route.ts
(Modify to read from Firestore first, fallback to local JSON)
- Query Firestore for
menus/latest. - Return
gdlorcoldataset depending on query param. - Fallback to
/data/menu_guadalajara_list2.jsonor/data/menu_colima_list2.json.
Example Usage Flow
- Admin logs in at
/admin(Firebase Auth Email/Password). - Uploads distributor PDF → Firebase Storage.
/api/parse-menuparses it → saves structured JSON to Firestore./api/menuserves menus directly from Firestore to/menu/[region]pages.- If Firestore is unavailable, pages use local JSON fallback.
✅ After Copilot Implements This
- Add
FIREBASE_SERVICE_ACCOUNT_JSONto Netlify env vars. - Commit and push generated changes.
- Redeploy on Netlify.
- Test PDF upload → verify
menus/latestandmenus_historyin Firestore. - Hit
/api/menu?region=guadalajara→ should return data from Firestore.