{"id":13477051,"url":"https://github.com/anselm94/googlekeepclone","last_synced_at":"2025-03-27T04:32:11.938Z","repository":{"id":47793251,"uuid":"216822202","full_name":"anselm94/googlekeepclone","owner":"anselm94","description":"A clone of Google Keep with its original Material Design aesthetics","archived":false,"fork":false,"pushed_at":"2024-06-12T22:55:27.000Z","size":2989,"stargazers_count":558,"open_issues_count":5,"forks_count":126,"subscribers_count":14,"default_branch":"master","last_synced_at":"2024-10-30T09:35:55.072Z","etag":null,"topics":["golang","google","gqlgen","graphql","hooks","keep","material-design","material-ui","reactjs","urql"],"latest_commit_sha":null,"homepage":"https://googlekeep-anselm94.herokuapp.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anselm94.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-22T13:35:04.000Z","updated_at":"2024-10-28T12:17:13.000Z","dependencies_parsed_at":"2024-10-30T09:41:28.130Z","dependency_job_id":null,"html_url":"https://github.com/anselm94/googlekeepclone","commit_stats":{"total_commits":93,"total_committers":3,"mean_commits":31.0,"dds":"0.11827956989247312","last_synced_commit":"5be41ada8f06d71db3cc3d535b586d911604893b"},"previous_names":["anselm94/googlekeep-clone"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anselm94%2Fgooglekeepclone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anselm94%2Fgooglekeepclone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anselm94%2Fgooglekeepclone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anselm94%2Fgooglekeepclone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anselm94","download_url":"https://codeload.github.com/anselm94/googlekeepclone/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245785485,"owners_count":20671622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","google","gqlgen","graphql","hooks","keep","material-design","material-ui","reactjs","urql"],"created_at":"2024-07-31T16:01:37.688Z","updated_at":"2025-03-27T04:32:11.933Z","avatar_url":"https://github.com/anselm94.png","language":"JavaScript","readme":"# ![Logo](./docs/logo.ico) A Clone of Google Keep\n\nA minimal *Clone* of [Google Keep](https://keep.google.com) written in [ReactJS](https://reactjs.org/) with [Material UI Components](https://material-ui.com/), themed to look exactly like *Google Keep*, with complex features like sharing, archiving, reminders etc. shoved away. The backend is a [GraphQL](https://graphql.org/) server written in [Golang](https://golang.org/), with data persisted in [SQLite](https://sqlite.org) DB file, via [GORM](https://gorm.io). The server implementation is complete with *Cookie based Authentication*, implemented using [Authboss](https://github.com/volatiletech/authboss).\n\n![Docker Image CI](https://github.com/anselm94/googlekeepclone/workflows/Docker%20Image%20CI/badge.svg)\n\n\u003cdiv align=\"center\"\u003e\n\n![Light and Dark theme demo](./docs/dark-light-theme.gif)\n\u003cbr/\u003e*Light and Dark theme*\n\n\u003c/div\u003e\n\n## Features\n\n* 🔐 **Login** \u0026 🔏 **Register** for creating a new user\n\n* 🌈 **Colors**, 📐 **Sizes**, ❮❯ **Margins**, ❯❮ **Paddings** etc., matches exactly that of *Google Keep*'s Web App\n\n* 📲 **Responsive Design** - Adapts all screen sizes from mobile screens up to 4k displays\n\n* 🌚 **Dark Mode** - Dynamically change light/dark theme\n\n* 📝 **Notes** - Create, Update, *Copy*, Delete items on the fly. Dynamically change between these 2 modes\n\n  * 🗒 **Simple Notes** - Update/delete text in a simple text mode\n\n  * ☑️ **Todos with Checkboxes** - Mark items complete/incomplete using the checkbox\n\n* 🚥 **Colors** - Assign colors to Notes \u0026 adapts to dark/light theme\n\n* 📜 **Display Mode** - Notes can appear in the canvas in 2 different modes\n\n  * **List** - Displays notes as one item per row\n\n  * **Tile** - Displays notes as tiles, and spread across the canvas\n\n*  🏷 **Labels** - Label your notes, assign/unassign labels dynamically and filter notes by selecting labels in Sidebar\n\n* 🔗 **Subscriptions** - When notes are created/deleted in different browser tabs, the updates are pushed from server to client\n\n\u003cdiv align=\"center\"\u003e\n\n  [![Preview Button](./docs/preview-button.png)](https://googlekeep-anselm94.herokuapp.com/)\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n![Mobile demo](./docs/mobile-add-todo.gif)\n\u003cbr/\u003e*Toggling themes, adding notes and assigning color and label. Later marking it as complete*\n\n\u003c/div\u003e\n\n## Libraries Used\n\n#### Frontend\n\n* [ReactJS](https://reactjs.org) - See [`Web source`](./web/src)\n\n  - Complete frontend JS framework\n\n  - Follows [*React Hooks*](https://reactjs.org/docs/hooks-intro.html) pattern\n\n* [MaterialUI](http://material-ui.com/) - See [`Login.js`](web/src/components/Login.js)\n\n  - Follows the *new* [Material Design](https://material.io/) guidelines (known as *Material v2*)\n\n  - Completely themed to adapt Google's version for *Keep* - See [`theme.js`](./web/src/theme.js)\n\n  - Uses [Montserrat](https://fonts.google.com/specimen/Montserrat) font to match Google's Product Sans (*See [this Subreddit post](https://www.reddit.com/r/androiddev/comments/a6q5js/free_font_which_is_similar_to_google_product_sans/ebx6y2x?utm_source=share\u0026utm_medium=web2x)*) and [Roboto](https://fonts.google.com/specimen/Roboto) font - See [`fonts.js`](./web/src/assets/fonts.js)\n\n* [MaterialUI Icons](https://material-ui.com/components/material-icons/) - See [`AppBar.js`](./web/src/components/appbar/AppBar.js)\n\n  - Uses *Outlined* Icon design\n\n* [Reach Router](https://reach.tech/router) - See [`App.js`](./web/src/App.js)\n\n  - For client-side (browser) routing\n\n* [URQL](https://formidable.com/open-source/urql/) - See [`gql.js`](./web/src/gql.js)\n\n  - Complete [GraphQL](https://graphql.org/) client-side JS library\n\n  - Provides [React-hooks](https://formidable.com/open-source/urql/docs/basics/queries/) based implementations\n\n  - Has [*Subscriptions*](https://formidable.com/open-source/urql/docs/advanced/subscriptions/) (via *Websockets*) for dynamic updates from server (to create/delete notes with different tabs open)\n\n* [Axios - React Hooks](https://github.com/simoneb/axios-hooks) - See [`Login.js`](web/src/components/Login.js)\n\n  - *React-hook* based extension for [Axios](https://github.com/axios/axios)\n\n#### Backend\n\n* [Gorilla Mux](https://www.gorillatoolkit.org/pkg/mux) - See [`main.go#main()`](./cmd/server/main.go#L73)\n\n* [GORM](https://gorm.io/) - See [`models_gen.go`](./server/models_gen.go)\n\n* [gqlgen](https://gqlgen.com/) - See [`resolver.go`](./server/resolver.go)\n\n* [AuthBoss](https://github.com/volatiletech/authboss) - See [`main.go#setupAuthboss()`](./cmd/server/main.go#L94)\n\n#### Deployment\n\n* [Docker - Multistage build](https://docs.docker.com/develop/develop-images/multistage-build/) - See [`Dockerfile`](./Dockerfile)\n\n  - Builds a deployable Docker image in 3 stages\n\n    * *Stage 1* - Builds runtime binary for Golang server\n\n    * *Stage 2* - Builds Production-ready ReactJS artifacts\n\n    * *Stage 3* - Assembles the artifacts from *Stage 1* \u0026 *Stage 2*, and builds a container image\n\n* [Heroku - Container Deployment](https://devcenter.heroku.com/categories/deploying-with-docker) - See [`heroku.yml`](./heroku.yml)\n\n  - Builds and deploys the Docker image, with a `git push`\n\n## Design\n\n![Architecture](./docs/architecture.png)\n\nThis diagram explains the high-level architecture design of this project. This stack is a *Monolith*, with frontend-backend-database all packed into one single *container* deployment. Frontend is a *ReactJS* stack. \n\nThe **Frontend** is built with *ReactJS* using *Material UI React* components. The state management is through *React's Hooks for State, Context \u0026 Reducer* (see [`store.js`](web/src/store.js)). The main application is available at root `/`, which on load tries to load the noteitems. \n\nSince the user will not authenticated by this time, the *Router* navigates the user to `/login` where the user can enter `email` \u0026 `password` to login. To register for a new user, the user clicks on the 'Register' link to navigate to `/register` route. The user may enter any `name`, `email` (no email verification in place) and `password`. All Login \u0026 Registration HTTP calls are REST and are made via *Axios* React *Hooks* API.\n\nOnce logged in, a session cookie will be set in the browser. Now, the *GraphQL* API is available at `/query` and *URQL* client loads all the *Notes*, *Labels* \u0026 *User* information, in a single *query* (However, has to be optimised, as URQL's caching mechanism, makes involuntary calls, whenever any of the *mutation* happens). UI displays the items. User may create, update, delete *note* items, and may also create \u0026 assign/unassign labels to note items. The *labels* may be added, but update/delete hasn't be implemented now. User can sign out, by clicking the 'Profile' icon and then 'Sign Out' button.\n\nThe **Backend** is built with *Golang* and no server framework is used, except *Gorilla Mux*, which provides utils for *routing*. The router consists for 3 major routes:\n\n* `/` - handles UI resources\n\n* `/query` - handles GraphQL requests and will be delegated to *gqlgen* generated GraphQL handlers. Throws `NotAuthenticated` error, if user is unauthenticated. Also, understands user information, via session cookie.\n\n* `/auth` - handles all authentication related requests and will be delegated to *AuthBoss* framework. The `/auth/register`, `/auth/login` \u0026 `/auth/logout` routes handle Registration, Login \u0026 Logout respectively.\n\nThe DB is a *SQLite* DB and the persistence is a `file` based API. *GORM* allows quick and easy Database modelling. The database tables are generated as per the modelling defined as *Go Structs* (see [models_gen.go](./server/models_gen.go)). The database modelling is done as per this *ER Diagram*\n\n![ER Diagram](./docs/er-diagram.png)\n\nBoth *gqlgen* \u0026 *AuthBoss* has resolvers. *gqlgen*'s resolvers (see [`resolver.go`](./server/resolver.go)) helps in resolving Notes related data from database. While *AuthBoss*'s resolvers (see [`storer.go`](./server/storer.go)) help in resolving user related information.\n\nThe **Deployment** is through a muti-stage Docker build, which facilitates building Go binary and ReactJS artifacts in one single command. The *Docker image* generated is a *Monolith*, which can be deployed \u0026 run, without any other external setup.\n\n## How to Setup and Build\n\n### Method 1: Docker\n\n1) Clone the Git repository\n\n```sh\ngit clone https://github.com/anselm94/googlekeepclone.git\n```\n\n2) CD into the folder\n\n```sh\ncd googlekeepclone\n```\n\n3) Build a docker image containing all the web resources and server executable\n\n```sh\ndocker build -t anselm94/googlekeepclone .\n```\n\n4) Run the Docker image as a container\n\n```sh\ndocker run -p 8080:8080 -e PORT=8080 anselm94/googlekeepclone:latest\n```\n\n5) Open the URL in browser - https://localhost:8080\n\n### Method 2: Manual\n\n1) Clone the Git repository\n\n```sh\ngit clone https://github.com/anselm94/googlekeepclone.git\n```\n\n2) CD into the Web folder\n\n```sh\ncd googlekeepclone/web\n```\n\n3) Install Node dependencies (Install [NodeJS](https://nodejs.org/en/download/) in prior) and build the resources into `/build` folder\n\n```\nEXPORT REACT_APP_WEBSOCKET_ENDPOINT=ws://localhost:8080/query\nnpm install\nnpm run build\n```\n\n4) Run the Golang server (Install [golang](https://golang.org/dl/) in prior)\n\n```\ncd ..\nexport HOST=http://localhost\nexport PORT=3000\nexport STATIC_DIR=web/build\nexport DB_FILE=keepclone.db\nexport COOKIE_STORE_KEY=$(uuidgen | base64)\nexport SESSION_STORE_KEY=$(uuidgen | base64)\ngo run ./cmd/server/main.go\n```\n\n5) Open the URL in browser - \n  - Root - http://localhost:3000\n  - GraphQL Playground - http://localhost:3000/playground\n\n## Development\n\n1) Clone the Git repository\n\n```sh\ngit clone https://github.com/anselm94/googlekeepclone.git\n```\n\n2) Download and Install [Visual Studio Code](https://code.visualstudio.com/)\n\n3) Start the **Go server** in *Debug* mode. See [`launch.json`](./.vscode/launch.json)\n\n    * Go to 'Run' -\u003e 'Launch Go API server'\n\n4) Start the **React Dev Server** task. See [`tasks.json`](./.vscode/tasks.json)\n\n    * Press 'Ctrl + Shift + P' -\u003e 'Tasks: Run tasks' -\u003e Select 'Start React server'\n\n5) Launches https://localhost:3000 in the browser\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2020 Merbin J Anselm\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n```","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanselm94%2Fgooglekeepclone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanselm94%2Fgooglekeepclone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanselm94%2Fgooglekeepclone/lists"}