PackLoop is a mobile-first application designed to incentivize urban circular economy practices by facilitating reusable packaging collection. Users drop off packaging at smart IoT collection stations across public transit hubs and retail locations, earning points that can be redeemed directly to digital e-wallets.
The mobile client is engineered as a lightweight single-page application wrapped inside a native Tauri v2 Android shell, prioritizing low-latency rendering, instant tab switching, and seamless hardware interaction.
- Station Identification: Scan station QR codes or auto-select the nearest active station.
- Packaging Scanning & AI Inspection: Instant camera-based QR scanning (
react-webcam+jsQR) for item verification. - Unit & Weight Tracking: Input unit count or weight for eco-impact calculation.
- Instant Rewards: Immediate point allocation upon successful deposit confirmation.
- Interactive Map: Powered by Leaflet with canvas rendering for optimal mobile GPU performance.
- Real-Time Compartment Capacities: View live capacity levels (cardboard, paper bags, tote bags, bubble wrap) for each station.
- Status Indicators: Clear status markers for available, full, or maintenance-mode stations.
- Points Balance & Level Progression: Tiered user status based on total recycled mass and points earned.
- Instant Payouts: Withdraw points to GoPay, OVO, DANA, or LinkAja powered by backend Midtrans Iris webhook integration.
- Community Leaderboard: Gamified rankings showcasing top eco-contributors.
- Flexible Sign-In: Phone OTP authentication or Google OAuth via Supabase Auth.
- Deep Link Callback handling: OAuth redirects automatically caught via custom protocol handlers (
packloop://). - Impact Metrics: Profile dashboards tracking total packaging mass, CO2 emissions prevented, and total reuse cycles.
PackLoop decouples native shell responsibilities from application state, using Tauri purely as an execution container.
+-------------------------------------------------+
| Tauri v2 Mobile Shell |
| - Android WebView Container |
| - Deep-link Protocol Handler (packloop://) |
| - Native Plugins (Opener, Log) |
+------------------------+------------------------+
|
v
+-------------------------------------------------+
| React 19 Application |
| |
| +-------------------+ +-------------------+ |
| | TanStack Query 5 | | Zustand 5 | |
| | (Server State) | | (Persisted App) | |
| +---------+---------+ +---------+---------+ |
| | | |
+------------|-----------------------|------------+
| |
v v
+------------------------+------------------------+
| REST API Backend | Supabase Auth / DB |
| (FastAPI/Express) | (OAuth & Phone OTP) |
+------------------------+------------------------+
- DOM Keep-Alive Caching (
AppShell): Core shell views (Home,Explore,Rewards,Profile) are kept permanently mounted in the DOM. Tab navigation toggles CSS visibility (hidden), preserving Leaflet map tile buffers, canvas layers, and scroll positions without re-render performance penalties. - Leaflet Mobile Optimization: Maps utilize
preferCanvas={true}to route vector overlay rendering to a 2D HTML5 canvas context, preventing ARM Mali GPU texture memory overflow (BAD ALLOC) on Android WebViews. - OpenAPI Client Generation: API client SDK and TanStack Query option factories are generated automatically via
@hey-api/openapi-tsfrom remote OpenAPI definitions, eliminating manual fetch wrapper maintenance. - Tailwind CSS v4 CSS-First Engine: Theme definitions utilize OKLCH color space for perceptual uniformity defined inside
@themeblocks insrc/styles/app.css.
web-packloop/
├── docs/ # Past feature plans and API reference specs
├── public/ # Static branding assets and images
├── src-tauri/ # Tauri v2 native shell configuration
│ ├── Cargo.toml # Rust crate configuration
│ ├── tauri.conf.json # Tauri app configuration & permissions
│ └── src/lib.rs # Plugin initialization & entrypoint
├── src/
│ ├── api/ # API client, Query client setup & generated SDK
│ │ ├── client.ts # Base HTTP client with Auth bearer injection
│ │ ├── queryClient.ts # TanStack Query client configuration
│ │ └── generated/ # Auto-generated openapi types & mutation options
│ ├── components/ # Reusable UI components
│ │ ├── layout/ # AppShell & Navigation bars
│ │ ├── map/ # Leaflet map components & marker layers
│ │ └── ui/ # Reusable UI components (Modals, Headers, Toast)
│ ├── hooks/ # Custom React hooks (Auth, State observers)
│ ├── lib/ # Utility helpers (Supabase client, Environment flags)
│ ├── pages/ # Flat application pages (Home, Explore, Deposit, etc.)
│ ├── stores/ # Client state management (Zustand persistent store)
│ ├── styles/ # Global CSS & Tailwind v4 theme configuration
│ └── App.tsx # React Router v7 browser router configuration
├── index.html # App HTML entrypoint
├── vite.config.ts # Vite build & HMR server configuration
└── README.md # Documentation
- Node.js runtime: Bun (v1.1+ recommended)
- Rust Toolchain: Stable Rust (for Tauri desktop/mobile builds)
- Android Development: Android Studio, SDK Platform 34+, and NDK configured
- ADB Command Line Tools: For Android USB debugging & reverse port mapping
-
Clone the repository:
git clone https://github.com/ramarfx/web-packloop.git cd web-packloop -
Install dependencies:
bun install
-
Configure Environment Variables: Create a
.envfile in the root directory:VITE_API_BASE_URL=https://packloop-backend-beryl.vercel.app VITE_SUPABASE_URL=https://your-supabase-project.supabase.co VITE_SUPABASE_ANON_KEY=your-supabase-anon-key
| Action | Command | Description |
|---|---|---|
| Vite Dev Server | bun run dev |
Starts local development server at http://localhost:1420 |
| Android Development | bun run android |
Sets up ADB port forwarding (1420 & 1421) and launches Tauri Android app |
| Type Check | bun run typecheck |
Runs TypeScript compiler verification (tsc --noEmit) |
| Generate API Client | bun run generate |
Auto-generates TypeScript SDK and TanStack Query options from OpenAPI spec |
| Web Production Build | bun run build |
Compiles production assets into dist/ |
| Tauri Desktop Dev | bun run tauri dev |
Runs application in desktop Tauri shell |
API types and TanStack Query option factories in src/api/generated/ are automatically generated using @hey-api/openapi-ts.
To regenerate the API client after backend changes:
bun run generateNote: Ensure VITE_API_BASE_URL is configured in .env as the generator fetches openapi definitions remotely.