git clone https://github.com/pratama1246/PickupOrder-App.git
cd PickupOrder-App
composer run setup- System Overview
- Practical Use Cases
- Core Engineering Capabilities
- System Architecture
- Repository Structure
- Environment Configuration
- Local Setup and Runbook
- Midtrans Integration and Webhook
- Operational Deployment Runbook
- Default Demo Accounts
- Interface Gallery
- License
PickupOrder-App is a multi-role web platform built to solve physical queue congestion across Politeknik Negeri Cilacap (PNC) canteen food stalls during peak break hours. The system enables students to explore canteen menus, submit orders ahead of class dismissal, and choose between automated online payment (Midtrans Snap), manual QRIS transfers with image proof validation, or cash settlement at pickup.
The platform coordinates three distinct user roles:
- Student (Mahasiswa): Menu discovery, multi-item cart management, checkout with time-fencing validation, order tracking, code-based pickup verification, and menu ratings.
- Canteen Vendor: Food stall profile configuration, live order intake dashboard, barcode/code scanner verification at the counter, menu inventory toggling, daily revenue target monitoring, and sales summaries.
- Campus Administrator: Canteen stall lifecycle management, bulk student account provisioning via spreadsheet/CSV import, access toggles, and system-wide audits.
The application adheres to local-first data residency: all transactions and session states persist in MySQL, static media and payment slips reside on local disk storage with public symlinks, and zero external telemetry is collected.
- Problem: 15 to 30-minute campus break windows are consumed waiting in line at physical food counters, causing delayed returns to lecture halls.
- Solution: Students order meals 10 to 20 minutes prior to break from their phone or laptop. The system holds the order in state until the kitchen prepares it, sending a status update when the food is ready for counter pickup.
- Problem: Stall operators manage orders via paper notes and unverified phone chat screenshots, resulting in incorrect meals, unpaid orders, and counter chaos.
- Solution: The vendor portal surfaces a structured incoming order board. When a student arrives, the vendor enters or scans the order pickup code, marks the item fulfilled, and checks daily gross revenue progress against predefined financial targets.
- Problem: Academic terms require provisioning hundreds of student accounts and regulating authorized vendors without manual database queries.
- Solution: Department administrators use bulk CSV template imports with automatic initial credential configuration (
is_first_loginflag) and manage vendor stall allocations through a single console.
- Operational Window Enforcement (
CheckOnlineOrderHoursMiddleware): Order placement is strictly bounded to campus operating hours defined in.env(ORDER_START_TIMEtoORDER_END_TIME, with active day filtering). Requests outside this window are intercepted at the HTTP pipeline level and rejected with contextual feedback. - Dual Payment Verification Flow:
- Automated Webhook: Incoming Midtrans notifications (
POST /payment/notification) undergo cryptographic SHA-512 signature validation (hash('sha512', order_id + status_code + gross_amount + server_key)) without external SDK roundtrip overhead. Grouped order records tied to a single payment code are transitioned atomically. - Manual QRIS: Image proofs submitted by students are validated via Intervention Image, stored in private disk directories, and gated behind vendor review before order preparation begins.
- Automated Webhook: Incoming Midtrans notifications (
- Non-Blocking Client Status Polling (
/api/order/{id}/payment-status): A lightweight JSON polling endpoint allows client interfaces to reflect settlement status in real time if webhook delivery is delayed by network partitions. - Unified Cart Synchronization (
SyncCartSessionMiddleware): Cart contents are reconciled between guest session storage and authenticated database records, preventing item loss during login transitions. - First-Login Credential Rotation Gate: Accounts seeded or imported by administrators require an immediate password change on first authentication before accessing transactional endpoints.
- Layered HTTP Defense (
SecurityHeadersMiddleware): Applies Content Security Policy (CSP), clickjacking prevention (X-Frame-Options: SAMEORIGIN), MIME-type sniffing defense (X-Content-Type-Options: nosniff), and rate throttling on login (5 req/min) and checkout (10 req/min). - Tailored Design System Tokens:
Utilizes Tailwind CSS v4
@themetokens (fern-700,vanilla-custard-50,pnc-navy) combined with DaisyUI v5 components and Poppins typography.
flowchart TD
subgraph Clients["Client Layer"]
MClient["Mahasiswa (Mobile / Desktop Web)"]
VClient["Vendor Terminal (Stall Counter)"]
AClient["Campus Admin (Management Console)"]
end
subgraph HTTPGateway["HTTP Gateway & Middleware Pipeline"]
Nginx["Web Server / Vite Dev Server"]
SecHeaders["SecurityHeadersMiddleware\n(CSP, X-Frame-Options, Nosniff)"]
HoursCheck["CheckOnlineOrderHours\n(Schedule Verification)"]
RoleCheck["CheckRole Middleware\n(mahasiswa | vendor | admin)"]
end
subgraph AppKernel["Laravel 13 Application Layer"]
UserCtrl["User & Checkout Controllers\n(Cart, Orders, Reviews)"]
VendorCtrl["Vendor Controllers\n(Order Scan, Menus, Reports)"]
AdminCtrl["Admin Controllers\n(Canteen CRUD, CSV User Import)"]
CallbackCtrl["PaymentCallbackController\n(SHA-512 Signature Verification)"]
end
subgraph AsyncWorkers["Background Processing"]
QueueWorker["Laravel Queue Worker\n(Database Driver)"]
end
subgraph Persistence["Storage Layer"]
MySQL[("MySQL 8.0+ Database\n(Users, Canteens, Orders, Items, Reviews)")]
DiskStorage[("Local Disk Storage\n(/storage/app/public)")]
end
subgraph ExternalGateways["External Payment Infrastructure"]
MidtransSnap["Midtrans Snap Gateway\n(Online Payment Engine)"]
MidtransWebhook["Midtrans Webhook Callbacks\n(Notification POST)"]
end
Clients --> Nginx
Nginx --> SecHeaders
SecHeaders --> HoursCheck
HoursCheck --> RoleCheck
RoleCheck --> UserCtrl
RoleCheck --> VendorCtrl
RoleCheck --> AdminCtrl
UserCtrl -->|Request Payment Token| MidtransSnap
MidtransWebhook -->|POST /payment/notification| CallbackCtrl
UserCtrl --> MySQL
VendorCtrl --> MySQL
AdminCtrl --> MySQL
CallbackCtrl --> MySQL
VendorCtrl --> DiskStorage
UserCtrl --> DiskStorage
AppKernel -.->|Enqueue Background Jobs| QueueWorker
QueueWorker --> MySQL
pickuporder-app/
├── app/
│ ├── Helpers/
│ │ └── OrderHelper.php # Schedule validation and active day calculation
│ ├── Http/
│ │ ├── Controllers/
│ │ │ ├── Admin/ # Canteen CRUD, user bulk operations and CSV imports
│ │ │ ├── AuthController.php # Authentication, throttling and first-login password flow
│ │ │ ├── HomeController.php # Public landing and information pages
│ │ │ ├── ProfileController.php # User and vendor profile and credential updates
│ │ │ ├── User/ # Cart, Checkout, Order History, Payment Callback, Reviews
│ │ │ └── Vendor/ # Dashboard, live order processing, menu management, reports
│ │ └── Middleware/
│ │ ├── CheckOnlineOrderHours.php# Restricts checkout to configured operating schedule
│ │ ├── CheckRole.php # Role-based access control (mahasiswa, vendor, admin)
│ │ ├── SecurityHeadersMiddleware.php # CSP, frame isolation and security headers
│ │ └── SyncCartSession.php # Session-to-database cart synchronization
│ └── Models/ # Eloquent entities (User, Canteen, Menu, Order, OrderItem, Review)
├── bootstrap/
│ └── app.php # Pipeline configuration, route bindings and CSRF exemptions
├── config/ # Configuration profiles (services, app, database)
├── database/
│ ├── migrations/ # Schema migrations (relational tables, QRIS proofs, daily targets)
│ └── seeders/ # DatabaseSeeder with demo users, canteens and orders
├── docs/ # Layout analyses and UI design specifications
├── public/
│ ├── assets/ # Brand SVGs, vector assets and PNC illustrations
│ └── index.php # HTTP front controller
├── resources/
│ ├── css/
│ │ └── app.css # Tailwind CSS v4 custom theme and color tokens
│ ├── js/
│ │ └── app.js # Alpine.js, ApexCharts and Axios client scripts
│ └── views/
│ ├── admin/ # Campus administrator interface views
│ ├── components/ # Reusable Blade components (cards, navbar, status badges)
│ ├── layouts/ # Master templates (app, auth, admin)
│ ├── user/ # Student-facing views (browse, canteen, checkout, history)
│ └── vendor/ # Vendor booth portal views (dashboard, scan, menu CRUD)
├── routes/
│ ├── console.php # Artisan command definitions
│ └── web.php # HTTP routing, middleware groups and webhook entry points
├── tests/ # Unit and feature test suites
├── composer.json # PHP dependencies and automated workflow scripts
├── package.json # Node dependencies (Tailwind v4, DaisyUI v5, Alpine)
└── vite.config.js # Vite asset build and bundling configuration
Copy .env.example to .env and configure key parameters:
| Variable | Default Value | Description |
|---|---|---|
APP_NAME |
PickupOrder-App |
Platform identity title |
APP_ENV |
local |
Environment mode (local, production) |
APP_KEY |
(Generated) | 32-character application encryption key |
APP_URL |
http://localhost:8000 |
Base URL (must match Ngrok / production domain) |
DB_CONNECTION |
mysql |
Primary database driver |
DB_HOST |
127.0.0.1 |
MySQL server host |
DB_PORT |
3306 |
MySQL port |
DB_DATABASE |
pickuporder_app |
MySQL database name |
DB_USERNAME |
root |
Database username |
DB_PASSWORD |
"" |
Database password |
ORDER_START_TIME |
07:30 |
Daily operational opening time (WIB) |
ORDER_END_TIME |
15:30 |
Daily operational cutoff time (WIB) |
ORDER_ACTIVE_DAYS |
Monday,Tuesday,... |
Comma-delimited active order days |
MIDTRANS_SERVER_KEY |
(Required) | Midtrans server authentication key |
MIDTRANS_CLIENT_KEY |
(Required) | Midtrans client public key |
MIDTRANS_IS_PRODUCTION |
false |
Set true for live production transactions |
QUEUE_CONNECTION |
database |
Asynchronous queue driver |
SESSION_DRIVER |
database |
Session persistence storage |
| Component | Minimum Version | Note |
|---|---|---|
| PHP | ^8.3 |
Required extensions: pdo_mysql, curl, mbstring, gd |
| Composer | ^2.5 |
Dependency management |
| Node.js | ^20.0 |
Node Package Manager (npm) |
| MySQL | ^8.0 |
Or MariaDB ^10.5 |
Run the predefined setup script which handles dependency installation, .env initialization, key generation, database migration, and frontend asset compilation:
composer run setupAfter the script finishes, generate the public storage symlink for uploaded canteen images and QRIS receipts:
php artisan storage:link(Optional) Seed demo data (users, canteens, menus, and historical orders):
php artisan db:seedIf configuring step-by-step:
# Clone and enter workspace
git clone https://github.com/pratama1246/PickupOrder-App.git
cd PickupOrder-App
# Install backend dependencies
composer install
# Environment initialization
cp .env.example .env
php artisan key:generate
# Execute database migrations
php artisan migrate
# Link public storage disk
php artisan storage:link
# Install and build frontend assets
npm install
npm run buildTo run all development processes concurrently (Laravel server, queue listener, log streaming via Pail, Vite asset watcher, and Ngrok tunnel):
composer run devAlternatively, run each process in dedicated terminal tabs:
# Terminal 1: HTTP Server
php artisan serve --host=0.0.0.0 --port=8000
# Terminal 2: Queue Listener
php artisan queue:listen --tries=1
# Terminal 3: Asset Compiler
npm run devThe platform supports three checkout methods:
- Midtrans Snap: Credit Card, GoPay, ShopeePay, Bank Transfer (BCA, BNI, BRI, Mandiri). Handled via client popup and verified through backend webhook callbacks.
- Manual QRIS: The student transfers via standard static/dynamic QRIS, uploads the screenshot receipt, and awaits vendor counter confirmation.
- Pay Direct: Cash on pickup confirmed manually at the canteen register.
- This route is excluded from CSRF validation inside
bootstrap/app.phpto accept external calls from Midtrans servers. - The controller calculates the expected SHA-512 signature using the raw payload and
MIDTRANS_SERVER_KEY:If signatures match, order statuses ($expected = hash('sha512', $orderId . $statusCode . $grossAmount . $serverKey);
pending,settlement,expire,cancel) are propagated to all items associated with thepayment_code.
- Start an Ngrok tunnel pointing to port 8000:
ngrok http 8000
- Note the generated HTTPS forwarding URL (e.g.
https://your-domain.ngrok-free.app). - Set your notification endpoint in the Midtrans Sandbox Dashboard:
Settings > Configuration > Payment Notification URLhttps://your-domain.ngrok-free.app/payment/notification - Update
APP_URLin.env:APP_URL=https://your-domain.ngrok-free.app
When deploying to a production server (Ubuntu/Debian, Nginx, PHP-FPM, MySQL):
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan storage:link
php artisan migrate --forceCreate /etc/supervisor/conf.d/pickuporder-worker.conf:
[program:pickuporder-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/pickuporder-app/artisan queue:work database --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=2
redirect_stderr=true
stdout_logfile=/var/www/pickuporder-app/storage/logs/worker.log
stopwaitsecs=3600Update supervisor processes:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start pickuporder-worker:*Run test verification suites prior to shipping updates:
composer run testInitial data populated by php artisan db:seed:
Default password for all seeded accounts:
pncpickup123
| Role | Username / Identifier | Email Address | Initial State |
|---|---|---|---|
| Admin | admin |
admin@pnc.ac.id |
Active |
| Vendor 1 (Kantin Harmoni) | vendor_harmoni |
kantinharmoni@pnc.ac.id |
Active (Booth Open) |
| Vendor 2 (Kantin MI) | vendor_mi |
miacademy@pnc.ac.id |
Active (Booth Open) |
| Student (Mahasiswa) | demo_student |
demo.student@pnc.ac.id |
Requires password change on first login |
This software is open-source, distributed under the MIT License.





