Sustainable waste-to-product marketplace prototype built with Laravel + Vite.
Install / have on PATH:
| Tool | Recommended |
|---|---|
| PHP | 8.3+ (CLI) |
| Composer | latest |
| Node.js | 20+ |
| npm | 10+ |
| Git | latest |
| (Optional) MySQL / XAMPP | For MySQL instead of SQLite |
Quick demo can run with the included SQLite database (default config) – fastest path.
git clone <your-fork-or-repo-url> Waste2Product
cd Waste2Product
composer install
npm installAlready configured in config/database.php (points at database/database.sqlite). If the file is missing:
ni database\database.sqlite -ItemType FileRun migrations:
php artisan migrate- Start MySQL (XAMPP Control Panel: Start MySQL).
- Create a database (e.g.
waste2product) OR run:php scripts/create_mysql_db.php - Migrate:
php artisan migrate
Or run the helper (attempts dependencies + migrate):
./scripts/setup.ps1Terminal 1 (Laravel):
php artisan serve --host=127.0.0.1 --port=8000Terminal 2 (Vite with HMR):
npm run devOpen: http://127.0.0.1:8000
npm run build
php artisan config:cache route:cache view:cacheServe via a real web server (Nginx/Apache) pointing document root at public/.
The application features a WebSocket-based real-time bidding system. When users place bids, they appear instantly for other users viewing the same listing, and bid cards on the dashboard update in real-time.
See Real-time Bidding Documentation for setup and usage details.
The GitHub Actions workflow runs only for pushes and pull requests targeting the develop branch (feature branches open PRs into develop).
Pipeline stages / jobs:
- Stage 1 (build & test, run in parallel):
- php-tests: provisions SQLite DB, clears caches, runs
php artisan testwith Clover coverage output for SonarCloud. - frontend-build: Node 20, caches npm,
npm ci && npm run buildto validate asset build.
- php-tests: provisions SQLite DB, clears caches, runs
- Stage 2 (quality gates, all depend on both Stage 1 jobs and run in parallel):
- pint: Laravel Pint style check (
--test). - phpstan: Static analysis (Larastan) using
phpstan.neon.dist. - js-lint: ESLint (flat config) over
resources/jssources. - sonarcloud: Code + coverage analysis (public repo only, gated by secret
SONAR_TOKEN).
- pint: Laravel Pint style check (
- Stage 3 (final):
- docker-verify: Builds the multi-stage
Dockerfile(no push) taggedrecircle:testto ensure container reproducibility.
- docker-verify: Builds the multi-stage
Key implementation notes:
- Matrix removed: single baseline runtime on PHP 8.2 keeps the pipeline fast.
- Test coverage path:
coverage-reports/phpunit-coverage.xml(Clover) ingested by SonarCloud. - Sonar configuration centralized in
sonar-project.properties(no inline args) and only runs if the repository is public. - Docker build uses Buildx with provenance disabled for speed; no image is pushed (verification only).
- Future enhancements (not yet implemented): production asset copy stage, opcache tuning, path-based workflow filters to skip Docker on docs-only changes.
Repository rename: Upstream moved to ReCircle organization naming; historical badges & keys (Sonar project vvebwizards_Waste2Product) retained for continuity.
Local expectations before pushing:
- Format PHP:
vendor/bin/pint(or let pre-commit run it). - Static analysis:
composer run phpstan. - JS lint:
npm run lint. - Tests:
php artisan test.
Pre-commit hook
- Husky runs Pint, PHPStan, and ESLint. Bypass with
SKIP_HOOKS=1if absolutely required.
Troubleshooting CI
- If Blade Vite assets break tests: we guard
@vitein layouts to skip only intestingenv. - If coverage is empty, ensure Xdebug is enabled in CI (already configured) and the Clover path
coverage-reports/phpunit-coverage.xmlexists.
Implemented custom stateless auth using JSON Web Tokens (firebase/php-jwt) with HttpOnly cookie storage.
| Method | Path | Description | Auth Required |
|---|---|---|---|
| POST | /api/auth/login |
Authenticate user and set JWT cookie | No |
| POST | /api/auth/refresh |
Refresh (rotate) token before expiry | Yes (valid cookie) |
| GET | /api/auth/me |
Return current user (id, name, email) | Yes |
| POST | /api/auth/logout |
Clear JWT cookie | Yes (cookie optional for idempotency) |
POST /api/auth/login
{
"email": "test@example.com",
"password": "password"
}{
"token_type": "Bearer",
"expires_at": "2025-09-16T13:10:25+00:00"
}Token itself is stored only in an HttpOnly cookie named access_token (configurable via config/jwt.php). Not accessible from JS (document.cookie).
curl -H "Accept: application/json" -b "access_token=<copied-if-non-HttpOnly>" http://localhost:8000/api/auth/meResponse:
{
"data": { "id": 1, "name": "Test User", "email": "test@example.com" }
}Call periodically (e.g. 5 minutes before expires_at):
curl -X POST -H "Accept: application/json" -b cookies.txt -c cookies.txt http://localhost:8000/api/auth/refreshReturns same shape as login with a new expiry and rotated cookie.
curl -X POST -H "Accept: application/json" -H "X-CSRF-TOKEN: <csrf>" -b cookies.txt -c cookies.txt http://localhost:8000/api/auth/logoutResponse:
{ "message": "Logged out" }- After page load, JS attempts
/api/auth/me; if 200 it builds authenticated nav, else guest nav. - Login form posts to
/api/auth/login; upon success it calls/api/auth/meto hydrate user state then redirects. - Logout sends POST
/api/auth/logoutincludingX-CSRF-TOKEN(meta tag added to layouts) and then redirects to/auth. - All fetch calls include
credentials: 'include'to send the cookie.
| Aspect | Decision | Rationale |
|---|---|---|
| Storage | HttpOnly cookie | Prevent XSS token theft |
| SameSite | Lax | Allows normal navigation, reduces CSRF risk |
| Secure flag | Only in production | Local dev over HTTP still works |
| TTL | 60 minutes (configurable) | Reasonable session window |
| Refresh | Rotation endpoint | Prepares for silent refresh logic |
| Claims | iss, sub, iat, exp | Minimal set for validation |
We support TOTP-based 2FA with QR provisioning and one-time recovery codes.
Endpoints (require a valid JWT unless noted):
| Method | Path | Description |
|---|---|---|
| GET | /api/auth/2fa/setup |
Returns otpauth URI, QR SVG, and recovery codes; creates a secret/codes if missing |
| POST | /api/auth/2fa/enable |
Enable 2FA by verifying a 6-digit code from your authenticator app |
| POST | /api/auth/2fa/disable |
Disable 2FA and clear secret and recovery codes |
Login flow: If a user has 2FA enabled, /api/auth/login will return 403 with { "requires_twofa": true } until a correct twofa_code or recovery_code is provided.
UI: Visit /settings/security while signed in to set up or disable 2FA, scan the QR, and copy/download recovery codes.
Security notes:
- Recovery codes are one-time use; using a code immediately removes it from the list.
- QR is rendered as SVG (no external image fetches).
- CSRF is required for POST enable/disable.
- Silent refresh module in JS (schedule refresh before expiry)
- Separate refresh token & denylist for logout invalidation
- Role/permission claims or separate endpoint for authorization
- Rate limiting on
/api/auth/login(addthrottlemiddleware)
# Login (capture cookie)
curl -i -H "Accept: application/json" -H "X-CSRF-TOKEN: $(curl -s http://localhost:8000/auth | grep -oP 'meta name=\"csrf-token\" content=\"\K[^\"]+')" \
-c cookies.txt -X POST -d '{"email":"test@example.com","password":"password"}' \
-H "Content-Type: application/json" http://localhost:8000/api/auth/login
# Me
curl -H "Accept: application/json" -b cookies.txt http://localhost:8000/api/auth/me
# Refresh
curl -X POST -H "Accept: application/json" -b cookies.txt -c cookies.txt http://localhost:8000/api/auth/refresh
# Logout
CSRF=$(grep csrf-token: cookies.txt || echo "")
curl -X POST -H "Accept: application/json" -H "X-CSRF-TOKEN: $(curl -s http://localhost:8000/auth | grep -oP 'meta name=\"csrf-token\" content=\"\K[^\"]+')" -b cookies.txt -c cookies.txt http://localhost:8000/api/auth/logout| Route | Purpose |
|---|---|
/ |
Landing page |
/auth |
Auth page (sign in / sign up tabs) |
/twofa |
Placeholder 2FA step (demo) |
/settings/security |
Security settings (2FA setup/disable UI) |
/forgot-password |
Demo recovery flow |
/dashboard |
User dashboard |
/admin/dashboard |
Admin dashboard |
| Path | Description |
|---|---|
resources/views/layouts/app.blade.php |
Public layout |
resources/views/layouts/admin.blade.php |
Admin layout |
resources/views/admin/partials/sidebar.blade.php |
Reusable sidebar |
resources/js/main.js |
Global UI behaviors |
resources/js/dashboard.js |
User dashboard logic |
resources/js/admin-dashboard.js |
Admin dashboard logic |
resources/css/style.css |
Template styling |
Please read CONTRIBUTING.md for the branching model (feature -> develop -> release -> main), issue workflow, commit conventions, and PR checklist.
Before pushing or opening a PR, format PHP with Pint:
vendor/bin/pintContributions & feedback welcome.