A serverless Flutter framework designed as a solid starting point for new casual applications, demonstrated with an example app.

Warning

Note: Under construction; breaking changes may occur.

Built-in Features

  • Service Management
    • Service Status & Forced Upgrades: The ability to set a minimum required application version or disable the service for maintenance, and smoothly communicate this to users.
    • Service Administrators: Manage the users who can maintain policies and service status.
    • Beta/Authorized Users: Limit application access to a predefined set of regular users.
  • GDPR and App Store Compliance
    • Terms of Service & Privacy Policy: A complete flow for presenting and requiring user acceptance of legal terms, including versioning for updates.
    • Account Deletion: A clear, user-accessible path for account deletion.
    • User Data Access: Since all the event source data is cached on the client, the user can export their data at any time. The application just needs to provide an export feature (e.g., copying events to the clipboard). If the application supports media, then it can provide a way to export the media as well (according to its terms of service).
  • App Appearance & Personalization
    • Localization: Support for multiple languages.
    • Theming: Dynamic light and dark mode support.
  • Collaboration & Core Features
    • Shared Site (Resource) Management: Supports the common use case of members sharing a resource, or "site" (such as a set of photo albums, a calendar, etc.). The framework manages adding and removing site members, as well as self-removal. Site members can be assigned administrative roles. Backend security rules ensure site data privacy.
  • Event Sourcing Framework Replay on the Client
    • This eliminates the common practice of having separate models for UI forms, network marshalling, database storage, and business logic. This reduces boilerplate code and removes the need for app logic on the server side. Events are persisted on the client, significantly reducing service queries. Note: Backend logic (e.g., Cloud Functions or database hooks) is used to assist with cleanup upon account deletion.
    • Event and Replay Views: Service, account, and site events (and their resulting replays) can be viewed directly in the UI, assisting with debugging without needing to access the backend services.
    • Persistence-Agnostic: The framework is designed to support various storage providers (e.g., Firebase, PocketBase) and allows switching between them at runtime. Built-in memory and local file storage are also supported out of the box.

Usage

The repository includes examples of using the library. Follow the instructions below.

Prerequisites

  • Install Flutter with Chrome support.
  • Run flutter --version to check your version. Ensure it is at least 3.32.1.
  • Run flutter devices to check that Chrome is listed as an available device.

Installation & Setup

git clone git@github.com:bjorge/hyttahub.git
cd hyttahub
flutter pub get
flutter test

Running the Application

cd example/template
flutter run -d chrome

Persistence Registration

HyttaHub is persistence-agnostic and uses a dynamic registration system.

Please see PERSISTENCE.md for details on how to register and use multiple storage providers.

FAQ

I want to make some changes to the language files, how do I compile them?

After updating the .arb files, run:

flutter gen-l10n

How do I run the example app with a local backend?

HyttaHub supports multiple backends. To run the example with a local emulator:

How do I tag a new release?

git tag v0.1.53
git push origin --tags

How do I compile the protocol buffer files?

Protocol buffer files can be compiled for both Dart (Flutter) and TypeScript (Cloud Functions) using Podman or Docker. See the README in the tool/protobuf-compiler directory for instructions.

Is any server-side code required for this project?

The project requires no long-running server-side code. Backend logic (Cloud Functions for Firebase or Go hooks for PocketBase) is used sparingly—only when necessary to provide access to parts of the system that are inaccessible to the client due to security rules. For example, when a site admin removes a member, a backend process will securely add a "remove" event to that member's account stream (which the admin cannot access directly). This logic is also used for housekeeping tasks, such as removing abandoned site data when the last member leaves a site.

How is shared member data kept private?

Storage-specific security rules are designed to ensure member data privacy. For Firebase, these are defined in firestore.rules and storage.rules. For PocketBase, these same rules are implemented in the Go backend logic. In both cases, only site members are permitted to access site data, and only site administrators can add new members. Likewise, only the owner of an account can modify their account settings, and only a service administrator can update the global service status.

Can I add social authentication, such as Google or Apple logins?

The current implementations use email addresses as keys for member management and security rules. Any authentication provider that reliably retains and verifies the user's email will work natively. For Apple sign-ins, since users can choose to anonymize their email via a relay, updates would be required in the framework to accommodate that specific case.

Libraries

account_blocs/account_replay_bloc
account_blocs/account_submit_bloc
account_blocs/acount_replay
account_widgets/account_events_display
account_widgets/account_screen
account_widgets/account_submit_button
account_widgets/add_site_screen
account_widgets/auth_submit_button
account_widgets/copy_site_confirm_screen
account_widgets/copy_site_screen
account_widgets/join_site_screen
account_widgets/leave_site_screen
account_widgets/manage_sites_screen
account_widgets/remove_account_screen
account_widgets/reorder_sites_screen
account_widgets/update_terms_form
auth_bloc/auth_bloc
auth_bloc/auth_submit_bloc
auth_bloc/base_hyttahub_auth
auth_bloc/hydrated_hyttahub_auth
auth_bloc/hyttahub_auth_factory
auth_bloc/hyttahub_auth_user
auth_bloc/in_memory_hyttahub_auth
collection_paths
common_blocs/allowed_emails_bloc
common_blocs/base_replay_bloc
common_blocs/base_submit_bloc
common_widgets/allowed_emails_display
common_widgets/common_form
common_widgets/common_submit_form_layout
common_widgets/events_display
common_widgets/hytta_hub_button
common_widgets/hyttahub_app_bar_actions
common_widgets/hyttahub_info_page
common_widgets/layout
common_widgets/unimplemented_screen
functions/site_cleanup
hyttahub
hyttahub_app
hyttahub_initialization
hyttahub_options
l10n/intl_localizations
l10n/intl_localizations_en
l10n/intl_localizations_es
l10n/intl_localizations_it
l10n/intl_localizations_nb
l10n/intl_localizations_nl
preferences_cubits/language_cubit
preferences_cubits/login_cubit
preferences_cubits/platform_cubit
preferences_cubits/theme_cubit
proto/account_events.pb
proto/account_events.pbenum
proto/account_events.pbjson
proto/account_replay_bloc.pb
proto/account_replay_bloc.pbenum
proto/account_replay_bloc.pbjson
proto/allowed_emails_bloc.pb
proto/allowed_emails_bloc.pbenum
proto/allowed_emails_bloc.pbjson
proto/app_wrapper.pb
proto/app_wrapper.pbenum
proto/app_wrapper.pbjson
proto/auth_bloc.pb
proto/auth_bloc.pbenum
proto/auth_bloc.pbjson
proto/bloom_filter.pb
proto/bloom_filter.pbenum
proto/bloom_filter.pbjson
proto/cloud_functions.pb
proto/cloud_functions.pbenum
proto/cloud_functions.pbjson
proto/common_blocs.pb
proto/common_blocs.pbenum
proto/common_blocs.pbjson
proto/hyttahub_implementation.pb
proto/hyttahub_implementation.pbenum
proto/hyttahub_implementation.pbjson
proto/service_events.pb
proto/service_events.pbenum
proto/service_events.pbjson
proto/service_replay_bloc.pb
proto/service_replay_bloc.pbenum
proto/service_replay_bloc.pbjson
proto/site_email.pbenum
proto/site_events.pb
proto/site_events.pbenum
proto/site_events.pbjson
proto/site_name_replay_bloc.pb
proto/site_name_replay_bloc.pbenum
proto/site_name_replay_bloc.pbjson
proto/site_replay_bloc.pb
proto/site_replay_bloc.pbenum
proto/site_replay_bloc.pbjson
proto/site_util.pb
proto/site_util.pbenum
proto/site_util.pbjson
routes/hyttahub_routes
service_blocs/service_replay
service_blocs/service_replay_bloc
service_blocs/service_submit_bloc
service_widgets/add_admin_screen
service_widgets/email_login_form
service_widgets/email_signup_form
service_widgets/login
service_widgets/open_source_licenses_screen
service_widgets/remove_admin_screen
service_widgets/restore_admin_screen
service_widgets/service_admin_screen
service_widgets/service_admins_screen
service_widgets/service_down_page
service_widgets/service_events_display
service_widgets/service_network_error_page
service_widgets/service_new_version_page
service_widgets/service_privacy_display
service_widgets/service_settings_form
service_widgets/service_submit_button
service_widgets/service_terms_display
service_widgets/service_uninitialized_page
service_widgets/update_admin_screen
site_blocs/site_name_replay
site_blocs/site_name_replay_bloc
site_blocs/site_replay
site_blocs/site_replay_bloc
site_blocs/site_submit_bloc
site_widgets/add_member_screen
site_widgets/remove_member_screen
site_widgets/rename_site_screen
site_widgets/restore_member_screen
site_widgets/site_edit_mode_cubit
site_widgets/site_emails_display
site_widgets/site_events_display
site_widgets/site_info_screen
site_widgets/site_members_screen
site_widgets/site_name_widget
site_widgets/site_screen_settings_button
site_widgets/site_settings_dialog_options
site_widgets/site_submit_button
site_widgets/update_member_screen
storage/base_hyttahub_internal_storage
storage/base_hyttahub_storage
storage/hydrated_hyttahub_internal_storage
storage/hydrated_hyttahub_storage
storage/hyttahub_internal_storage_factory
storage/hyttahub_storage_factory
storage/in_memory_hyttahub_internal_storage
storage/in_memory_hyttahub_storage
utilities/app_wrapper_util
utilities/bloom_filter
utilities/common_error_handling
utilities/constants
utilities/ids
utilities/pattern_utils
utilities/persistence_registries
utils/refresh_helper
utils/refresh_helper_stub
utils/refresh_helper_web
utils/renderer_detection
utils/renderer_detection_stub
utils/renderer_detection_web