Full-stack fashion marketplace demo: Laravel 13 REST API + Next.js 15 storefront with Stripe Checkout, FedEx sandbox shipping, printable labels, and an admin panel for orders, customers, and multi-currency settlement.
flowchart LR
subgraph client [Next.js 15]
Store[Storefront]
Admin[Admin UI]
end
subgraph api [Laravel API :8088]
Orders[OrderService]
PayGW[PaymentGateway]
ShipGW[ShippingCarrier]
Events[OrderPaid event]
end
subgraph external [External]
StripeAPI[Stripe]
FedExAPI[FedEx Sandbox]
end
Store -->|REST JSON| Orders
Admin -->|Bearer token| Orders
Orders --> PayGW
Orders --> ShipGW
PayGW -->|fulfillment| Events
Events --> ShipGW
PayGW --> StripeAPI
ShipGW --> FedExAPI
See ARCHITECTURE.md for contracts, DTOs, and FedEx module layout.
| Layer | Stack | URL |
|---|---|---|
| Frontend | Next.js 15 (App Router) | http://localhost:3001 |
| API | Laravel 13 REST | http://localhost:8088/api |
| Database | MySQL 8.4 | localhost:3308 |
frontend/ Next.js storefront + admin
app/ Laravel API (services, controllers, models)
routes/api.php
docker-compose.yml
tests/ PHPUnit feature + unit tests
cp .env.example .env
# Optional: add Stripe + FedEx sandbox credentials
docker compose up --buildOpen:
- Store: http://localhost:3001
- API health: http://localhost:8088/api/health
- Integration status: http://localhost:8088/api/integrations/status
- Admin: http://localhost:3001/admin
Admin credentials (demo only):
- Email:
admin@marketplace.demo - Password:
password
- Browse designs → add to cart (single currency per checkout)
- Checkout → enter US ship-to address → Calculate FedEx shipping
- Pay with Stripe test card
4242 4242 4242 4242(or demo mode without keys) - Success page confirms payment; FedEx label generated when paid
- Admin → orders → view customer Stripe payload, settlement, print FedEx PDF label
Uses the FedEx sandbox when credentials are set:
| Step | Endpoint |
|---|---|
| OAuth | POST https://apis-sandbox.fedex.com/oauth/token |
| Rates | POST /rate/v1/rates/quotes |
| Labels | POST /ship/v1/shipments → official PDF (PAPER_4X6) |
Responses include source and fallback_reason when zone-based demo rates are used instead of live API data.
Label sources stored on each shipment:
label_source |
Meaning |
|---|---|
fedex_sandbox_pdf |
Official FedEx sandbox PDF |
fedex_sandbox_pdf_retry |
PDF using FedEx test address after invalid ship-to |
html_fallback |
Printable HTML when Ship API fails |
html_no_credentials |
HTML when FedEx keys are absent |
APP_DEMO_MODE=true # Enables POST /orders/{order}/complete-demo locally
STRIPE_KEY=pk_test_...
STRIPE_SECRET=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
FEDEX_CLIENT_ID=...
FEDEX_CLIENT_SECRET=...
FEDEX_ACCOUNT_NUMBER=...
FEDEX_BASE_URL=https://apis-sandbox.fedex.com
FEDEX_TOKEN_URL=https://apis-sandbox.fedex.com/oauth/token
FEDEX_ORIGIN_LINE1="350 5th Ave"
FEDEX_ORIGIN_CITY="New York"
FEDEX_ORIGIN_STATE=NY
FEDEX_ORIGIN_POSTAL_CODE=10001
ADMIN_EMAIL=admin@marketplace.demo
ADMIN_PASSWORD=password
ADMIN_TOKEN=demo-admin-tokenStripe webhooks (local):
stripe listen --forward-to localhost:8088/api/webhooks/stripe| Method | Path | Description |
|---|---|---|
| GET | /api/products |
Catalog |
| POST | /api/shipping/quote |
FedEx rates (sandbox or zone fallback) |
| POST | /api/checkout |
Create order + Stripe session |
| POST | /api/checkout/confirm |
Confirm paid Stripe session |
| GET | /api/orders/{orderNumber} |
Order details (access token or signature required) |
| POST | /api/orders/{order}/complete-demo |
Demo payment completion (APP_DEMO_MODE only) |
| POST | /api/webhooks/stripe |
Stripe payment webhook (signature required when configured) |
| GET | /api/labels/{id} |
FedEx label PDF/HTML (signed URL required) |
| POST | /api/admin/login |
Admin bearer token |
| GET | /api/admin/orders |
Orders list |
| POST | /api/admin/orders/{id}/label?force=1 |
Generate/regenerate FedEx label |
| Control | Implementation |
|---|---|
| Order PII | access_token or signed URL required |
| Label download | Laravel signed URLs (30-day expiry) |
| Demo payment bypass | Gated by APP_DEMO_MODE |
| Stripe webhooks | Signature verification required when STRIPE_SECRET is set |
| Admin API | Bearer token + rate limiting |
| Checkout | Server-side shipping re-quote prevents price tampering |
- Admin auth uses a static bearer token (not Sanctum) — acceptable for local demo only.
- Invalid international or malformed addresses may be retried with a FedEx sandbox test address (Seattle) to produce a valid PDF.
- HTML label fallback exists when FedEx Ship API rejects a shipment.
- Settlement FX rates are hardcoded in
SettlementService(documented for demo).
composer lint # Laravel Pint (code style)
composer test # Pest test suite
composer test:coverage # Pest + PCOV (fails below 70% app coverage)
cd frontend && npm run lintGitHub Actions runs Pint, Pest with ≥70% PHP coverage, frontend typecheck, and production build on push/PR.
Paid orders store charge currency totals plus a converted settlement amount in SETTLEMENT_CURRENCY (default USD). The admin settlements screen highlights multi-currency payout inconsistencies — the core business problem this demo targets.