The Developer Finder application is a container based application that demonstrates how to make a web application with multiple technologies and containers.
This sample includes a web application that allows users to authenticate and register with their GitHub and LinkedIn accounts, import data into their user profiles from those systems, and supplement their profile with additional information. The web application also provides users the ability to search for developers based on the information in their profile, and even suggests friends based on common profile information.
In addition to the profile and search capabilities, the web application interacts with a custom chat system that allows users to engage in chat conversation on the web site.
The entire application is packaged inside Docker containers and deployed to Microsoft Azure. In addition to the container apps, Azure resources such as a MySQL database, Application Insights, and other Azure services are used to implement the application.
Table of contents
The following diagram illustrates the overall system architecture.

The main components of the application are described in subsequent sections in this document.
2 Docker images implement the system, each runs in its own container and they communicate via HTTP/HTTPS.
The following diagram illustrates the containers.

The back-end is a Python (3.6) App.
Uses the Flask microframework to implement the web app and routing.
Uses the Python Social Auth library to enable GitHub and LinkedIn accounts to login and returns user profile information from these systems.
The following paths are exposed for authentication:
| Path | Description |
|---|---|
| /login/<github|linkedin-oauth2> | Navigates users to GitHub/LinkedIn login page |
| /complete/<github|linkedin-oauth2>/ | Endpoint that handles OAuth callback |
| /logout | Logout current user |
Uses peewee for ORM access to the MySQL Database.
Exposes the following APIs:
| Action | Path | Description |
|---|---|---|
| GET | /api/me | Get current user's profile |
| POST | /api/me | Update current user's profile |
| GET | /api/connected-accounts | Get current user's connected accounts |
| GET | /api/friends | Get current user's friend |
| POST | /api/friends | Add a friend for current user |
| GET | /api/profiles | Get user profiles |
| GET | /api/profiles/ | Get a profile by id |
| GET | /api/profiles/suggested | Get suggested profiles (friends) for current user |
| POST | /api/sms | Send a SMS |
| GET | /api/messages | Get new messages sent to current user |
| POST | /api/messages | Send a message from current user |
| GET | /api/messages/summary | Get messages summary (unread count) |
The front-end is an AuglarJS App which provides the following pages:
| Page | Path | Description |
|---|---|---|
| Login | /login | Allows users to login with GitHub or LinkedIn account |
| Connect | /connect | Allows current user to connect to the other account |
| My Profile | /profile | Allows current user to view and edit his/her profile |
| Search | /search | Allows current user to search friends, add friend, and start a chat |
| Profile | /profile/ | Allows current user to view other devs' profile |
| Chat | /chat/ | Allows current user to chat with a dev or a friend |
The Nginx combines the back-end app and front-end app, and exposes them through the same port - 80.
It also works with uwsgi to serve the back-end Python app.
The Chat App is a very simple chat back-end application implemented with Ruby-on-Rails. It does not include an authorization/authentication module, and has no user interface.
The Ruby Chat app exposes the following APIs:
| Action | Path | Description |
|---|---|---|
| POST | /api/messages | Send a new message |
| GET | /api/messages/summary?to=<receiver_id> | Get message summary |
| GET | /api/messages/unread?from=<sender_id>&to=<receiver_id> | Get unread messages |
Azure Services are also used to implement the application. The following services are used.
The MySQL Database is used by the Web App. It contains the following tables.
| Table | Description |
|---|---|
| user | Stores user info, like username and email |
| usersocialauth | Stores users' connected social account info, like provider and uid It contains a foreign key column user_id referencing the primary key column of the user table |
| profile | Stores users' profiles |
| position | Stores users' positions It contains a foreign key column profile_id referencing the primary key column of the profile table. |
| friend | Stores friends relationship Its 2 columns, user_id and friend_id, are foreign keys referencing the primary key column of the user table |
Note: In a true production environment, the data in the usersocialauth table would most likely be stored in a separate database to make the solution more secure. In this sample, it is stored in the same database to simplify the solution and the deployment process.
The profile table contains several columns which are divided into 5 groups:
The PostgreSQL database is used by the Chat App. It is very simple and only contains 2 tables:
| Table | Description |
|---|---|
| messages | Stores all the messages |
| message_read_records | Records users' last read message id |
Throughout the application, custom events are logged to Application Insights.
The following table describes the custom events logged to Application Insights at a high level.
| Source | Triggers |
|---|---|
| Python Web App | Python REST API, Function, and Logic App Calls |
| Python REST API | Python REST API, Function, and Logic App Calls |
| Logic App | Start, Events Taking Place In Logic App, Complete |
This image shows custom events logged to Application Insights.

The following image shows the detail of a custom event. In this example, the /api/messages/summary Python REST API was successfully invoked.

Because this is a sample application that is designed for anyone in the world to deploy their own isolated instance, the databases in the application are created each time the ARM template deploys the solution. The web apps are tied directly to the databases that are deployed.
Since this is the case, if you Geo-Replicate the solution, each Geo-Location will have a separate copy of the databases. You are still able to demonstrate Geo-Replicating the app as part of the demo, but if you Geo-Replicate the solution then subsequently logged into an instance of the app in the US with one user, and logged into an instance of the App in China with another user, they would not be able to see each other in search results or chat because they are interacting with separate databases.
In a real production scenario, there would be a common database, or multiple databases with a database sync. This would provide the ability to use the Traffic Manager to load balance traffic across multiple Geo-Locations and achieve global scale with the solution. You can re-architect the solution to provide these capabilities.
The name of the application is 'Developer Finder'. We suggest you follow the naming convention below when creating your instance of the application:
developer-finder-[suffix]
The suffix is used to avoid Azure resource naming conflicts.
IMPORTANT NOTE: Only use lowercase letters (a-z), numbers (0-9), and hyphens (-). Uppercase letters will cause errors to occur.
Below are some examples:
In this document, we use the first example to show you how to deploy the solution to Azure. When you are finished with the deployment, you will be able to browse to the web application by navigating to this URL in a web browser:
https://developer-finder-[suffix].azurewebsites.net
Example that matches the example in this document:
https://developer-finder-contoso.azurewebsites.net
To start, you must register OAuth applications for GitHub and LinkedIn. These OAuth applications allow the application to authenticate to GitHub and LinkedIn and download user profile information stored in these systems.
Sign into GitHub.
Fill the form with the following information:
Application name: Developer Finder
Homepage URL: https://developer-finder-[suffix].azurewebsites.net
Note: Replace the [suffix] placeholder with the one you choose to use. Use this same value throughout the deployment process.
Example:
https://developer-finder-contoso.azurewebsites.net
Authorization callback URL:
https://developer-finder-[suffix].azurewebsites.net/complete/github/
Note: Replace the [suffix] placeholder with the one you choose to use. Use this same value throughout the deployment process.
Example:
https://developer-finder-contoso.azurewebsites.net/complete/github/
Click Register application.
Copy aside the ClientID and Client Secret.
Note: These values will be used for the OAuth GitHub Client Id and OAuth GitHub client Secret ARM template parameters.
Sign into LinkedIn.
Fill the form with the following information:
Name: Developer Finder
Application Logo: download and use the image below

Website URL: https://developer-finder-[suffix].azurewebsites.net
Note: Replace the [suffix] placeholder with the one you choose to use. Use this same value throughout the deployment process.
Example:
https://developer-finder-contoso.azurewebsites.net
Input the other required fields, then click Submit.
Add the OAuth 2 Authorized Redirect URL:
https://developer-finder-[suffix].azurewebsites.net/complete/linkedin-oauth2/
Note: Replace the [suffix] placeholder with the one you choose to use. Use this same value throughout the deployment process.
Example:
https://developer-finder-contoso.azurewebsites.net/complete/linkedin-oauth2/
Click Update.
Copy aside the ClientID and Client Secret.
Note: These values will be used for the OAuth LinkedIn Client Id and OAuth LinkedIn Client Secret ARM template parameters.
Generate Token:
Open https://github.com/settings/tokens in your web browser.
Sign into GitHub.
Fork this repository to your GitHub account.
Click Generate Token.
Enter a value in the Token description text box.
Select the following scopes (your selections should match the screenshot below):
repo -> repo:status, repo_deployment, public_repo
user -> read:user, user:emial, user:follow
Note: the user scope itself must be selected.

Add the GitHub Token to Azure in the Azure Resource Explorer:
Open https://resources.azure.com/providers/Microsoft.Web/sourcecontrols/GitHub in your web browser
Log in with your Azure account
Selected the correct Azure subscription
Select Read/Write mode
Click Edit
Paste the token into the token parameter

Click PUT
When a chat is started between two users in the application, the app will send an SMS to notify the user the message was sent to them.
This app uses a Twilio trial account to send SMS.
If you wish to enable the SMS capabilities in the application you must create a Twilio trial account and register and verify a phone number to send SMS.
Register a trial account
Create a project
After the human verification is complete, you will be redirected to a page to let you create a project.
Input a name, for example: Developer Finder, then click Create Project.
After the project is created, copy aside the ACCOUNT ID and AUTH TOKEN values.
Note: These 2 values will be used for the Twilio Account SID and Twilio Auth Token ARM template parameters.
Get a phone number:
In the Phone Numbers section, click Manage Numbers.
Twilio will redirect you to the Phone Numbers Dashboard.
Click Get Started.
Click Get you first Twilio phone number.
Note: Twilio will pre-select a phone number. Use the number it gives you.
Click Choose this number:

Copy aside the phone number.
Note: This phone number will be used for the Twilio From Phone Number ARM template parameter.
Click Verified Caller IDs on the Phone Numbers page:

Click the red ⊕:

Follow the instructions to verify the phone number.
In your web browser, navigate to your fork of this repository.
Click the Deploy to Azure button below:
Fill in the values in the deployment page:

Resource group:
We suggest you create a new resource group and name it DeveloperFinderRG.
Location:
Web Apps on Linux are currently (2017/08) only available in the following regions. So, you must choose one of the regions below:

Web App Name:
Use the name you chose at the start of these instructions that follows the developer-finder-[suffix] naming convention.
No-Linux Web App Location:
You MUST choose a different region for the non-Linux web apps, because they cannot be created in the same region and the same resource group.
OAuth Git Hub Client Id & Secret:
Use the client id and secret of the GitHub OAuth app.
OAuth LinkedIn Client Id & Secret:
Use the client id and secret of the LinkedIn OAuth app.
Database Admin Login Name:
It cannot be 'azure_superuser', 'admin', 'administrator', 'root', 'guest' or 'public'.
Database Admin Login Password:
This field should be between 8 and 128 characters long. Your password must contain characters from three of the following categories – English uppercase letters, English lowercase letters, numbers (0-9), and non-alphanumeric characters (!, $, #, %, etc.).
Ruby Chat Docker Image:
Please keep the default value: appsvc/demoapp-rubychat.
Twilio Account SID & Auth Token & From Phone Number.
Use the values you got from you Twilio account.
Source Code Repository URL:
Use the URL of the repository you just cloned.
Check I agree to the terms and conditions stated above.
Click Purchase.
Wait until the ARM template deployment process completes.
Get TrackCustomEvent function URL from the Function App.
Open the Function App in the Resource Group:

Expand the functions, then click TrackCustomEvent. Click Get function URL at the right.

Copy the URL on the popup.
Configure application settings of the Web App.
Open the Web App in the Resource Group:

Click Application settings

Find the TRACK_CUSTOM_EVENT_FUNCTION_URL setting, paste the function URL you just copied to its value inputbox.
Click Save.
Navigate to the resource group you just created and deployed, then click the developer-finder-[suffix] Web App:

Click Continuous Delivery, then click Configure:

Click Choose container registry, the pre-configured private registry will be loaded:

Click OK (the right one).
Click Configure continuous delivery:

Click OK (the right one).
Click Select a Team Service account:

Click OK (the right one).
Click OK.
Note: It takes a few minutes to finish:
Open the https://developer-finder-[suffix].azurewebsites.net web app.
Note:
Make sure you use https instead of http.
Make sure you replace the [suffix] placeholder with the value you have used throughout the deployment process.
Example: https://developer-finder-contoso.azurewebsites.net
You will see the login page:

Note: If you get a "502 Bad Gateway" error, please wait for a few minutes and try again.
See the Demo Script slide deck.
Follow the steps in Demo Script slide deck.
| Roles | Author(s) |
|---|---|
| Project Lead / Architect | Todd Baginski (Microsoft MVP, Canviz) @tbag |
| Architect / Developer Lead | Tyler Lu (Canviz) @TylerLu |
| Developer | Albert Xie (Canviz) |
| Developer | Hubert Sui (Canviz) |
| Design | Justin So (Canviz) |
| Testing | Cindy Yan (Canviz) |
| Sponsor / Support | Ahmed Elnaby (Microsoft) |
| Sponsor / Support | Stella Lin (Microsoft) |
| Version | Date | Comments |
|---|---|---|
| 1.0 | August 31, 2017 | Initial release |
THIS CODE IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
Content type
Image
Digest
Size
350.3 MB
Last updated
about 9 years ago
docker pull tylerlu/demoapp-base