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

-- Note: Under construction; breaking changes may occur.

Features

  • 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.
    • Data Access: Users can copy and export their complete event streams.
  • 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.
  • 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 application use case of members sharing a common 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. Firebase rules ensure site data privacy.
  • Clean Architecture
    • Event Source Framework Replayed in the Client: The common practice of having separate models for UI forms, network marshalling, database storage, and business logic is eliminated. 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: Some cloud functions are included 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.
    • Persistence-Agnostic: The framework is designed to support various storage providers (e.g., Firebase, Supabase) 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

I want to run the example app using the Firebase Emulator, how do I do that?

  • Install either Docker or Podman.
  • Follow the instructions in the README found in the tool/firebase_emulator directory to set up and start the emulator (this will also start the cloud functions in the emulator).
  • In a separate terminal, navigate to the example/template folder and run:
    flutter run -d chrome
    
  • In the app, select "Firebase" as the storage implementation.

How do I tag a new release?

git tag v0.1.9
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. As far as Cloud Functions go, the intent is to use them sparingly—only when absolutely necessary to provide access to parts of the system that are inaccessible to the client due to Firebase security rules. For example, when a site admin removes a member, a Cloud Function will securely add a "remove" event to that member's account stream (which the admin cannot access directly). Cloud Functions are 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?

Firebase rules, defined in firestore.rules and storage.rules, are designed to ensure member data privacy. 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 implementation strictly uses email addresses as keys in Firebase rules and site-member management. Any Firebase Auth options that reliably retain the user's email will work natively. For Apple sign-ins, since users can choose to anonymize their email via a relay, changes would need to be made to 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
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
firebase_paths
functions/base_hyttahub_functions
functions/hyttahub_functions_factory
functions/in_memory_hyttahub_functions
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.pb
proto/site_email.pbenum
proto/site_email.pbjson
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
routes/hyttahub_routes
service_blocs/cloud_functions_bloc
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