Weave is an accessibility-first Flutter client for self-hosted collaboration stacks. It is being built around a repository-first, feature-first architecture so future protocol integrations can land behind stable domain boundaries instead of leaking transport logic into presentation code.
Weave aims to unify the core mobile workflows for self-hosted environments.
Release 1 is intentionally narrower:
- identity through OIDC providers such as Authentik and Keycloak
- communication through Matrix
- files through Nextcloud-backed services
Calendar and Deck remain future product areas, not Release 1 promises.
The app now starts through an explicit bootstrap phase before the router is built. Startup resolves into one of:
loadingneedsSetupneedsSignInreadyerror
That means routing no longer depends on a temporary default that flips later from storage.
Setup and Settings now share one persisted server configuration model:
- OIDC provider type
- OIDC issuer URL
- Infra-managed OIDC app client ID:
weave-app - Matrix homeserver URL
- Nextcloud base URL
- Backend API base URL
Defaults for Matrix, Nextcloud, and the backend API are derived from the issuer host using a homelab-friendly rule, but the user can override those values during setup and later in Settings.
App OIDC redirect handling is aligned to the infrastructure SSOT:
- Sign-in redirect URI:
com.massimotter.weave:/oauthredirect - Logout redirect URI:
com.massimotter.weave:/logout
For local development stacks, Weave accepts http:// issuer and service URLs in addition to https://.
For the default homelab convention, Weave assumes:
- OIDC issuer / auth provider:
https://auth.home.internal - Matrix homeserver:
https://matrix.home.internal - Canonical Nextcloud URL:
https://files.home.internal - Backend API base URL:
https://api.home.internal/api
Weave follows a feature-first clean architecture layout:
lib/
├── core/
│ ├── bootstrap/ # App start resolution before routing
│ ├── failures/ # Shared app-level error model
│ ├── persistence/ # Secure/non-secure storage boundaries
│ ├── router/ # go_router setup and route constants
│ ├── theme/
│ └── widgets/
├── integrations/
│ └── nextcloud/ # Shared Nextcloud auth/session/platform boundary
└── features/
├── auth/
├── calendar/
├── chat/
├── deck/
├── files/
├── onboarding/
├── server_config/
└── settings/
Inside each feature:
presentation/contains screens, widgets, and Riverpod UI statedomain/contains entities and repository contractsdata/contains repository implementations, persistence adapters, DTOs, and protocol/service clients
Inside each shared integration:
presentation/contains reusable Riverpod providers and composition for the integration stackdomain/contains shared entities, failures, and service/repository contractsdata/contains persistence, protocol clients, and integration-level orchestration
Today, Nextcloud auth, session persistence, login-flow handling, bearer fallback, and connection lifecycle live under lib/integrations/nextcloud/, while features/files/ stays focused on DAV directory browsing and file-domain mapping.
See docs/architecture.md for the detailed design notes.
The first public release only presents Chat, Files, and Settings in the main app shell.
Calendar and Deck code may still exist behind the scenes while those features are under construction, but they are not presented as release-ready surfaces.
Chat is the first real post-auth product slice in the app shell:
- app-level OIDC auth still only controls bootstrap and shell access
- Matrix protocol auth is handled separately inside
features/chat/ - chat restores its own Matrix session from the SDK database when available
- legacy-only homeservers without Matrix OAuth metadata currently fail with a clear unsupported message instead of falling back to password login
The current Matrix security foundation also includes:
- chat-owned E2EE bootstrap state, device/account trust state, key backup state, and encrypted-room readiness mapping
- first-device crypto identity setup through secret storage, cross-signing, and online key backup
- recovery reconnect for devices that know the account but have lost local crypto secrets
- self-verification via SAS emoji/numbers, including the Matrix SDK
askSSSSpath where verification must be continued with a recovery key or passphrase
This is intentionally still a security foundation, not full encrypted timeline/send-receive chat. The current product surface focuses on secure session setup, trust health, and recovery without leaking raw Matrix crypto types into presentation code.
Accessibility is a hard requirement, not a follow-up:
- interactive targets must be at least
48x48 - icon-only affordances must expose semantics labels
- complex layouts must keep a predictable reading order
- setup, settings, shell navigation, and shared states must remain screen-reader friendly during refactors
flutter pub getflutter run
Integration tests require a live local Weave stack, including the backend API and Keycloak OIDC provider. Start the stack from the weave-infra setup first, with local hostnames resolving to the stack and the local CA trusted by the machine or simulator running the tests.
The local stack writes reusable test settings to weave-infra/weave-workspace/.generated/bootstrap.env and mirrors them to /tmp/weave-infra/weave-workspace/.generated/bootstrap.env for the self-hosted GitHub runner path. make integration-test sources the repo-local file first, then falls back to the /tmp mirror. Use WEAVE_BOOTSTRAP_ENV when your infra checkout lives elsewhere.
Expected local hostnames include weave.local, api.weave.local, auth.weave.local, matrix.weave.local, and files.weave.local.
Files and calendar product flows must use Weave/backend protocol contracts or documented WebDAV/CalDAV/OCS access. Tests must not depend on parsing or scraping Nextcloud HTML pages.
Run against the default local stack:
cd ../weave-infra/weave-workspace
TF_VAR_create_test_user=true ./install.sh
cd ../../weave
make integration-testRun against a different infra checkout:
WEAVE_BOOTSTRAP_ENV=../weave-infra/weave-workspace/.generated/bootstrap.env make integration-testThe GitHub Actions live-stack paths run on a dedicated self-hosted, macOS, ARM64, weave-live runner. Pull-request CI uses the loopback 127.0.0.1.sslip.io tenant so shared runners do not need /etc/hosts mutation. The standalone Live Stack E2E workflow uses the canonical *.weave.local hostnames used by local developers; if that runner cannot resolve them and cannot update /etc/hosts non-interactively, the job fails fast with the exact host line to add. Both paths build the backend image from the selected backend ref and read the generated bootstrap env so Flutter tests consume the exact API/Auth/Matrix/Nextcloud endpoints that infra exposed.
Supported overrides:
WEAVE_BASE_URL: base URL for the Weave backend API, defaulting tohttps://api.weave.local/apiWEAVE_OIDC_ISSUER_URL: OIDC issuer URL, defaulting tohttps://auth.weave.local/realms/weaveWEAVE_OIDC_CLIENT_ID: app OIDC client ID, defaulting toweave-appWEAVE_NEXTCLOUD_BASE_URL: canonical Nextcloud URL, defaulting tofiles.<workspace-host>(legacyWEAVE_NEXTCLOUD_URLis also accepted)WEAVE_MATRIX_HOMESERVER_URL: Matrix homeserver URL, defaulting tomatrix.<workspace-host>(legacyWEAVE_MATRIX_URLis also accepted)WEAVE_TEST_USERNAME: username for the test accountWEAVE_TEST_PASSWORD: password for the test account
Run the full validation suite before opening a change:
flutter pub getflutter gen-l10ndart run build_runner build --delete-conflicting-outputsdart format --output=none --set-exit-if-changed .flutter analyze --fatal-infosflutter test