What we built
Right now, absolutely nobody needs an explanation of the psychological strain one undergoes when isolated from other humans. Whether we like it or not, we need each other. Inspired by the currently developing global phenomenon we have envisioned Fireside, an accessible anti-isolation tool made for connecting people, having fun and bringing excitement to these very trying times.
Our goal is to motivate people to start using their phones for talking again. We specifically considered the needs of our oldest generations, the people for whom this period of social distancing is especially difficult. Continue reading to find out how. Fireside matches strangers based on their common interests and sets up a call between them (we like to call this a Fireside Chat 😉).
The game is to find out what the participants have in common, if they get it right, we reward them with Sparks. The important aspect of this matching is that we do not disclose any information, our users are free to share what they feel comfortable with. Since all of this works with any regular old phone number, you don’t need to own a smartphone for Fireside, even a standard landline will suffice (you will need to be able to receive SMS messages though for our verification). We exclusively ask for information we need to set up the matches. But let us get back to users without a smartphone. How do they initiate calls? We’re glad you asked. In addition to being able to manually set up a Fireside Chat, we allow our users to set up scheduled calls. With this activated, our schedule-wizard 🧙♂ will automagically initiate calls in the selected time frame. Zero effort, works flawlessly.
And before you ask: While we can imagine that wonderful friendships are formed when using Fireside, it is not yet another dating app. We just want everyone to have some meaningful conversations again. Why not on Fireside? Give it a try 😊
Category Submission
COVID-19 Communications
Demo Link
Link to Code
https://github.com/patrickgoeler/fireside
As you can see on Github I did not build this alone but I had help from my friend Manuel.
How we built it
Frontend
We built the frontend with Vue which was entirely new for both of us. But I thought this would be great opportunity to learn something new, so we went with it. To make things pretty we used Vuetify.
The setup was quite easy with the Vue CLI. These were our settings.
To add Vuetify all we needed to do was run vue add vuetify
.
Since we were using Typescript already I also wanted a nice way to manage the Vuex state. After some research I came across Vuex-Module-Decorators. With a little bit of trial and error the state management was up and running. You can find out how we did it by taking a look at the code on Github.
Overall frontend development went smoothly and once we understood how to manage the state with Vuex the pace increased significantly.
To deploy the application we used Netlify. This was as simple as connecting the repo via Github, choosing frontend
as a subdirectory, npm run build
as the build command and dist
as the folder to be published.
To make things work properly with the Vue Router we also needed to add a _redirects
file to the public
folder.
/* /index.html 200
And that's it. Now on every push to the specified branch the app is built and deployed.
We included a few other cool things like update messages from the service worker that discards the cached version right away. But I'm afraid that's out of scope for this post.
Backend
For the database Mongodb seemed like a safe bet. Together with an Express + Typescript Backend we are able to interact with the Database, Twilio APIs and authenticate users with JWTs. To kickstart development we used this project because it provides great error handling and JWT authentication.
Next, I want to briefly go over how the matching and calling works in our app.
When a user signs up we store the city, interests and the job in the profile. When the user starts looking for a call we first check if a user with at least one field matching (city, interest or job) is in the FIFO queue.
If yes: we remove the found user from the queue, save a new conference object in the database containing info about the call and common interests and we dispatch two calls, one each, to a newly created conference room.
// search db for match
const foundMatch = await QueueRepo.findMatchingParticipant(incomingParticipant)
if (foundMatch) {
// connect with match
Logger.info("Match found, initiating...")
// Call being initiated, create conference in db to keep track
// for this route the incoming participant is never scheduled
await ConferenceRepo.create(
{ user: foundMatch, isScheduled: foundMatch.isScheduled },
{ user: incomingParticipant, isScheduled: false },
)
const conferenceXml = buildConference(
"Welcome to your fireside chat. Enjoy!",
Types.ObjectId().toHexString(),
)
const numbers = [incomingParticipant.phone, foundMatch.phone]
...
If no: put the user in the queue collection and wait to be found.
// put number in db and wait to be found
const alreadyExists = await QueueRepo.getEntryByPhone(incomingParticipant.phone)
if (alreadyExists) {
Logger.info("User is already in queue")
return new SuccessResponse("User is already in queue", { queue: true }).send(res)
}
Logger.info("Adding to queue")
// again for this route incoming is never scheduled
await QueueRepo.addToQueue(incomingParticipant, false)
return new SuccessResponse("No match found. Putting in db.", { queue: true }).send(res)
To achieve FIFO like functionality in the queue collection we simply order the collection by creation date ascendingly.
public static findMatchingParticipant(user: User): Promise<QueueUser> {
// order by date asc to have FIFO like queuing
// match either city, interests or job
return QueueModel.find({ phone: { $ne: user.phone } })
.sort({ date: "ascending" })
.findOneAndRemove({
$or: [{ city: user.city }, { interests: { $in: user.interests } }, { job: user.job }],
})
.exec()
}
Once both users accept the call we receive the "conference-started" webhook event and we can find the corresponding database object by looking at the phone numbers of the participants. For now we only add a "callStartedAt" to compute the correct duration later on.
When both participants hang up we receive the "conference-end" webhook event and we can delete the conference database object. In turn we create a permanent call object, one for each participant, so the call with all the info can be shown in the frontend.
const confUpdate = req.body as ConferenceUpdate
if (confUpdate.StatusCallbackEvent === "conference-start") {
Logger.info("Conference Started")
// update conference with a callStartedAt Date
const conference = await getConference(confUpdate.ConferenceSid)
const participants = await conference.participants().list()
await ConferenceRepo.updateStart(participants, confUpdate.ConferenceSid)
} else if (confUpdate.StatusCallbackEvent === "conference-end") {
// update call with length and status
Logger.info("Conference Ended")
const conference = await ConferenceRepo.removeConference(confUpdate.ConferenceSid)
await CallRepo.create(conference)
}
So it goes from (Queue) -> Conference -> Call. That way we can show the current status to the user.
The scheduling feature works by checking the submitted schedule settings of each user and if the time frame matches the current time we put the user in the queue. This is done with a Mongodb Stitch App that runs a function every 20 minutes. Users are also removed from the queue if the time passes their time frame of course.
We are also deploying the backend when pushing to master. Using Heroku we connected the repository, enabled automatic deploys and added a buildpack that lets Heroku change the working directory due to the monorepo style. After that all the environment variables need to be entered like the database credentials and the backend is up and running.
And that is pretty much it. You can take a look at the code on Github of course.
Additional Resources/Info
Towards the later stages of development it became clear to us that Firebase would probably have been a better choice for the database. I started to transition to firebase on a separate branch and it was pretty painless, so we will tackle that in the future.
Also it is entirely possible that our twilio account will run out of funds rather quickly. Therefore we ask you to responsibly use Fireside and to have a bit of patience should we need to replenish funds. If the service should be down, feel free to clone the project from Github and try it out yourself.
We hope you give it a shot and maybe it helps just a little bit with social isolation.
Top comments (0)