Thai Joint PH ordering, payment verification, and kitchen prep automation.
Responsive customer web app, seller/admin dashboard, PHP JSON API, and Capacitor Android APK.
Live Web · Admin Dashboard · API Health · Architecture · Deployment · Diagrams
- Overview
- Live Deployment
- Current Production Evidence
- Product Screenshots
- System Visuals
- Stack
- Feature Map
- Repository Layout
- Local Development
- Android / APK
- Deployment
- Verification Gates
- Documentation Index
- Team
- License
- Course Note
PrepFlow replaces Thai Joint PH's scattered Facebook/Instagram DM ordering workflow with a single system for:
- customer menu browsing, cart, checkout, receipt upload, and order tracking
- seller payment verification with receipt screenshot + OCR text
- menu CRUD with recipe ingredient mapping
- automatic prep/procurement aggregation from confirmed orders
- fulfillment settings, shipping tiers, batch capacity, analytics, and courier-link updates
- Android packaging through Capacitor with native camera capture
Payment is intentionally receipt upload + seller verification. There is no PayMongo, GCash API, bank API, card processing, or courier dispatch API. That keeps payment scope simple and avoids PCI territory.
| Surface | URL | Notes |
|---|---|---|
| Customer web | https://prepflow-vercel-static.vercel.app | Current Vercel static app URL |
| Admin dashboard | https://prepflow-vercel-static.vercel.app/admin | Login with seeded admin account |
| Legacy/stale Vercel URL | https://thaijoint-prepflow.vercel.app | Older alias; do not use until it is reassigned to the latest deployment |
| Same-origin API proxy | https://prepflow-vercel-static.vercel.app/api/menu | Vercel rewrite to Render; should return JSON, not index.html |
| Laravel API | https://prepflow-api.onrender.com | Render Docker service; cold starts are expected on free tier |
| Public API health | https://prepflow-api.onrender.com/api/menu | Returns seeded menu JSON |
| Deployment runbook | docs/deployment/free-tier.md | Render + TiDB + Vercel setup |
| Role | Password | |
|---|---|---|
| Admin | admin@thaijoint.ph |
prepflow123 |
| Customer | maria@example.com |
prepflow123 |
Do not reuse these credentials for any real deployment. They are seeded demo accounts only.
Use these dashboards when something breaks in production. Do not put secrets in issues, screenshots, docs, or memory; only record env variable names and non-secret service names.
| Dashboard | Project / service | Use it for | Known-good checks |
|---|---|---|---|
| GitHub | cikeyz/prepflow |
PR history, commits, branch state, source of render.yaml and vercel.json |
main must include PR #24 or newer, same-origin Vercel API proxy |
| Vercel | cikeyzs-projects/prepflow-vercel-static |
Static web deploys, aliases, VITE_API_URL, build logs |
prepflow-vercel-static.vercel.app points to latest production deploy; VITE_API_URL=/api |
| Render | prepflow-api |
Laravel Docker API logs, env vars, deploys, migrations, cold-start diagnosis | Health check path /api/menu; Docker image installs PHP PDO MySQL + Tesseract |
| TiDB Cloud | PrepFlow Starter, AWS Singapore |
MySQL-compatible production database, connection/firewall/metrics | Port 4000; Render uses SSL CA bundle via MYSQL_ATTR_SSL_CA |
| Cloudinary | PrepFlow image cloud | Menu photos, payment proofs, payment-method QR images, OCR input URLs | API stores Cloudinary URLs only; no data URLs in DB |
| Brevo | Transactional email | SMTP credentials, sender verification, delivery/open logs | Render uses SMTP on port 2525; domain auth still needs an owned domain |
| Android Studio | Local apps/mobile/android project |
Debug APK build/install/logcat | bun run build:mobile targets deployed Render API for production APK testing |
Provider dashboard details and recovery steps live in docs/deployment/free-tier.md. The current rubric audit is docs/planning/submission-readiness-2026-06-29.md; older planning logs remain historical context.
mainis synced withorigin/mainat734c61c fix: polish admin prep controls (#51).- The live web app is served from
https://prepflow-vercel-static.vercel.app. The olderhttps://thaijoint-prepflow.vercel.appalias has served stale bundles and should not be used until it is reassigned to the latest Vercel deployment. - Vercel serves the web app from
https://prepflow-vercel-static.vercel.appand proxies/api/*to Render. The browser bundle should use/api, not the direct Render URL, so login cookies are same-origin on the web dashboard. - Latest verified gate:
bun run build,bun run build:mobile, Android.\gradlew.bat assembleDebug, PHP tests122 passed (429 assertions), andvendor\bin\pint --test. - Latest debug APK:
apps/mobile/android/app/build/outputs/apk/debug/app-debug.apk(SHA-256 13B8A6D256766CFC39BF363C49BEECAC6DEF41B3D4FE5290F339CB5891545EED). - Free web domains are Vercel subdomains. A branded sender/domain still requires a domain you control so Brevo can authenticate SPF/DKIM/DMARC.
- OCR was tested locally and through the deployed API using a GCash receipt screenshot. Render uploaded the receipt to Cloudinary, ran Tesseract, stored
proof_ocr_text, and parsed:
{
"amount_paid": "674.00",
"reference_number": "9042061574023",
"order_date": "Jun 20, 2026",
"order_time": "5:40 PM"
}A live demo payment-uploaded order exists in the admin queue as evidence of the deployed OCR path.
The screenshots below are committed evidence for the rubric's user documentation, responsive UI, admin workflow, and mobile-app sections.
| Customer web landing | Mobile menu |
|---|---|
![]() |
![]() |
| Admin dashboard | Menu management | COD order detail |
|---|---|---|
![]() |
![]() |
![]() |
| Rubric section | Evidence in this repo |
|---|---|
| I. Documentation & planning | Proposal/background in docs/planning/, architecture in docs/ARCHITECTURE.md, ERD/DFD/C4/flowcharts in docs/SYSTEM-DIAGRAMS.md, screenshots in docs/screenshots/, and this README. |
| II. Responsive website design | Vite/React/Tailwind app, mobile/tablet/desktop layouts, committed desktop and mobile screenshots, and same-origin Vercel deployment. |
| III. PHP session management | Laravel session auth with regeneration, role middleware, timeout/config hardening, and feature tests. |
| IV. AJAX implementation | Centralized JSON API wrapper in apps/web/src/lib/api.ts, TanStack Query mutations, loading/error UI, and no full-page reloads for data operations. |
| V. JSON data handling | Explicit PHP json_encode response trait, Content-Type: application/json, JSON parsing in the React API wrapper, zod/client validation, and Laravel validation. |
| VI. Database integration | Normalized MySQL-compatible schema, migrations, foreign keys, indexes, CRUD, transactions, and procurement aggregation view. |
| VII. Mobile application | Capacitor Android APK, deployed API connectivity, native camera/gallery receipt capture, local notifications, and FCM token plumbing. |
| VIII. Presentation & defense | docs/planning/presentation-script.md, docs/planning/submission-readiness-2026-06-29.md, screenshots, diagrams, and verification gates. |
flowchart LR
Customer["Customer Browser"] --> Web["Vercel Static React App"]
Admin["Seller/Admin Browser"] --> Web
Mobile["Capacitor Android APK"] --> API
Web -->|"JSON + session cookies"| API["Render Docker API<br/>PHP 8.2 + Laravel 12"]
API -->|"PDO MySQL + SSL"| DB[("TiDB Cloud Starter<br/>MySQL-compatible")]
API -->|"signed image uploads"| Cloudinary["Cloudinary<br/>menu photos + payment proofs"]
API -->|"receipt OCR"| Tesseract["Tesseract OCR<br/>in Docker image"]
API -->|"log driver by default"| Mail["Transactional Email"]
sequenceDiagram
participant C as Customer
participant W as React / Capacitor UI
participant A as Laravel API
participant D as TiDB / MySQL
participant S as Seller Admin
C->>W: Browse menu and add cart items
W->>A: GET /api/menu, /api/batches
A->>D: Read available menu + capacity
C->>W: Select fulfillment + payment method
W->>A: POST /api/orders
A->>D: Transaction: lock batch, validate cutoff/capacity, insert order/items
C->>W: Upload GCash/bank receipt screenshot
W->>A: POST /api/orders/{id}/payment-proof
A->>D: Store proof URL, OCR text, status payment_uploaded
S->>W: Open payment verification queue
W->>A: GET /api/admin/orders?status=payment_uploaded
S->>A: Verify payment
A->>D: Transaction: status confirmed + audit log
S->>W: Open Prep & Procurement
W->>A: GET /api/admin/prep?date=...
A->>D: Aggregate recipe_ingredients x order_items
| Layer | Technology | Why |
|---|---|---|
| Backend | PHP 8.2, Laravel 12, PDO/MySQL | Keeps rubric-visible sessions, json_encode, and prepared statements while retaining migrations/tests |
| Database | TiDB Cloud Starter locally-compatible MySQL | Free MySQL-compatible production DB with SSL |
| Web | Vite, React 18, TypeScript, Tailwind, TanStack Query | SPA for customer/admin workflows with JSON API calls |
| Shared contract | packages/shared zod schemas + apps/web/src/types.ts |
Client/server DTO validation and schema mirror discipline |
| Mobile | Capacitor 6 Android | Wraps the React build and uses native Camera for receipt capture |
| Images | Cloudinary | Stores menu images, payment proof screenshots, and QR images |
| OCR | Tesseract in Render Docker; Cloudinary OCR if available | Best-effort receipt text extraction; never auto-approves payments |
Laravel Mailables, Brevo SMTP in production, log driver by default locally |
Order confirmation/courier-link email without committing SMTP secrets | |
| Deployment | Render API, Vercel web, TiDB DB | Free-tier deployment without card-gated Koyeb |
- Landing/menu highlights from live
menu_items. - Menu browse, search, availability filter, image rendering, smart favorites/reorder.
- Cart, checkout, fulfillment/date picker, batch capacity meter, shipping tier fee display.
- Seller-configured payment method display with QR/account details.
- Receipt screenshot capture via shared
capturePhoto()and payment-proof upload. - Orders list, order tracker, courier-link card, and post-checkout success screen.
- Session login/register with role routing.
- Dashboard: revenue, average order, customers, repeat rate, status counts, revenue by day, top sellers, peak days.
- Menu Manager: CRUD, Cloudinary image upload, recipe ingredient mapping, availability rules.
- Orders: status filters, payment verification queue, screenshot + expected total + OCR text/hints, verify/reject, bulk status updates.
- Order Detail: full customer/order/items/payment proof/OCR/audit trail/status controls.
- Prep & Procurement: confirmed dish counts + ingredient totals grouped by fulfillment date.
- Settings: payment methods and QR images, fulfillment options, shipping tiers, batches/cutoffs.
PrepFlow/
├── api/ # Laravel API, migrations, PHPUnit tests, Docker runtime
├── apps/
│ ├── web/ # Vite React customer/admin SPA
│ └── mobile/ # Capacitor Android shell; generated android/ is ignored
├── db/ # Canonical MySQL schema reference
├── docs/ # Architecture, ERD, DFD, deployment, planning reports
├── packages/
│ └── shared/ # zod schemas and shared TypeScript DTOs
├── tools/ # composer.phar, no global Composer required
├── DECISIONS.md # locked product/architecture decisions
├── render.yaml # Render Blueprint reference
└── package.json # Bun workspace shortcuts
- Windows + PowerShell
- XAMPP with PHP 8.2 and MySQL/MariaDB (
C:\xampp\phpexpected) - Bun 1.3+
- Android Studio + Android SDK for APK work
- Cloudinary account for image upload testing
- Optional local OCR: Tesseract at
C:\Program Files\Tesseract-OCR\tesseract.exe
git clone https://github.com/cikeyz/prepflow.git
cd prepflowIf you have SSH keys set up with GitHub, you can use the SSH URL instead:
git clone git@github.com:cikeyz/prepflow.git.
bun installcd api
$env:PATH = 'C:\xampp\php;' + $env:PATH
php ..\tools\composer.phar install
Copy-Item .env.example .env
php artisan key:generateSet local .env values. Keep .env uncommitted.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=prepflow
DB_USERNAME=root
DB_PASSWORD=
CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>
OCR_TECHNIQUE=none
TESSERACT_BIN=
For local Tesseract OCR:
OCR_TECHNIQUE=tesseract
TESSERACT_BIN=C:\Program Files\Tesseract-OCR\tesseract.exe
Run these from the api/ directory (same as Step 2):
& 'C:\xampp\mysql\bin\mysql.exe' -u root -e "CREATE DATABASE prepflow CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
php artisan migrate --seed
php artisan storage:linkThe storage:link command creates a symlink for locally-stored files.
On Windows, this may require Developer Mode or running PowerShell as
Administrator. If it fails, enable Developer Mode in Settings →
Privacy & Security → For Developers.
Terminal 1:
cd api
$env:PATH = 'C:\xampp\php;' + $env:PATH
php artisan serve --host=127.0.0.1 --port=8000Terminal 2:
cd apps/web
bun run devOpen http://localhost:5173.
Prebuilt debug APKs are on GitHub Releases (PrepFlow-debug.apk and production-API variants). Install with unknown sources allowed. These are debug builds, not Play Store packages.
Rebuild locally:
# from repo root
bun run build:mobile
cd apps/mobile/android
# Set these to match your local Android SDK and Java paths
$env:ANDROID_HOME='C:\Android\Sdk'
$env:ANDROID_SDK_ROOT='C:\Android\Sdk'
$env:JAVA_HOME='C:\Program Files\Android\Android Studio\jbr'
.\gradlew.bat assembleDebugDebug APK output:
apps/mobile/android/app/build/outputs/apk/debug/app-debug.apk
For production APKs, the root mobile build script targets the deployed Render API:
bun run build:mobileFor emulator/local API testing, use bun run build:mobile:local; it targets http://10.0.2.2:8000/api.
More details: apps/mobile/README.md.
The current free-tier deployment is:
PrepFlow production
├── Vercel static app
│ └── /api/* rewrite -> Render Docker Laravel API
│ ├── TiDB Cloud Starter
│ ├── Cloudinary
│ └── Tesseract OCR
└── Capacitor Android APK
└── HTTPS JSON/session API -> Render Docker Laravel API
Required production environment variables are documented in docs/deployment/free-tier.md. Key values:
| Provider | Required setting |
|---|---|
| Vercel | VITE_API_URL=/api or leave unset; vercel.json proxies /api/* to Render |
| Render | APP_ENV=production, APP_DEBUG=false, APP_URL=https://prepflow-api.onrender.com |
| Render | DB_* TiDB values, MYSQL_ATTR_SSL_CA=/etc/ssl/certs/ca-certificates.crt |
| Render | SESSION_DRIVER=database, SESSION_SAME_SITE=none, SESSION_SECURE_COOKIE=true |
| Render | CLOUDINARY_URL, OCR_TECHNIQUE=tesseract, TESSERACT_BIN=/usr/bin/tesseract |
| Render | CORS_ALLOWED_ORIGINS=https://prepflow-vercel-static.vercel.app,https://thaijoint-prepflow.vercel.app,https://localhost,http://10.0.2.2 |
| Render | MAIL_MAILER=smtp, MAIL_HOST=smtp-relay.brevo.com, MAIL_PORT=2525, MAIL_ENCRYPTION=tls |
After first successful migration, set RUN_MIGRATIONS=false unless a new migration is intentionally being deployed.
Run these before marking a change complete:
cd api
$env:PATH = 'C:\xampp\php;' + $env:PATH
php artisan test
vendor/bin/pint --test
cd ..\apps\web
bun run build
cd ..\mobile
bun run syncLatest verified gate after the Android notification, admin prep, and README rubric-packaging fixes:
bun run build: passed
bun run build:mobile: passed
Android assembleDebug: passed
PHP tests: 122 passed (429 assertions)
Pint: passed
Debug APK SHA-256: 13B8A6D256766CFC39BF363C49BEECAC6DEF41B3D4FE5290F339CB5891545EED
Useful deployed smoke checks:
Invoke-WebRequest -Uri https://prepflow-api.onrender.com/api/menu -UseBasicParsing
Invoke-WebRequest -Uri https://prepflow-api.onrender.com/api/payment-methods -UseBasicParsing
Invoke-WebRequest -Uri https://prepflow-vercel-static.vercel.app/api/menu -UseBasicParsingOCR diagnostic:
cd api
$env:PATH='C:\xampp\php;' + $env:PATH
$env:OCR_TECHNIQUE='tesseract'
$env:TESSERACT_BIN='C:\Program Files\Tesseract-OCR\tesseract.exe'
php artisan ocr:receipt-check --image-file='D:\Users\Carl\Downloads\724483969_1335935291314941_416704984620132909_n.jpg'- Bun only. Do not use npm/yarn/pnpm for repo tasks.
- Do not commit
.env, Cloudinary keys, TiDB passwords, Render secrets,vendor/,node_modules/,dist/, or generatedandroid/. - Keep graded primitives visible: explicit
json_encoderesponses, session regeneration on auth changes, PDO/prepared statements/transactions for critical writes. - Any schema/enum change must update all mirrors:
db/schema.sql, Laravel migration,packages/shared/src/index.ts, andapps/web/src/types.ts. - No payment processor APIs, card processing, courier dispatch APIs, multi-tenant support, or PayMongo.
- Every async UI path should have loading state and user-visible error feedback.
Read DECISIONS.md before changing product scope or architecture.
| Document | Purpose |
|---|---|
| DECISIONS.md | Locked product scope, architecture, and tradeoffs |
| docs/planning/submission-readiness-2026-06-29.md | Current rubric readiness audit and latest verification evidence |
| docs/planning/defense-cheat-sheet.md | Short panel-question answers with source files to show |
| LICENSE | MIT terms and brand/media notice |
| docs/SYSTEM-DIAGRAMS.md | Rubric diagram index: Structurizr C4 model plus DFD, flowchart, sequence, and ERD |
| docs/architecture/workspace.dsl | Structurizr DSL source of truth for the C4 architecture model |
| docs/screenshots/ | Curated README and presentation screenshots |
| docs/ARCHITECTURE.md | System design and rubric traceability |
| docs/ERD.md | Entity relationship model |
| docs/DFD.md | Data flow diagrams |
| docs/deployment/free-tier.md | Render + TiDB + Vercel deployment guide |
| docs/planning/session-final-report.md | Historical implementation and verification report |
| docs/planning/deployment-hardening-session-2026-06-28.md | Historical deployment/auth/email/OCR/APK hardening session log |
| docs/planning/completion-audit.md | Historical audit baseline |
| apps/mobile/README.md | Capacitor/Android build notes |
| Member | Role and contribution |
|---|---|
| Ortiz, Carl Kristian R. | Sole full-stack implementer: architecture, frontend, backend, database, deployment, Android packaging, documentation, and integration |
| Alferez, Rey Lawrence P. | UI/UX and Figma direction, screen references, user-flow review |
| Patanao, Xian Zheniel Asha R. | Customer-flow QA, responsive checks, presentation readiness |
| Paulo, Alfonso Leon A. | Admin/mobile QA, demo testing |
MIT. See LICENSE.
Thai Joint PH names, logos, product photos, and related brand assets remain the property of their respective owners. MIT covers PrepFlow source code and project docs; brand media is not free for unrelated commercial reuse.
Built for CMPE 364 (Web and Mobile Systems), Polytechnic University of the Philippines, under Engr. Arlene B. Canlas. Final group project; defended and graded. Published here as a standalone portfolio product.




