This full-stack example shows how to build an integration with GitHub that syncs data between GitHub issues and Miro app cards.
🚨 🚨 🚨 Only deprecated "Classic" GitHub projects work with this app. This means that you cannot connect this app to your own repo unless you have a deprecated "Classic" GitHub project. 🚨 🚨 🚨
This app is meant to show the basic concepts behind 2-way sync, but is in no way a working solution. This is intended for simple demo purposes to show a simple 2-way sync with free services like Netlify, Supabase, and Miro.
This app involves setting up different tools such as Netlify for deploying your app, Supabase for storing access tokens and GitHub for using GitHub actions to detech any changes in your projects. It takes 30-40 minutes to configure.
github-app-cards-demo.mov
- Included Features
- Tools and Technologies
- Prerequisites
- Associated Developer Tutorial
- Associated Video Tutorial
- Database Configuration
- Netlify Configuration
- Miro App Configuration
- Run the app locally
- Folder Structure
- Contributing
- License
- You have a Miro account.
- You're signed in to Miro.
- Your Miro account has a Developer team.
- Your development environment includes Node.js 14.13 or a later version.
- GitHub Account and access token.
- Supabase account and database.
- Netlify account.
To view a more in depth developer tutorial of this app (including code explanations) see the GitHub app cards 2-way sync tutorial on Miro's Developer documentation.
To view a more in depth developer tutorial in video format, you can watch the YouTube video below. This video explains how to build a 2-way data sync integrations with GitHub projects (classic) and Miro. It goes through demo videos, architecture diagrams, and code examples to teach you the fundamentals around building a 2-way data sync integration.
- Create a database in Supabase. First you may need to create an Org.
- Go into your dashboard and into your project and to the
table editor. - Click on
Create a new table - Name this table
authand add in the following columns, with the respectiveFormatas shown in the screenshot below. Note that capitalization is important for the table name. This table will hold access_tokens to be able to call the Miro REST API to sync changes which happen in the GitHub project. Disable Row Level security.
This is the schema for the auth table - make sure it is exactly the same to ensure this code works.
This is what the auth table should look like once it's been updated.
- Click on
Create a new tableand name this tablecard-mappingand add in the following columns, with the respectiveFormatas shown in the screenshot below. This table will hold the app card ID from Miro and the GitHub issue ID along with the MiroUserId.
This is the schema for the card-mapping table - make sure it is exactly the same to ensure this code works.
This is what the card-mapping table should look like once it's been updated.
- Click on
Edit columnfor themiroUserIdin thecard-mappingtable, and then add in the followingForeign Key Relationas shown in the screenshot below.
- Once you save the
Foreign Key RelationyourmiroUserIdfrom thecard-mappingtable should look something like the screenshot below. ClickSave. We need this to be able to associate the miroUserId with a access_token so we can invoke the Miro REST API.
The code in this repo contains three different functions which are meant to be serverless functions:
- netlify/functions/authorize.js
- netlify/functions/issues.js
- netlify/functions/project-cards.js
authorize.js is going to run when you share your app with someone and then go through the OAuth flow.
issues.js is going to run when you update the title or description of an issue. We have a GitHub action which will do this, defined in .github/workflows/issues.yml. You will need to update the GitHub Action URL to point to your deployed Netlify function. It should look something like https://miro-github.netlify.app/.netlify/functions/issues.
project-cards.js is going to run when you move a card to a different column i.e. if you move a card from To Do to Done. We have a GitHub action which will do this, defined in .github/workflows/project-cards.yml. You will need to update the GitHub Action URL to point to your deployed Netlify function. It should look something like https://miro-github.netlify.app/.netlify/functions/project-cards.
Now we will show you step by step how to set this up for free with Netlify. When you deploy your site with Netlify, it will
automatically generate those functions since Netlify is looking for serverless functions in the netlify/functions directory.
-
Go to your Netlify account and auth with your GitHub account.
-
Download the
github-appcardsrepo by going to developers.miro.com and then scrolling down toCreate apps using samples. Then find GitHub App Cards and click on theDownload source code as .zip. Unzip the files. Rename the project togithub-appcards.
-
Create a new GitHub repo, and push up your
github-appcardsproject which you just downloaded to it. You can use the following commands to do so:
cd github-appcards
git init
git add .
git commit -m "first commit"
git remote add origin https://github.com/<your-github-username>/<your-new-github-repo-which-will-hold-github-appcards-code>
git push -u origin main
-
At this point, you should have a personal repo which has the GitHub-appcards code in it. We will use this repo as a way to deploy this app with Netlify.
-
Go into Netlify, login, and from the
Team overviewsection, click onAdd new site->Import an existing project->Deploy with GitHuband then authenticate into GitHub and select this project which you just created which holds the GitHub app cards code. Select themainbranch andDeploy -
Once the deploy is complete, you app should be deployed to
<site-name>.netlify.app. For example, mine washttps://peaceful-fairy-c2e727.netlify.appas shown in the screenshot below. I will use thehttps://peaceful-fairy-c2e727.netlify.appas the example for how to connect your Miro app to the Netlify app but just understand that your URL will be different.
- Now, let's create a new Miro app on
developer.miro.com. - Once you've created the app, from the app setting page, click on
edit in Manifestand paste in the following:
appName: GitHub App Cards
sdkVersion: SDK_V2
sdkUri: https://peaceful-fairy-c2e727.netlify.app
boardPicker:
allowedDomains: []
redirectUris:
- https://peaceful-fairy-c2e727.netlify.app/.netlify/functions/authorize
redirectUriForSdk: https://peaceful-fairy-c2e727.netlify.app/.netlify/functions/authorize
scopes:
- boards:write
- boards:read
icons:
colored: ""
outline: "" Make sure to change sdkUri, redirectUris, and redirectUriForSdk with your site name.
- From the
Redirect URI for OAuth2.0section in app settings, click onOptionsand make sureUse this URI for SDK authorizationis checked, as shown in the screenshot below.
- Rename the
.sample.envfile at the base of thegithub-appcardsrepo to.envand fill in the values as detailed in the comments. Note, yourredirectUriForSdkon your app settings should be the same as theMIRO_REDIRECT_URIin your env variables. Below, I have used thepeaceful-fairyexample to show how you should fill in this env file. Note that you must use your own deployed app base name and then it should end in.netlify/functions/authorizefor theMIRO_REDIRECT_URI.
# Generate an access token in GitHub, and enter the value here.
# To generate the access token, go to https://github.com/settings/tokens
VITE_GH_ACCESS_TOKEN=
# In Supabase, you create a Postgres database, and you assign it a password.
# Enter the password of the created database in Supabase here.
# For more information, see:
# https://supabase.com/docs/guides/database/managing-passwords
VITE_SUPABASE_PASSWORD=
# Enter the URL of the Supabase database that the app uses for data persistence here.
# For more information, see:
# https://supabase.com/docs/guides/database
# Login to your account, then go down to Project Settings -> API -> URL.
# Your connection should look like `https://ahnvcdiskdadfgbljsdm.supabase.co
VITE_DATABASE_URL=
# Enter the API key of the Supabase project with the database that the app uses for data persistence here.
# For more information, see:
# Login to your account, then go down to Project Settings -> API -> Project API keys -> anon public.
VITE_DATABASE_PUBLIC_KEY=
# Enter the base URL of the hosting service your app runs on here.
# If you're developing locally, it can be 'localhost'.
# Netlify example: https://peaceful-fairy-c2e727.netlify.app/
VITE_BASE_URL=
# Enter the client secret of your app here.
# To retrieve the client secret, go to https://miro.com/app/settings/user-profile/
# Select 'Your apps', and then the app whose secret you want to retrieve.
# The app client secret is under 'App Credentials' > 'Client secret'.
MIRO_CLIENT_SECRET=
# Enter the OAuth code grant flow redirect URI for your app here.
# For more information, see:
# https://developers.miro.com/docs/getting-started-with-oauth
# Netlify example: https://peaceful-fairy-c2e727.netlify.app/.netlify/functions/authorize
MIRO_REDIRECT_URI=-
Once you have filled this in, go back to your Netlify deploys and click on
Site configuration-> then click onEnvironment variables->Add a variable->import from a .env fileand then just copy and paste the content and click onImport variables. -
Trigger a new deploy.
Make sure your URLs have https:// at the beginning, otherwise the OAuth flow will not work.
Also make sure that your MIRO_REDIRECT_URI ends in .netlify/functions/authorize.
- Lastly, you will need to change the URL in the GitHub action to point to your own deployed serverless functions. Point your GitHub action for
issuesto point to yourissuesendpoint from your serverless functions. The same should be done forproject-cards. Go to .github/workflows/issues.yml and change the URL on line 11. Go to .github/workflows/project-cards.yml and change the URL on line 13.
- Go back to your app home page, and under the
Share appsection, click onCopyand paste the URL in your browser. Install the app on a dev team.
⚠️ We recommend to install your app on a developer team while you are developing or testing apps.⚠️
- Go to your developer team, and open your boards.
- Click on the plus icon from the bottom section of your left sidebar. If you hover over it, it will say
More apps. - Search for your app
GitHub App Cardsor whatever you chose to name it. Click on your app to use it, as shown in the video below. In the video we search for a different app, but the process is the same regardless of the app.
search-for-app.mov
.
├── .github
├── netlify
├── src
│ └── assets
│ └── style.css <-- CSS styles for the app.
| └── components <-- Folder of all UI components used in the app.
| └── utils
│ └── github.ts <-- Utility functions for interacting with the GitHub API.
│ miro.ts <-- Utility functions for interacting with the Miro Web SDK and REST API.
│ supabase.ts <-- Main entry for interacting with Supabase.
│ └── app.tsx <-- The main entry. Contains structure for the sidebar when launched.
│ appcard-modal.tsx <-- The main entry for the modal that appears when an app card is expanded.
│ constants.ts <-- A collection of static variables used throughout the app.
│ index.ts <-- Initializes app, and contains logic for opening the app from the sidebar and expanding an app card.
│ modal.tsx <-- The main entry for the modal that appears when selecting a GitHub issue to import.
├── app.html <-- The app itself. This is loaded on the board inside 'app.tsx'.
├── appcard-modal.html <-- The app card modal itself. This is loaded on the board inside the 'appcard-modal.tsx'.
├── index.html <-- The app entry point. This is the value you assign to 'sdkUri' in the app manifest file.
└── modal.html <-- The modal itself. This is loaded on the board inside the 'modal.tsx'.
If you want to contribute to this example, or any other Miro Open Source project, please review Miro's contributing guide.





