docs
/
Appmint Mobile

Running and testing

Debug builds against a local backend, the web build that lets you drive the app from Chrome, and the rules that stop you chasing ghosts.

Prerequisites

  • Flutter with the Dart SDK the project pins (>=3.5.0 <4.0.0 in pubspec.yaml).
  • A running appengine on port 3300, reachable at the address in lib/config/environment.dart. In development that is the developer's LAN IP (http://192.168.1.239:3300), not localhost, so a physical phone on the same network can reach it. Change that line if your machine's address differs.
  • For iOS: Xcode with the current iOS SDK; for Android: a signing config only when building release.

Debug builds

flutter run on a device or simulator. A debug build always uses the development environment (EnvironmentConfig.setEnvironment keys off kReleaseMode); there is no in-app switch.

Fast Login (Dev) — the login screen shows an outlined button under kDebugMode that signs in as demo / [email protected] with a fixed password. It never ships in release, but the credentials are in lib/screens/auth/login_screen.dart, so keep that file out of anything public.

One `flutter run` per physical device

Two concurrent runs targeting the same phone deadlock each other's installs. If someone is deploying to a device, do not start a second run against it — build and analyze only.

Running on web

The app was not written for web, but it runs there well enough to drive every screen from a browser, which is how the last test pass was done.

1. The thermal-printer shim makes it compile. flutter_thermal_printer pulls Windows FFI code that cannot build for web. lib/services/thermal/thermal_printer.dart is a conditional export: thermal_printer_io.dart re-exports the real plugin, thermal_printer_web.dart is a no-op stand-in (scans find nothing, printing throws). Mobile behaviour is unchanged.

2. Start the dev server.

flutter run -d web-server --web-port 8092 --web-hostname 127.0.0.1

Wait for lib/main.dart is being served at http://127.0.0.1:8092. There is no hot reload without stdin; to pick up edits, kill the process, free the port, and relaunch.

3. Frame it at phone size. Flutter sizes itself to the browser window, and a full-screen window gives you a desktop layout. Serve a one-line wrapper from a scratch folder:

<iframe src="http://127.0.0.1:8093/" width="430" height="700"></iframe>

with python3 -m http.server 8094 --bind 127.0.0.1, then open http://127.0.0.1:8094/. The app inside gets a real 430 px viewport, keyboard and clicks work, and the console is readable from the outer page.

4. Expect slow transitions. Route pushes take 8–15 s in a debug web build. Click after a screen has settled or the tap lands on the previous screen.

5. Read the wire. AppengineHttpClient logs every request as 📤 METHOD /path with the body and a truncated response, so the browser console is a complete API trace. Filter on 📤, failed or rror.

Known web-only quirks, not product bugs: after a page reload some header and back taps stop registering until the next reload; pressing back on a top-level screen reloads the page; Stripe Terminal, NFC and native printing are unavailable.

Static checks and tests

flutter analyze lib
flutter test

analyze reports pre-existing infos (deprecated radio APIs, unnecessary casts) but no errors or warnings on a clean tree. The test suite is the scaffold test/widget_test.dart only; there is no CI configuration.

Working against the backend

The app talks to a shared appengine, and three things about it cost people hours:

A rebuilt dist is not a restarted server. npx nest build (with NODE_OPTIONS=--max-old-space-size=8192, a plain build runs out of memory) updates dist/, but the running Node process keeps the code it loaded. Restart the process with the same flags and log path it was started with. Check lsof -iTCP:3300 and ps -o command= on the pid before you kill anything — the port may belong to someone else's session.

Rate limiting is per IP over 15 minutes. RATE_LIMIT_MAX (default 10000) applies globally. Scripted checks from 127.0.0.1 can trip it and get 429 while the app on the LAN IP is fine. Pace your scripts.

Money is server-owned. Item changes and settles re-price on the server. Writing data.productItems through update-partial does not recompute totals; write data.subtotal and data.total alongside, or route product lines through POST /storefront/order/:id/items.

Verifying a change end to end

The approach that found real bugs in the last pass: drive the screen in Chrome, watch the console trace, then confirm the record on the server with a small script against the repository endpoints. flutter analyze and a green tsc are necessary, not sufficient — the open-tabs list was empty in the app while every check passed.