{"id":22514667,"url":"https://github.com/jdizm/node-express-firebase-mongodb","last_synced_at":"2026-04-13T04:06:11.317Z","repository":{"id":193933842,"uuid":"689450851","full_name":"JDIZM/node-express-firebase-mongodb","owner":"JDIZM","description":"A starter template for a backend API with Node, Express, TypeScript, Prisma, MongoDB. Authentication with Firebase with role based permissions. Deployment via DigitalOcean docker registry.","archived":false,"fork":false,"pushed_at":"2025-03-26T12:08:18.000Z","size":548,"stargazers_count":1,"open_issues_count":11,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-26T13:23:53.773Z","etag":null,"topics":["api","backend","cicd","digitalocean","express","firebase","gcp","github-actions","node","pkgroll","prisma","template","ts","tsx","typescript","zod"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JDIZM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2023-09-09T21:06:13.000Z","updated_at":"2025-02-12T09:22:58.000Z","dependencies_parsed_at":"2024-02-11T07:19:48.970Z","dependency_job_id":"b49fb582-366d-4b15-9cd1-cb1dbffbed90","html_url":"https://github.com/JDIZM/node-express-firebase-mongodb","commit_stats":null,"previous_names":["jdizm/node-express-backend-component","jdizm/node-express-firebase-mongodb"],"tags_count":0,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDIZM%2Fnode-express-firebase-mongodb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDIZM%2Fnode-express-firebase-mongodb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDIZM%2Fnode-express-firebase-mongodb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDIZM%2Fnode-express-firebase-mongodb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JDIZM","download_url":"https://codeload.github.com/JDIZM/node-express-firebase-mongodb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245954175,"owners_count":20699785,"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":["api","backend","cicd","digitalocean","express","firebase","gcp","github-actions","node","pkgroll","prisma","template","ts","tsx","typescript","zod"],"created_at":"2024-12-07T03:20:09.880Z","updated_at":"2026-04-13T04:06:11.268Z","avatar_url":"https://github.com/JDIZM.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# node-express-firebase-mongodb\n\n- [tsx](https://github.com/esbuild-kit/tsx)\n- [pkgroll](https://github.com/privatenumber/pkgroll)\n- [eslint](https://eslint.org/)\n- [prettier](https://prettier.io/)\n- [typescript](https://www.typescriptlang.org/)\n- [vitest](https://vitest.dev/)\n- [prisma](https://www.prisma.io/)\n- [mongodb](https://www.mongodb.com/)\n- [zod](https://zod.dev/)\n- [zod-prisma-types](https://github.com/chrishoermann/zod-prisma-types)\n- [firebase auth](https://firebase.google.com/docs/auth/admin)\n- [gcp](https://cloud.google.com/)\n- [digitalocean](https://www.digitalocean.com/)\n- [helmet](https://helmetjs.github.io/)\n- [cookie-parser](https://www.npmjs.com/package/cookie-parser)\n\nA simple node/express backend api template.\n\n## Requirements\n\nThis project requires node.js to be installed. This project uses volta to manage node versions.\n\nTo install volta run the following command in the terminal.\n\n```\ncurl https://get.volta.sh | bash\n```\n\nThis will require a mongodb database to be setup. You can set one up at https://cloud.mongodb.com/\n\nThis project also uses firebase auth for authentication. You can set one up at https://firebase.google.com/ and deployment is handled with DigitalOcean. See the [Firebase Auth](#firebase-auth) section for more info on setting up your credentials and project.\n\n## ESM Node\n\nhttps://www.typescriptlang.org/docs/handbook/esm-node.html\n\nThis project has been setup to use ESM Node. This allows us to use ES6 imports in Node.\n\nThis uses [tsx](https://github.com/esbuild-kit/tsx) as a dev server and [pkgroll](https://github.com/privatenumber/pkgroll) to bundle and build the project.\n\nNote: Prisma does not support ESM by default and [have an open issue](https://github.com/prisma/prisma/issues/5030) -- looking to migrate this to another ORM (drizzle) for ESM support.\n\n\"the Prisma client relies on globals like `__dirname` that used to be part of Node but in ESM have been moved to import.meta.dirname. See: https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-js-when-using-es6-modules\"\n\nAs a result of this it's best to stick to the `.cjs` format when running in production.\n\n## Setup\n\n```\n# install dependencies\nnpm i\n\n# start the dev server\nnpm run dev\n\n# view it running on localhost\ncurl localhost:4000\n```\n\nBe sure to configure the .env file with the correct values and make sure you have a mongodb database setup and firebase application credentials.\n\n## Testing\n\nThis project uses [vitest](https://vitest.dev/) for testing.\n\n1. run the unit tests with `npm run test`\n\nIt's also recommended to install the [vitest extension for vscode](https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer).\n\n## Build with docker\n\n### locally\n\nThe `GOOGLE_APPLICATION_CREDENTIALS` env variable is mapped to the docker container from your home directory. This is required for the firebase admin sdk to verify the token and decode the claims. see the [Firebase Auth](#firebase-auth) section for more info on the service account key file and Google Application Credentials.\n\n```\ndocker compose up -d\n```\n\n### production\n\n```\n# build the app\nnpm run build\n\n# build with docker\ndocker build . --tag node-express\n\n# or to build with a specific platform\ndocker build . --tag node-express --platform linux/amd64\n\n# start the docker container\ndocker run -d -p 4000:4000 node-express\n\n# view it running on localhost\ncurl localhost:4000\n```\n\nWhen building with Docker locally it will require the service account key to be set; this is because the Dockerfile is copying the service account key file into the image. See the [Firebase Auth](#firebase-auth) section for more info on the service account key file and Google Application Credentials.\n\n## Database\n\nThis is setup to use MongoDB with Prisma. If you want to use a different database you can change the db provider in Prisma schema and use a different Database.\n\nNote: when using Prisma the MongoDB database connector uses transactions to support nested writes. Transactions require a replica set deployment. The easiest way to deploy a replica set is with Atlas. It's free to get started.\n\nhttps://www.prisma.io/docs/concepts/database-connectors/mongodb\n\n### env\n\ncreate a .env file in the root of the project and copy the contents of .env.example into it.\n\nYou can replace `DATABASE_URL` with your mongodb connection string whether that be cloud or locally hosted.\n\n### seed the db\n\nrun the seed script to seed the db the first time.\n\n```bash\nnpx prisma db seed\n```\n\n### updating db schema\n\n```\n# after updating the model you want to generate the schema\nnpx prisma generate\n```\n\n## Import aliases\n\nAliases can be configured in the import map, defined in package.json#imports.\n\nsee: https://github.com/privatenumber/pkgroll#aliases\n\n## Authentication\n\nThis project uses JWT bearer token for authentication. The claims, id and sub must be set on the token and the token can be verified and decoded using the configured auth provider.\n\nYou can sign in an retrieve user tokens without having to use the client sdk.\n\nSee the [Firebase REST API docs for more info on how to sign in with email and password.](https://firebase.google.com/docs/reference/rest/auth#section-sign-in-email-password)\n\nSign in with email and password is supported out of the box with Firebase Auth.\n\n```js\n# sign in with email and password by posting\nhttps://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]\n\n# refresh token\nhttps://securetoken.googleapis.com/v1/token?key=[API_KEY]\n```\n\n## Permissions\n\nHow permissions work.\n\nA resource will have a permission level. A user will have a role/claim.\n\nRoutes will have their permission level defined in `./src/helpers/permissions.ts`\n\nWhen a user makes a request to a route the route will check the user's role/claim against the permission level of the resource.\n\nPermissions for the user can be set using the /auth/set-permissions endpoint which sets the database userId and claims on the firebase user. The token will have access to this data to verify the user's permissions.\n\n### Route permission levels\n\n1. Owner - Route can only be accessed by the owner of the resource. Defined by the id of the resource being accessed matching the id of the user making the request.\n2. User - Can access all resources with user permissions.\n3. Admin - Can access all resources.\n\n### Claims\n\nA claim is defined when the user is created which defines the user's role and permissions level.\n\n1. User - default user permissions\n2. Admin - admin permissions\n\n## Firebase Auth\n\nThis project uses Firebase Auth for authentication. The firebase admin sdk is used to verify the token and decode the claims.\n\nBecause we are not running in a google environment we need to initialize the firebase admin sdk with a service account key file. see the [Firebase Admin SDK docs](https://firebase.google.com/docs/admin/setup#initialize_the_sdk_in_non-google_environments) for more info.\n\nThis requires a service account key file at `$HOME/gcloud.json`. The `GOOGLE_APPLICATION_CREDENTIALS` env variable must be set to the path of the service account key file.\n\nYou can create a service account from the firebase console and place in your home directory and set the environment variable like so:\n\n```\nexport GOOGLE_APPLICATION_CREDENTIALS=$HOME/gcloud.json\n```\n\nYou can also set this in the `.env` file but if you have set the env variable in your shell it will take precedence.\n\nWhen running in CI/CD the service account key file is stored as a secret and the env variable is set in the Dockerfile using the copied service account key file fron secrets.\n\n## Deployment with DigitalOcean\n\nA docker image can be built and deployed to a [container registry](https://docs.digitalocean.com/products/container-registry/getting-started/quickstart/). We can configure DigitalOcean to deploy the image once the registry updates using their [App Platform](https://docs.digitalocean.com/products/app-platform/)\n\nThe following secrets will need to be added to Github Actions for a successful deployment to DigitalOcean.\n\n- `DIGITALOCEAN_ACCESS_TOKEN` https://docs.digitalocean.com/reference/api/create-personal-access-token/\n- `REGISTRY_NAME` eg registry.digitalocean.com/my-container-registry\n- `SERVICE_ACCOUNT_DEV` The GOOGLE_APPLICATION_CREDENTIALS Service Account file for development env.\n- `SERVICE_ACCOUNT_PROD` The GOOGLE_APPLICATION_CREDENTIALS Service Account file for production env.\n- `IMAGE_NAME_DEV` the name of the DEV image we are pushing to the repository eg `express-api` it will be tagged with the latest version and a github sha.\n- `IMAGE_NAME_PROD` the name of the PROD image we are pushing to the repository eg `express-api` it will be tagged with the latest version and a github sha.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdizm%2Fnode-express-firebase-mongodb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdizm%2Fnode-express-firebase-mongodb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdizm%2Fnode-express-firebase-mongodb/lists"}