โ๏ธ Running Local Development Version
Most components of Frankly can be run on your local machine. This section describes how to setup and run the Flutter client app and the Firebase emulators (which can be setup in place of a Firebase/GCP project). The app still connects to several third-party services, which are also described below.
Tools and Flutter Setup
Important
Frankly runs on Flutter 3.22.2.
Please use this version of Flutter in order to avoid any unexpected errors.
This section covers setting up a new computer for Flutter development.
Part 1: Platform-specific
- Download and install Google Chrome here if itโs not already pre-installed. This is used for live debugging on web.
- Download and install XCode from the Mac App Store. This is used for developing iOS apps and running on macOS as a desktop app.
- Optional, but recommended: Install Homebrew here.
- Xcode should've installed git automatically, but if not for some reason, you can install it via Homebrew:
brew install git
- Clone the Frankly repo in a directory where you prefer your projects to live:
git clone https://github.com/berkmancenter/frankly && cd frankly
- Follow the instructions here to install Flutter on your machine. You can choose iOS as your target platform.
- This includes a link to install CocoaPods. However, you may run into issues with installing CocoaPods due to a Ruby version issue (the pre-installed Ruby on MacOS is too old). You can install ruby via Homebrew instead by running
brew install cocoapods
, which should alleviate those errors. - Recommended: Install the Flutter SDK in your home folder under a directory called
dev
(or something similar).
- This includes a link to install CocoaPods. However, you may run into issues with installing CocoaPods due to a Ruby version issue (the pre-installed Ruby on MacOS is too old). You can install ruby via Homebrew instead by running
- Install VSCode here.
- Recommended: Install the Flutter VSCode extension and use the extension to install Flutter via VSCode.
- Add Flutter to your PATH. For Mac with Zsh (you can also copy this command from here), create or open ~/.zshenv and add this line:
Restart terminal sessions to see the changes.
export PATH=$HOME/dev/flutter/bin:$PATH
- Download and install chromium and git if they're not already installed. Chromium is used for live debugging on web.
a. Set the path to chromium so flutter can find it:
sudo apt-get update && sudo apt-get upgrade && sudo apt-get install -y chromium git
export CHROME_EXECUTABLE=$(which chromium)
- Clone the Frankly repo in a directory where you prefer your projects to live:
git clone https://github.com/berkmancenter/frankly && cd frankly
- Follow the instructions here to install Flutter dependencies on your machine. You can choose web as your target platform.
-
Install VSCode here.
You may need to download the binary for your specific architecture here
- Recommended: Install the Flutter VSCode extension and use the extension to install Flutter via VSCode.
- Recommended: Install the Flutter SDK in your home folder under a directory called
dev
(or something similar).
-
You will probably need to add both flutter and dart to your PATH. Run:
export PATH="$PATH:$HOME/[path to flutter]/flutter/bin"
Part 2
- Install Node.js and npm. We strongly recommend that you do this via
nvm
(steps here) since it is the easiest end cleanest way to do so. - Once nvm is installed and sourced to your CLI profile, run:
nvm install --lts
-
Install the Firebase CLI Tools: Most of the operations for development and deployment take place via the Firebase CLI. You can find documentation for the Firebase CLI here.
npm install -g firebase-tools
-
You may run into permissions issues when installing this due to being a non-root user. To remedy this, reassign ownership of the relevant folders to yourself by running the following 2 commands before running
npm install
:sudo chown -R $USER /usr/local/bin/ && sudo chown -R $USER /usr/local/lib/node_modules
For more information, you can read this Stack Overflow post.
-
-
Activate the Firebase CLI for Flutter by following these steps.
a. Sign into Firebase using your Google account and create a new project. Use a name like "frankly-dev".
b. Log into Firebase. Run:
c. Install the FlutterFire CLI by running:firebase login
d. From your Flutter project directory (dart pub global activate flutterfire_cli
client
), run the to start the app configuration workflow:- You can choose web as the platform for now.flutterfire configure
Please check โTroubleshooting / FAQ for suggested resolutions to common Flutter installation errors.
Environment Setup
These are the steps for getting started with developing Frankly:
- ๐ฆ Build the data models
- ๐ฅ Setting up and connecting to the Firebase emulators
- ๐ Connecting to third-party services
- ๐ฆ Running the frontend Flutter app
The following section will cover these steps for running the app for the first time.
๐ฆ Data Models
The first step in running the app is to build the data_models package. Some code in this package is auto-generated by Freezed. Run the following steps in the data_models
directory to generate code and make the package available to the client and Firebase functions:
- To install all Dart dependencies run:
flutter pub get
- Run:
dart run build_runner build --delete-conflicting-outputs
You can also just run ./build.sh
.
๐ฅ Firebase
Firebase Functions Installation
Firebase Functions are built on top of Cloud Functions (GCP's serverless functions product), which is why there are references to Cloud Functions tooling below. Functions are written in dart
and are compiled to javascript
with dart2js
.
For the following sub-section, switch to the firebase/functions
directory to run all commands.
- To install all Javascript dependencies, run:
npm install
- To install all Dart dependencies, run:
flutter pub get
You don't need to run npm install
again unless you've added new dependencies or made updates to existing ones. Same applies to flutter pub get
, but for changes to any function dependencies.
Emulators
Firebase has a full suite of emulators called Firebase Local Emulator Suite. You can find the full description of the Firebase Local Emulator Suite and its capabilities here.
You should emulate services locally for development purposes, and set up the client to use these emulators instead of connecting to a live Firebase project. By default, the emulators will run against the default project "dev," specified in the .firebaserc
file.
Using config in emulators
You do not need to run functions:config:set.
as the emulators are configured by a file.
- To configure the emulators, create the file
firebase/functions/.runtimeconfig.json
. - A sample file containing the config properties described above can be found in
firebase/functions/.runtimeconfig.json.local.example
.
Running the emulators
Important
Do this before running the client.
To run the emulators locally, run the following while in the firebase/functions
directory:
dart run build_runner build --output=build
firebase emulators:start --only firestore,functions,auth,pubsub,database
You can also just run npm run emulators
.
We recommend using the emulators import and export functionality to make development easier.
Please refer to the Cloud Functions Emulator section at โTroubleshooting / FAQ for common issues and resolutions!
Optional: Setup Firebase Cloud Project
In order to allow the capability to run the app locally without needing to create/modify a live Firebase project, emulators for all Google Cloud services that are needed (Functions, Auth, Realtime Database, etc.) suffice for most development task.
If you plan on using Mux within your local app, however, the emulator version of the functions host is inadequate, since that service needs an actual deployed URL to send webhooks to. You will need a Firebase project of your own.
- Create a new Firebase project here .
- Make a note of the unique ID that is created for your project. It will be in the format of
my-dev-project-d2f8c
. - You may need to create a default realtime database.
-
From your command line within the
firebase/functions
directory, run:firebase login
Logging In
When the login window appears, ensure you are logging in as the same user that created your project.
-
Now run:
You should see a message likefirebase use <project_id>
Now using project my-dev-project-d2f8c
You can follow the official documentation to find out how to deploy, but you might use a command like this: firebase deploy --only functions
.
๐ Third Party Services
The Firebase Functions and/or Flutter client app connect to the following third party services, which must be set up and configured for local development.
Agora
Sign up for Agora and open the Agora console. The following instructions are geared towards using V2 of the Agora console.
The following instructions will guide you through retrieving the values to fill in the following command for setting Agora-related values in your Functions configuration:
agora.app_id="<YOUR_VALUE_HERE>"
agora.app_certificate="<YOUR_VALUE_HERE>"
agora.rest_key="<YOUR_VALUE_HERE>"
agora.rest_secret="<YOUR_VALUE_HERE>"
agora.storage_bucket_name="<YOUR_VALUE_HERE>"
agora.storage_access_key="<YOUR_VALUE_HERE>"
agora.storage_secret_key="<YOUR_VALUE_HERE>"
๐ง Setting up the integration
-
Agora Create a new project in the Agora console. For Authentication Mode, select Secure Mode: App ID + Token.
-
app_id
: Copy the App ID from the Projects list in the console home. app_certificate
: Select Configure on your project. Copy the value under Security > Primary Certificate.rest_key
: In the left navigation panel, select Restful API under either Developer Toolkit or Developer Resources, depending on your screen size. Click Add a Secret. Download the Customer Secret, and input the value for Key.-
rest_secret
: From the Customer Secret file, input the value for Secret. -
Google Cloud Storage Create a Google Cloud Storage bucket to store event recordings. Navigate to Google Cloud Storage and select Create a Bucket. Provide a bucket name. Then, configure the bucket with your desired settings for the remaining options.
storage_bucket_name
: Enter the bucket name you selected.storage_access_key
: Select Settings under the Cloud Storage left-side settings panel. Click on the Interopability tab. You may choose to either create an access key for a service account, or create a key for your user account. For whichever method you have opted to use, select Create a Key. Then, paste the generated Access key here.storage_secret_key
: From the generated key, paste the Secret.- In the codebase
In
client/lib/app/community/admin/conversations_tab.dart
, change the URIs in the_buildRecordingSection
method (replacing the ASML values appearing ahead of/us-central1/downloadRecording
) to reflect your staging and prod Firebase project IDs.
๐พ Testing the integration
Once you have the keys set up, you can follow the below checklist to test that key behaviors that depend on Agora are working successfully.
- Basic video functionality: Create a community, start an event, and join the event from two different browser windows with two different users. Verify that when video and audio are enabled, both parties can see and hear each other.
- Mobile size: Verify that video still works on mobile size.
- Adjusting AV settings: In the bottom navigation bar, adjust your microphone and video input. Verify that the change occurs successfully.
- Breakout rooms: Start breakout rooms. Verify that users are assigned to breakout rooms and video still works.
- Recording: Record the meeting by going into Settings and toggling the "Recording" option on before joining the event. After joining the meeting, verify that the top right corner says "Recording".
- Go to your Settings view, select Conversations, and select 'Download'. Verify that a .zip file should be downloaded with several different files, including audio and video.
- Bottom navigation: Interact with everything on the bottom navigation bar, including chat and emoji reactions. Verify that behavior works as expected.
- Show participant info: In the right side bar, click on a participant to show their user info. Verify that user details show as expected.
- Kicking a user: In a hosted meeting, kick a user. Verify that the host sees the user disappear, and the user should see that they are banned if they try to navigate back to the event.
Optional: Mux
๐ง Setting up the integration
Mux streaming is used when a customer wants to stream video from a third party streaming service, such as Zoom, to Frankly. Essentially the customer will record video from the third party platform, the data is sent to Mux, which will then notify Frankly's MuxWebhook Firebase function that a stream has started. Once the stream has started, the Frankly event page will display the streaming video.
-
Using Mux's instructions, get a new access token. Use the environment of your choice and set the permission level to "Mux Video".
-
Set up Mux secrets for your local development environment, either by running the firebase command line or copying and pasting the information.
As the names suggest, the mux.token_id corresponds to your Mux token ID and mux.secret corresponds to your Mux token secret.
firebase functions:config:set mux.secret="<YOUR_VALUE_HERE>" mux.token_id="<YOUR_VALUE_HERE>"
Or, paste your token and secret into the
.runtimeconfig.json
file where themux
field is."mux": { "secret": "...", "token_id": "..." },
-
To connect Mux to the MuxWebhooks cloud function, the function first needs to be deployed to your Google Cloud Project. Get the URL of the deployed function provided by Google Cloud, which should resemble this format: https://us-central1-myproject.cloudfunctions.net/MuxWebhooks.
- Login to Mux and go to Settings > Webhooks. Select the environment for which you want to use the webhook, then click โCreate new webhook.โ For the URL to Notify field, provide the URL for your deployed MuxWebhooks function. Then click "Create webhook."
๐พ Testing your setup
You can verify the integration is working by manually triggering a new call directly from Mux.
- Visit your Google Cloud Platform Logging page so you can scan for any errors and expected logs during the live stream test.
- In the Mux dashboard, go to Video > Live Streams. Click "Create your first live stream."
- Run the default request.
The following should be true if your Mux setup works as expected:
The logs displayed on the Logging page should indicate that the MuxWebhook Firebase function was called. You can filter the logs by function name in the Google Cloud Console to find logs associated to this function. When viewing the logs, you will likely observe the following error message: "Error: Unexpected number of documents matching livestream ID"
. This is due to the liveStreamId not matching an id associated to an existing LiveStreamInfo.kFieldMuxId value in the database. This is an expected error. For more thorough testing, we recommend the steps below.
(Recommended) You can also use the following steps to set up a live stream in Zoom and test your Mux integration end-to-end:
- Create a new event in Frankly and configure it for livestreaming using steps 1-2 in these instructions.
- Open Zoom and verify you have livestreaming enabled using these steps. Then follow these steps to setup your livestreaming event on Zoom. Use the following values:
- For Stream URL, use the Stream URL provided on the Frankly event page.
- For Stream Key, use the Stream Key provided on the Frankly event page.
- For โLive streaming page URL,โ use the page URL of the event setup page where you got the Streaming values above. The URL should look like this: https://gen-hls-bkc-7627.web.app/space/
/discuss/ ?status=joined - Visit your Google Cloud Platform Logging page so you can scan for any errors during the live stream test.
- When you are ready, start the live stream on Zoom using these steps
The following should be true if your Mux setup works as expected:
- The live streaming page on Frankly is now showing your streaming video from Zoom
- The logs displayed on the Logging page should not display any errors related to the MuxWebhook function. Be sure to query logs from the past 1 hour or longer. You can also use this query to include only Errors.
Cloudinary
- Sign up for Cloudinary.
-
Create two upload presets here, one for images and one for videos.
You can learn about upload presets here.
-
On the General panel, use this configuration for images:
- Name: "frankly-image-default" (or whatever you'd like) - Signing mode: Unsigned - Disallow public ID: โ๏ธ - Asset folder: empty - Generated public ID: Auto-generate - Generated display name: Use the last segment of the public ID
- Now, on the Transform panel, under "Incoming transformation", enter
c_crop,g_custom
and click Save.
These settings are required so that users are able to crop images. They also ensure that all images, cropped or not, are compressed before storage).
- Now, on the Transform panel, under "Incoming transformation", enter
-
On the General panel, use this configuration for videos:
- Name: "frankly-video-default" (or whatever you'd like) - Signing mode: Unsigned - Disallow public ID: โ๏ธ - Asset folder: "videos/uploads" (this value doesn't matter, just somewhere unique to store your videos) - Generated public ID: Auto-generate - Generated display name: Use the last segment of the public ID
- Click Save.
-
-
Now update the following in
client/.env
:Your
CLOUDINARY_CLOUD_NAME
is found here under "Product environment cloud name".
CLOUDINARY_IMAGE_PRESET=frankly-image-default (or name you used)
CLOUDINARY_VIDEO_PRESET=frankly-video-default
CLOUDINARY_DEFAULT_PRESET=frankly-video-default
CLOUDINARY_CLOUD_NAME=<value>
SendGrid
- Uses a Firestore extension. Emails definitions are written to the firestore collection sendgridemail.
- Configure the firestore extension "Trigger Email" firebase/firestore-send-email@0.1.9 with your sendgrid info
Stripe
Stripe is currently disabled for the platform. The following instructions will apply if you choose to enable Stripe:
- Set your Stripe secret key in functions config by replacing placeholder values in the following command:
firebase functions:config:set stripe.connected_account_webhook_key="<YOUR_CONNECTED_ACCOUNT_WEBHOOK_SECRET_KEY>" stripe.pub_key="<YOUR_STRIPE_PUBLISHABLE_KEY>" stripe.secret_key="<YOUR_STRIPE_SECRET_KEY>" stripe.webhook_key="<YOUR_WEBHOOK_SECRET_KEY>"
- Set up products for each type with a metadata field "plan_type" of individual, club, pro and prices for each one
๐ฆ Running and building the Client
โ But first, if using, have you setup and run the emulators?
Recommended instructions (debug configs)
In general, you can use the configs defined in .vscode/launch.json
to run debug mode. We have defined 2 environments for you:
- Client
- ๐ Client Dev (Emulators) - this connects to functions, firestore, database, and auth emulators
Note
The default debug platform is Web (Chrome), so please ensure it is selected as the target platform when running. We do not currently officially support any other platform.
.env File
You will need to create a .env file for client configuration. Copy client/.env.example.local
to client/.env
and update the missing secrets marked with <value>
accordingly. The VSCode profiles assume the .env file lives in the client
directory.
You can also add an EMULATORS
environment variable to override the default Emulators profile behavior of running firestore, auth, functions, database
. Set the value to any desired combination of emulators.
Manual instructions
If you want to use emulators, ensure you start the emulators first. Then run the following commands in the /client
directory.
To run the app with backend pointing at staging.
flutter run -d chrome --release --web-renderer html -t lib/main.dart --dart-define-from-file=.env
To run the app with locally running functions, firestore, and auth emulators
flutter run -d chrome --release --web-renderer html -t lib/dev_emulators_main.dart --dart-define-from-file=.env
Supported browsers
The client app runs only on the Flutter web platform. Flutter uses Chrome for debugging web apps, but it does support all major browsers in production Web FAQ | Flutter; Chrome, Firefox, Safari, Edge.
Testing
End-to-End Tests
See instructions here for developing and running end-to-end Playwright tests.
Flutter Unit Tests
The client/test
directory holds Flutter unit and widget tests.
To run existing tests, you can run the following command from the client/test
directory:
flutter pub run build_runner build
cd ../
flutter test --platform chrome
To run newly added tests:
flutter test <optional path to test files>
To run unit tests with locally generated HTML coverage report:
flutter test --coverage && format_coverage --in=coverage && genhtml coverage/lcov.info -o coverage/html