── The full-address path was reaching the Miler empty ──
`DestinationGroup.toBookingJson` spread its details FLAT across the
destination. The contract nests them under `details{}`, and a destination
carrying keys the server does not recognise is accepted without a word — so
every building number, street, landmark, recipient name, recipient phone and
pin a customer typed was written, answered 201, and thrown away. The Miler
arrived with a district.
Four more on the same call. The destination pin spelled `latitude`/`longitude`
— the same spelling that answered 422 unserviceable for months on the pickup
before it was fixed there and missed here. A PATCH that sent `null` to clear a
field, with a comment saying so, when the server writes only non-nil values, so
a landmark could be added and never removed. Per-destination `instructions`
folded into the visit's one `remarks` line on the belief the contract had no
per-destination note; it has one. And `contactName`/`contactPhone` on the
pickup object, which the create contract has no room for and drops.
The fix ships unverified, deliberately. If `details{}` is also the wrong shape
the fields drop exactly as they do today — it cannot be worse, and holding it
costs every full-address booking in the meantime. docs/BACKEND_CHANGES.md asks
for the confirmation; tool/verify_booking.sh runs it in one command.
── Who the Miler rings ──
One number reaches the rider and it is the account's: `GET /miler/bookings`
returns a single `customerphone`, verified against production and written down
in the rider app's own stop_contact.dart. So "Someone else is handing it over?"
was collecting a number that reached nobody.
Review now shows the number that will actually be dialled, and the handover
person travels in `remarks` with a name, labelled for whoever reads it. Both
screens say plainly that the rider's call button still dials the account —
better than letting somebody hand their parcel to a neighbour believing
otherwise.
── Account's rows led nowhere ──
Two had no `onTap` at all — a chevron pointing at a page that did not exist —
and three answered with a toast. Five rows making a promise, one keeping it.
Notifications, Payment, Help and About are real screens now, written to one
rule: say only what is true of this app today. There is no notification
endpoint, no stored payment instrument and no push SDK wired in, so none of
them pretends to manage any of that. Support shows no contact block at all
rather than a number that rings nowhere — AppConfig carries the fields empty
until somebody fills them in.
── ONE TOUCH is one sheet ──
It was two in sequence with a dismissal between them, and the destination step
made you open a state to see any city — two levels of navigation for something
its own search already flattened. One flat list headed by state, which is also
the answer to "where do you deliver?", and one surface that changes its
question instead of closing so another can open.
Home says the reach in a line, and it needed two fixes to appear at all:
`cachedCities` walked closed states looking for districts that are only fetched
for open ones, and `loadCities` filled two caches while notifying nobody.
── Sending a second parcel ──
`maxDestinations` is 1 in production, so two parcels for two places means
booking twice — and that cost the whole flow twice, re-answering a door the
customer had not moved from. `startBookingFrom` carries the door, carries the
destination only when asked, and never carries the window: a slot fills up, and
a second booking pinned to one that is now full is refused at confirm with
nothing the customer can act on.
Review also says why there is no "add another destination", so a cap reads as a
limit rather than a missing button.
── Bundle ──
pubspec named its images one by one. Declaring `assets/images/` as a folder
shipped a 974 KB launcher-icon master to every customer for a file no code
opens.
151 lines
6.4 KiB
YAML
151 lines
6.4 KiB
YAML
name: doormile_cx
|
|
description: "Doormile — book a pickup from your door, track it to delivery."
|
|
# The following line prevents the package from being accidentally published to
|
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|
|
|
# The following defines the version and build number for your application.
|
|
# A version number is three numbers separated by dots, like 1.2.43
|
|
# followed by an optional build number separated by a +.
|
|
# Both the version and the builder number may be overridden in flutter
|
|
# build by specifying --build-name and --build-number, respectively.
|
|
# In Android, build-name is used as versionName while build-number used as versionCode.
|
|
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
|
|
# Read more about iOS versioning at
|
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
# In Windows, build-name is used as the major, minor, and patch parts
|
|
# of the product and file versions while build-number is used as the build suffix.
|
|
version: 1.0.0+1
|
|
|
|
environment:
|
|
sdk: ^3.13.2
|
|
|
|
# Dependencies specify other packages that your package needs in order to work.
|
|
# To automatically upgrade your package dependencies to the latest versions
|
|
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
|
# dependencies can be manually updated by changing the version numbers below to
|
|
# the latest version available on pub.dev. To see which dependencies have newer
|
|
# versions available, run `flutter pub outdated`.
|
|
dependencies:
|
|
flutter:
|
|
sdk: flutter
|
|
|
|
# The following adds the Cupertino Icons font to your application.
|
|
# Use with the CupertinoIcons class for iOS style icons.
|
|
cupertino_icons: ^1.0.8
|
|
|
|
# Lucide — the icon set the whole UI draws from.
|
|
#
|
|
# Material's stock glyphs are heavy, inconsistently weighted and instantly
|
|
# recognisable as "default Flutter". Lucide is a single 1.5px-stroke family,
|
|
# so an icon sits at the same visual weight as the type beside it instead of
|
|
# shouting over it. Same set the Miler rider app uses, so the two apps in
|
|
# this repo read as one product.
|
|
lucide_icons_flutter: ^3.1.17
|
|
flutter_map: ^8.3.2
|
|
latlong2: ^0.10.1
|
|
# Pinned below 14.0.3: that patch pulls geolocator_linux 0.2.6, which pins
|
|
# win32 ^6 through package_info_plus and makes flutter_secure_storage 9.x
|
|
# unsolvable. 10/11.x of that package need compileSdk 37, which this
|
|
# project's Android Gradle plugin does not support. Neither desktop plugin
|
|
# ships here; the constraint is pub's arithmetic, not a runtime need.
|
|
geolocator: 14.0.2
|
|
|
|
# Networking. `http` is the whole transport — every call goes through
|
|
# `ApiClient`, which is the only place in the app that knows about it.
|
|
http: ^1.5.0
|
|
|
|
# Session persistence. Refresh tokens live 60 days and rotate on every use,
|
|
# so they belong in the keychain / EncryptedSharedPreferences, not in a
|
|
# plaintext preferences file.
|
|
flutter_secure_storage: ^9.2.4
|
|
flutter_animate: ^4.5.2
|
|
lottie: ^3.6.1
|
|
url_launcher: ^6.3.2
|
|
|
|
dev_dependencies:
|
|
flutter_test:
|
|
sdk: flutter
|
|
integration_test:
|
|
sdk: flutter
|
|
|
|
# The "flutter_lints" package below contains a set of recommended lints to
|
|
# encourage good coding practices. The lint set provided by the package is
|
|
# activated in the `analysis_options.yaml` file located at the root of your
|
|
# package. See that file for information about deactivating specific lint
|
|
# rules and activating additional ones.
|
|
flutter_lints: ^6.0.0
|
|
|
|
# For information on the generic Dart part of this file, see the
|
|
# following page: https://dart.dev/tools/pub/pubspec
|
|
|
|
# The following section is specific to Flutter packages.
|
|
flutter:
|
|
|
|
# The following line ensures that the Material Icons font is
|
|
# included with your application, so that you can use the icons in
|
|
# the material Icons class.
|
|
uses-material-design: true
|
|
|
|
# Switzer (Indian Type Foundry, via Fontshare) is the app's voice as of
|
|
# 2026-09-23. One variable file, so the weight is selected through the `wght`
|
|
# axis in `DmText` rather than by bundling a file per cut.
|
|
#
|
|
# It replaced Poppins, which has no variable release: four static cuts at
|
|
# ~155 KB each, 625 KB of sans. This is 141 KB and covers 100-900.
|
|
fonts:
|
|
- family: PlusJakartaSans
|
|
fonts:
|
|
- asset: assets/fonts/PlusJakartaSans-Variable.ttf
|
|
- family: Switzer
|
|
fonts:
|
|
- asset: assets/fonts/Switzer-Variable.ttf
|
|
- family: GeistMono
|
|
fonts:
|
|
- asset: assets/fonts/GeistMono-VF.ttf
|
|
|
|
assets:
|
|
# ── Named one by one, not as a folder ──
|
|
#
|
|
# `assets/images/` bundled the whole directory, and that directory is also
|
|
# where the launcher-icon master lives — 974 KB of PNG that `tool/icons.py`
|
|
# reads at build time on a developer's machine and the app never loads.
|
|
# Declaring the folder shipped it to every customer, along with anything
|
|
# else dropped in there to work from. These two are the only images any
|
|
# code actually opens; see `splash_screen.dart` and `auth_scaffold.dart`.
|
|
- assets/images/doormile-mark.png
|
|
- assets/images/doormile-logo.png
|
|
- assets/animations/
|
|
|
|
# To add assets to your application, add an assets section, like this:
|
|
# assets:
|
|
# - images/a_dot_burr.jpeg
|
|
# - images/a_dot_ham.jpeg
|
|
|
|
# An image asset can refer to one or more resolution-specific "variants", see
|
|
# https://flutter.dev/to/resolution-aware-images
|
|
|
|
# For details regarding adding assets from package dependencies, see
|
|
# https://flutter.dev/to/asset-from-package
|
|
|
|
# To add custom fonts to your application, add a fonts section here,
|
|
# in this "flutter" section. Each entry in this list should have a
|
|
# "family" key with the font family name, and a "fonts" key with a
|
|
# list giving the asset and other descriptors for the font. For
|
|
# example:
|
|
# fonts:
|
|
# - family: Schyler
|
|
# fonts:
|
|
# - asset: fonts/Schyler-Regular.ttf
|
|
# - asset: fonts/Schyler-Italic.ttf
|
|
# style: italic
|
|
# - family: Trajan Pro
|
|
# fonts:
|
|
# - asset: fonts/TrajanPro.ttf
|
|
# - asset: fonts/TrajanPro_Bold.ttf
|
|
# weight: 700
|
|
#
|
|
# For details regarding fonts from package dependencies,
|
|
# see https://flutter.dev/to/font-from-package
|