Comprehensive feature audit of the BFC mobile-first ordering platform. Covers implementation status, completion percentages, source file references, and recommended next steps for pending functionality.
The But First Coffee (BFC) delivery app is a full-stack, mobile-first progressive web application built for the Philippines market. The core ordering pipeline — user authentication, menu browsing, cart management, order placement, and real-time order tracking — is fully operational. The platform successfully handles end-to-end order flows, WebSocket-driven live status updates, AI-assisted chat support, and geolocation-based address selection.
As of this report, 20 of 28 scoped features (71%) are complete and production-ready. The remaining 29% consists primarily of secondary authentication methods (Google/Facebook OAuth), home-page widget wiring, delivery fee logic, and password reset email delivery — none of which block the core ordering experience.
The app is deployed and accessible at bfc.webtour.ph, backed by apigateway.webtour.ph for REST and WebSocket services, and a local Express.js AI chat server (port 3002) for the BFC Assistant.
| Total Features Scoped | 28 |
| ✓ Implemented | 20 |
| ✗ Not Functional (0–5%) | 5 |
| ⚠ Partially Wired (10–30%) | 3 |
| Overall Completion | 71% |
20 features fully implemented, tested, and API-connected.
Email/password login with JWT access + refresh tokens. Tokens persisted to localStorage. Auto-redirects authenticated users away from login page.
api/auth.ts
store/authStore.ts
Full name, email, and password signup. Client-side validation (min 6 chars, password match check). Auto-login via JWT after successful registration.
pages/auth/Register.tsx
Browse and order without an account. Guest flag stored in localStorage. Full app access granted with a guest user object (id: 0, name: "Guest").
store/authStore.ts
ProtectedRoute redirects unauthenticated users to /login. GuestRoute redirects authenticated users away from auth pages back to home.
routes/ProtectedRoute.tsx
routes/GuestRoute.tsx
Responsive grid of all menu items across 9 categories. Category tabs + real-time client-side search filtering via useMemo. No page reload required.
pages/Menu.tsx
data/menu.ts
Bottom-sheet modal with size selector (S/M/L + price delta), quantity input, and sugar-level customization (0–100%). Sends full metadata to cart API.
components/menu/AddToCartModal.tsx
Full CRUD via REST API (GET, POST, PATCH qty, DELETE item, DELETE /cart). Cart badge shows live item count. Two-column layout on desktop.
context/CartContext.tsx
api/cart.ts
POST /orders with full item payload and total. Shows loading spinner during API call. Clears cart on success and redirects to Order History.
pages/Cart.tsx
api/orders.ts
Accordion list of past orders fetched from GET /orders. Expandable to show item thumbnails, prices, and quantities. Status badges: pending → confirmed → preparing → ready → delivered → cancelled.
pages/Orders.tsx
Socket.io client connects to apigateway.webtour.ph, joins user room, listens for order:updated/update/status events. Deduplication prevents double notifications.
lib/socket.ts
context/OrdersContext.tsx
Slide-in panel from right. Bell icon shows unread badge. Mark as read / mark all / clear all actions. Color-coded info/success/warning types.
components/layout/NotificationsPanel.tsx
Ephemeral toast stack auto-dismisses after 4.5s. Ready/delivered orders trigger a celebratory sound; other updates play a softer chime via Web Audio API.
lib/sound.ts
context/OrdersContext.tsx
BFC Assistant — local AI chat server (Express.js, port 3002). Answers menu, price, and delivery questions. Chat modal with typing indicator, accessible from the header.
components/ai/AIChatModal.tsx
server/index.js :3002
Photon/OSM autocomplete (PH-biased bbox), 500ms debounce. Two-step flow: search results → map preview → confirm. Recent addresses saved in context.
components/location/AddressPickerModal.tsx
Browser Geolocation API auto-fills address via Nominatim reverse geocoding. OpenStreetMap iframe embed previews the selected location with a marker. No API key needed.
AddressPickerModal → MapPreview + reverseGeocode
Profile page shows name, email, and avatar. Avatar upload via PATCH /users/:id/avatar (multipart/form-data). Full CDN URL built from relative path. Zustand store updated on success.
pages/Profile.tsx
api/upload.ts
GET /rewards returns total points + history. Points summary card (1 pt per ₱10 spent). Transaction history list with descriptions and timestamps.
pages/Rewards.tsx
api/rewards.ts
Fixed bottom nav: Home, Menu, Cart, Profile. Active route highlighting. Cart badge with live count. Max-width 1200px, centered on desktop.
components/layout/BottomNavigation.tsx
Access token, refresh token, and user object stored via a typed storage service wrapper. Axios interceptor attaches Bearer token to every API request automatically.
services/storage.ts
api/axios.ts
8 features stubbed, commented out, or hardcoded — not yet functional in production.
Form UI exists but the API call is a TODO comment. Handler always shows a success message — no email is sent. forgotPasswordApi(email) must be implemented.
pages/auth/ForgotPassword.tsx:40
Button renders in Register but handler only calls console.log("Google Login"). Completely commented out in Login page. No Google SDK or OAuth flow.
pages/auth/Register.tsx
Button renders in Register only. Handler calls console.log("Facebook Login"). No Facebook SDK, no OAuth redirect, no token exchange.
pages/auth/Register.tsx
Delivery fee hardcoded to ₱0 in CartSummary. No distance-based tiers, no minimum order threshold, no free delivery logic.
pages/Cart.tsx
DeliveryCard renders in Cart but onClick only calls console.log("Delivery"). No pickup vs. delivery toggle, no time-slot booking, no address confirmation.
pages/Cart.tsx
SearchBar renders on Home but onSearch only calls console.log(value). No navigation to Menu with pre-filled search query.
pages/Home.tsx
PointsCard renders on Home with points hardcoded to 0. onClick logs to console rather than navigating to /rewards. Not connected to GET /rewards.
pages/Home.tsx
"What's Nearby" shows a single hardcoded BFC Makati card (3.3 km). No API call, no geolocation-based distance sort, no dynamic branch list.
pages/Home.tsx
| POST | /auth/signin |
| POST | /auth/signup |
| GET | /orders |
| POST | /orders |
| GET | /cart |
| POST | /cart |
| PATCH | /cart/:id |
| DELETE | /cart · /cart/:id |
| GET | /rewards |
| PATCH | /users/:id/avatar |
| POST | /api/chat (port 3002) |
| / | Home (protected) |
| /menu | Menu browse + search (protected) |
| /cart | Cart & checkout (protected) |
| /orders | Order history (protected) |
| /rewards | Points & rewards (protected) |
| /profile | User profile (protected) |
| /login | Login (guest-only) |
| /register | Register (guest-only) |
| /forgot-password | Reset (guest-only) |
Jul 21 – Jul 27, 2026 · Sprint goal: close all P1 & P2 gaps, ship P3 OAuth
deliveryFee=0 in CartSummary with dynamic value from AddressContext
POST /auth/forgot-password endpoint is live on apigateway
forgotPasswordApi(email) in api/auth.ts
console.log with navigate("/menu", { state: { q } })
GET /rewards on Home mount, pass real points to PointsCard
navigate("/rewards")
data/branches.ts with BFC branch list (lat/lng per branch)
POST /auth/google token exchange on apigateway, return BFC JWT
FB.login() in Register.tsx
bfc.webtour.ph — rebuild Vite, update Apache
deliveryFee=0.await forgotPasswordApi(email) in ForgotPassword.tsx and wire the backend email endpoint.console.log("Delivery") with a bottom sheet for pickup vs. delivery toggle and time-slot selection.console.log with navigate("/menu", { state: { q: value } }) and read state in Menu.data.totalPoints to PointsCard. Wire onClick to navigate("/rewards").