Totem is a space for guided group introspection. This Flutter app is the official open-source mobile client for the Totem platform. It connects people through structured group sessions and authentic conversations, powered by a thoughtfully crafted UI and backend.
This client targets iOS, Android and the Web, using Flutter and Riverpod for a fast, modern, and scalable development experience.
Make sure you have Flutter installed and configured.
git clone https://github.com/totem-technologies/totem_app.git
flutter config --enable-swift-package-manager
make install
make githooks # Install git hooks for code formattingNote
You must setup firebase locally.
make flutterfire to generate firebase_options.dart and add your own Firebase config files (google-services.json, GoogleService-Info.plist) locally. This runs flutterfire configure inside both the totem_app (android + ios) and totem_web (web) packages. These files are not committed to the repo. Learn more
For development:
make run
make run-chromeRuntime config is composed from the layered files in config/ into each package's .env. make run / make run-chrome do this automatically for the development flavor; run make env-dev to (re)generate it manually. To override a value on your machine, copy config/development.local.env.example to config/development.local.env and edit it. See config/README.md for the full layering model and available keys.
If testing on an iOS device, ensure you're using macOS and have Xcode installed.
You can use the --flavor option to build for staging or production (default).
On android, When reattaching, use:
adb logcat "*:S" flutter:V
flutter attachor
flutter run --use-application-binary=packages\totem_app\build\app\outputs\apk\debug\app-debug.apkRun all tests:
make testTo test deep linking, with the app running, you can use the following commands:
For Android:
adb shell 'am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://totem.org/spaces/session/doa689fvb"' org.totem.appFor iOS:
xcrun simctl openurl booted "https://totem.org/spaces/session/doa689fvb"To run the app with a local server, you can set the MOBILE_API_URL environment variable at the .env file in the packages/totem_app or packages/totem_web directory of the project. This allows you to connect to a local instance of the Totem API.
MOBILE_API_URL="http://localhost:8000/"This repository is organized as a multi-package Flutter workspace.
.
├── packages/
│ ├── totem_core/ # Shared library: firebase_options.dart, common logic, models
│ │ └── lib/
│ ├── totem_app/ # Mobile app (iOS / Android)
│ │ └── lib/
│ └── totem_web/ # Web client
│ └── lib/
├── scripts/
├── specs/
└── README.md
Notifications are handled using Firebase Cloud Messaging (FCM). In the notification data, one may include a path key to specify the route to navigate to when the user taps on the notification.
The release process is automated via a Dart script that handles versioning, tagging, and pushing to the repository.
Before creating a release, ensure:
- You are on the
mainbranch - Your working tree is clean (no uncommitted changes)
- Your local
mainbranch is up-to-date withorigin/main
Run the release command:
make releaseThe script will:
- Display the current version from
pubspec.yaml - Suggest a default version (increments patch and build number)
- Prompt you to enter a new version
The totem_web client is mounted at the /room/ base route. The Django
origin serves (and patches) the HTML document — it proxies the page from this
deployment — while the Cloudflare Worker acts as a CDN, serving every other
asset directly. Two build settings make this work:
--base-href /room/sets<base href="/room/">so the page and go_router routing live under/room/on the Django origin.--web-define=ASSET_BASE=<worker-url>points Flutter's loader (web/flutter_bootstrap.js) at the Cloudflare deployment, somain.dart.js, CanvasKit, the wasm runtime andassets/are fetched directly from the CDN.
The bootstrap script is inlined into index.html (via the
{{flutter_bootstrap_js}} token), so there is no separate
flutter_bootstrap.js request: Django serves only the HTML document and the CDN
serves everything the loader pulls.
The Worker is assets-only and serves the bundle flat from its own origin. SPA
fallback is off (not_found_handling = "none") — Django owns the HTML and
client-side routing, so a missing asset 404s instead of being masked by
index.html. Because the assets are fetched cross-origin, they ship with CORS
headers via web/_headers (honored by Workers Static Assets); scripts/serve_web.dart
mirrors those headers for local testing.
Config lives in packages/totem_web/wrangler.toml; deploys are driven by
.github/workflows/web.yml:
- Pull request / push to
main— builds the web bundle as a check (no deploy). - Push a release tag
v*— builds and deploys the staging environment. - Publish the GitHub release (move the draft out to latest) — builds and deploys the production environment.
Required repository secrets (in addition to the existing FIREBASE_OPTIONS_B64):
CLOUDFLARE_API_TOKEN— a token with the Workers Scripts: Edit permission.CLOUDFLARE_ACCOUNT_ID— the target Cloudflare account id.
ASSET_BASE (the public URL the loader fetches assets from) is hardcoded per
environment in .github/workflows/web.yml — currently the *.workers.dev
URLs. Update those values there if the Worker moves to a custom domain.
To build and deploy manually:
cd packages/totem_web
flutter build web --wasm --base-href /room/ \
--web-define=ASSET_BASE=https://totem-web-staging.<sub>.workers.dev/
bunx wrangler deploy --env staging # or --env productionJoin the Totem movement at totem.org. To discuss development or get involved, feel free to open an issue or pull request.