Smart Parking Suite · Full-stack Delivery
Resident and guard mini programs, an admin console and a Spring Boot backend covering the full parking loop
- Role
- Full-stack (backend, mini programs, admin console)
- Scale
- 4 clients · 390+ mini-program pages · 170+ endpoints
- Period
- Aug 2026 — Present
What I did
- One line covering the whole loop for three roles — driver, guard, lot operator — from finding a space through temporary/monthly/reserved parking, payment and invoicing, entry and exit, to exception release
- Backend is a Spring Boot 2 multi-module monolith (~170 controllers, 1,400+ Java files); parking, property and custody share account, tenancy, payment and messaging capabilities
- Six payment entry points unified into in-app WeChat Pay (main-scan), with validity extension on callback and channel-accurate status queries
- Resident client (390 pages / 5 subpackages), guard client, Vue 2 console (190+ pages) and backend share one set of state definitions, aligned by API contract
Context
The company runs a smart-parking SaaS: lot operators use it to manage spaces and charging, drivers use it to pay and to find spaces, guards use it at the gatehouse to handle entries, exits and exceptions. The business is not complicated; keeping it coherent across four clients is.
The business loop
| Role | What they do in the system |
|---|---|
| Driver | Find a nearby lot, pay for temporary parking, buy monthly/short-term passes, rent a space, reserve, get e-invoices |
| Guard | Watch live video at the gatehouse, register entries and exits, release exceptions, raise barriers |
| Lot operator | Configure lots, lanes, billing rules, monthly plans, spaces and sharing rules; read reports and reconcile |
| Platform operations | Manage lots and tenants, deliver permissions, configure payment channels and revenue split |
The parking space is the object that runs through the whole line: temporary parking occupies it, a monthly pass binds it, sharing rents it out, custody operates it. The same space has different states and billing models per business, but there is never a second copy of the space data.
My role
Full-stack. The line is delivered by the team; my part is:
- Backend endpoints: monthly renewal, space-management fees, temporary-parking toggle, payment-record aggregation, callback period extension
- Mini programs: resident home and nearby lots, monthly-pass lot selection and renewal, vehicle certification, unified session handling; parts of the guard client
- Admin console: gatehouse video and barrier permissions, lane notifications, monthly-pass issuance, merged arrears payment
- Cross-cutting: payment channel migration, package-size optimisation, cross-tenant and cross-user data validation
What was done
Unifying the payment path
Parking has six or seven payment entry points: temporary exit, pending orders, monthly renewal, lease signing, space-management fees, reservations. Each used to redirect to the Lakala cashier mini program — a long chain, a high failure rate, and inconsistent callbacks.
The team moved them all to in-app WeChat Pay (main-scan). On the backend, my entry points handle:
- validity extension by business type on callback (a renewal extends from the original expiry, not from today)
- status queries dispatched on the channel that actually placed the order, so Lakala and WeChat channels never mix
- zero-amount orders and concurrent purchases guarded by a distributed lock to prevent duplicate issuance
Old and new channels coexisted at page level for a period and were switched lot by lot — a problem could be rolled back for one lot instead of the whole site.
Billing and accounts
Temporary parking bills by tiered duration, monthly/short-term passes by validity period, shared spaces settle by revenue share, custody spaces by split settlement. All four billing models land on the same order and payment records: the lot needs revenue, the platform needs splits, the driver needs a payment history, and all three must agree on the same money.
My part concentrates on the validity layer: issuing, renewal, arrears payment and refunds all have to compute start and end correctly, and the console rules and mini-program display must come from the same endpoint.
Mini-program experience and constraints
The resident client has 390 pages across five subpackages. I rebuilt the parking home and nearby-lot recommendations, reworked monthly-pass lot selection and renewal, and consolidated scattered session-expiry checks into one path.
Real-device debugging hit the main-package ceiling (2,306 KB vs 2,048 KB). I moved 1,152 KB of static assets to OSS behind a single prefix constant, recompressed subpackage and tabBar icons, and wrote “new images go to OSS” into the team conventions.
The gatehouse
The closest this line gets to hardware: guards watch live video (WebRTC primary, MJPEG over WebSocket fallback), register entries, release exceptions and raise barriers. The team built the feature as a whole; I added granular permissions for video and barrier control (previously all-or-nothing), plus real-time entry/exit notifications and merged lane records.
Engineering notes
- One business, four clients: console, resident app, guard app and backend share the same state definitions, aligned by API contract rather than by document
- Reversible migration: old and new payment channels coexisted, switched lot by lot
- Constraints first: package size, signing and auth treated as conventions rather than bugs to rediscover
- One copy of the data: spaces, orders and payment records are shared across roles; reports and the mini program read the same source
Team and scope
The line is delivered jointly by backend, frontend, QA and product. The team owns lot and lane modelling, the billing rule engine, reports and reconciliation, payment gateway integration, and the guard client and gatehouse feature set. I own the endpoints, pages and cross-cutting changes listed under “My role”. Project value is described here to explain what the line solves, not to claim every line of code.