From da1cc8a12d82c371f9be85d755fef6e842ff5acb Mon Sep 17 00:00:00 2001 From: Sk_Akib_Ahammed Date: Sun, 11 Jan 2026 13:52:39 +0530 Subject: [PATCH] fixed package issue and documented recent changes --- .env.example | 4 ++ README.md | 157 +++++++++++++++++++++++++---------------------- app/app.py | 2 +- app/auth.py | 1 - app/webhook.py | 2 +- requirements.txt | 2 +- 6 files changed, 91 insertions(+), 77 deletions(-) diff --git a/.env.example b/.env.example index eae7ed4..49142e9 100644 --- a/.env.example +++ b/.env.example @@ -10,3 +10,7 @@ FIREBASE_MEASUREMENT_ID= GEMINI_API_KEY= FIREBASE_SERVICE_ACCOUNT= + +RAZORPAY_KEY_ID= +RAZORPAY_KEY_SECRET= +RAZORPAY_WEBHOOK_SECRET= \ No newline at end of file diff --git a/README.md b/README.md index ae90d8e..1fe6d80 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,28 @@ # GreenPlate — Backend (FastAPI) -A lightweight FastAPI backend for managing college food stalls, staff, and menus. -It uses Firebase Authentication + Firestore and supports AI-assisted menu extraction (Google Gemini). +A compact FastAPI backend for managing college food stalls, staff, menus and orders. -Purpose -- Manage stalls, staff and menus for colleges. -- Staff can upload and edit menus for their assigned stall only. -- Managers can add/remove staff for their stall. -- Optional image-based menu extraction returns JSON of item names and prices. - -Tech stack -- Python 3.13, FastAPI, Uvicorn -- Firebase Authentication (pyrebase + firebase_admin) and Firestore -- Google Generative AI (Gemini) for menu image parsing (optional) -- Docker (Dockerfile + compose.yaml) provided +Quick summary +- Auth: Firebase ID tokens (verify with firebase_admin). +- Data: Firestore collections (colleges, stalls, staffs, users, menu_items). +- AI menu extraction: optional (Google Gemini) — returns JSON list of {name, price, description}. +- Payments: Razorpay integration for creating orders and a webhook to record payments. +- Docker ready (Dockerfile + compose.yaml). Quick start (local) -1. Create and activate a virtual environment: +1. Create & activate a virtualenv: ```bash python -m venv .venv && source .venv/bin/activate ``` -2. Install dependencies: +2. Install deps: ```bash pip install -r requirements.txt ``` -3. Provide Firebase service account and env vars. - - Recommended: set FIREBASE_SERVICE_ACCOUNT to the full JSON content of the service account file. - - Alternatively mount a local file into the container (see Docker section) and set FIREBASE_SERVICE_ACCOUNT to its path. +3. Provide Firebase & other secrets (recommended via `.env` or env vars). Important vars listed below. 4. Run the app: @@ -41,83 +33,102 @@ uvicorn app.app:app --reload --host 0.0.0.0 --port 8000 ``` Docker -- Build image and run (from repo root): +- Build and run container: ```bash docker build -t greenplate-backend . docker run --rm -p 8000:8000 --env-file .env -v $(pwd)/secrets:/app/secrets:ro greenplate-backend ``` -- With Docker Compose (recommended for local development): +- With Compose (repo root): ```bash docker compose up --build docker compose down ``` -Environment variables (important) -- FIREBASE_SERVICE_ACCOUNT: JSON string or path to the service account key file used by firebase_admin. -- FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN, FIREBASE_DATABASE_URL, FIREBASE_PROJECT_ID, FIREBASE_STORAGE_BUCKET, FIREBASE_MESSAGING_SENDER_ID, FIREBASE_APP_ID, FIREBASE_MEASUREMENT_ID — used by pyrebase client (see `app/config.py`). -- GEMINI_API_KEY — required only if you use image scanning (`/staff/menu/scan-image`). - -Security / Auth headers -- All protected endpoints require a Firebase ID token (not the UID) in the Authorization header: +Authentication +- Use Firebase ID token (NOT the UID). Send in Authorization header as a Bearer token: ``` -Authorization: Bearer {idToken} +Authorization: Bearer ``` -- You can obtain an ID token via the `/login/users` endpoint (or use `get_token.py` for tests). -- If you receive {"message": "Authorization header required"} or 401, ensure the header key is exactly `Authorization` and the value starts with `Bearer ` followed by the idToken. - -Main endpoints (summary) -- GET /health — health check - -Auth / User -- POST /signup/users — Sign up a student (payload: email, password, confirm_password) -- POST /login/users — Sign in (returns idToken) -- GET /user/menu — List available menus for the student’s college (requires Bearer idToken) - -Staff / Manager -- POST /auth/verify-staff — Verify token and initialize manager account (if email matches a stall email) — returns role, stall_id, college_id -- POST /staff/menu — Upload menu JSON for a stall (staff only; stall_id must match the authenticated staff's stall) -- GET /staff/menu — Get menu for the authenticated staff's stall -- POST /staff/menu/scan-image — Upload an image; AI returns JSON array of items (name, price, description) -- PATCH /staff/menu/{item_id} — Update a menu item (staff/manager for that stall) -- DELETE /staff/menu/{item_id} — Delete a menu item (staff/manager for that stall) - -Manager-only -- POST /staff/add-member — Add a staff member (manager only) -- GET /staff/list — List staff members for the manager's stall -- DELETE /staff/{staff_uid} — Remove a staff (manager only) -- PUT /staff/{staff_uid}/email — Update staff email (manager only) - -Key behavior / rules -- Stall-level authorization: staff/manager tokens are checked against `staffs` collection. A staff can only modify menu items for their assigned `stall_id`. -- Manager initialization: when a verified token's email matches a stall's email and no staff document exists, the endpoint will create a manager record automatically. -- Menu upload expects JSON matching the Pydantic schema `MenuSchema`: - - stall_id: string (must equal the staff's stall) +- Obtain a test idToken via `/login/users` or the helper `get_token.py` (dev-only). + +Key environment variables +- FIREBASE_SERVICE_ACCOUNT: JSON content or path for firebase_admin credentials (required). +- FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN, FIREBASE_DATABASE_URL, FIREBASE_PROJECT_ID, FIREBASE_STORAGE_BUCKET, FIREBASE_MESSAGING_SENDER_ID, FIREBASE_APP_ID, FIREBASE_MEASUREMENT_ID — used by the auth client and helper scripts. +- GEMINI_API_KEY — optional, required for image-based menu scanning. +- RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET — required for payment order creation. +- RAZORPAY_WEBHOOK_SECRET — secret used to validate incoming Razorpay webhook signatures (used by `/webhook/razorpay`). + +Important files +- `app/firebase_init.py` — initializes firebase_admin and exposes `db` (Firestore client). +- `app/auth.py` — verifies tokens and initializes manager records when a manager signs in using the stall email. +- `app/schema.py` — Pydantic models (MenuSchema, MenuItemSchema, MenuScanResponse, CreateOrderSchema, etc.). +- `app/staff.py` — staff routes logic: upload/get/update/delete menus, add staff, image scan. +- `app/manager.py` — manager-only helpers: list staff, remove staff, update staff email. +- `app/user.py` — student-facing: list menus and create payment orders. +- `app/webhook.py` — Razorpay webhook: validates HMAC signature (X-Razorpay-Signature) and saves successful payments to Firestore `orders` collection. +- `get_token.py` — helper to exchange email/password for idToken (dev/test only). + +Core rules / behavior (short) +- Staff authorization is enforced by token -> `staffs` lookup. A staff can only manage the stall they belong to (stall_id check). +- Manager init: when a user signs in and their email matches a stall's email (in that college), a manager `staffs` document is created automatically. +- Menu upload expects JSON matching `MenuSchema` (see `app/schema.py`): + - stall_id: string (must equal authenticated staff's stall) - items: list of {name: str, price: float (>0), description?: str, is_available?: bool} -- Image scan returns a list of extracted items; results should be reviewed before saving (the AI may be imperfect). +- Image scan returns a JSON array of extracted items. Results must be reviewed before saving. -Testing tokens -- Use `get_token.py` (dev helper) to exchange an existing Firebase user email/password for an idToken. -- Or call POST /login/users to get idToken on successful sign-in. +API (selected endpoints) +- GET /health — health check -Troubleshooting -- Authorization header required: Header missing or malformed. Ensure `Authorization: Bearer `. -- 401 Unauthorized: token invalid or expired — re-login to get a fresh idToken. -- 403 Forbidden: trying to modify a stall you don’t belong to or role mismatch. -- 413 Request Entity Too Large: uploaded image exceeds 5MB limit. +Auth +- POST /auth/verify-staff — Verify staff token; initializes manager if needed. +- POST /auth/verify-student — Verify student token and auto-register student (by college domain). -Useful paths -- API docs (Swagger): http://localhost:8000/docs +User (student) +- GET /user/menu — List menus for the student's college (only active & verified stalls returned). +- POST /user/order/create — Create a Razorpay order (payload: CreateOrderSchema) -Contributing -- Keep secrets out of version control: do not commit `.env` or `secrets/serviceAccountKey.json`. -- See `app/firebase_init.py` to understand service account loading. +Staff / Manager +- POST /staff/add-member — Manager adds a staff (payload: {email}) +- GET /staff/list — Manager: list staff for manager's stall +- DELETE /staff/{staff_uid} — Manager: remove a staff member (must be same stall) +- PUT /staff/{staff_uid}/email — Manager: change a staff's email (creates user if needed) + +Menu management (staff/manager) +- POST /staff/menu — Upload menu JSON for the authenticated staff's stall (MenuSchema) +- GET /staff/menu — Get menu for authenticated staff's stall +- POST /staff/menu/scan-image — Upload image (JPEG/PNG, <5MB) → returns MenuScanResponse (requires GEMINI_API_KEY) +- PATCH /staff/menu/{item_id} — Update a menu item +- DELETE /staff/menu/{item_id} — Delete a menu item + +Webhook +- POST /webhook/razorpay — Receives Razorpay events, validates `X-Razorpay-Signature` using `RAZORPAY_WEBHOOK_SECRET`, and stores successful payments in Firestore `orders` collection. Configure your Razorpay webhook to point to this endpoint. + +Testing & troubleshooting +- Swagger UI: http://localhost:8000/docs — use the Authorize button and paste the idToken (Bearer token). +- If you see {"message":"Authorization header required"} or 401: ensure header name is exactly `Authorization` and value starts with `Bearer ` followed by the idToken. +- If token expired or invalid: re-login to get a fresh idToken. + +Security notes +- Do NOT commit secrets. The repo includes a `secrets/` folder in .gitignore — keep service account JSON and .env out of VCS. +- The server uses Firestore security via server-side checks: stall_id and college_id are validated in code before writes. + +Where to look next (dev pointers) +- To change menu schema, edit `app/schema.py` (Pydantic models used for validation). +- To modify staff authorization behavior, check `app/auth.py` and `app/staff.py:get_staff_details`. +- GEMINI integration is in `app/staff.py` (_extract_menu_from_image) and requires `GEMINI_API_KEY`. + +Short checklist for running locally +1. Populate `.env` (or export env vars). Ensure FIREBASE_SERVICE_ACCOUNT is set. +2. pip install -r requirements.txt +3. uvicorn app.app:app --reload --host 0.0.0.0 --port 8000 +4. Use Swagger or a REST client. Authorize with `Authorization: Bearer `. License - See LICENSE in repo root. -Last updated: 2026-01-07 +Last updated: 2026-01-11 diff --git a/app/app.py b/app/app.py index eb5297d..e91ef7f 100644 --- a/app/app.py +++ b/app/app.py @@ -149,4 +149,4 @@ async def delete_menu_item_endpoint( return await delete_menu_item( item_id, credentials.credentials - ) \ No newline at end of file + ) diff --git a/app/auth.py b/app/auth.py index a3fdf37..cf2f364 100644 --- a/app/auth.py +++ b/app/auth.py @@ -1,6 +1,5 @@ # app/auth.py -import os from fastapi.responses import JSONResponse from starlette import status from firebase_admin import auth, firestore diff --git a/app/webhook.py b/app/webhook.py index 4571168..57b5e67 100644 --- a/app/webhook.py +++ b/app/webhook.py @@ -1,8 +1,8 @@ # app/webhook.py + import os import hmac import hashlib -import json from fastapi import APIRouter, Request, HTTPException from firebase_admin import firestore from .firebase_init import db diff --git a/requirements.txt b/requirements.txt index 7686fb6..1c2ed5d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -61,5 +61,5 @@ tqdm==4.67.1 typing-inspection==0.4.2 typing_extensions==4.15.0 uritemplate==4.2.0 -urllib3==1.26.20 +urllib3==2.6.3 uvicorn==0.40.0