This file tells AI coding agents (Cursor, Claude, etc.) how to work safely and effectively in the reverto app.
ReVerto is a two-sided waste marketplace built on Frappe Framework (backend) with a React SPA (frontend) using shadcn-style UI components and frappe-react-sdk for talking to Frappe. It supports product listings, real-time negotiation/chat, cart checkout, environmental impact tracking, and a full seller dashboard.
From apps/reverto:
# install JS deps (runs frontend install via postinstall)
yarn install
# dev server (Vite, React SPA)
yarn dev # or: cd frontend && yarn dev
# build SPA and wire it into Frappe
yarn build # or: cd frontend && yarn build
# outputs assets to /assets/reverto/frontend/*
# and copies HTML to reverto/www/reverto.html
# lint/format frontend
cd frontend && yarn lintNotes for agents:
- Local SPA URL (dev):
http://reverto.localhost:5173(seefrontend/vite.config.ts). - Dev proxy to Frappe:
- Vite proxies
/api,/assets, and/filestohttp://reverto.localhost:8000. - When you call
/api/method/...from the browser, requests go through the dev server and hit the Frappe site without CORS issues.
- Vite proxies
- Frappe + SPA integration (build/production):
- Built assets are served from
/assets/reverto/frontend/. yarn buildcopiesreverto/public/frontend/index.htmltoreverto/www/reverto.html.hooks.pydefineswebsite_route_rulesso/reverto/...is handled by the SPA.
- Built assets are served from
Always run bench commands from the bench root, not from apps/reverto.
# install app to a site
bench --site <site-name> install-app reverto
# after DocType/schema changes
bench --site <site-name> migrate
# run server-side tests for this app
bench --site <site-name> run-tests --app reverto
# export fixture data (CO2 factors etc.)
bench --site <site-name> export-fixtures --app revertoLinting and formatting (Python + JS/TS) are handled via pre-commit and CI:
cd apps/reverto
pre-commit install
pre-commit run --all-filesTools configured (see pyproject.toml, pre-commit config, and CI):
- Python:
ruff(lint + format),pyupgrade. - JS/TS:
eslint,prettier. - Security/quality (CI): Semgrep Frappe rules,
pip-audit.
- Backend: Frappe app
reverto/- DocTypes:
Product,CO2 Factor,Reverto Enquiry,Reverto Message,Reverto Seller Profile,Reverto Rating. - Frappe handles multi-tenant DB, authentication, roles/permissions, background jobs, and REST API.
- All SPA-facing logic lives in
reverto/api/(auth, products, profile, enquiry).
- DocTypes:
- Frontend: React SPA in
frontend/- Built with Vite + React + TypeScript + Tailwind CSS 4.
- UI primitives follow shadcn/ui patterns (Radix + Tailwind; see
frontend/src/components/ui). - Uses
frappe-react-sdkfor talking to Frappe (auth, data fetching/mutations, realtime). - Global cart state via
CartContext.
- Integration:
- SPA HTML entry lives at
reverto/www/reverto.html. website_route_rulesinhooks.pyroute/reverto/<path:reverto>to the SPA.- Built assets are served from
/assets/reverto/frontend/via Frappe's asset pipeline.
- SPA HTML entry lives at
See ARCHITECTURE.md for a detailed overview of flows and entities.
reverto/api/
auth.py signup, get_user_profile
products.py list_products, my_products, create/update/delete_product
profile.py seller profile CRUD, rate_seller, get_my_rating_for_enquiry
enquiry.py create_enquiry, send_message, propose_price,
respond_to_price, confirm_payment, direct_purchase,
get_my_orders, get_seller_orders, get_sustainability_stats,
get_buyer_enquiries, get_seller_enquiries
reverto/reverto/doctype/
product/ Marketplace listing
co2_factor/ CO₂ kg/kg factors by waste category
reverto_enquiry/ Negotiation session (Open→Negotiating→Accepted→Closed)
reverto_message/ Chat messages within an enquiry
reverto_seller_profile/ Seller profile + aggregate avg_rating / rating_count
reverto_rating/ Post-transaction buyer rating (1–5 stars)
frontend/src/
App.tsx Top-level router, auth guard, page switcher
context/CartContext.tsx Global cart state (items, totals, open/close)
components/
Navigation.tsx Sticky navbar (search, location label, badges, cart)
WasteCard.tsx Product card (buy, enquire, details, add-to-cart)
ProductDetailsModal.tsx Full product + seller detail modal
ProductMap.tsx MapLibre interactive map with Supercluster clustering
CategoryFilters.tsx Horizontal category filter chips
SustainabilityWidget.tsx Personal + community CO₂/waste stats
CartDrawer.tsx Cart slide-out with GST totals + batch checkout
PaymentModal.tsx Confirm payment (enquiry or direct purchase)
BuyerEnquiriesDrawer.tsx Buyer's open/negotiating enquiries list
MyOrdersDrawer.tsx Buyer's completed orders
ProfilePage.tsx Editable user/seller profile
enquiry/
ChatWindow.tsx Real-time chat + price negotiation UI
EnquiryModal.tsx Batch enquiry creation results
seller/
AddListingModal.tsx Create/edit product listing form (with location parsing)
auth/ LoginForm, SignupForm, AuthLayout, BrandingPanel
ui/ Shadcn/ui primitives
- Add a new marketplace entity:
- Create DocType JSON + controller:
reverto/reverto/doctype/<name>/. - Add validation/side-effect logic in
<name>.py. - Run
bench --site <site-name> migrateafter schema changes. - Register data patches in
reverto/patches.txtif existing records need updating.
- Create DocType JSON + controller:
- Add a new API endpoint:
- Add to the right module in
reverto/api/(or create one for a new domain). - Use
@frappe.whitelist(allow_guest=True)for public read endpoints. - Use
@frappe.whitelist()for authenticated endpoints and always validatefrappe.session.userownership. - Never use
ignore_permissions=Trueon write paths.
- Add to the right module in
- Real-time events:
- Publish with
frappe.publish_realtime(event="enquiry_{name}", message={"type": "..."}). - Include a
typefield so the frontend can route without parsing the full payload. - See Real-time Events below.
- Publish with
Frontend code lives under frontend/:
-
Entry points:
frontend/src/main.tsx– React root, wrapped inFrappeProviderfromfrappe-react-sdkusingurl={window.location.origin}.frontend/src/App.tsx– top-level router, page switcher, auth state, enquiry badge counts.
-
UI components:
- Shared primitives in
frontend/src/components/ui/*– always prefer these over one-off inline styles. - Feature components are in
frontend/src/components/– compose from primitives.
- Shared primitives in
-
Adding a new page/view:
- Create a component in
frontend/src/components/. - Add a
currentPagestate case inApp.tsxwith the appropriate auth guard. - If a new URL path is needed, add a route rule in
hooks.py.
- Create a component in
-
Accessing Frappe from React – always use
frappe-react-sdkhooks:// Read list useFrappeGetCall("reverto.api.products.list_products", { limit: 50 }); // Read doc useFrappeGetDoc("Product", name); // Read doc list with filters useFrappeGetDocList("Product", { fields, filters, limit, order_by }); // Mutation const { call } = useFrappePostCall("reverto.api.enquiry.create_enquiry"); await call({ product_id: id, quantity_kg: qty }); // Polling useFrappeGetCall("...", {}, undefined, { refreshInterval: 15000 }); // Real-time useFrappeEventListener("enquiry_ENQ-0001", (data) => refetch());
-
Cart changes: All cart state, totals, and GST (18%) live in
CartContext.tsx. Update there first;CartDrawer.tsxandPaymentModal.tsxconsume it. -
Enquiry/checkout changes:
CartDrawer.tsx→create_enquiry(batch),PaymentModal.tsx→confirm_paymentordirect_purchase. GST rate is also hardcoded inenquiry.py– change both if the rate changes.
Location URL parsing happens in two places:
- Backend
reverto/api/products.py(_parse_location_url): resolves short URLs (HTTP redirect), then applies regex patterns for Google Maps@lat,lng, query paramsq=lat,lng, OpenStreetMap hash format, and bare decimal pairs. - Frontend
AddListingModal.tsx: client-side preview; short URLs are flagged for backend resolution on submit.
If a new Maps URL format needs to be supported, update the regex patterns in both files.
- CO₂ factors are stored in the
CO2 FactorDocType and can be edited via Frappe Desk or viareverto/fixtures/. get_sustainability_stats()inenquiry.pyloads all factors in a single query; missing categories fall back to1.0 kg CO₂/kg.- The
fixtureskey inhooks.pycontrols which records are exported/imported viabench migrate.
| Event | Publisher | Listener |
|---|---|---|
enquiry_{enquiry_id} |
enquiry.py on any state change |
ChatWindow.tsx + 15s polling fallback |
new_enquiry |
create_enquiry |
SellerDashboard.tsx + 15s polling fallback |
When adding a new real-time event:
- Publish from Python with a
typefield in the message. - Subscribe in the React component with
useFrappeEventListener. - Add a 15s
refreshIntervalfallback on theuseFrappeGetCallhook covering the same data.
-
Python/Frappe tests:
bench --site <site-name> run-tests --app reverto
- Test files live next to their DocType:
reverto/reverto/doctype/<name>/test_<name>.py. - In CI the site is
test_site.
- Test files live next to their DocType:
-
Frontend checks:
cd frontend && yarn lint
- Do not modify bench-level configuration or external services unless explicitly asked.
- Prefer small, focused changes: update one DocType or feature at a time; keep frontend changes isolated to a component where possible.
- Respect existing tooling: ensure
pre-commit run --all-filespasses before considering work done. Fix lints you introduce; avoid large unrelated reformatting. - Security & data safety:
- Do not hardcode secrets, tokens, or credentials.
- Use Frappe's permission and role system to protect seller/buyer data.
- Never expose another user's data via a guest or buyer endpoint.
- No speculative abstractions: write code for the task at hand; do not add helpers, configs, or flags for hypothetical future requirements.
- Documentation: when you add user-visible or architectural features, update
ARCHITECTURE.mdorREADME.mdas appropriate.
If in doubt about where something should live:
- Backend/domain logic → Frappe DocTypes and API modules in
reverto/. - UX and presentation → React components in
frontend/src/components/. - Cross-cutting conventions or architecture changes →
ARCHITECTURE.md.