GithubHelp home page GithubHelp logo

grarer / boop Goto Github PK

View Code? Open in Web Editor NEW
2.0 4.0 0.0 2.45 MB

Spontaneous Social Messaging

License: MIT License

JavaScript 4.87% TypeScript 63.24% HTML 25.42% SCSS 2.67% Shell 0.09% PLpgSQL 3.71%

boop's Introduction

Boop

Boop is an app that uses spontaneous push notifications to remind friends to chat with each other online. We developed this concept as a project for Georgia Tech's 2-semester Junior Design course. At the height of the COVID-19 pandemic, with most of our team taking classes remotely, we noticed that we missed those unplanned social interactions that happen when you cross paths with a friend at the dining hall or see someone you know while walking to class. Boop is designed to replicate the social benefits of these spontaneous moments by prompting users to reach out to their friends and start a conversation when they wouldn't otherwise.

We used an AWS free trial, so unfortunately we have had to close down the web-app after the end of the project. You can still view a video demo of the application or read our design document and UI screenshots.

Installation Guide for Developers and Contributors

You can clone or fork the Boop source code from https://github.com/GRarer/boop/

Dependency Installation

This project uses NPM as a package manger, and is divided into three Node packages: one for the NodeJS-based backend, one for the Angular-based frontend, and a "core" package that is a decency for both the front-end and back-end. Navigate to the /core, /backend, and /frontend directories and run npm ci in each to install the dependencies.

You will also need to install PostgreSQL version 12 or 13, which provides the SQL relational database system used by the backend. You may need to add the Postgres psql command-line program to your path environment variable to be able to run the database initialization script.

How to Run Boop Locally

Initializing the database

init.sql contains the sql script that sets up the database tables. To set up or reset the database, you can run this script from psql in your terminal. Note that re-initializing your local copy of the database completely resets it.

On Windows, the default Postgres superuse is called postgres. On Unix platforms, it may be your system username.

$ psql -U <your Postgres username>
<enter your Postgres user password>
\i init.sql

init.sql is located in the top directory of this project. You can also find the initialize_examples.sql script; run this after init.sql to set up testing example accounts.

Building The Core Package

The core package contains type definitions and utilities that are common to both the frontend and backend. It is a dependency for the backend and frontend, so you'll need to build the latest version of core before building the frontend or backend. Navigate to the core directory and run npm run build.

Running a Local Instance of the Boop Backend

Before you run your local version of Boop, you will need to configure the environment variables for your backend.

Generating VAPID keys

Boop uses the web push protocol to send notifications, which requires a VAPID key pair. You can generate a new key pair for your instance of the Boop server by running npx web-push generate-vapid-keys.

Backend environment variables

The Boop backend uses dotenv so that you can configure the backend environment variables by creating a file called /backend/.env. The environment variables used by Boop are:

  • BOOP_VAPID_PUBLIC_KEY public half of a VAPID key pair for web push notifications
  • BOOP_VAPID_PRIVATE_KEY private half of a VAPID key pair for web push notifications
  • PORT port for Express server. Defaults to 3000.
  • PGUSER username to use to connect to Postgres. Defaults to 'postgres'.
  • PGPASSWORD password to use to connect to Postgres.
  • PGHOST host url of Postgres server. Defaults to 'localhost'.

Backend server command line options:

  • --pg-password <your Postgres password> password to use to connect to Postgres. Overrides "PGPASSWORD" environment variable.
  • --pg-user <your Postgres username> username to use to connect to Postgres. Overrides "PGUSER" environment variable.
  • --frequent-push speeds up the frequency of push notifications to several per minute instead of once every few hours, for testing the push notification system

Running the Angular Frontend Locally

First navigate your terminal to the frontend directory. Run npx ng serve for a dev server. Navigate to localhost:4200/. The app will automatically reload if you change any of the source files.

However, the ng serve dev server does not support service workers; this means that push notifications and other PWA features are unavailable in this mode.

Running the Angular Frontend Locally with Service Workers Enabled

To build a version with service workers included and run it with a local http server, use npm run start-pwa and navigate to localhost:8080/. Note that this server will not automatically recompile and reload when you make changes.

The service worker caches the application to improve load times, but this means that when you first open localhost:8080/ after recompiling, the browser will show an old version of the application that has been cached. The service worker waits up to 30 seconds before checking for a new version, so to see your most recent changes you will need to open the page, wait 30 seconds, and then refresh.

Style Checking

Navigate to either the frontend, backend, or core directory and run npm run lint to run the eslint style checker on that package. Some formatting issues can be automatically fixed with npm run lint -- --fix. In addition to ensuring consistent formatting, the linter will warn about code that may lead to errors or unintentional behavior, such as misused promises. You can also use the lint.sh shell script to run linters on all three modules.

GitHub actions is also configured to automatically run linting on all pull requests and block changes that would cause linter warnings or errors.

You may want use the .editorconfig file to ensure that your editor or IDE uses 2-space indentation, removes trailing whitespace, etc. For Visual Studio Code, this requires installing a plugin.

Strict Types

Be aware that this project uses TypeScript in --strict mode. This disallows implicit any, enforces strict null checking to prevent null-pointer bugs, etc. See the typescript compiler options documentation for details.

Installation Guide for Deploying Boop to Production

We deployed the Boop prototype at https://boopboop.app using GitHub pages and AWS. If you want to deploy your own instance of Boop, you will first want to make a few changes to the code.

  • update the FAQ, Terms of Service, and Privacy Policy to refer to your organization and your Boop instance's URL.
  • update the backend base url in /frontend/environment.prod.ts to point to your instance's backend server.
  • update the URLs of icons that are used in notification metadat
  • generate a new VAPID key-pair and make sure that your VAPID private key is kept secret
  • if you are not planning to use GitHub Actions to deploy your front-end to GitHub Pages, remove deploy_site.yaml from .github/workflows

Hosting the Production Frontend

To build the production frontend, navigate to /frontend and run npm run build-prod. This will build the front-end with service workers enabled and with Angular ahead-of-time compilation optimizations. The production frontend will be set to send its API requests to the production backend URL defined in /frontend/environment.prod.ts rather than trying to access the server on localhost.

The compiled frontend will be output to /frontend/dist. We serve our frontend with GitHub pages, but you can use any static-site hosting option. We use GitHub actions to automatically redeploy the static site when PRs are merged into the main branch.

Hosting the Production Backend

We host our production Postgres database on Amazon RDS, but you can use any Postgres hosting option or host the database on your own servers. You simply need to configure the environment variables of your production backend with the username, password, and host URL needed to access your database.

You can host your production backend server on any device that can run NodeJS. We use an Amazon Ec2 instance, with Nginx as the reverse proxy to allow incoming internet traffic. We recommend purchasing a domain, with te apex domain and www subdomain pointing to your frontend's static site host and the api subdomain pointing to your backend server's reverse proxy.

To make sure that the NodeJS server restarts if anything goes wrong, you can use either systemd or the "forever" npm package to keep it running continuously.

Troubleshooting and Potential Issues For Deployment

If you use GitHub pages as your static site host, GitHub will only automatically generate an SSL certificate for the main domain that you use (e.g. boopboop.app) and not any additional subdomains (e.g. www.boopboop.app). If you use a TLD like .app that disallows HTTP, then users will not be able to connect through the additional subdomains. We solved this by switching out GitHub pages site to use the www subdomain long enough for the SSL certificate to be generated and then switching back, but this would require repeating this workaround every few months to prevent the certificate from expiring, so we do not recommend using GitHub pages as the host for a long-term production deployment.

If you try to compile your backend on the same machine that you serve the backend from (e.g. an AWS EC2 instance), you may find that needed dependencies are not installed to node_modules even when running npm ci or npm install. This is most likely caused by the $NODE_ENV environment variable being set to production, which causes npm to skip installing dev dependencies, including the TypeScript compiler. You should unset the $NODE_ENV on machines that you use for compilation.

Release Notes

The Boop web-app uses continuous integration. This changelog shows major milestones, but some of these milestones correspond to several smaller changes deployed over multiple days.

We set a code-freeze deadline for ourselves to have the development of Boop finished by the end of March. We met this goal and completed all of the features planned in our original design, as well as several smaller additions and stretch goals such as friend request notifications and data portability.

2020-03-30

Final Boop release before end-of-semester code-freeze

Features:

  • users can now export their data to JSON, in compliance with GDPR data portability requirements
  • adds a dialog warning when users access Boop from a browser or device that does not support web push notifications
  • improves privacy policy with a guarantee to never sell user data
  • adds ARIA labels to images and buttons that did not already have descriptive text
  • minor UI improvements
  • adds Instagram, Google Hangouts, and Skype to chat platforms drop-down
  • adds more formats of reminder notification messages

Bugfixes:

  • improved detection of platforms that do not support web push notifications (e.g. Safari)

2020-03-24

This release makes several user interface improvements inspired by user feedback:

  • adds a "home" icon to the top of the page as a more intuitive way to navigate out of menus (issue #100)
  • show outgoing friend requests on the friends page, and allow users to cancel friend requests after they have sent them (resolves #102)
  • improve responsiveness and efficiency of friends page
  • add FAQ dialog to landing page (issue #66 and issue #67)
  • remove extraneous front-end logging
  • update terms of service and privacy policy

2021-03-22

Features:

  • overhauls registration and onboarding with a new, easier-to-navigate registration page
  • adds icon and badge to push notifications
  • increases notification cooldown time and decreases notification frequency based on user feedback

Bugfixes:

  • prevents notifications disappearing without opening the app if the user clicks on the notification body rather than the action buttons (issue #96)

2021-03-18

This release makes several improvements to notifications

Features:

  • the notifications when someone sends you a friend request or accepts your friend request now show their name in the notification message

Bugfixes:

  • fixes a bug where users who had do-not-disturb mode enabled or had already recieved a reminder notification in the last 4 hours still had a change to be sent a reminder notification (issue #88)
  • fixes "you are friends with this user" and "you sent a friend request to this user" text being invisible on the profile page because of a bug in Angular SCSS minification (issue #81)
  • fixes the Boop icon being cropped incorrectly when installed as a PWA on Android (issue #85)

2021-03-16

First production deployment of the Boop application. Features supported at launch include:

  • registration, login, and collection of contact information
  • friends list and friend requests
  • user profiles, status messages, and privacy options
  • spontaneous push notifications

boop's People

Contributors

grarer avatar porterehunley avatar juancaicedo119 avatar mandra-thomas avatar

Stargazers

Andrew Chafos avatar  avatar

Watchers

Sanjana Jampana avatar  avatar  avatar  avatar

boop's Issues

landing page design improvements

we should improve the landing page to attract users. the current placeholder text at the top of the landing page is not very good at explaining what boop is and why you should use it. we should also consider making more extensive visual changes to the landing page to make it look more appealing.

Require confirmation when unfriending

Currently, the friends list page has a single button on each card that immediately unfriends the person. This isn't ideal, since if a user accidentally unfriends someone they have to redo the whole friend-request process. It would be better if clicking unfriend opened a dialog that would prompt the user to confirm or cancel the unfriending.

terms and conditions and privacy policy

as follow-up to #14, we need to write out a user agreement and privacy policy and add them to the app. these should also be available from somewhere else in the app after registration, probably a card at the bottom of the settings page.

stay logged in between sessions

currently, when the user closes or refreshes the page, their session token is lost and they are no longer logged in. this also would result in problematic behavior if a user linked to or bookmarked a page other than the landing page.

we should implement a way to restore the user's session when they reopen the app. one option is to store the session token in local storage, allowing the session service to retrieve and use the session when the app starts up. one downside of this would be that the backend would have to remember all active sessions, potentially indefinitely, and those sessions would be lost when the backend restarts. another option would be to store the user's username and password in local storage and have the session service create a new session using those credentials when the app restarts, but I'm not sure whether or not that would be a security risk that could allow other programs on the user's computer to read their plaintext password.

a third possible solution would be to store session tokens in local storage, and to persist session tokens in the database rather than in the server' memory. this might negatively impact server performance by adding an additional database read every time we authenticate a request, but we could reduce this problem by still having an in-memory cache of recently-used sessions and only going to the database when given a session token that is not in memory.

Terms, Privacy Policy, and Legal Compliance

Currently the "user agreement" and "privacy policy" dialogs in the registration process are placeholder text. We need to figure out what these terms should say, and what information we need to provide to be compliant with GDPR and similar data privacy laws. Relatedly, are there other features that we would need to have because of privacy laws, such as a right to be forgotten?

Account Settings

Users should be able to change any of their account data (except for the permanent UUID, which is not visible to users). Probably there should be one UI and associated backend endpoint for changing username, one for changing password, and one for changing all other registration information (email, name, gender, birthday, etc).

notification cooldown appears to not be enforced

Now that we've deployed the service and I've been using on my phone for about a day, I've noticed that I seem to be getting Boop reminders more than once in a 4-hour period, which isn't supposed to happen.

Contact Methods

Users should provide 1 or more forms of contact: phone numbers or usernames for social messaging platforms like Discord, WhatsApp, Messenger, etc. They should be prompted to add at least 1 method when they sign up, and they should be able to edit, remove, or add methods later.

One thing we need to figure out is what format to use for this information. Should we have a list of supported chat platforms, or allow users to enter whatever they want? How do we support users listing two usernames for the same platform?

add more notification message templates

when we send notifications, we randomly choose from a list of templates that we fill out with the friend's name and pronouns. adding more of them would increase variety and could make our app be perceived as more lively and friendly.

frontend webpack and closure compilation

before we deploy our frontend to the web, we should try using the closure compiler and webpack to create a smaller and faster version for the frontend that can be deployed more efficiently

account data export

for compliance with internet regulations, we need to make it possible to download a human-readable and machine-readable exported version of their user data. For us this means their account info, friends, status, and profile (although profiles are not yet implemented). This should probably be a human-readable json file like

{
    "username": "alice",
    "fullName": "Alice Exampleton",
    "friendlyName": "Alice",
    "gender": "Female",
    "email": "[email protected]",
    "birthDate": "1995-03-05",
    "friends": [
        {
            "username": "bob",
            "fullName": "Robert Defacto",
            "friendlyName": "Bob"
        },
        {
            "username": "charlie",
            "fullName": "Charlie McExampleface",
            "friendlyName": "Charlie"
        }
    ],
    "statusMessage": null,
    "doNotDisturb": false
}

This should not include user UUIDs, since those are an internal representation specific to boop. Users' friends should be identified by their names and usernames, not their UUIDs.

The json-beautify package looks like a good choice for rendering the object into JSON that has whitespace for human-readability, rather than JSON.stringify() which puts everything on one line and is not very human readable.

Friends and Friend Requests

We need a system for users to tell us who their friends are.

  1. User A enters a username to send "friend request" to user B. This should fail and show an error message (via snackbar popup) if that username does not exist or if the users are already friends or if there is already a pending friend request.
  2. When User B visits the home page, they see that they have one or more pending friend requests. They can visit a page where they can choose to either accept or reject that friend request. If they reject it, the friend request is removed from the database.
  3. If User B accepts the friend request, then the two users are now friends.
  4. Either User A or User B is able to go to their "friends list" page and see that they are now friends.
    5 The friends list page also allows a user to unfriend one of their friends.

One thing we need to figure out is how to represent friendships in the database. If it's one table with two columns for user_uuid's, then how do we decide which person goes in which column?

account deletion

we should add a button in the settings to close an account. this should delete the user from the users table and remove any rows that reference that user's UUID. The tables defined in inti.sql already set on delete cascade for all columns that reference the user uuid, so it should be sufficient to delete the row from the user table.

on the front-end, there should be a dialog that pops up prompting the user to confirm or cancel deletion and informing them that this is an irreversible action before the deletion request is sent.

hide VAPID private key

currently our VAPID keys are committed to the codebase, which is problematic because anyone who has our VAPID private key could send notifications to our users and impersonate Boop. we need to generate a new pair of keys and create a way for the private key to be kept secret.

remove platform links and instead just copy contact IDs

Instead of having different behavior for different platforms, we determined that it would be better simplify the chat page so that clicking on a contact card always just copies that contact ID to the clipboard. this will also allow us to remove the homepage link/profile link template system from platforms.ts.

improve onboarding navigation

the onboarding flow seems to confuse users; they sometimes want to go back to a previous step, but using the browser/os back button/gesture instead takes them back to the landing page. We should either use a stepper control or refactor to support the back button (or both).

add icon to notifications

now that our frontend is deployed, we can add an icon to our web push notifications rather than letting it default to the browser icon. we would host the icon image on our github pages as a front-end asset, and link to it from the notification metadata

relationship indicators not shown on profile page

when logged in and viewing another person's profile, there should be text saying "you are friends with this user" or "you sent a friend request to this user" if one of those is true. in production, the html element that should have this text is generated, but for some reason this isn't visible. i'm not sure what the root cause is and i haven't yet reproduced this on a local front-end.

Custom Friend Notifications

Upon a "Friend request" and a "Friend accepted request" notifications, users should be aware of who is sending/accepting friend requests. "Who" will take the form of the username in this context.

incorporate contact methods and friends into registration process

we should modify the registration process to encourage users to enter their contact methods and send friend requests after they create their account. this might require us to either modify or modularize the friends and contact methods pages so that they can be presented differently in the registration flow.

FAQ Information

Our original iteration plan mentions "FAQ information" that we would add to help explain the app to users. Our clients recommended that we could deprioritize this to work on more important features since an FAQ or tutorial is not necessary for MVP, so we could just remove it in our sprint 4 iteration plan revision. However, given how far ahead of schedule we are, we probably have time to include something to meet this requirement.

Resolve offline behavior to avoid losing PWA support in upcoming Chrome

Chrome shows this warning in the browser console:

Site cannot be installed: Page does not work offline. Starting in Chrome 93, the installability criteria is changing, and this site will not be installable. See https://goo.gle/improved-pwa-offline-detection for more information.

Chrome 93 doesn't release until this fall, so it doesn't really affect this as a class project, but it's a good idea to resolve this if it wouldn't be too much effort.

improve backend logging

now that we deploy the backend to AWS, we'll want a logging system other than writing to the console. we should also remove or reduce logging that is not necessary or was left in from debugging earlier features.

Deployment to public web server

By the end of the project, we must deploy the application so that anyone can use it. Since our architecture uses separate servers for the frontend and the backend, we can use separate hosting solutions for each.

GitHub Pages should provide adequate hosting bandwidth for our prototype's Angular frontend. As of sprint 2, the build output without minification is around 11mb; GitHub pages is limited at a total page size of 1GB and a bandwidth cap of 100GB/month. Note also that using service workers means that the client does not have to redownload the app every time they visit. If we purchase a custom domain, it will be easy to connect that domain to the GitHub Pages site.

For the backend and database, Heroku seems like a good choice. The "hobbyist" tier dyno supports SSL and gives us an always-on 512mb VM (memory footprint of Node when running the current version of our backend is around 15-20mb). Heroku supports both Node and Postgres. However, the free tier of the Heroku Postgres addon is very limited, allowing at most 1GB of storage and 10,000 database rows, so before the demo we would probably want to upgrade to the $9/month tier (10GB and 10,000,00 database rows).

Of course, we could also choose to host the backend on our own hardware, e.g. a raspberry pi or spare computer converted into a web server. this would be cheaper (assuming we can find adequate hardware), but we would loose the benefits of continuous integration and the coolness of being able to say that we use cloud computing.

aws setup

AWS might be much easier to set up that running our own hardware, and it should be easy to test. we can deploy a version of our app to AWS and test the connection by sending http requests manually from a REST client. if this works it could save us a lot of configuration effort of hosting it ourselves.

Visually indicate when "confirm password" doesn't match while typing

The current behavior of the "confirm password" box on the landing page can confuse users. The box is supposed to change color if the passwords don't match, but it only checks and updates when focus shifts to another control. If the user fills that box out wrong, the register button is disabled but the user doesn't see an indication of why. We should updated the validity of the confirm password input after every keypress.

start chat screen

the screen where the user will be taken when clicking on a push notification should show their friend's name and list of contact methods for contacting them. there are two major design decisions we need to address:

  • is it feasible to have clickable links for some common chat platforms? If so, will it look okay to merge clickable and nonclickable contact cards, since we certainly can't have clickable links for every chat platform?
  • do we need to keep people's contact methods private so that only their friends can see them? authenticating this permission would be difficult since we can't guarantee that the user will be signed in when they get the notification, and it would probably require us to transmit extra information in the notification body.

ui for gravatar

if we use gravatar for profile photos, then users will be able to edit their avatars using the gravatar website, so we won't need to create our own UI for uploading profile images. we will still need to direct users to the gravatar website and show them what image is currently being used for them. we should do this on both the onboarding process and the settings page

remove /test page and related functionality

Early in the prototyping stage, I created the "api tests" page on the frontend, and associated backend endpoints and tables, so we would have an example of how to send http requests, connect to a database, and use web-push notifications. Since we now have actual application code for all of these things, we can safely remove the examples. Simply removing the api tests page will leave a lot of other dead code, and in the process of cleaning up unused functions we might also want to refactor or move some code.

boop logo

We need a custom vector-graphics logo for Boop, to be used in our title bar (see #26), in our favicon, and in our push notifications.

status toggle

users should be able to temporarily opt out of notifications (and prevent other people from getting notifications about them) by toggling their availability status. in addition to affecting the notification-scheduling algorithm, a user's status should be clearly indicated on the home page.

we have also discussed allowing users to set a custom status message, as in some social platforms like Discord, although this is a stretch goal and is not required for MVP.

user profiles

user profiles will show a user's contact methods, friends list, and a user-written bio description. which information will be shown and who can view a bio will be restricted by privacy settings, and we will need to show a message when a user tries to view a bio that they dont have permission for.

we will also need to have a way for users to edit their bio message, and the profile editing page should also link to the settings page where users can adjust their privacy settings or change their profile image

Notification Demonstration

We should demonstrate the ability to send push notifications to specific users, even before we have built the friends system and the push scheduling system. Once we have users' VAPID tokens, we can create an admin command for sending a push to a specific user.

We will also want a page that will be shown when the user clicks on the notification. The push payload will need to include a new session token so that the push still works even if the app was not open or the user was not logged in when they clicked it.

set up backend server

if we host our backend on our own hardware, we will need to install and configure the machine that will act as the server. this may also require setting up dynamic dns and configuring router settings to allow the outside internet to connect to the server.

spontaneous push notifications algorithm planning

the backend will need to decide when to send notifications to which pairs of friends or friends-of-friends. so far this has been a black box in our design, but we need to figure out exactly how it should work before we can implement the core feature of our product.

use a different backend url when the frontend is built in production mode

in order to deploy the backend to a server, the frontend needs to be able to substitute in a non-localhost url when it is built in production mode. for most of our endpoints this could be handled by the API service, but there are also endpoints that the session service accesses without the api service

privacy settings

there are three privacy settings that we should give to users during the registration process and allow them to change from the settings page

  • whether to show age on profile
  • whether to show gender on profile
  • profile visibility level

visibility levels are "public" (visible to anyone) "private" (visible to friends and friends of friends) and "restricted" (visible to friends only). we will need to make it clear to users that if they are restricted they will not be matched with friends-of-friends. we also need to modify the notification scheduling query to exclude those users from friends-of-friends pairings

stop storing UUIDs in local storage and session service

As a holdover from when we first prototyped the authentication system, the LoginResponse object returned from the back-end contains both the session token and the user uuid, and both are stored in local storage by the SessionService. Currently the front-end doesn't actually use this stored uuid for anything. The only state the front-end needs to have is the session token, which can be used to fetch up-to-date versions of any other information (including the current user's uuid if it is never needed, which it shouldn't be) from the backend as needed. Since we don't need and shouldn't use a cached copy of the uuid, we should probably stop storing it.

push notification implementation

once we have designed out push-scheduling algorithm (see #30), it has to be implemented into the backend's job loop so that the backend will send web-push notifications. these notifications should link to the "start chat" screen when clicked (see #29).

for testing purposes, we will want the ability to adjust the rate of push notifications so that they occur much more frequently in testing than in production. one way of doing this would be with admin commands, but a config file might be easier.

display avatars on contacts page and start chat page

We can show "gravatar" profile images on the contacts page and the start chat page. This will require modifying the backend to send the user's gravatar URL, which is derived from the hash of their username. To accomodate users who have not set gravatars, we can use a query parameter telling gravatar to default to "identicons". Adding the gravatar package to the backend's dependencies might help with generating those URLs.

Notification Sign-Up

Once the user registers, they should be prompted to allow notifications, and the resulting tokens need to be sent to the backend so that it can send notifications.

Relevant concerns:

  • allowing users to skip notifications
  • allowing users to get notifications on more than one device/browser
  • handling the case where notifications are not available on the current platform
  • handling the case where the user denies notifications permission
  • allowing users to subscribe their current device if it is not already.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.