Prerequisites
- Flutter with Dart
^3.11.0(the constraint inpubspec.yaml). - An appengine reachable at the development endpoint in
lib/config/environment.dart—http://192.168.1.239:3300, a LAN address so a physical phone can reach it. Edit that line for your machine. - The demo organization (
orgId: demo) with seeded events; see the seed scripts below.
Debug builds
flutter run on a device or simulator. Debug builds use the development environment; release builds switch to production (https://appengine.appmint.io, org eventos) through kReleaseMode. There is no runtime switch.
Fast Login (Dev) on the login screen signs in as [email protected] under kDebugMode. The credentials sit in lib/screens/auth/login_screen.dart; the button never renders in release.
Running on web at phone size
The app compiles for web without changes, and driving it from Chrome is the fastest way to exercise every screen. Two things get in the way: Flutter sizes itself to the browser window, and a full-screen window gives you a stretched desktop layout that neither wheel nor drag will scroll.
1. Start the dev server.
flutter run -d web-server --web-port 8093 --web-hostname 127.0.0.1Wait for lib/main.dart is being served at http://127.0.0.1:8093. Edits are not hot-reloaded without stdin; kill the process, free the port and relaunch.
2. Wrap it in a 430 px iframe. Put this in a scratch folder as index.html and serve it with python3 -m http.server 8094 --bind 127.0.0.1:
<!doctype html>
<style>html,body{margin:0;background:#1d1d1d}iframe{width:430px;height:700px;border:0}</style>
<iframe src="http://127.0.0.1:8093/" allow="camera; microphone; clipboard-write"></iframe>Open http://127.0.0.1:8094/. Flutter now sees a real phone viewport, taps and typing land, localStorage persists the session across reloads, and the browser console shows the app's log lines from inside the frame.
3. Wait for transitions. Route pushes take 8–15 s in a debug web build, and My Events can take 30–45 s on first load (one event fetch per ticket). A tap during a transition lands on the screen underneath.
4. Read the wire. AppengineHttpClient logs 📤 METHOD /path with bodies and truncated responses. Filter the console on 📤, rror or the path you care about; it is a complete API trace of what the app did.
Web-only limits, not bugs: card payment is a throwing stub (stripe_service_mobile.dart has a web counterpart that does nothing), the camera picker needs the iframe allow attribute, and the Inbox photo glyph renders as a box because the icon font is missing on web.
"A Stack requires bounded constraints from its parent" repeats on route transitions in the web debug build. Screens render correctly and release builds strip assertions. Its origin has not been pinned down; the calendar cells and the shell's bottom bar are the candidates.
Static checks and tests
flutter analyze lib
flutter testanalyze is clean of errors and warnings; the infos are pre-existing. test/ contains only the scaffold widget test.
Seeding an organization
scripts/ holds Node utilities that gave the demo org its content: seed_data.js (events, sessions, ticket types), seed_participants.js (94 participants across the types), upload_avatars.js, and the fix_images*.js / fix_participants.js repair scripts. Run them against a fresh org before testing People, Schedule or the feed; an org with no participants makes half the app look broken when it is simply empty.
Working against the backend
- Event-scoped client routes resolve slug or id on the server (
resolveEventIdinevents-client.service.ts). If a list is empty for the app but populated by id, check that resolution first — that was the schedule bug in September 2026. - A rebuilt
dist/is not a restarted server. Restart the Node process with the flags and log path it was started with, after checking who owns port 3300. - The global rate limiter (15-minute window,
RATE_LIMIT_MAX) is per IP. Scripted checks from127.0.0.1can hit 429 while the app on the LAN IP is fine. repository/update-partial$sets the keys you send. Mongo operators such as$incare hoisted to the top level of the update since the September fix; before that, every comment returned "Database operation failed".
Verifying social features
Most community flows need two accounts to close the loop: accepting a connection, replying in chat, responding to a meeting. With one account you can still verify request → Pending, message sent with a tick, like and comment counters, reposts and bookmarks. Confirm counters on the server with a small script against POST /repository/find/community_post rather than trusting the UI alone; that is how the corrupted reactionSummary was found.