{"id":13761012,"url":"https://github.com/userdashboard/dashboard","last_synced_at":"2025-05-10T12:30:33.019Z","repository":{"id":52191989,"uuid":"156593623","full_name":"userdashboard/dashboard","owner":"userdashboard","description":" Dashboard is software for creating web apps and SaaS (support @ freenode #userdashboard)","archived":false,"fork":false,"pushed_at":"2020-12-22T17:40:44.000Z","size":3398,"stargazers_count":280,"open_issues_count":2,"forks_count":23,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-11-09T14:50:28.693Z","etag":null,"topics":["dashboard","organizations","saas","saas-admin","saas-boilerplate","stripe-connect","stripe-subscriptions","webapp","webapplication"],"latest_commit_sha":null,"homepage":"https://userdashboard.github.io","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/userdashboard.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}},"created_at":"2018-11-07T18:53:43.000Z","updated_at":"2024-10-22T05:53:42.000Z","dependencies_parsed_at":"2022-08-27T18:30:31.460Z","dependency_job_id":null,"html_url":"https://github.com/userdashboard/dashboard","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/userdashboard%2Fdashboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userdashboard%2Fdashboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userdashboard%2Fdashboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userdashboard%2Fdashboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/userdashboard","download_url":"https://codeload.github.com/userdashboard/dashboard/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224957931,"owners_count":17398493,"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":["dashboard","organizations","saas","saas-admin","saas-boilerplate","stripe-connect","stripe-subscriptions","webapp","webapplication"],"created_at":"2024-08-03T13:01:32.042Z","updated_at":"2024-11-16T18:31:56.904Z","avatar_url":"https://github.com/userdashboard.png","language":"JavaScript","readme":"# Documentation for Dashboard\n\n#### Index\n\n- [Introduction](#introduction)\n- [Hosting Dashboard yourself](#hosting-dashboard-yourself)\n- [Configuring Dashboard](#configuring-dashboard)\n- [Customize registration information](#customize-registration-information)\n- [Adding links to the header menus](#adding-links-to-the-header-menus)\n- [Access the API from your application server](#access-the-api)\n- [Localization](#localization)\n- [Storage backends](#storage-backends)\n- [Storage caching](#storage-caching)\n- [Logging](#logging)\n- [Dashboard modules](#dashboard-modules)\n- [Creating modules for Dashboard](#creating-modules-for-dashboard)\n- [Testing](#testing)\n- [Github repository](https://github.com/userdashboard/dashboard)\n- [NPM package](https://npmjs.org/userdashboard/dashboard)\n\n# Introduction\n\nWeb applications often require coding a user account system, organizations, subscriptions and other 'boilerplate' again and again.  \n\nDashboard packages everything web apps need into reusable, modular software.  It runs separately to your application so you have two web servers instead of one, and Dashboard fuses their content together to provide a single website or interface for your users.  To get started your web app just needs a `/` for guests and `/home` for signed in users.\n\n| Application | Dashboard      | + modules          |\n|-------------|----------------|--------------------|\n| /           | /account       | /account/...       |\n| /home       | /administrator | /administrator/... |\n\nDashboard uses a `template.html` with header, navigation and content structure.  Dashboard and modules use HTML pages and CSS for all the functionality users need.  Your application server can serve two special CSS files at `/public/template-additional.css` and `/public/content-additional.css` to theme the template and pages to match your application design.  Dashboard assumes you must be signed in to access any URL outside of `/` and `/public/*`.\n\nYour application server can return special HTML attributes and tags to interoperate with the Dashboard server.  Your content can be accessible to guests by specifying `\u003chtml data-auth=\"false\"\u003e` and you can serve full-page content by specifying `\u003chtml data-template=\"false\"\u003e` in your HTML.\n\nYou can inject HTML snippets into the template by including `\u003ctemplate id=\"head\"\u003e\u003c/template\u003e` in your content or populate the template's navigation bar by including `\u003ctemplate id=\"navbar\"\u003e\u003c/template\u003e` with the links and any other HTML for your menu.  \n\n# Hosting Dashboard yourself\n\nDashboard requires NodeJS `12.16.3` be installed.\n\n    $ mkdir my-dashboard-server\n    $ cd my-dashboard-server\n    $ npm init\n    $ npm install @userdashboard/dashboard\n    $ echo \"require('@userdashboard/dashboard').start(__dirname)\" \u003e main.js\n    $ node main.js\n\n# Configuring Dashboard\n\nDashboard is configured with a combination of environment variables and hard-coded settings in your `package.json`:\n\n    {\n        \"dashboard\": {\n            \"title\": \"Title to place in Template\",\n            \"modules: [\n                \"@userdashboard/organizations\",\n                \"@userdashboard/stripe-connect\"\n            ],\n            \"server\": [\n                \"/src/to/script/to/run/receiving/requests.js\"\n            ],\n            \"content\": [\n                \"/src/to/script/to/modify/content.js\"\n            ],\n            \"proxy\": [\n                \"/src/to/script/to/modify/proxy/requests.js\n            ],\n            \"menus\": {\n                \"administrator\": [\n                    {\n                        \"href\": \"/administrator/your_module_name\",\n                        \"text\": \"Administrator link\",\n                        \"object\": \"link\"\n                    }\n                ],\n                \"account\": [\n                    {\n                        \"href\": \"/account/your_module_name\",\n                        \"text\": \"Account link\",\n                        \"object\": \"link\"\n                    }\n                ]\n            }\n        }\n    }\n\n| Attribute | Purpose                                   |\n|-----------|-------------------------------------------|\n| title     | Template header title                     |\n| modules   | Activates the installed modules           |\n| menus     | Add links to header menus                 |\n| proxy     | Include data in requests to your server   |\n| content   | Modify content before it is served        |\n| server    | Modify requests before they are processed |\n\nServer handlers can execute `before` and/or `after` a visitor is identified as a guest or user:\n\n    module.exports = {\n        before: async (req, res) =\u003e {\n            // req.account is not set\n            // req.session is not set\n        },\n        after: async (req, res) =\u003e {\n            // req.account may be set\n            // req.session may be set\n        }\n    }\n\nContent handlers can adjust the `template` and `page` documents before they are served to the user:\n\n    module.exports = {\n        page: async (req, res, pageDoc) =\u003e {\n            // adjust page before mixing with template\n        },\n        template: async (req, res, templateDoc) =\u003e {\n            // page is now in `src-doc` of application iframe\n        }\n    }\n\nProxy handlers can add to the headers sent to your application servers:\n    \n    module.exports = async (req, proxyRequestOptions) =\u003e {\n        proxyRequestOptions.headers.include = 'something'\n    }\n    \n\n# Customize registration information\n\nBy default users may register with just a username and password, both of which are encrypted so they cannot be used for anything but signing in.  You can specify some personal information fields to require in an environment variable:\n\n    REQUIRE_PROFILE=true\n    PROFILE_FIELDS=any,combination\n\nThese fields are supported by the registration form:\n\n| Field         | Description                |\n|---------------|----------------------------|\n| full-name     | First and last name        |\n| contact-email | Contact email              |\n| display-name  | Name to display to users   |\n| display-email | Email to display to users  |\n| dob           | Date of birth              |\n| location      | Location description       |\n| phone         | Phone number               |\n| company-name  | Company name               |\n| website       | Website                    |\n| occupation    | Occupation                 |\n\n# Adding links to the header menus\n\nThe account and administrator drop-down menus are created from stub HTML files placed in Dashboard, modules, and your project.  To add your own links create a `/src/menu-account.html` and `/src/menu-administrator.html` in your project with the HTML top include.\n\n## Account menu compilation\n\n1) Your project's `package.json` and `/src/menu-account.html`\n2) Any activated module's `package.json` links or `/src/menu-account.html` files\n3) Dashboard's `package.json` and `/src/menu-account.html`\n\n## Administrator menu compilation\n\n1) Your project's `package.json` and `/src/menu-administrator.html`\n2) Any activated module's `package.json` links or `/src/menu-administrator.html` files\n3) Dashboard's `package.json` and `/src/menu-administrator.html`\n\n# Access the API\n\nDashboard and official modules are completely API-driven and you can access the same APIs on behalf of the user making requests.  You perform `GET`, `POST`, `PATCH`, and `DELETE` HTTP requests against the API endpoints to fetch or modify data.  You can use a shared secret `APPLICATION_SERVER_TOKEN` to verify requests between servers, both servers send it in an `x-application-server-token` header.  This example fetches the user's session information using NodeJS, you can do this with any language:\n\n    const sessions = await proxy(`/api/user/sessions?accountid=${accountid}`, accountid, sessionid)\n\n    const proxy = util.promisify((path, accountid, sessionid, callback) =\u003e {\n        const requestOptions = {\n            host: 'dashboard.example.com',\n            path: path,\n            port: '443',\n            method: 'GET',\n            headers: {\n                'x-application-server': 'application.example.com',\n                'x-application-server-token': process.env.APPLICATION_SERVER_TOKEN,\n                'x-accountid': accountid,\n                'x-sessionid': sessionid\n            }\n        }\n        const proxyRequest = require('https').request(requestOptions, (proxyResponse) =\u003e {\n            let body = ''\n            proxyResponse.on('data', (chunk) =\u003e {\n                body += chunk\n            })\n            return proxyResponse.on('end', () =\u003e {\n                return callback(null, JSON.parse(body))\n            })\n        })\n        proxyRequest.on('error', (error) =\u003e {\n            return callback(error)\n        })\n        return proxyRequest.end()\n      })\n    }\n# Storage backends\n\nDashboard by default uses local disk, this is good for development and under some circumstances like an app your family uses, but generally you should use any of Redis, PostgreSQL, MySQL, MongoDB or S3-compatible for storage.\n\n| Name                                                                                              | Description                             |\n|---------------------------------------------------------------------------------------------------|-----------------------------------------|\n| File system                                                                                       | For development and single-server apps  |\n| [@userdashboard/storage-s3](https://npmjs.com/package/@userdashboard/storage-s3)                  | Minimum speed and minimum scaling cost  |\n| [@userdashboard/storage-mysql](https://npmjs.com/package/@userdashboard/storage-mysql)            | Medium speed and medium scaling cost    |\n| [@userdashboard/storage-mongodb](https://npmjs.com/package/@userdashboard/storage-mongodb)        | Medium speed and medium scaling cost    |\n| [@userdashboard/storage-postgresql](https://npmjs.com/package/@userdashboard/storage-postgresql)  | Medium speed and medium scaling cost    |\n| [@userdashboard/storage-redis](https://npmjs.com/package/@userdashboard/storage-redis)            | Maximum speed and maximum scaling cost  |\n\nYou can activate a storage backend with an environment variable.  Each have unique configuration requirements specified in their readme files.\n\n    $ STORAGE=@userdashboard/storage-mongodb \\\n      MONGODB_URL=mongodb:/.... \\\n      node main.js\n\n# Storage caching\n\nYou can complement your storage backend with optional caching, either using RAM if you have a single instance of your Dashboard server, or Redis if you need a cache shared by multiple instances of your Dashboard server.\n\n|Name                                                                                          | Description                            |\n|----------------------------------------------------------------------------------------------|----------------------------------------|\n| NodeJS                                                                                       | For single-server apps                 |\n| [@userdashboard/storage-cache-redis](https://npmjs.com/package/@userdashboard/storage-redis) | For speeding up disk-based storage     |\n\nYou can optionally use Redis as a cache, this is good for any storage on slow disks.\n\n    $ CACHE=@userdashboard/storage-cache-redis \\\n      CACHE_REDIS_URL=redis:/.... \\\n      node main.js\n\nIf you have a single Dashboard server you can cache within memory:\n\n    $ CACHE=node \\\n      node main.js\n\n# Logging\n\nBy default Dashboard does not have any active `console.*` being emitted.  You can enable logging with `LOG_LEVEL` containing a list of valid console.* methods.\n\n    $ LOG_LEVEL=log,warn,info,error node main.js\n\nOverride Dashboard's logging by creating your own `log.js` in the root of your project:\n\n    module.exports = (group) =\u003e {\n      return {\n        log: () =\u003e {\n        },\n        info: () =\u003e {\n        },\n        warn: () =\u003e {\n        }\n      }\n    }\n\n# Dashboard modules\n\nDashboard is modular and by itself it provides only the signing in, account management and basic administration.  Modules add new pages and API routes for additional functionality.\n\n| Name                                                                                                | Description                               |\n|-----------------------------------------------------------------------------------------------------|-------------------------------------------|\n| [@userdashboard/localization](https://npmjs.com/package/userdashboard/localization)                 | Specify language or allow users to select |\n| [@userdashboard/maxmind-geoip](https://npmjs.com/package/userdashboard/maxmind-geoip)               | IP address-based geolocation by MaxMind   |\n| [@userdashboard/organizations](https://npmjs.com/package/userdashboard/organizations)               | User created groups                       |\n| [@userdashboard/stripe-connect](https://npmjs.com/package/userdashboard/stripe-connect)             | Marketplace functionality by Stripe       |\n| [@userdashboard/stripe-subscriptions](https://npmjs.com/package/userdashboard/stripe-subscriptions) | SaaS functionality by Stripe              |\n\nModules are NodeJS packages that you install with NPM:\n\n    $ npm install @userdashboard/stripe-subscriptions\n\nYou need to notify Dashboard which modules you are using in `package.json` conffiguration:\n\n    \"dashboard\": {\n      \"modules\": [\n        \"@userdashboard/stripe-subscriptions\"\n      ]\n    }\n\nIf you have built your own modules you may submit a pull request to add them to this list.  \n\nDashboard modules are able to use their own storage and cache settings:\n\n    $ SUBSCRIPTIONS_STORAGE=@userdashboard/storage-postgresql \\\n      SUBSCRIPTIONS_DATABASE_URL=postgres://localhost:5432/subscriptions \\\n      ORGANIZATIONS_STORAGE=@userdashboard/storage-postgresql \\\n      ORGANIZATIONS_DATABASE_URL=postgres://localhost:5433/organizations \\\n      STORAGE=@userdashboard/storage-redis \\\n      REDIS_URL=redis://localhost:6379 \\\n      node main.js\n\n# Creating modules for Dashboard\n\nA module is a NodeJS application with the same folder structure as Dashboard.  When Dashboard starts it scans its own files, and then any modules specified in the `package.json` to create a combined sitemap of UI and API routes.  You can browse the official modules' source to see examples.\n\n    $ mkdir my-module\n    $ cd my-module\n    $ npm install @userdashboard/dashboard --no-save\n    # create main.js to start the server\n    # create index.js optionally exporting any relevant API\n    # add your content\n    $ npm publish\n\nThe \"--no-save\" flag is used to install Dashboard, this prevents your module from installing a redundant version of Dashboard when it is being installed by users.\n\nWhen your module is published users can install it with NPM:\n\n    $ npm install your_module_name\n\nModules must be activated in a web app's `package.json`:\n\n    dashboard: {\n        modules: [ \"your_module_name\" ]\n    }\n\nThese paths have special significance:\n\n| Folder                                    | Description                                      |\n|-------------------------------------------|--------------------------------------------------|\n| `/src/www`                                | Web server root                                  |\n| `/src/www/public`                         | Static assets served quickly                     |\n| `/src/www/account`                        | User account management pages                    |\n| `/src/www/account/YOUR_MODULE/`           | Your additions (if applicable)                   |\n| `/src/www/administrator`                  | Administration pages                             |\n| `/src/www/administrator/YOUR_MODULE/`     | Your additions (if applicable)                   |\n| `/src/www/api/user`                       | User account management pages                    |\n| `/src/www/api/user/YOUR_MODULE/`          | Your additions (if applicable)                   |\n| `/src/www/api/administrator`              | Administration APIs                              |\n| `/src/www/api/administrator/YOUR_MODULE/` | Your additions (if applicable)                   |\n| `/src/www/webhooks/YOUR_MODULE/`          | Endpoints for receiving webhooks (if applicable) |\n\nContent pages may export `before`, `get` for rendering the page and `post` methods for submitting HTML forms.  API routes may export `before`, `get`, `post`, `patch`, `delete`, `put` methods.   If specified, the `before` method will execute before any `verb`.\n \nGuest-accessible content and API routes can be flagged in the HTML or NodeJS:\n\n    # HTML\n    \u003chtml auth=\"false\"\u003e\n\n    # NodeJS API route\n    { \n        auth: false,\n        get: (req) = \u003e {\n\n        }\n    }\n\nContent can occupy the full screen without the template via a flag in the HTML or NodeJS:\n\n    # HTML\n    \u003chtml template=\"false\"\u003e\n\n    # NodeJS page handler\n    { \n        template: false,\n        get: (req, res) = \u003e {\n\n        }\n    }\n\n# Testing\n\nDashboard's test suite covers the `API` and the `UI`.  The `API` tests are performed by proxying a running instance of the software.  The `UI` tests are performed with `puppeteer` remotely-controlling `Chrome` to browse a running instance of the software.  Github Actions can be run locally [using 'act'](https://github.com/nektos/act).\n\n    $ act -j test-fs-storage\n    $ act -j test-redis-storage\n    $ act -j test-postgresql-storage\n    $ act -j test-mongodb-storage\n    $ act -j test-mysql-storage\n    $ act -j test-s3-storage\n    $ act -j test-redis-cache\n    $ act -j test-node-cache\n\nYou may need to install Chromium manually to ensure all its dependencies are met.  This can be configured via environment variables placed in a `.env` file for `act` to use:\n\n    PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=\"true\"\n    CHROMIUM_EXECUTABLE=\"/usr/bin/chromium\"\n\nYou may need to install Git manually:\n\n    INSTALL_GIT=true\n\nYou may need to install PostgreSQL or LocalStack separately because `act` doesn't start services.\n\n    S3_ENDPOINT=http://0.0.0.0:4566\n    DATABASE_URL=postgres://...\n\nYou can also configure an NPM and APT cache to speed up working with multiple test suites.  This is known to work with [Sonatype Nexus Repository Manager 3](https://github.com/sonatype/docker-nexus3).\n\n    APT_PROXY=\"http://192.168.1.30:8081/repository/apt-proxy\"\n    NPM_PROXY=\"http://192.168.1.30:8081/repository/npm-proxy/\"\n\nWhen running the Github Actions locally the storage may create Docker containers that need to be manually removed:\n\n    $ docker container ls\n    $ docker stop ab12 # first four digits of id\n    $ docker rm ab12\n\n# Support and contributions\n\nIf you have encountered a problem post an issue on the appropriate [Github repository](https://github.com/userdashboard).  \n\nIf you would like to contribute check [Github Issues](https://github.com/userdashboard/dashboard) for ways you can help. \n\nFor help using or contributing to this software join the freenode IRC `#userdashboard` chatroom - [Web IRC client](https://kiwiirc.com/nextclient/).\n\n## License\n\nThis software is licensed under the MIT license, a copy is enclosed in the `LICENSE` file.  Included icon assets and the CSS library `pure-min` is licensed separately, refer to the `icons/licenses` folder and `src/www/public/pure-min.css` file for their licensing information.\n\nCopyright (c) 2017 - 2020 Ben Lowry\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuserdashboard%2Fdashboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuserdashboard%2Fdashboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuserdashboard%2Fdashboard/lists"}