Changelog — ChargeGrid
[2026-06-17] — The whole app now feels native on your phone
- Your whole app is now a real phone app. The home dashboard, your customers, the New swap screen — and every screen below — were rebuilt for mobile: a big money summary up top, tap-friendly cards instead of tiny tables, and large green buttons. Nothing is a shrunk-down desktop page anymore, and your staff get the same clean phone app when they sign in.
- Expenses, Categories and Reports got the full mobile treatment. On a phone these now look and tap like a real app — big number tiles, clean cards and full-width buttons — instead of a shrunk-down desktop page. Same plain-English labels you already know: "Money in (swaps)", "Money out" and "What's left" on Expenses, and "Money in each day" on Reports.
- Swaps, Plans, Deposits, Activity and Locations are native on mobile too. Every one of these screens is now a proper phone app — your swap history and deposits as tappable cards (with "Held", "Part-paid", "Kept" or "Refunded" right there), plans you add or edit with a tap, and a one-tap switch between your shops. Big targets, warm plain words, ₦ amounts throughout.
- Settings is native on your phone now too. Your share links (with one-tap Copy and Open), business details and defaults, support contact, notifications, the customer app options, and your staff list — all in clean phone-sized cards. Add, edit or remove staff with a tap, and jump to your locations or expense categories from the same screen.
- Power banks and a customer's page are native on your phone now too. Your power banks show as tappable cards — each one's code, colour and size, with a clear "Ready", "With customer", "Damaged", "Lost" or "Out of use" tag, plus quick counts up top — and registering new units is one button. Open any customer to see their plan, deposit held, units out and login PIN as big tiles, with one-tap buttons to collect or refund a deposit, edit them, give a new PIN, or remove them, and their recent swaps below.
- Wider, less cramped pages on a computer. Several admin pages (Reports, Expenses, Plans, Settings, a customer's page, your locations and more) were only using a narrow strip of the screen — they now use the full width, so nothing looks squished on a big monitor.
- Simpler, everyday words. Plainer labels throughout: "Money in today" instead of "takings", "Login PIN" instead of "portal PIN", "Remove" instead of "archive", "Out of use" for a power bank that's retired, and refundable "deposits" instead of "collateral".
[2026-06-17] — ChargeGrid is now your own power-bank-swap business (v3)
ChargeGrid has been rebuilt from the ground up. It's no longer a franchise network with managers and agents — it's now a simple business app you run yourself, just like DrycleanPro or PropertyPro, but for power banks. Everything below is new.
- Run your own shop. You're the owner. You add your staff (they sign in with their phone + a PIN) and your customers, and you run it all across one or more locations — each with its own power banks, customers and staff. Switch locations from the chip at the top.
- Membership plans. You set up plans — each one is a refundable deposit, a swap fee, and how many power banks a customer can hold at once. Put each customer on a plan when they join.
- Swaps in seconds. A customer brings a dead power bank, you enter the returned code and the charged unit you hand out, and you're done. The fee comes from their plan, and every few swaps earns them a free swap automatically.
- Refundable deposits protect your power banks. A customer's deposit is your security — if they lose or damage a unit, its cost comes out of their deposit and is recorded as paid to you. Collect, refund or forfeit deposits right in the app.
- Your books, done for you. Record swap fees and deposits as cash or transfer, track your expenses, and see your profit and reports (swaps, takings, top customers, daily totals) without a spreadsheet.
- A clean app for your customers. Share one link and customers sign themselves up, pick a plan, and check their deposit, the unit they're holding, and their swap history any time. Each swap has a shareable receipt.
- New pricing — pay only when you earn. No monthly fee and no setup fee. The platform simply takes 40% of each swap fee, charged automatically — so a quiet day costs you nothing, and every deposit stays with you.
Internal
- Complete rebuild on the DryCleanPro architecture (entities/staff/customers, cash-basis payments, expenses/P&L, customer portal) while keeping ChargeGrid's existing visual design (
_shell.php / _admin-head.php tokens, cg- CSS, CG./CGP.* helpers, the green accent and 02·Bold landing). All v2 franchise code (managers, agents, funders, wallets, payouts, refund wizard, loans, revenue splits, network settings) and tables removed; fresh schema.sql. ChargeGrid is the platform's first app on usage billing — app.json metered_features.swap (40%) reported via report_usage() after each swap, idempotent on the swap id.
- Report/P&L windows now use a UTC reporting clock (
cg_today()/cg_month_start()) to match the datetime('now') row stamps, so "today's" swaps are no longer dropped from the dashboard, Expenses and Reports under the platform's local timezone.
- The Activity log now shows a readable actor ("Owner" or the staff member's name) instead of a raw id.
[2026-06-15] — Fixed the dashboard & menu errors
- Fixed the error that broke the Dashboard, Agents, Settings and every other admin page. A missing database column (
agent_user_id on power banks) couldn't be added automatically on older installs, so any page that looked at power banks failed half-way through loading — which is why the page looked broken (styles missing) and showed an error. The database now repairs itself on the next visit, and every admin page loads cleanly. Verified end to end: all admin pages, plus the agent, manager and customer apps, now load without errors.
- The "Landing page" share link is now a clean short address (
…/p/{your-id}/chargegrid) and opens correctly — the bare app address used to 404; it now goes straight to your landing page.
- Fixed the app's catalogue description. Your ChargeGrid card was still showing old copy ("Agents keep 30%…"). It now reads the correct franchise summary (agents keep their 60%, manager 10%, platform 30%). This corrects itself automatically on existing installs without overwriting any description you've edited yourself.
[2026-06-13] — Your shareable links in Settings
- Settings now shows your public links to share, front and centre (top of the page, "Share links"): your landing page (introduce ChargeGrid and send people to sign up), your sign-in page (where managers, agents, staff and customers all log in), and the agent application link. Each has Copy and Open buttons, and the labels say plainly what each one is for.
[2026-06-13] — Pop-up messages no longer hide behind panels
- **Fixed admin messages and warnings appearing behind the open panel so they looked like nothing happened. They now always pop up on top. This is why "Move a customer to another agent" seemed to do nothing — it was actually telling you "they still hold a power bank — it must be returned or swapped in first,"** but that warning was hidden behind the slide-out panel.
- Made the "move customer" warnings unmissable. If the move can't happen (they still hold a unit, a refund is in progress, or no agent was picked), you now get a clear pop-up explaining exactly why, instead of a small note. A successful move shows a green confirmation.
- About moving customers in bulk (when you move all of an agent's customers to another agent): this already does the sensible thing — anyone still holding a power bank or with a refund in progress is left where they are (their unit belongs to the old agent and must come back first), and the result tells you how many moved and how many were skipped. Sort those few out, then move them individually.
[2026-06-13] — Admin nav fix + clearer refund choices
- The admin dashboard now stays on your admin area, full stop. The in-app portal (the phone+PIN sign-in) is only for managers, agents, staff and customers. If your admin session ever landed on a portal page — where links broke and some data was missing — it now sends you straight back to the matching admin page automatically.
- Fixed the "Managers" link (and Plan Template / Settings / Activity) giving an error when you'd signed in through the app's own login. Those admin-only pages live on your admin dashboard, but the menu was pointing them at the in-app portal address where they don't exist. The admin menu now always sends you to the right place.
- Fixed "Move a customer to another agent" not doing anything when you pressed Save — same cause: the action was being sent to the in-app portal instead of your admin dashboard, where it's now handled correctly.
- Made the refund choices clear — for both customers and agents. The two cramped "Deposit only / Close account" buttons are now full options that spell out exactly what each does:
- Just give my deposit back — refunds the deposit; the account stays open and they can keep swapping.
- Close my account — refunds everything (deposit plus wallet balance) and closes the account for good. Each option shows its own total.
- Clarified the bank step. It now says plainly "where should we send your money?" and notes the bank details are used only for this refund (we don't keep them on file) — on both the customer's own refund screen and the agent's "start a refund for a customer" screen.
Internal
- Refreshed the help/training and overview docs to the current model: "stores" → "locations", "late fee" → "holding fee" (now a manager-set daily fee with its own free window and grace period), removed the dropped "charged/charging/depleted" unit states, and documented the new manager phone alerts, expanded manager controls, the "take a unit out of service" (damaged/lost) flow, and the admin-stays-on-
/app rule. (marketing/articles/*, getting-started, running-your-store, day-to-day, customizing, app-overview.md.)
[2026-06-13] — Clearer "out of service" page + two bug fixes
- Redesigned the "Take a unit out of service" page (was "Report a unit problem"). It now asks one plain question — what happened to it? — with two clear choices: damaged or faulty, or a customer never returned it (lost/stolen). Declaring a unit lost is now a first-class option instead of a tiny link hidden at the bottom.
- Fixed the money wording. It no longer implies you're charged when a unit is damaged. If it's normal wear or your own mistake, there's no charge — it's your own power bank, it just comes out of your fleet. Only when a customer damaged or lost it do we recover the unit's cost from that customer's deposit and pay it to you. The page now says exactly that, and updates as you choose.
- Fixed the "Top up wallet" and "Take cash" buttons giving an error. They now open the cash-loading page correctly.
- Fixed the buttons on the agent Account page (edit/add/delete location, share link, staff, bank) doing nothing when tapped.
[2026-06-13] — "Locations" for agents (was "stores")
- Renamed "stores" to "locations" everywhere an agent sees them — they're just tags for where your power banks are kept, not a full store system.
- Your main location is now visible and editable. On the Account page, the "Your locations" list shows your main location first (marked MAIN, with its unit count) alongside any extra locations you've added. Tap Edit to change its name or address.
- Add and edit locations now include an address. Previously you could only set a location's name; the add and edit forms now have an address field too, and editing actually shows the existing address instead of just the name.
[2026-06-13] — Signup fix & agent-application routing
- Fixed the "Rent power banks" signup giving a 500 error. The customer signup page was missing a required file (a bug introduced with the recent hosted-checkout work) — clicking through from "Create an account" now works.
- Generic agent applications now get a manager. When someone applies to be an agent through a manager's invite link, they join that manager (unchanged). When someone applies through the generic application link (e.g. from the landing page), there's now a Settings option: route them to a chosen default manager, or leave them unassigned for you to assign when approving. Either way they can be reassigned later from the Agents page. (No more agents with nobody responsible for them.)
[2026-06-13] — Manager invite link + payout wording
- Managers can find their agent invite link easily. It now sits front-and-centre on the manager's Dashboard and again in My Network, with Copy and Share buttons. Anyone who signs up through it joins that manager's network automatically.
- Clearer payout confirmation for managers. The "Run payouts" dialog wrongly said "every agent and manager" even for a manager. It now correctly tells a manager they're paying out "your agents (and yourself)… only your own network" (the payout itself was already scoped correctly — this was just the wording). The admin still sees the network-wide message.
[2026-06-13] — Push alerts for managers + landing photo
- Managers get phone alerts for everything that needs a follow-up. Using free ntfy push notifications (no account needed), a manager now gets a push on their phone — without having to keep checking the dashboard — when: a new agent applies, a refund is waiting for their approval, or a customer reports a problem / asks to change agent. The alert topic defaults to the manager's phone number and can be changed in My Network → "Phone alerts", which has setup steps and a "Send me a test alert" button.
- Friendlier agent-application result. After applying, an agent now sees "your manager will call you shortly to confirm and approve you" (instead of "within 24 hours"), plus a one-tap Call your manager button showing the manager's number so they can follow up.
- Landing hero photo is now self-hosted — downloaded the exact demo photo into the app so it always loads (no dependency on an external image host).
[2026-06-13] — New "Bold" welcome hero
- Adopted the "02 · Bold" welcome design for the landing page — a full-bleed photo hero with the green-gradient wash, the "Charged up. All day, every day." headline (Space Grotesk), the "SWAP IN SECONDS" kicker with its animated accent, and a single green "Get started" call to action over "I already have an account". Ported pixel-faithfully from the design file, with the links wired to signup/login and the Get-started button's glow toned down a notch. The how-it-works, agent, trust and install sections sit below it.
[2026-06-13] — Landing page redesign
- New mobile-native landing page. Cleaner hero with trust chips, numbered "how it works" steps, a punchy agent card, and a protection section — all tuned to feel like a native app screen. The agent card's text no longer overflows behind the button (it's now a bold "60% of every swap is yours" with three short bullet points instead of a dense paragraph). Added an "Install the app" nudge that appears when the browser supports it (with an iPhone Add-to-Home-Screen hint).
[2026-06-13] — More power to managers; holding-fee defaults
- Managers now control the whole holding-fee policy. A manager can set their network's return window (hours), extra free grace (hours), holding fee per day (₦), and declared-lost days — not just the fee. The free window is no longer admin-only.
- Managers tune their own watch-list. The "Things to look into" thresholds — when an idle unit is flagged and how often agents must check in — are now per-manager settings, since the manager is the one watching them day to day. Agents' check-in cadence follows their manager's setting.
- New defaults: holding fee ₦600/day, grace 0 hours (the fee starts the moment the unit is overdue — there's no extra free period unless a manager adds one), return window 24h, lost after 14 days. Setting grace to 0 means no grace; set it higher to give customers a buffer.
[2026-06-13] — "Holding fee", charged by the day
- "Late fee" is now a "holding fee" everywhere — customers don't like being told they're "late", so the charge for keeping a power bank past the free window is now called a holding fee on every screen (customer wallet, history, receipts, agent earnings, admin/manager settings).
- Charged by the day, not the week. The holding fee now accrues daily (a power-bank swap is a short-term thing — weekly never made sense). The cron charges the customer's wallet each day they keep the unit; once they've held it past the "declared lost" limit, the unit's cost comes out of their deposit and is paid to the agent.
- Sensible, clear settings for admin and managers. The platform admin sets the defaults — return window (hours), free grace (hours), holding fee per day (₦), and declared lost after (days). Each manager can override the per-day fee and the lost threshold for their own network (it sits in My Network under a clear "Holding fee" card that explains exactly what happens). Sensible defaults: 24h window, 24h free grace, ₦150/day, lost after 14 days.
[2026-06-13] — Dashboard spacing & clearer labels
- Dashboard breathes now. "Things to look into" and "Power banks right now" were stacked tightly against each other and the stats — added clear spacing so each section stands apart.
- "Power banks right now" reads correctly for managers. "At your station" was confusing (a manager has no station — units sit across their agents). It now says Available, with a caption: "Across all your agents" for managers, "Across the whole network" for the admin.
[2026-06-13] — Installable app (PWA) & impersonation nav fix
- Install ChargeGrid on your phone's home screen. The app is now a proper installable PWA: on Android/Chrome an "Install this app on your phone" button appears on the login screen (and the browser's own install prompt works), and on iPhone a hint shows how to "Add to Home Screen" via Share. Once installed it opens full-screen like a native app with its own icon — important because customers and agents won't always have the link handy. Added the iOS home-screen meta tags, a maskable icon, app description, and a one-tap install button wired into the login page.
- Impersonation no longer 404s the dashboard. While impersonating a manager from the admin area, the Dashboard and My Network links pointed at admin-surface URLs that don't exist for a manager (you got a "Page Not Found"). The nav now routes to the manager's real pages, and the "Exit to admin" button is present on every one of them.
[2026-06-13] — Charge-state cleanup & working impersonation
- Charge states gone from the admin Power Banks page too. The status filters, the per-unit label, and the edit dropdown no longer offer "Charging" / "Depleted" — units are just Ready · With customer · Damaged · Lost · Retired. Any old unit still marked charging/depleted now shows as Ready.
- "Log in as this manager/agent" actually switches now. Before, clicking it kept you in the admin view (the platform session overrode the impersonation). Now you genuinely experience that person's app — their scoped dashboard, their nav (admin-only items hidden), their data — and "Exit" returns you to admin. This is the proper way to preview exactly what a manager or agent sees.
- You can always get back to admin. While impersonating, an "Exit to admin" button now shows on every back-office page (not just the manager portal), including the admin-only pages that previously dead-ended with no way out.
[2026-06-13] — Dashboard polish & manager payouts
- "Things to look into" is now a clean grid. The wall of text on the admin/manager dashboard became tidy cards — Customer reports, Swaps dropped, Not moving, Check-in overdue — each with a short caption and the units as compact chips. Much easier to scan.
- Power-banks card simplified. Since charge state isn't tracked anymore, the dashboard now shows "At your station / With customers" (plus Damaged/Lost/Retired only when there are any), instead of the old charged/charging/depleted split.
- Managers can run payouts for their network. Running the weekly payout as a manager used to fail with a token error and wasn't permitted anyway. Fixed: managers can now run it, and it pays out only their own agents (and themselves), never the whole platform.
Internal
- Root cause of the manager token error: the admin views emitted the platform CSRF token, but the
/p manager surface validates the per-app app-user token. _admin-head.php now emits the correct token based on the surface, so every manager action on the dashboard (run payout, mark report handled, approve agent) works.
[2026-06-13]
- Production hardening. Three money-safety upgrades from the go-live review: wallets can never be driven below zero (a race between two simultaneous charges is now refused outright instead of going negative); card payments credit exactly once no matter how many confirmation paths fire (in-page callback, hosted-checkout return, webhook); and a Paystack webhook backstop now credits a wallet top-up or deposit even if the customer's browser died right after paying — no more "I paid but it's not showing".
- Admin can correct any wallet. Agent and Manager detail panels gained the same "Adjust wallet" action customers already had — credit or debit with a mandatory reason, written to the audit log. (Managers can adjust their own agents' wallets too.)
- Customer photos now show on the agent's profile view — a URL check was rejecting the app's own photo paths, so the main customer's picture never appeared (extra users' pictures did). Fixed everywhere photos render.
- Photos load (and upload) much faster. Every photo taken in the app — customer selfies, extra-user photos, signup photos, unit serial stickers — is now resized in the browser before upload (multi-MB camera shots become ~50–150KB), the server re-shrinks anything that slips through, and photos uploaded before this change are automatically shrunk in the background (a few per hour until done). Browsers also cache photos for an hour, so profiles open instantly on repeat views.
- Agents see the whole family on a customer's profile. Opening a customer now shows a collapsed "Extra users on this account (N)" section — tap to expand and see each person's photo, name and phone, so the agent can verify someone collecting or returning on the family's behalf. Looking up an extra user directly shows a clear blue "EXTRA USER on [name]'s account" banner and the FAMILY's plan, deposit and wallet (it used to wrongly show the sub's empty figures).
- Extra users always know whose account they're on. A blue "Extra user on [name]'s account" badge now shows on their home screen and Account page, and their Users tab explains that only the main account holder manages users.
- Extra users can't add extra users. Closed a hole where a sub-account could create its own sub-accounts, nesting families past the plan limit — the server now refuses.
- Add a photo when adding an extra user. The "Add a user" form has an optional photo capture ("the agent uses it to verify them"), and editing a user can attach one too.
- Customers fully own their account details. On the Account tab, tapping your profile photo (it has a little camera badge now) lets you snap or upload a new one — it saves instantly, and it's the photo your agent sees at every swap. The edit panel also gained Change my PIN, which asks for your current PIN first so a borrowed phone can't quietly take over your account. Name, phone and email were already editable.
[2026-06-12]
- Find a customer by name on the swap screen — instantly. "Hand out a unit" no longer demands the exact phone number: type a few letters of the customer's name (or any part of their number) and matching customers appear as you type — one tap opens their swap screen. Built for a busy counter; extra users are findable too.
- No more tracking whether a power bank is charged. The app no longer asks agents to mark units "charging" or "needs charging" — that was busywork. A returned unit goes straight back to Ready, the fleet view just shows "At your station" vs "With customers", and managing a unit shows a simple "ready to give out" (with a one-tap "Mark ready" only for units flagged damaged). The agent inspects and only hands out a charged unit — the system trusts that.
- Family / extra users can now actually swap. Sub-accounts carry the unit but the plan, deposit, wallet and loyalty all live on the main account — so a family member's swap now correctly spends the primary's wallet and is covered by the primary's deposit (and the deposit must cover every unit the whole family holds). Before, their swaps hit a phantom empty wallet.
- Staff can take cash (when you trust them). New "Trusted to take cash" toggle when adding/editing a staff member. Trusted staff can record cash wallet-loads and deposits at the counter (the money still moves through your float — staff never touch your bank). The Cash hub now opens for them; untrusted staff are kept out.
- Agents can reset a customer's PIN. The customer Help screen says "ask your agent to reset your PIN" — and now the agent actually can, from a "Reset their login PIN" row on the customer profile.
- Staff can run the weekly inventory check-in. It's a physical presence check, so any staff member can do it now — the prompt shows for them too.
- Warning before you raise a plan's deposit. Raising a plan's deposit makes every customer already on it unable to swap until they top up the difference — the app now warns you, with the customer count, before saving.
- Declare a unit lost/stolen on the spot. No need to wait for the overdue-rental sweep — "Report a unit problem" now has a "Declare it lost" option that draws the unit's cost from the holder's deposit, pays you, and removes it from your fleet.
- Move ALL an agent's customers at once. When an agent leaves, the admin/manager can move their whole customer base to another agent in one action (each customer keeps their wallet, deposit and history; anyone with a unit out or a refund in flight is skipped and reported).
- Plan switch respects the whole family. Switching to a smaller plan now counts the power banks the family is holding (not just the main account) before allowing it.
- Returning customers can pick a power bank back up. A customer who returned their unit (without closing their account) and comes back later had no visible path to get a new one. The swap screen's bottom card now reads "Nothing to return? — a new member's first swap or a returning customer picking a power bank back up", their profile shows "⚡ Hand them a power bank", and the receipt no longer mislabels a pickup as a "first swap" (which also protected referral rewards from double-firing). Bonus fix: recording a fresh cash deposit for a customer whose account froze after a deposit draw now automatically reactivates them.
- Customer profile actions, organised. The pile of differently-styled buttons on the customer profile is now ONE clear primary action (collect their deposit, process their first swap, or swap/return their unit — whichever fits that customer) followed by a clean uniform action list: take cash & load wallet · take a unit back. Delete moved to a small muted link at the very bottom so it can't be hit by accident.
- Swapping from a profile is locked to that customer. Starting a swap from a customer's profile now refuses a power-bank code that belongs to a different customer ("Wrong unit — it belongs to a different customer") instead of silently switching to the other person's profile — no more mix-ups in a hurry. A banner on the swap screen shows who it's locked to.
- Manager view ready for big networks. The agents list inside a manager's detail panel now shows "23 total · 20 active" up front with the full list in a compact scrollable box, instead of stretching the panel forever at 20–50 agents.
- Edit a unit to fill in anything you skipped. The manage-unit sheet now carries everything from registration: battery size can be corrected, and you can snap (or replace) the serial-sticker photo right from the edit screen — it shows "✓ Photo on file" when one already exists. Whatever you skipped when registering can be added later.
- Swap screen decluttered. The controls on the swap flow sat flush against each other on mobile — easy to tap the wrong one. Every step now has proper spacing, a clear OR divider separates "type the returning unit's code" from the "New member?" path, the main hand-over button stands out with a shadow, and the cancel link is visually quieter than the real actions.
- Plain returns are easy to find now. A customer who just wants to hand their power bank back (no new unit) was hard to serve — the option only appeared deep inside the swap flow. The home button now says "⚡ Swap or return a unit", the swap screen explains that both start with the unit's code and you choose "hand over a new unit" or "just take it back" on the next screen, that take-it-back button is now highlighted, and a customer's profile shows "Returning a unit? Take it back →" whenever they're holding one.
- A full Earnings page for agents. Agents now have one place to see all their money: wallet balance with Top up / Withdraw, Today · 7 days · Lifetime · total-swaps stats, and a toggle between Swaps & commissions (every swap with the unit code, customer, fee charged, discounts/free-swap tags, who processed it, and the agent's cut) and Wallet activity (the raw money in/out). Reachable from the two stat cards on the agent home and a "See all transactions →" link on the Money tab.
- Manager details open again. Clicking a manager on the admin Managers page did nothing — a typo introduced with the "move all their agents" feature broke the page's script, so the detail panel (with the PIN, wallet, agents and actions) never opened. Fixed.
- Unit codes readable at a glance. On the agent's Units page each power bank's #code now leads the row in bold — no more squinting at the tiny square or opening the editor to read it. The square shows a colored status icon instead.
- Signing up a customer lands on the customer list. After the agent creates an account manually, the app now returns to "My customers" with the new customer visible (and flagged OWES DEPOSIT if they still need to pay) instead of staying on the blank form.
- Topping up the agent wallet is now front and centre. The agent's wallet card on the home screen and the Money tab both lead with a white "+ Top up wallet" button (next to Withdraw) that opens the Paystack top-up straight away — no hunting through the Cash hub. The home wallet card's explainer is also trimmed to two short lines, and the Money tab reminds agents why the float matters: it's what lets them take customers' cash.
- Card payments open reliably. The Paystack checkout script is now loaded the moment you tap pay (not only at page load), so script-deferring optimisers and slow first loads can't leave the button saying the internet is down when it isn't. And if the in-page window still can't open for any reason, the app now redirects to Paystack's own secure checkout page instead — you pay there, land back in the app, and the payment confirms automatically. Works for customer top-ups, deposits, the signup deposit, and the agent's own wallet top-up.
- Pop-ups stack correctly. Confirmation dialogs opened from inside a bottom sheet (like "Delete this unit?") appeared BEHIND the sheet — they now always appear on top, and toasts float above everything.
- Swap screen now asks for the right code length. Power-bank codes are 5 digits, but the swap screen (and the damage report) asked for 6 — the code boxes, damage form and customer how-it-works copy now all say and accept 5 digits.
- Phone numbers match no matter how they're typed. Searching for a customer, logging in, signing up, taking cash, refunds — all phone fields now understand every common format: +234 801…, 234 801…, 0801…, or bare 801…, with or without spaces. Sign-up also detects an existing account regardless of the format it was originally saved in, so nobody ends up with two accounts because of a country code.
- "Take cash & load their wallet" right on the profile. Every customer profile the agent opens now has a wallet-loading button that lands on the Cash hub with the customer's phone pre-filled. If their wallet is too low for their plan's swap fee, the profile says so in amber — "they're ₦300 short of the ₦500 fee" — and the button turns solid so the fix is one tap away.
- First swap, one tap from the profile. When an agent opens a customer who has paid their deposit but never swapped, the profile now shows a golden "🎉 Process their FIRST swap →" button that jumps straight into the first-swap flow with the customer already loaded — no retyping their phone on the swap screen. Customers who've swapped before keep the regular "Start a swap for them" button.
- No more endlessly spinning payment buttons. If a card payment can't start — Paystack's checkout script blocked by the network, a missing/mistyped public key, or a connection drop — the wallet top-up, deposit, signup and agent top-up buttons now recover and show a clear message saying exactly what's wrong, instead of spinning forever. Pasted Paystack keys are also cleaned of stray spaces automatically, and if only the secret key was pasted the error now says the PUBLIC key is missing.
- Fixed the agent Account page erroring right after the staff-discounts update on installs whose database hadn't picked up the new column yet — the page now degrades gracefully while the automatic migration catches up.
- Recording a cash deposit works again. Recording a customer's cash deposit failed with a confusing "there is already an active transaction" error every time (it looked like a stuck pending transaction, but it was a database bug, not leftover records). Fixed — take the cash, record it, done.
- "Start a refund for a customer" is now a proper button. The barely-visible text link on the agent's Refunds tab is now an outlined button with an icon, with the explainer underneath.
- Trusted staff can give discounts. When adding or editing a staff member there's a new "Trusted to give one-off swap discounts" toggle. Staff with it see the same "Adjust this swap's fee" option as the agent; staff without it don't (and the server enforces it). Discounts by staff are recorded in the audit log under the staff member's name.
- Agents can discount a single swap. On the swap confirm screen there's now a quiet "Customer short on money? Adjust this swap's fee" link. The agent (owner only — staff don't see it) can charge any amount below the plan fee, down to free, for that one swap — so a regular who's a little short still walks out with a charged power bank instead of walking away. The discount shows clearly before confirming (with Undo), the receipt screen shows "₦300 · ₦200 off", the revenue split applies to what was actually charged, and every discount is recorded on the transaction and in the audit log. The "wallet too low" warning now suggests this option too.
- Customers in the bottom bar. The agent app's bottom navigation now has a Customers tab (Home · Swap · Customers · Units · Account) on every screen — one tap to the customer list from anywhere.
- Delete a customer for real. Agents (their own customers), managers and the admin can now permanently delete a customer. Everything personal goes with them — family/extra users, wallet history, deposit records, reports, refund requests, referrals — and the phone number is freed up to sign up again. Swap transactions stay (they're the business's money records). Deleting is refused with a clear reason while anything is still attached: a power bank out, a held deposit, money in the wallet, an open rental charge, or a refund in flight.
- Money declines now tell you exactly what to do. "Top up your own wallet first" became "Their deposit is ₦20,000 but your wallet has ₦5,000. Top up at least ₦15,000, then record their deposit. Nothing was recorded yet." Same for wallet transfers. And the "request already in progress" refund error now says exactly where it's stuck (waiting on agent / manager / safety hold / being paid out) and that you can cancel it.
- Notifications you can't miss. The small black pill toasts are gone — notifications are now large, bold cards with a shadow, and errors show in red (success in green). Cash-loading declines open a full alert dialog instead of a passing toast. Applies across the customer, agent, manager and admin screens.
- Back means back. The back arrow on every agent/customer screen now returns to wherever you actually came from instead of always jumping to the home screen — and when you're viewing one customer's profile, back returns you to the customer list first.
- Agents see their whole customer book. The Customers page now opens with a searchable list of ALL the agent's customers — name, phone, plan, units out, and status at a glance — instead of a bare phone-lookup box. Type to filter, tap anyone for their full profile (the old phone lookup still works for walk-ups).
- No more invisible cash signups. When a customer signs up choosing "pay cash to my agent", the agent now actually finds out: an amber "X customers waiting to pay their deposit" alert on the agent home and at the top of the customer list, an OWES DEPOSIT badge on those customers (sorted to the top), and a one-tap "Take their cash deposit & record it →" button on the customer's profile that lands on the Cash loading page with Deposit mode and their phone pre-filled. Record it and the customer can start swapping.
- Agents can start a refund for a customer. Some customers can't drive the app themselves — on the agent's Refunds tab there's now "Customer can't use their app? Start their refund for them". The agent enters the customer's phone, picks deposit-only or full account closure, and enters the customer's bank account (verified by name before submitting). Starting it counts as the agent's "power bank is back" confirmation, so the request goes straight to the manager — the manager approval, the safety hold and the automatic transfer to the customer's bank all still apply, the customer sees the same live timeline in their app and can still cancel, and the action is written to the audit log.
- Shared links are now clickable in WhatsApp. Sharing the customer sign-up link (or a referral invite) could arrive as plain text glued to the message, so the recipient couldn't tap it. The link is now sent on its own line, so WhatsApp and other apps always make it tappable.
- Grow comes first. On the agent's Account page, the Grow tab (your customer sign-up link + stores) is now the first tab and opens by default — growing the customer base is the agent's most valuable move, so it leads.
- Sign-up link right where you sign people up. The "Sign up new" side of the Customers page now opens with a rich orange card holding the agent's personal sign-up link with Copy and Share buttons — for customers who'd rather fill the form on their own phone — followed by "— or sign them up right here —" and the manual form.
- Cleaner agent home. The header no longer repeats the agent's name and business twice — it's now one identity: a colored monogram, a small "Welcome back" greeting, and the business name (staff see "Welcome back, [name] (staff)" over the business they work for). The wallet is now a rich orange card with a bigger balance, a clear "Withdraw to bank" button, and the confusing "record customers' cash payments" line rewritten: when a customer hands you cash, the app moves that amount from your wallet into theirs — you keep the cash, the books stay balanced.
- Customers page: two clear modes. "Your customers" no longer mixes the lookup field and the signup form on one scroll. A toggle at the top switches between Look up a customer (phone search, full profile) and Sign up new (the registration form) — one job on screen at a time.
- One simple screen to manage a power bank. Tapping the pencil on a unit no longer walks the agent through a chain of "More… / Other…" pop-ups. It now opens one sheet with everything at once: tap a status (Charged & ready / Charging now / Needs charging), edit the colour, store, cost and serial, jump to the damage report, retire the unit — or delete it. Delete is for units that were never used (registered by mistake, returned to the seller); anything with swap history must be retired instead so the records stay.
- Customers can ask to change their agent. A quiet "Want a different agent? Request a change" link on the customer's Account tab opens a short form (with an optional "why"). The request shows up in the manager's "Things to look into" panel with a Call button — the manager phones the customer, agrees the destination, and does the move from the Customers page. The customer sees a "request sent" note until it's handled, and the Help FAQ now points to this instead of saying it's not possible.
- Move a customer to another agent. If a customer is unhappy with their agent, the admin can now open them on the Customers page and pick "Move to another agent" — same account, phone, PIN, wallet, deposit and swap history, and their family/extra users come along, so there's nothing to re-register (and no duplicate-phone conflict). If the new agent's price list has a plan with the same name they keep it; otherwise they pick a plan at the new agent. The move is blocked while they're still holding a power bank or a refund is in flight, and every move is written to the audit log. Managers can do this too — but only between agents in their own network; the admin can move anyone anywhere.
- Where an account's login PIN isn't on record yet (accounts created before PIN display existed), the Manager/Agent/Member detail panels now explain "Not on file — set a new PIN to show it" instead of showing a blank dash. Setting a new PIN from the edit form records it for display.
Internal
- Security hardening on the agent member-lookup page: member display values are fully escaped, and a member's photo is only rendered when it's a clean image URL. Closes a cross-site-scripting / CSS-injection gap. No visible change.
[2026-06-11] — Customer-app polish, real problem reports, WhatsApp contacts & one-tap manager replacement
- Less "we have your money" talk. The customer home no longer shows the "deposit held & protected" banner — the deposit details live under Account. The home only mentions the deposit when action is needed (pay it, or top it back up after a charge).
- "Report it" is now a real report. Instead of a free-text box, customers fill a short form: what went wrong (swap / cash / deposit not showing), the day and time of day, the power-bank code, the amount and how they paid, plus optional details. Managers get one clean line they can actually investigate.
- Calmer wallet screen. Toned down the heavy card shadows, and the fee note is now just "bank charge added at checkout".
- "Extra users", not family. The Users tab no longer reads family-only — add family, staff, a driver, anyone you trust to swap on your wallet. Plan editors and limits use the same wording.
- Referral rewards are a network switch. ON by default; the MANAGER (not the agent) can turn them off for their network from My Network Settings. When off, no rewards are granted and customers see a friendly "referrals are off right now" instead of their code.
- WhatsApp numbers for agents (and managers). Many businesses use different numbers for calls and WhatsApp — there's now a WhatsApp field at agent application, agent onboarding, the agent's own profile, and manager records. The customer Help tab leads with their agent: WhatsApp + Call buttons, "Report a problem" now goes to the manager, and a small "still stuck?" line shows the manager's name and number.
- Replace a manager in one move. On the Managers page, "Move ALL their agents to another manager…" transfers every agent — and any refund approvals in flight — to the new manager instantly. Past earnings stay with the old manager; future swaps pay the new one.
Internal
app_users.whatsapp_phone (additive). cg_qualify_referral is network-aware (manager 0 = no grant; referral stays pending). New managers/transfer-agents action (agents + open refund_requests). Structured report-missing-swap payload formatted server-side into flags.note. customer.php now stamps the portal CSRF token (report POSTs were 419). Removed a max(1,…) clamp that made referral-off unreachable in account.php. Demo reseeded (agent 2 has a distinct WhatsApp number).
[2026-06-11] — Custom-domain mapping, clearer agent identity & wording polish
- Point your own domain at ChargeGrid. ChargeGrid now appears in the custom-domains app picker (Account → Domains), and you choose which page the domain opens — the overview/landing page or the login page.
- Customers always see who their agent is. A "Your agent: …" badge sits right under the greeting on the customer home, next to the full agent card with call button — and a clear notice shows if no agent is linked yet.
- "Agent", not "shop". All customer-facing copy now says agent — because agents can be shops, roadside stalls, or individuals. Agent-facing screens say your business.
- Every agent always has a price list. Plans are now also self-checked at agent login, so an agent can never end up without their own editable plans.
Internal
custom_domains.subtargets contract added (app.json + cg_cd_list_subtargets); public/index.php honors __cd_subtarget === 'login'. Guarded one-time platform backfill in sync_apps() flips ChargeGrid's stale category='marketplace' registry value to business (it hid the app from the domains picker). cg_seed_agent_plans on agent login. Demo reseeded.
[2026-06-11] — ChargeGrid 2.0: run it like a franchise
ChargeGrid is reborn as a franchise-style network. Agents now own their businesses end to end, managers run networks of agents, and every payment flows through one company account with automatic splits and payouts. Existing v1 installs are reset by this release (the data model changed completely).
- Agents own their power banks. Buy your units anywhere, register each one in the app, and it gets a permanent 5-digit code — write it on the unit and it's trackable for life. Optional serial number + photo for your records.
- Agents set their own prices. Every agent gets their own full plan list (deposit, swap fee, units allowed, family slots) seeded from the platform template — then it's theirs to edit from the new My prices screen.
- Managers run networks, not territories. Agents belong to a manager (by invitation or application link), and the manager sees ONLY their own network: agents, customers, swaps, devices, refunds. A new My Network page lets each manager set their agents' split, support contact, and loyalty policy.
- One company account, automatic money. Every swap splits instantly — platform 30% (you fix this), agent ~60%, manager the rest. Customers pay the small card fee on top at checkout, and bank-transfer fees come out of payouts — your account always stays whole.
- Refunds with real safety steps. A customer asking for their deposit (or closing their account) now goes through a wizard: their agent confirms → the manager approves → a 48-hour hold → the bank transfer goes out automatically. Anyone in the chain can stop it before the money moves, and the customer sees a live 4-step timeline.
- Staff logins. Agents add staff who can process swaps for the shop — the money still goes to the agent, and every swap records who handled it.
- Multi-store agents. Add stores, tag units to them, and filter/search the whole fleet from one screen.
- Customers belong to their shop. Sign-up links and QR codes carry the shop, customers see that shop's prices, and swaps only work at their own shop — which is exactly what keeps their deposit protecting the right hardware.
- Anti-fraud, built in. Weekly inventory check-ins ("It's here ✓"), idle-unit alerts, swap-velocity warnings, and a customer "swap not showing? report it" button that lands on the manager's desk.
- A fresh face everywhere. New landing/overview page, rebuilt sign-up flows, a cleaner agent app (Home / Swap / Units / Account), refreshed dashboards, and plain-language copy across every screen.
- Removed: investors/funders, geographic areas, the capital-cycle screen, and company-owned hardware — agents own the units now, so none of these exist anymore.
Internal
- Clean-break schema v2 (stores, refund_requests, inventory_checkins, flags; per-agent plans; staff role; manager affiliation; per-agent device codes UNIQUE(agent,device)). New refund-wizard engine (lib/refunds.php), gross-up/transfer-fee helpers, affiliation-based scoping across all operator APIs/views,
chargegrid_tick cron task (extension fees, lost units, due refunds, weekly opt-in payout sweep). CLI engine test rewritten (60 assertions, green). Tutorials + marketing collateral rewritten for the franchise model.
- "Log in as" now covers managers too. From Areas & Managers, tap Log in as on any manager to see the app exactly as they do (an "Exit" banner brings you back). This joins the existing log-in-as for agents and members — and managers can still log in as the agents and members in their own region.
- Help articles, app overview and promo materials updated to the new self-funding direction — no more investor talk. The in-app "How it works" guides, the app overview, and the affiliate promo copy (email, social, WhatsApp, SMS, proposal) all describe the deposit→power-bank capital cycle, managers running each region, and the agent self-healing deposit.
Internal
- New
managers/impersonate action (admin-only, via the areas permission) + a "Log in as" button on the managers table in views/areas.php; reuses cg_do_impersonate/cg_start_impersonation. Agent/member impersonation already worked dual-surface.
- Added
apps/chargegrid/app-overview.md (sample logins for every demo role at the top). Rewrote marketing/articles/*, the 6 social/email templates, and proposal.md. Demo seed gains a 2nd manager (Adaeze, Ikeja) so reassignment + manager login-as are testable; the network is installed + demo-seeded locally for the NGN owner.
[2026-06-03] — Self-funding capital cycle, agent self-healing deposits & easy reassignment
- A brand-new Capital screen — see if you're on the right path at a glance. It turns the whole business into one honest picture: how much refundable deposit money you're holding, how much of it you've turned into power banks, and whether you still have enough cash to refund everyone who might ask. One big coverage number tells you if you're in the clear (green), getting thin (amber), or underwater (red) — and it spells out, in naira, how much more you can safely turn into units.
- Watch the cycle fill up. A simple flow follows the money: deposits held → power banks bought → units live at agents → idle units. Per-power-bank, you see exactly how much each one has earned back and which have fully paid for themselves.
- Managers run their region's money. You disburse cash to a manager; they record each power bank they buy with it; the screen reconciles, per manager, cash given vs. spent vs. still in hand. Managers see only their own region.
- Agents can start small and self-heal. An agent posts a security deposit to join. If a unit is damaged and it's their fault, the unit's cost comes straight out of that deposit — then their swap earnings quietly rebuild it back to standard before they're paid again. So one broken power bank never sinks an agent, and you can onboard lots of them without big upfront money.
- Damage now has a clear "who's at fault?" step. When an agent reports a damaged unit, they say whether it was the member, themselves, or normal wear — and the unit cost is charged to the right deposit on the spot. A charged member can't rent again until they top their deposit back up. Made a wrong call? Open Damage and hit Reverse to put the money back.
- People move, managers change — now that's a one-tap edit. Replace the manager on an area and the whole area (its members, agents, units and capital) moves to the new manager at once. Move a single member or agent to another area and their deposits / held units follow them automatically.
- Investors are gone. ChargeGrid is now fully self-funded from the deposits your members pay — simpler, and all the swap revenue an investor used to take now stays with you.
Internal
- Removed the entire funder/investor feature (role, login, signup, 8 portal views, admin roster,
api/funders.php, lib/funder.php, funder_investments table, and the power_banks/transactions funder columns — clean-cut, pre-launch). The swap/extension split (cg_swap_split/cg_extension_split) folds the old funder share into the platform; split_platform_bp default is now 70%. Stale pre-pivot views (swap.php/earnings.php/portfolio.php/wallet.php) deleted; api/dashboard.php + api/wallet.php rewritten against the live schema.
- New self-funding cycle:
capital_ledger table (admin disbursements IN, unit purchases OUT → manager float = in−out); lib/capital.php (cg_capital_overview shared by the admin-server-render + api/capital.php JSON twin) computes solvency (liquid = collected − refunds − hardware + swap_revenue), funnel, per-unit recoup, and per-manager reconcile, all area-scoped via cg_scope_where. New /capital route + nav + capital permission.
- Region attribution: members capture
area_id at signup (region picker / ?area_id= / ?agent= link); cg_collect_member_deposit stamps deposits.area_id.
- Agent self-healing deposit: new
security_deposit_target_kobo (drives slot_capacity so a draw doesn't shrink capacity); cg_draw_from_agent_deposit, cg_credit_agent_share (routes swap earnings to deposit-rebuild until target, then wallet), cg_rebuild_agent_deposit. Customer rent-gate tightened to require held deposit ≥ plan deposit.
- Damage charging:
report-damage captures charged_to and deducts immediately (member via cg_charge_member, agent via the new draw); new api/damage.php + views/damage.php list with a reverse action (cg_credit_member_deposit / cg_rebuild_agent_deposit); damage_reports gains deposit_drawn_kobo + a reversed status.
- Reassignment:
managers/set_area_manager hands an area to a new manager; member/agent update accept area_id (admin-gated for members) and cascade open deposits / held units' area_id.
- Seeds rewritten (no funders; ₦7,000 unit/slot economics; a demo manager float + an agent mid-rebuild + a resolved agent-fault damage report). Run
php seed.php reset after deploy — the funder columns/tables were dropped, which SQLite can't migrate additively.
[2026-05-30] — "Funders" are now "Investors" — tappable detail + a profit calculator
- Funders are now called Investors everywhere — it's the word people actually relate to. Nothing about how it works changed, just the name.
- See the story behind every number. In the Investor app, tap any earning, any power bank, or any item in your live rental feed to open a clean detail card — what happened, which unit, how much, and when.
- A built-in profit calculator. On the Invest screen, as you choose how many power banks to buy, you instantly see what you pay, what you earn back, your profit, and the % return — no maths required.
- A plain-English help section. New "How it works" page explains, in simple words: how you own power banks, how every rental pays you, when you get paid, and what happens if a unit is lost — with a worked profit example and one-tap WhatsApp/Call support.
Internal
- Display-only rename Funder→Investor across admin nav/list/dashboard/settings/devices/swap-split labels, marketplace + help copy, the investor portal views and signup. Internal role
funder, routes /funder, columns, cg_funder_ functions and /api/funders endpoints are unchanged.
funder-earnings rows reuse the shared activity-detail endpoint (already funder-scoped); the portfolio live feed + funder-devices cards open client-side CGP.detail; funder-invest gained a live profit/ROI breakdown; new public/funder-help.php + funder-help public route + Help entry points on the portfolio home and Invest page.
[2026-05-30] — Referrals are a free swap, not cash · support contact saves
- Referrals now reward a free swap, not money. When you invite a friend and they make their first swap, you both get a free swap — the fee is simply waived on your next one, exactly like a loyalty reward. It's a perk, not wallet cash, so there's nothing to withdraw. (This replaces the earlier money-credit bonus from the 2026-05-30 "honest referral bonuses" note — crediting cash could be cashed out and abused. Free swaps cost the platform nothing and mint no money; agents/funders agree to the occasional waived fee as a term of joining.)
- Support contact now actually saves. The support phone, WhatsApp and hours you set in Settings now save correctly and show up under Account → Help for members. (They were previously dropped on save.)
Internal
cg_qualify_referral grants free_swaps_available += referral_reward_swaps (default 1) to both referrer and referred, marks the referral rewarded with reward_kobo=0 — no cg_wallet_record, no platform debit. New referral_reward_swaps setting replaces referral_reward_kobo in helpers defaults, both seeds, the admin Settings field (now a swap count, not ₦), and api/settings.php whitelist.
- Added
support_phone / support_whatsapp / support_hours to CG_WRITABLE_SETTINGS — the save endpoint silently skips any key not in that whitelist, which is why they never persisted.
[2026-05-30] — Member lookup, clearer deposits & loyalty, "log in as"
- Agents can look up a member by phone. Walk-up with a dead phone? Agents now have a "Look up a member" screen — type the number and see a clean profile: deposit status, plan, wallet, the unit they're carrying and their loyalty standing. (Read-only — no swap.)
- Your deposit, front and centre. Your Account now shows a bold "Refundable deposit ₦X — held & protected" card with a checkmark, so you can see at a glance what you've paid without digging into your plan.
- Agents see the deposit is good. When an agent pulls you up for a swap, a green "Deposit verified" mark confirms you're ready to swap — and if you've earned a free swap, a clear "this swap is FREE — loyalty reward" banner tells the agent so. (Free swaps cost nobody — the fee is simply waived.)
- Clearer loyalty wording. The rewards screen now reads plainly: "Pay for 2 more swaps and the one after is free."
- Edit your own details. Update your name, phone and email yourself from Account.
- Bolder wallet top-up. The card / transfer top-up area is redesigned — bigger amount buttons and a clearer, secure "Top up" button.
- Friendlier plan-switch message. Moving to a smaller plan while holding a power bank now says, simply, "It looks like you still have a power bank out from your current plan. Please return it to any agent first."
- Plan-switch confirmation stays put. After switching, the confirmation now waits for you to tap "Got it" instead of flashing by.
- Staff "log in as". Admins can log in as any app user (and see their login PIN for support); managers can log in as their own agents and members. A banner shows when you're viewing as someone else, with one tap to exit.
- Fixed a payment error ("invalid email") when paying without an email on file.
Internal
- Impersonation helpers in
lib/auth.php (cg_start/stop_impersonation, cg_do_impersonate) modelled on ServicePro; impersonate actions in api/agents|members|funders.php, stop-impersonate portal action (CSRF-exempt), banner in _shell.php, PIN shown in admin drawers.
- New
member-lookup portal action + public/agent-member.php view + agent-member route + agent-home entry.
update-member-profile portal action; member profile card with inline edit in account.php.
cg_paystack_email returns a real @mypancho.com synthetic address (Paystack rejects placeholder TLDs).
- Agent swap card gained a
Deposit verified badge + free-swap banner; account gained a held-deposit hero; change-plan return_first copy softened on both the unit-count and solvency guards.
[2026-05-30] — Self-serve deposits, account closure & honest referral bonuses
- Pay & top up your deposit yourself. Your deposit can now be paid (or topped back up after a charge) right from the Wallet with card / transfer — paying cash or transfer to an agent is just an option, not the only way. Your Account now shows exactly how much deposit you hold.
- Close your account & get refunded. From Account, request to close — give your bank, and your wallet + deposit are refunded together. For safety, money is never sent automatically: a manager reviews the request (new Closures screen) and runs the transfer.
- Referral bonuses are honest now. When you and a friend both earn a referral bonus, that free money is funded by the platform (out of its own cut) and shown clearly in everyone's activity — no agent/funder/manager is silently charged, and no money is invented from nowhere. (Also fixed a bug where first-swap referral rewards silently failed.)
Internal
cg_qualify_referral rewards both sides, books a matching platform debit (referral_reward), and is transaction-safe (joins the swap's transaction instead of nesting — the previous nested beginTransaction silently rolled back).
deposit-init/-callback + agent-collect-deposit are now shortfall-based (plan deposit − held) so the same flow pays the first deposit and tops up a partial one.
account_closures table + member request-closure/cancel-closure (snapshots wallet+deposit, captures bank, flags status='closing'); manager api/closures.php (list / process / reject) + views/closures.php queue; closure releases the deposit into the wallet then pays the lot out via cg_request_payout. cg_authenticate permits closing login; resolve-bank permits members.
- Wallet/Account deposit cards are shortfall-aware; self-serve card/transfer is the primary CTA.
[2026-05-30] — Tappable activity, return-without-swap & flexible downgrades
- Tap any activity for the full story. Every row in your Wallet activity, your swap History, and an agent's Earnings now opens a clean detail card — date, who/where, the units involved, the method, and the receipt number — so every transaction is accountable.
- Return a power bank without swapping. Agents can now take a unit back on its own: on the swap screen, look up the returning unit and tap "Just take it back — no new unit." No fee — the member is then holding nothing and can collect their deposit or change plan.
- Smarter plan downgrades. You can move to a smaller plan as long as its deposit still covers the power bank you're holding — you only have to return a unit if it genuinely wouldn't.
Internal
CGP.detail bottom-sheet in the portal shell; activity-detail endpoint resolves a wallet-ledger row + its linked swap; wallet / history / agent-earnings rows wired to it.
- New
return-unit agent endpoint (unit → depleted at agent, holder cleared, open extension charge closed, no fee) + a "Return only" flow on the agent swap screen.
change-plan downgrade guard relaxed back to the solvency rule only (held unit cost ≤ new deposit); the over-strict "can't downgrade while holding" block was removed.
[2026-05-30] — Agent app: an Account home, saved bank & a bolder swap
- New "Account" tab for agents (replaces "Earnings"), with sections:
- Earnings — your wallet balance, a one-tap Withdraw, and recent commissions.
- Bank — save your payout bank once; withdrawals reuse it (no re-typing).
- Profile — update your owner name, business name, and address.
- Help — call / WhatsApp your manager and ChargeGrid support, plus quick links to load a member or report a damaged unit.
- Withdraw, simplified. Big, bold screen that shows your balance and the saved bank it's going to — just tap Withdraw. (Set the bank under Account → Bank first.)
- Process-a-swap, bolder. Bigger code boxes, a clearer heading, a prominent "New member?" card for first swaps, and a roomier phone field.
Internal
- New
public/agent-account.php (tabbed) + agent-account route; agent bottom-nav "Earnings"→"Account" across agent screens; agent-payout.php rebuilt to use the saved bank only.
- New
update-agent-profile portal action; manager contact resolved via manager_areas for the agent's area.
[2026-05-30] — Agent confirmations, friendlier popups & a cleaner app
- Agent swap, rebuilt for trust. When an agent enters a power-bank code, the member's card now shows a clear green/red verdict — deposit on file? wallet covers the fee? — and won't let the swap proceed if not, with exactly what to fix. After a swap, a big, bold confirmation shows the member their handed-out unit, the fee, and their new wallet balance — so they can see it's done even though their phone is dead. Same for agent cash top-ups.
- Beautiful pop-ups everywhere. Replaced the plain browser "OK/Cancel" boxes (like switching plans) with clean in-app cards — for confirmations, prompts, and errors, across the member and manager apps.
- "Agents" tab. The map tab is now Agents, and you pick your area from a searchable list (works whether you have 5 areas or 500). Each station shows how many power banks it has in stock; tap in to see the sizes it carries. (We no longer claim how many are "charged" — that can't be verified.)
- Tidier wallet. "Prefer to pay with cash or transfer?" with the safety tip tucked behind a tap; removed the duplicate "agents near you" list (use the Agents tab).
- Nicer plan cards in Account → Plan — clear deposit, swap fee, and limits at a glance.
- Support number is a setting. Set your call / WhatsApp line under admin Settings → Support contact; it shows to members in Account → Help.
- Damage charges take the deposit first (then the wallet only if the deposit somehow can't cover it).
Internal
cg_swap_customer_payload() adds fee/deposit/wallet validity to the swap lookup; agent-swap gates on it + big confirmation; swap result returns customer name + new wallet balance.
cg_charge_member() flipped to deposit-first → wallet-fallback.
- Portal
CGP.confirm/alert/prompt + admin CG.confirm/alert/prompt styled modals; all native confirm/prompt in live views replaced.
- Map: searchable area sheet +
units (on-hand) counts; agent-detail groups by capacity_mah without status claims; "Map"→"Agents" nav across member screens.
support_phone/support_whatsapp/support_hours editable in admin Settings.
[2026-05-30] — Self-serve plans, a deposit safety rule & damage charges
- Redesigned Account page. Cleaner icon tabs that fit any phone, and each section (Account · Plan · Users · Refer · Help) now shows on its own — no more scrolling past everything at once.
- Change your plan yourself. In the Plan tab, tap "Switch to …" to upgrade or downgrade instantly. If the new plan's deposit is higher, the difference comes from your wallet; if it's lower, it's refunded to your wallet. (You're stopped if you'd be holding a power bank your new deposit can't cover.)
- A deposit can never be "underwater." New platform-wide rule: a member can never hold power banks that cost more than their deposit — enforced at the moment of every swap, so the business is always covered even if a limit was set wrong.
- Power-bank sizes & cost are now managed. Units default to 10,000 mAh; an admin or manager can set each unit's size (10k/20k/30k) and cost from the Devices screen.
- Damage & loss charges. A manager can charge a member for a lost or spoiled unit — taken from their wallet first, then their deposit — and release the unit, all in one action.
Internal
account.php: class-based panel switching (fixes the inline-display vs hidden bug that showed all sections), compact icon segmented tabs, click delegation.
change-plan portal action: wallet-reconciled deposit delta with unit-count, sub-account, and solvency guards. Verified an upgrade/downgrade round-trip balances exactly.
- Solvency invariant
Σ(held unit_cost) ≤ held deposit enforced in cg_process_swap (step 3b) and change-plan.
power_banks.capacity_mah default → 10000; devices add/update + admin drawer expose size + cost.
cg_charge_member() (wallet-first → deposit) in the deposit engine + devices/charge_loss action + drawer button.
[2026-05-30] — Loyalty, agent discovery, power-bank sizes & editable users
- Loyalty rewards page. Tap the Loyalty card on your home screen to see exactly how many more swaps until your next free one, your progress, and your totals. It's fully automatic — when you hit the target, your next swap's fee is waived at the agent. (Also fixed a glitch where a brand-new member saw "free swap ready" before earning one.)
- Power banks now come in sizes. Every unit is tagged 10,000 / 20,000 / 30,000 mAh, so you can find the capacity you want (bigger = more charges).
- "Find an agent" is now useful. Pick your area, search by name or street, and each station shows how many power banks it has on hand and which sizes are available (10k/20k/30k chips). Tap an agent to see their full stock — each unit's ID, size, and status.
- Honest stock counts. Replaced the old "X charged" claim (which couldn't be verified) with real "on hand" and "ready" counts.
- Edit additional users. You can now edit a family/staff member's name, phone, or PIN — not just remove them.
- Sign-up screens (rent / agent / funder) now match the new login look.
Internal
power_banks.capacity_mah column (10000/20000/30000) — additive, the lazy migrator adds it; demo seeds a 3/3/4 spread.
- New
public/loyalty.php and public/agent-detail.php routes; home loyalty card + nearby-agent cards now link out; map.php gains an area filter, name search, capacity chips, and devices-on-hand counts.
- New
edit-subaccount portal action (owner-scoped) + edit UI in Account → Additional users.
_authskin.php re-tints the cg-* system to the login's Manrope / Space Grotesk warm palette for the three signup forms (per-page role accent preserved).
[2026-05-30] — Member app: new look, Account hub & safer top-ups
- A beautiful new sign-in. Brand-new login screen — warm, clean, and native-feeling, with phone + PIN, a "Forgot PIN?" helper, and a "Create account" toggle. The sign-up role chooser now matches it exactly.
- New Account area. Tap Account in the bottom bar for a tidy, tabbed home for everything about you:
- Account — your name, plan, deposit status, wallet balance, and quick links.
- Plan — see your membership and compare every plan (deposit, swap fee, units, extra users).
- Additional users — add family or staff who swap on your wallet (renamed from "Family" — it's for anyone, not just family). Limited by your plan.
- Refer & earn — your referral code, a one-tap share link, and how much you both earn.
- Help — call or WhatsApp support, common questions, and "report a problem" if an agent didn't load your wallet.
- Safer top-ups (important). You can no longer "top up" without actually paying. Top-ups now happen by card/transfer or by paying cash to an agent who loads your wallet on the spot — with a clear reminder to check your new balance before you leave.
- Clearer wallet. The wallet card is easier to read (solid "Top up wallet" button, a "per swap" badge), and a "No card? Top up with cash" card lists agents near you.
Internal
- Money-minting fix: removed the manual free-credit path on
wallet-topup-init/callback. Wallet credit now requires a verified Paystack payment or the balanced agent cash-transfer; in manual mode the API returns no_online and the UI routes to an agent.
- New
public/account.php (tabbed hub) + account route; bottom-nav "Family" tab replaced by "Account" across member screens. Sub-account gating reads plans.max_sub_accounts (not the old family tier check).
- Added
support_phone / support_whatsapp / support_hours settings (seeded), surfaced in Account → Help.
- Login brand renders as "ChargeGrid" (not all-caps); subtitle trimmed.
[2026-05-30] — Smoother signup, login fix & nationwide branding
- Fixed login. Signing in no longer fails with a "session/CSRF" error — the login screen now talks to the right place. (You can sign in again.)
- Beautiful new sign-in & join screens. Signing in now opens on a striking Earth-at-night backdrop — a world lit up with power — with the phone + PIN fields (each with its own icon) floating in a clean, centered glass form, no boxed-in white card. The "join the grid" page keeps its full emerald hero. A proper native-app feel instead of a blank page.
- Now just "ChargeGrid". Dropped the "Lagos" tag everywhere — ChargeGrid runs nationwide.
- Joining is quicker. Customers now simply create a PIN when signing up (the step that used to be missing), and we no longer ask for your NIN/BVN up front — your refundable deposit covers it. Staff can still add a NIN/BVN later from the admin if ever needed.
- Clearer "pay" choices. Instead of a payment brand name, you pick "Card or bank transfer" or "Pay cash to an agent" (with a reminder to make sure your deposit shows before you leave).
- Friendlier wording. Agents sign up a "business" (not a "shop") — stalls and roadside spots welcome. Every signup screen now has a back button and an "Already have an account? Log in" link.
- Two new membership plans. Added Starter (₦7,000 deposit · ₦1,000/swap) for the easiest way in, and Business (₦100,000 deposit · ₦1,200/swap) for teams holding up to 5 units. Existing Standard, Family, and Professional plans are unchanged.
- Agent cash-loading, done right. An agent now tops up their own wallet once, then instantly transfers wallet credit or a deposit to a member who pays them cash — so the books always balance. Family/Professional/Business members can be given sub-accounts based on their plan.
Internal
- Root cause of the login failure: the
/p/{uuid}/{appId}/login route rendered without $basePath, so the client posted to the platform API path and tripped the platform CSRF gate. Fixed in [core/index.php](../../core/index.php) by passing $basePath (and mirroring $GLOBALS['basePath']) to the login view, matching every other public route.
agent-topup is now a balanced wallet→wallet transfer (debit agent, credit member, in one transaction) instead of a one-sided credit that minted money; added agent-collect-deposit. Sub-account gating reads plans.max_sub_accounts instead of a hardcoded family tier.
- Shared auth-hero styles (
.cg-auth*) added to the portal shell; nin_bvn wired into the agent/funder edit drawers + APIs.
- Belt-and-suspenders for the login fix: the portal shell JS now self-heals an empty
cg-base by deriving /p/{uuid}/{appId} from the URL, so login posts to the app API even if a server still serves the un-updated login route (works from the app folder alone, without the core change).
[2026-05-29] — Full production rebuild
ChargeGrid was rebuilt from the ground up into a complete, production-ready three-sided network app — customer, agent, and funder mobile portals, plus an owner/manager operations dashboard.
- Customer app — sign up with NIN/BVN + photo and pay your refundable deposit online, see a live map of agents with charged stock, top up your wallet, view swap history, and add family members on the Family plan.
- Agent app — process a swap in seconds (type the returning unit's 6-digit code, confirm the customer's photo, type the outgoing unit's code — the fee auto-deducts), track inventory and earnings, withdraw to your bank, report damaged units, and load a customer's wallet for cash.
- Funder app — fund units via Paystack, then watch each one earn toward its payoff live, with weekly auto-payouts to your bank.
- Manager (renamed from "Director") runs the day-to-day for their assigned areas; the owner oversees everything with full control.
- Phone + PIN login for everyone; the customer portal installs as a phone app (PWA).
This builds on the foundations below:
- Three-sided marketplace economics. Configurable ₦1,200 swap fee and ₦20,000 refundable deposit, with every swap split between the platform, the hosting agent, and the unit's funder. A funder's unit earns a boosted share on each swap until it hits its promised return (e.g. invest ₦20,000 → earn ₦30,000), then it's "Paid Up" and the split reverts to platform + agent — tracked per device.
- Day-to-day is run by Managers. The old "Director" role is now Manager — the person who handles agents, devices, deposits, and payouts on the ground for their area(s). The account owner oversees everything with full control.
- Solid wallet + deposit engine. Every member, agent, and funder has a wallet; swaps deduct automatically. Refundable member deposits and configurable agent security deposits (with a per-agent waiver a manager can grant) protect units in the field. Lost units draw against the deposit after a configurable grace + weekly extension-fee window.
- Loyalty & referrals. Every 10th swap is free, and referring a friend earns credit once they complete their first swap.
- Online deposits, wallet top-ups, and automatic payouts to agents/funders are wired for Paystack (card + bank transfer + USSD in, bank-account transfers out).
Internal
- Schema rebuilt for the per-user model: a single
app_users table for all roles + family sub-accounts (no shared members registry), all money stored in kobo, and a wallet_ledger. Fixes the broken install where the old schema referenced a members table it no longer created.
- New engine libraries under
lib/ (swap, deposits, extensions, funder payoff, payouts) verified by an integration test covering split math, the payoff cap, and unit rotation.
[2026-05-14]
- Added a Watch/Read tab on the tutorial page — every lesson now has a written version alongside the video for users who prefer to read.
[2026-04-20]
- Fixed demo data not loading on install — the seed file was referencing an outdated column name, so new customers never saw the sample agents, funders, and transactions.
Internal
seeds/demo.sql now writes to members.pancho_user_id (schema has been on UUIDs for a while); every foreign-key to a member row is a matching UUID placeholder instead of the old 100-series integers.
[2026-04-18] — Renamed
- Renamed from Charge Pro to ChargeGrid (slug
chargepro → chargegrid).
- Every display string, marketing copy, schema reference, code-comment, folder path, DB filename, and
subscriptions.app_id value now uses the new slug. Platform had not gone live yet, so old URLs are not preserved.
All notable changes to this app are recorded here. Newest entries on top.
[2026-04-17] — Funder rename, 30% agent share, payoff mechanic
- Renamed the "investor" role to "funder" across every screen, API route, setting, and URL — less regulatory baggage, clearer to Nigerian users.
- Agents now earn a fixed 30% of every swap (was 33%). Changed is visible on the new "How you earn" page in the agent dashboard — no more splitting hairs over platform math.
- Funded units now have a payoff target. When you fund a unit, the platform records the purchase price × (1 + interest %) as your payoff goal (default 20% interest). Every swap on that unit credits you the non-agent share until your earnings reach the target, at which point the split reverts to the platform.
- Director settings page simplified: just set the agent % and the default interest rate — the rest is derived automatically.
- Funder portfolio page shows a per-unit payoff progress bar.
- New in-app event
chargegrid_unit_paid_off fires when a unit crosses its payoff target (useful for future notification hooks).
Internal
- Full rename of
investor_* → funder_* across schema (investor_devices → funder_devices, investor_id, investor_share), API routes (/investors/ → /funders/), app.json permissions, role values, and setting keys.
- New columns on
funder_devices: interest_rate, payoff_target, paid_off_at. Guarded ALTERs for existing installs.
[0.3.0] — 2026-04-17
- Role-aware home dashboard: customers see wallet/device status and quick actions, agents see inventory counts and today's earnings, funders see portfolio summary, directors see area overview
- 3-step swap wizard for agents: verify customer identity (photo + name), scan returned and outgoing device IDs, confirm and process with automatic wallet debit and three-way revenue split
- Customer swap view showing active device info and how-to-swap instructions
- Wallet page with balance card, top-up flow, withdrawal requests (agents/funders), and full transaction history
- Customer swap history with chronological transaction list
- Family sub-accounts page for managing household members under one membership
- Agent inventory view with filter tabs (charged/charging/damaged) and device grid
- Earnings view shared by agents, funders, and directors — shows relevant commission data per role
- Funder portfolio showing all owned devices with ROI calculation, rental counts, and lifecycle status
- Director area management: view/create geographic zones with agent/device/swap counts
- Director agent management with enriched stats per agent (devices, swaps, earnings)
- Director member management with search, role filtering, detail sheet with freeze/unfreeze actions
- Director device fleet view with table layout, status filters, and create-new-device form
- Director settings page for configuring swap fee, deposit, revenue split percentages, late fees, and payout thresholds
- Self-service public signup portal at /p/{userId}/chargegrid/signup — multi-step form with photo capture, NIN/BVN collection, tier selection, and deposit payment flow
[0.2.0] — 2026-04-17
- Full database schema: members with NIN/BVN and photo verification, sub-accounts, geographic areas, power banks with 6-digit device IDs, transactions with three-way revenue split, wallets, funder devices, agent profiles, deposits, damage reports, late returns, corporate sponsors, director area assignments, and payouts
- Four first-class roles: customer, agent, funder, director — each with role-specific navigation and permissions
- Role-aware dashboard API returning tailored stats per role
- Swap processing API with wallet debits, three-way revenue split (platform/agent/funder), and device status tracking
- Wallet API: balance check, top-up recording, transaction history, payout requests
- Devices API: fleet CRUD with filtering by status/area, device creation with funder linking
- Members API: list, update, freeze/unfreeze, account closure request and approval flow
- Agents API: list with enriched stats, profile updates, approve/suspend
- Funders API: portfolio view, device purchase flow
- Deposits API: payment recording, refund processing with wallet integration
- Geographic areas API: CRUD with director assignment
- Demo seed with Lagos zones, sample agents, funders, customers, power banks, and transactions
- Fresh seed with default settings (1,200 NGN swap fee, 20,000 NGN deposit, configurable revenue split)
[0.1.0] — 2026-04-16
- Initial shell scaffold with customer / agent / admin roles.
- Concept page outlining PIN-based swap confirmation and deposit flow.
- Added funder role as a stretch idea — outside funders fund individual power banks and earn a cut of every rental their unit generates, tracked live in-app.