Changelog — LocksmithKit
[2026-05-28]
- "Modules" section dissolved into its natural homes. A separate "Modules" tab made new users hunt for an Online-payments toggle while the Stripe / Paystack keys sat in another section. Now every feature toggle lives with what it controls:
- Online payments toggle → top of Payment provider (right above the provider/keys fields).
- Multiple locations + Reports toggles → bottom of Business (with Open buttons).
- Service rate card toggle → inside Workflow & alerts (where it sits naturally alongside the booking rules).
- Pricelist and Locations pages get a proper Back button. When you click "Open" on either from Settings, the page now adds
?from=settings so its back-link returns you to Settings instead of bouncing you to Home. Direct navigation (e.g. via the location picker) still falls back to Home as before.
- Save settings button text fixed. The label was rendering in dark brown on the accent background — switched to white so it reads cleanly on every theme.
- Booking form shows which location the customer's reaching. When a customer lands on
/book?loc=<id> (the per-branch URL surfaced in Settings), the form's topbar now stacks the business name with a tiny amber-tinted "📍 Downtown Branch" pin beneath it — so the customer knows which branch they're booking with before they even start. The chip only renders on multi-entity installs (single-location businesses don't need the extra chrome), and is suppressed when the entity name effectively duplicates the business name. Submission routing is fully automatic — the form forwards the loc URL parameter in its submit payload and api/book.php tags the booking + customer with that entity, so a booking made on Downtown Branch's URL lands in Downtown Branch's queue with no extra config.
- Switching locations actually shows different data now. Bookings list, customer list, dashboard stats, reports, and the live-alert poll were all reading every record regardless of which location was active in the entity picker — the seed data masked the bug because everything was tagged to entity 1. Every read path now scopes
WHERE entity_id = ? against the active entity (same pattern as DryCleanPro and PropertyPro), every write path (staff-side bookings/create and customers/add) inserts at the active location instead of being hardcoded to entity 1, and customer dedupe on bookings is also scoped — same phone at a different branch is its own customer record. Verified: with two entities seeded, each location's list returns its own count.
- Per-location settings now read as one stream with the rest. Dropped the heavy amber-tinted frame around the per-location overrides — the three cards (Job handling, SMS & push, Booking form) now use the exact same
.settings-group look as every app-wide card above. The only thing separating them is a thin horizontal divider with a small "📍 Just for Main Location" label centered on the line, plus a one-line helper underneath. All three cards are collapsed by default just like the app-wide ones, so the page feels uniform and predictable.
- Live alert "View" never dead-ends. Tapping a booking alert that points to a missing booking (deleted, archived, or the test alert) now bounces you to the bookings list with a brief toast — no more blank "No booking selected" page. Same applies to direct
/booking links with no ?id=.
- Vehicle fields properly aligned. Make / Model / Year / Color now live in a clean 2×2 CSS grid with consistent column widths, generous row spacing, and label baselines guaranteed to line up. The previous nested flex rows were drifting by a pixel on some screens.
- Settings page redesigned to match DryCleanPro / PropertyPro. Adopted the platform's
.settings-group accordion styling — same look and feel admins already know from the other apps. Every section now has a small lucide icon in its title (🏢 Business, 👥 Customer-facing, 👤 Staff, ▦ Modules, ↻ Workflow, 💳 Payment, 💬 SMS, 🏷 Labels), and the chevron now uses the platform's smooth CSS arrow instead of a hand-rolled icon. Cleaner, more compact, less custom CSS to maintain.
- Booking URL auto-adapts to the active location. Switching the location picker at the top of Settings now changes the "Your customer link" URL in the Customer-facing card — the primary location shows the plain URL, every other location gets
?loc=<id> appended automatically. No more hunting in the per-location section for the right URL to share with a branch's customers.
- Settings can now differ per location. Five settings can be set differently for each branch you run: auto-accept new bookings, Twilio "From" number, ntfy push topic, quick-send SMS templates, and the booking form HTML. Everything else stays app-wide and applies to every location. The Settings page now ends with a clearly-divided "📍 [Location] only" section — leave any field blank to use the app-wide value above. New locations automatically inherit the primary location's overrides so you don't have to re-enter them from scratch. The customer-facing form picks up the right location via a
?loc=<id> URL param (the copy-link in the per-location section already builds the right URL for you).
- Confirmation screen actions are clearer. The hard-to-find "Done" link in the top-right of the confirmation page is gone — now it sits as a second, equally-prominent button next to "Call us" at the bottom. Both are pill-styled and smaller than the old full-width Call CTA. Done takes the customer back to step 1 of the booking form (so they can book another job right away) instead of dumping them on the customer portal; the portal is still one tap away via the "Track an existing booking" tile that already lives on the form's home page. Also added breathing room above the footer so the timeline never touches the buttons.
- Booking form home polish. "How can we help you today?" now fits on a single line (was wrapping after "help you") — title size tightened so the page reads more compact. The "Track an existing booking" tile got an amber accent treatment (tinted background, amber border, amber chevron) so returning customers don't miss it. On step 2 of the booking wizard, more breathing room sits between the last field (access notes / photo) and the sticky Continue button.
[2026-05-27]
- Customers can add vehicle info + a photo to their booking. On the booking form, picking "Car lockout" now reveals optional Make / Model / Year / Color fields. Every service type also gets a "Take or upload a photo" tile — phones open the rear camera directly, photos are resized to 1280px and uploaded with the form. The photo shows on the admin's booking-detail page; tapping it opens the full size in a new tab. Stored under
users/{uuid}/uploads/locksmithkit/bookings/{id}/.
- One-tap SMS to the customer from the booking page. New "Message customer" section on every booking — pre-written templates appear as amber pills (tap to load), a 320-char textarea lets you tweak before sending, and the templates themselves live in Settings → SMS & push under "Quick-send SMS templates" (one per line,
{name} {ref} {phone} {amount} {biz} get auto-filled). Sends via the existing Twilio config.
- The new-booking alert just got loud. Three new signals layer on top of the existing card + ding + vibrate so a fresh booking is impossible to miss:
- Native OS notification that pops out of the browser even when the tab is backgrounded. Asks for permission lazily (once per session, never on first load) and clicking the notification jumps straight to the booking-detail page.
- "Dashboard lights up" — while any unhandled booking card is on screen, the viewport gets a pulsing amber edge-glow and a sticky strip at the very top of the page shows the count ("🔔 2 bookings waiting"). Both turn red and pulse faster for emergencies. Clears the moment every card is dismissed.
- Customer portal: PIN always required. The phone-only lookup path is gone — every customer signs in with phone + PIN, or creates an account with the same fields. The "I have a PIN" toggle and the "Require a PIN" setting are removed (the setting is now ignored, the API hard-rejects PIN-less lookups). Simpler, more secure.
- Staff logout lands on the staff login. Logging out as admin/staff previously dumped you on the customer portal — now you go back to
/staff. Customers and unauthenticated users still land on /track.
- Admin "New booking" now uses the customer form inline. When admins tap the +New button, the same multi-screen customer form opens embedded in the page (no popup, no new tab) and lands them right on step 1 of the booking wizard. The submission flows through the same pipeline, so what an admin captures over the phone is indistinguishable from a customer's self-booking. The form's URL accepts new
?step=book and ?service=<id> parameters for deep-linking.
- Location pickup now actually asks for permission. The platform was sending
Permissions-Policy: geolocation=() which silently blocks the geolocation API at the browser level — the customer never even sees the "Allow location?" prompt. Switched to geolocation=(self) so the standard browser flow fires.
- Confirmation screen now matches the booking type. For ASAP bookings the timeline reads "Confirming with our team → Driving to you → Arrived" (no false claim that a tech is already dispatched). For scheduled bookings the timeline switches to "On the books → Technician dispatched on the day → Arrived" and the ETA card shows the actual scheduled date/time instead of a generic "25–35 min".
- Home dashboard surfaces Reports / Activity Log / Settings. Added a Quick actions pill right under the summary cards (opens the actions sheet) and a 3-tile Quick Links grid below the Money row — Reports, Activity Log, Settings. Activity Log is also now in the Quick Actions list. Owner-only.
- Staff "New booking" form fixes. Services list now mirrors the public customer form (dropped the catch-all "Other"). A new "Use the customer booking form instead" tile sits at the top — opens the same multi-screen flow customers see, in a new tab, for when you'd rather walk a caller through the real thing. Create button restyled to the amber accent (was the indigo block).
- Staff section moved up + edit support. The Staff card now sits right under Customer-facing so you don't have to scroll past Save to manage your team. Every staff row gets an Edit (pencil) action — change a name or phone number after creation without removing and re-adding the person. PIN changes still live behind the key icon.
- Save settings button restyled. The bottom Save button picks up your amber accent now instead of the platform's generic indigo block — matches the rest of the settings page.
- One-tap-Spanish booking link. Settings → Customer-facing now shows an extra "Español link" row alongside your main customer link. Send this version to Spanish-speaking customers and the booking form opens with Spanish already selected — no need to ask them to tap the EN/ES toggle. The form reads a
?lang= URL parameter, so adding more languages later (Portuguese, French…) is a one-line change.
- Fixed: "This form is no longer available" error when submitting the public booking form on older installs. The booking endpoint now self-heals — if the default form row is missing, it's rebuilt from the canonical HTML on the first submit.
- Staff can do everything except open Settings. Promoted staff permissions across bookings, customers, payments, pricelist, portal, forms, locations and reports — full create/edit/delete on all of them. Settings (and the activity log) stay admin-only.
- ntfy push — set your own topic. Settings → SMS & push now has a dedicated "ntfy push topic" field. Pick any unique string (defaults to your business phone digits) and subscribe to that same topic in the ntfy phone app to start getting native banners. Also added an optional self-hosted ntfy server field.
- Clearer SMS setup. Twilio fields now show concrete placeholders and helper text. The Twilio From number falls back to your business phone if you leave it blank.
- Better recovery when location pickup fails. If the customer's browser blocks location (or returns an error), the booking form now auto-focuses the address input and pulses it amber — making it obvious they can just type the address by hand.
[2026-05-26] — First full release 🚀
LocksmithKit is now a complete field-service app — built for locksmiths, and for anyone who goes out to the customer.
- Design your own booking form. Paste your form's HTML (and optional CSS) under Settings → Booking forms; LocksmithKit renders it on a shareable, embeddable public page. The only requirement is a name and a phone field. Run several forms for different services or markets.
- Every submission becomes a job. New bookings land in a live queue (New → Accepted → In Progress → Completed). Customers are matched or created automatically by phone, so you build a customer list without lifting a finger.
- Instant team alerts. When a booking comes in, your signed-in team gets a real push notification on their device — it feels like a dispatch room in your pocket. One tap to Accept and assign a technician.
- Price after the job, get paid your way. The technician sets the final price once the work's done, then marks it paid or collects online — Stripe and Paystack are built in. Customers can pay their balance from their own portal.
- Customer portal. Customers look up and track their jobs by phone — or with a phone + PIN if you switch that on under Settings.
- Make it yours. Turn modules on or off (online payments, rate card, reports, multiple locations), rename labels, and manage your team — all from Settings.
- Dark by default. Your public pages open in a sleek dark theme; visitors can flip to light, and you can change the default.
[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]
- Demo and subscribe now work out of the box — finished migrating the app to Pancho's UUID identity model so Try Demo no longer errors with 'We could not start the demo'.
Internal
- Added the
tenant_members table to schema.sql (backed by the platform's _per_user_app_bootstrap_owner() hook).
[2026-04-18] — Renamed
- Renamed from Locksmith Pro to LocksmithKit (slug
locksmithpro → locksmithkit).
- 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.
[0.1.0] — 2026-04-16