{"id":15642061,"url":"https://github.com/seancdavis/everything-is-a-cms","last_synced_at":"2025-04-30T09:24:05.708Z","repository":{"id":146757512,"uuid":"302010989","full_name":"seancdavis/everything-is-a-cms","owner":"seancdavis","description":"Use multiple non-traditional back-ends for Next.js project. Built to support talk at Next.js Conf 2020.","archived":false,"fork":false,"pushed_at":"2020-10-28T10:19:37.000Z","size":501,"stargazers_count":66,"open_issues_count":0,"forks_count":4,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-30T14:51:12.499Z","etag":null,"topics":["cms","jamstack","nextjs","talk"],"latest_commit_sha":null,"homepage":"https://youtu.be/9j9bxDf428o","language":"JavaScript","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/seancdavis.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":"2020-10-07T11:11:20.000Z","updated_at":"2023-05-12T17:00:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"625a52e6-a654-4a4f-83ec-77da3d2cb443","html_url":"https://github.com/seancdavis/everything-is-a-cms","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancdavis%2Feverything-is-a-cms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancdavis%2Feverything-is-a-cms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancdavis%2Feverything-is-a-cms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seancdavis%2Feverything-is-a-cms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seancdavis","download_url":"https://codeload.github.com/seancdavis/everything-is-a-cms/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251675359,"owners_count":21625796,"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":["cms","jamstack","nextjs","talk"],"created_at":"2024-10-03T11:54:03.068Z","updated_at":"2025-04-30T09:24:05.686Z","avatar_url":"https://github.com/seancdavis.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Everything is a CMS!\n\nThis code supports the demo from the _Everything is a CMS!_ talk from [Next.js Conf 2020](https://nextjs.org/conf/speakers/seancdavis).\n\nIts purpose is to demonstrate that we can easily swap data sources in and out by building abstracted and normalized engines. There are two types of engines, both which are shown within this project:\n\n- API-Based\n- File-Based\n\nCurrently, the supported data sources are:\n\n- [Bear](https://bear.app/)\n- [Contentful](https://www.contentful.com/)\n- [Dropbox](https://www.dropbox.com/)\n- [Fauna](https://fauna.com/)\n- [Google Sheets](https://www.google.com/sheets/about/)\n- [Trello](https://trello.com/)\n\n## Getting Started\n\n_Note: This project is built to run in development mode for demo purposes. I haven't tested the build and deploy processes._\n\nTo run the project, start the Next server:\n\n    $ npm run dev\n\nAnd then visit your browser at [localhost:3000](http://localhost:3000/).\n\nSee below for working with the various data engines and their drivers (i.e. sources).\n\n### ⚠️ Environment Variables\n\nThere are a series of environment variables that are required to work with various data sources:\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eData Source\u003c/th\u003e\n      \u003cth\u003eRequired Environment Variables\u003c/th\u003e\n      \u003cth\u003eNotes\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=\"2\"\u003eBear\u003c/td\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eBEAR_DATABASE_PATH\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eLocal \u003cb\u003eabsolute path\u003c/b\u003e to Bear's SQLite database.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eBEAR_TAG\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eNotes are filtered by tag. This is the name of the tag without the \u003ccode\u003e#\u003c/code\u003e.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=\"3\"\u003eContentful\u003c/td\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eCONTENTFUL_ACCESS_TOKEN\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eCONTENTFUL_CONTENT_TYPE_ID\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eThis is a word you control when creating the content type. Usually, if the type is called \u003ccode\u003eSandwich\u003c/code\u003e, the ID will be \u003ccode\u003esandwich\u003c/code\u003e. \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eCONTENTFUL_SPACE_ID\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=\"2\"\u003eDropbox\u003c/td\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eDROPBOX_ACCESS_TOKEN\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\u003ca href=\"https://www.dropbox.com/developers/apps\"\u003eCreate an app\u003c/a\u003e to generate a token.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eDROPBOX_FILES_DIR\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eSandwich files are filtered by directory. The path to the directory in which your files are stored should begin with a slash (e.g. \u003ccode\u003e/everything-is-a-cms\u003c/code\u003e.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=\"2\"\u003eFauna\u003c/td\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eFAUNA_API_KEY\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eFAUNA_INDEX_NAME\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eThe items are pulled from an index you create with Fauna. This is the name of that index.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=\"2\"\u003eGoogle Sheets\u003c/td\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eGOOGLE_CREDENTIALS\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eCreate a service account and then a JSON key. Download the key and store it as an env var, escaping quotes and other characters as necessary.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eGOOGLE_SHEET_ID\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eYou can pull this from the URL when viewing the sheet.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=\"2\"\u003eTrello\u003c/td\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eTRELLO_ACCESS_TOKEN\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003eYou can find your API key and generate a token for your user \u003ca href=\"https://trello.com/app-key\"\u003ehere\u003c/a\u003e.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\n        \u003ccode\u003eTRELLO_API_KEY\u003c/code\u003e\n      \u003c/td\u003e\n      \u003ctd\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n## API-Based Engine\n\nThe API-based engine example here is an [Apollo GraphQL server](https://www.apollographql.com/). Its contents live in the `api-engine` directory.\n\nAll drivers for this engine live in the `api-engine/lib/drivers` directory and are plugged into the `api-engine/index.js` entry file.\n\nThe server must be running to see it in action on the front-end. You can start the server by running:\n\n    $ node api-engine/index.js\n\nYou can then work with any of the API-based examples. You can also visit a playground for your GraphQL queries at [localhost:4000](http://localhost:4000/).\n\n## File-Based Engine\n\nThe file-based engine has a reader and a writer. The reader is used by the front-end templates to read local markdown files. The writer pulls data from the data sources and writes them to markdown files in the `_data` directory.\n\nYou can import files by running the appropriate command-line script:\n\n    $ npm run import:[driver]\n\nSupported drivers are (i.e. replace `[driver]` with one of the following):\n\n- `bear`\n- `contentful`\n- `dropbox`\n- `fauna`\n- `sheets`\n- `trello`\n\n## Questions and Feedback\n\nIf you have question regarding the implementation here or want to talk about the approach, the quickest way to get ahold of me is on Twitter: [@seancdavis29](https://twitter.com/seancdavis29).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseancdavis%2Feverything-is-a-cms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseancdavis%2Feverything-is-a-cms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseancdavis%2Feverything-is-a-cms/lists"}