{"id":32966306,"url":"https://github.com/nanawel/our-shopping-list","last_synced_at":"2026-02-14T09:11:57.972Z","repository":{"id":59801776,"uuid":"363989760","full_name":"nanawel/our-shopping-list","owner":"nanawel","description":"OSL is a simple shared list web-application based on Node and VueJS. Typical uses include shopping lists of course, and any other small todo-list that needs to be used collaboratively.","archived":false,"fork":false,"pushed_at":"2026-02-05T17:23:01.000Z","size":4683,"stargazers_count":164,"open_issues_count":2,"forks_count":16,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-02-05T20:09:51.222Z","etag":null,"topics":["collaborative","mongodb","nodejs","pwa","todolist","vuejs","websocket"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nanawel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":"nanawel","issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"anaelo","thanks_dev":null,"custom":null}},"created_at":"2021-05-03T16:18:35.000Z","updated_at":"2026-02-05T17:23:05.000Z","dependencies_parsed_at":"2024-04-21T17:12:21.742Z","dependency_job_id":"1043d3d6-3110-4305-88c9-d973d6d5b06c","html_url":"https://github.com/nanawel/our-shopping-list","commit_stats":null,"previous_names":[],"tags_count":73,"template":false,"template_full_name":null,"purl":"pkg:github/nanawel/our-shopping-list","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanawel%2Four-shopping-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanawel%2Four-shopping-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanawel%2Four-shopping-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanawel%2Four-shopping-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nanawel","download_url":"https://codeload.github.com/nanawel/our-shopping-list/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nanawel%2Four-shopping-list/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29441359,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T07:24:13.446Z","status":"ssl_error","status_checked_at":"2026-02-14T07:23:58.969Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["collaborative","mongodb","nodejs","pwa","todolist","vuejs","websocket"],"created_at":"2025-11-13T03:00:21.464Z","updated_at":"2026-02-14T09:11:57.966Z","avatar_url":"https://github.com/nanawel.png","language":"JavaScript","funding_links":["https://liberapay.com/nanawel","https://buymeacoffee.com/anaelo"],"categories":["Software","mongodb"],"sub_categories":["Task Management \u0026 To-do Lists"],"readme":"\u003ca href=\"https://github.com/nanawel/our-shopping-list\"\u003e\n  \u003cimg src=\"client/src/assets/logo.png\"\n    alt=\"OSL logo\"\n    title=\"Our Shopping List\" align=\"right\"\n    height=\"120\" /\u003e\n\u003c/a\u003e\n\n# Our Shopping List\n\nOSL is a simple **shared list** application. Typical uses include **shopping\nlists** of course, and any other small todo-list that needs to be used\n**collaboratively**.\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"doc/osl-usage.gif\" height=\"400\" /\u003e\u003c/p\u003e\n\nThe current implementation provides the following features:\n- **Multiple boards** (can be disabled, see `VITE_APP_SINGLEBOARD_MODE`)\n- Each board with **multiple lists**\n- **Real-time sync** between users\n- Items with the following fields: name, quantity, details\n- **Checkable** items\n- 2 **display modes** for items (unchecked only / checked only, sorted by check time)\n- Intuitive **search**\n- **Mobile-first UI** with swipeable items\n- [PWA](https://en.wikipedia.org/wiki/Progressive_web_application) basic support\n- Internationalisation (i18n) ([available languages listed here](./client/src/locales))\n  - Want to help? Create or update translations on [Weblate](https://hosted.weblate.org/projects/our-shopping-list/client-src-locales/)\n\nBut, at this date it lacks the following:\n- Full PWA support with offline mode and deferred sync\n\n## ⭐ New in v2: Boards feature\n\nBefore v2, **all of the lists** on an instance were available to **all users**.\n\nVersion 2 introduces a new feature called \"boards\". It's simply a way to group\nlists together under a common name. That name can then be shared so that\npeople use the lists from a board collaboratively.\n\nBut, you might want to disable that feature and keep using a unique board for\nyour whole instance. In that case, just use the provided\n`VITE_APP_SINGLEBOARD_MODE` environment variable.\n\n**But have no fear, you can always:**\n\n- Switch from _singleboard_ mode to multi-board\n  - In that case you'll have to\n    create a new board and choose it as target for existing lists with the\n    provided CLI tool.\n- Switch from multi-board mode to _singleboard_\n  - In that case you can choose which lists to migrate to the special\n    unique board, but you'll lose access to all other lists (they are not\n    deleted, just not accessible anymore)\n\n\u003e See next § for instructions on how to enable one mode or the other.\n\n## ☝ Instructions when migrating from v1 to v2\n\nVersion 2 has added the _multiboard_ feature which changes the default mode\nthe application runs into.\n\nIf you already had a working v1, and would like to upgrade to v2 please follow\nthe steps below:\n\n\u003e ⚠ **Back up your data before proceeding!**\n\n### If you want to keep using one single board on your instance (just like on v1)\n\n  - Make sure you set the `VITE_APP_SINGLEBOARD_MODE` to `1`\n  - Once started, use the CLI to migrate existing lists to the special board\n    used as common parent for lists in \"singleboard\" mode.\n    ```shell\n    docker compose exec app node cli.js board:create --singleboard\n    docker compose exec app node cli.js list:move-to-board --all --singleboard\n    ```\n  - Use the application as usual (you might have to clear your browser's cache\n    to make sure there's no invalid data left).\n\n### If you want to enable the new _boards_ feature and migrate your existing lists to a dedicated board\n\n  - Make sure `VITE_APP_SINGLEBOARD_MODE` is **not set** or set to `0`\n  - Create a new board with the name of your choice\n    ```shell\n    # Get the created board's slug from the output and use it in the following command\n    docker compose exec app node cli.js board:create my-board\n    docker compose exec app node cli.js list:move-to-board --all --board my-board\n    ```\n  - Open the application, and from the home screen open the board you've just created\n    to find your lists.\n\n## 🖼 Screenshots\n\n### Mobile\n\n\u003e ☝ Screenshots are from v1, but v2 looks mostly the same.\n\n\u003ca href=\"doc/mobile-01.png\"\u003e\n  \u003cimg src=\"doc/mobile-01.png\" height=\"240\" /\u003e\n\u003c/a\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick here to see more!\u003c/summary\u003e\n  \u003ca href=\"doc/mobile-02-menu.png\"\u003e\n    \u003cimg src=\"doc/mobile-02-menu.png\" height=\"240\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"doc/mobile-03-search.png\"\u003e\n    \u003cimg src=\"doc/mobile-03-search.png\" height=\"240\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"doc/mobile-04-edit-list.png\"\u003e\n    \u003cimg src=\"doc/mobile-04-edit-list.png\" height=\"240\" /\u003e\n  \u003c/a\u003e\n\u003c/details\u003e\n\n### Desktop\n\n\u003e ☝ Screenshots are from v1, but v2 looks mostly the same.\n\n\u003ca href=\"doc/desktop-01.png\"\u003e\n  \u003cimg src=\"doc/desktop-01.png\" height=\"240\" /\u003e\n\u003c/a\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick here to see more!\u003c/summary\u003e\n  \u003ca href=\"doc/desktop-01-swipe.png\"\u003e\n    \u003cimg src=\"doc/desktop-01-swipe.png\" height=\"240\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"doc/desktop-02-edit-item.png\"\u003e\n    \u003cimg src=\"doc/desktop-02-edit-item.png\" height=\"240\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"doc/desktop-03-search.png\"\u003e\n    \u003cimg src=\"doc/desktop-03-search.png\" height=\"240\" /\u003e\n  \u003c/a\u003e\n\u003c/details\u003e\n\n## 📦 Installation\n\n### 🐋 With Docker\n\nWith a running [MongoDB](https://hub.docker.com/_/mongo) container as\n`mymongo` on the host:\n\n```shell\ndocker run --detach \\\n  --name our-shopping-list \\\n  --link mymongo:mongodb \\\n  --publish 80:8080 \\\n  ourshoppinglist/our-shopping-list\n```\n\n### 🐋 With `docker compose`\n\nUse the provided [`docker-compose.yml`](doc/docker-compose.yml) and adapt it to\nyour needs.\n\nThen to start the containers:\n\n```shell\ndocker compose up -d\n```\n\n**Available environment variables for the `app` container**\n\n⚠️ The original `VUE_APP_` prefix has been replaced due to the migration to Vite.  \nYou must now use `VITE_APP_` instead.\n\n- **System keys**\n  - `LISTEN_PORT` (default: `8080`)\n  - `MONGODB_HOST` (default: `mongodb`)\n  - `MONGODB_PORT` (default: `27017`)\n  - `MONGODB_DB` (default: `osl`)\n  - `BASE_URL` (default: _empty_) Set to base path if your web root is not `/` (ex: `/my-osl/`)\n    - ⚠️ Not supported in development mode (Vite-related limitation)\n\n  \u003e MongoDB authentication is not supported yet.\n\n- **Application keys**\n  - `VITE_APP_APM_ENABLED` (default: `0`) [Reference](https://www.elastic.co/guide/en/apm/agent/rum-js/current/intro.html)\n  - `VITE_APP_APM_LOGLEVEL` (default: `warn`) [Reference](https://www.elastic.co/guide/en/apm/agent/rum-js/current/configuration.html#log-level)\n  - `VITE_APP_APM_SERVERURL` (default: `http://localhost:8200`) [Reference](https://www.elastic.co/guide/en/apm/agent/rum-js/current/configuration.html#server-url)\n  - `VITE_APP_APM_SERVERURLPREFIX` (default: `/intake/v${apiVersion}/rum/events`) [Reference](https://www.elastic.co/guide/en/apm/agent/rum-js/current/configuration.html#server-url-prefix)\n  - `VITE_APP_APM_SERVICENAME` [Reference](https://www.elastic.co/guide/en/apm/agent/rum-js/current/configuration.html#service-name)\n  - `VITE_APP_BOARD_DELETION_ENABLED` (default: `0`) [Reference](https://github.com/nanawel/our-shopping-list/issues/17)\n  - `VITE_APP_CHECKED_ITEMS_HISTORY_SORT_FIELD` (default: `lastCheckedAt`, see available fields [here](./client/src/models/Item.js))\n  - `VITE_APP_CHECKED_ITEMS_HISTORY_SORT_ORDER` (default: `desc`)\n  - `VITE_APP_CLIENT_LOG_CONSOLE_ENABLED` (default: `false`, [see doc here](https://github.com/dev-tavern/vue-logger-plugin/tree/v1.2.3#enabled-vs-consoleenabled))\n  - `VITE_APP_CLIENT_LOG_ENABLED` (default: `false`, [see doc here](https://github.com/dev-tavern/vue-logger-plugin/tree/v1.2.3#enabled-vs-consoleenabled))\n  - `VITE_APP_CLIENT_LOG_LEVEL` (default: `debug`)\n  - `VITE_APP_EDIT_ITEM_ON_CREATE` (default: `0`)\n  - `VITE_APP_HIDE_FORCE_REFRESH_HINT` (default: `0`)\n  - `VITE_APP_HOME_MESSAGE` (default: _empty_)\n  - `VITE_APP_I18N_FALLBACK_LOCALE` (default: `en`)\n  - `VITE_APP_I18N_FORCE_LOCALE` (default: `0`)\n  - `VITE_APP_I18N_LOCALE` (default: `en`)\n  - `VITE_APP_LIST_ALL_BOARDS_ENABLED` (default: `0`, has no effect in _singleboard_ mode)\n  - `VITE_APP_LOCALSTORAGE_KEY_PREFIX` (default: `OurShoppingList_`)\n  - `VITE_APP_SHORT_TITLE` (default: `OSL`)\n  - `VITE_APP_SINGLEBOARD_MODE` (default: `0`)\n  - `VITE_APP_SOCKETIO_CSR_MAXDISCONNECTIONDURATION` (default: `1800000` = 30mn)\n  - `VITE_APP_SOCKETIO_PING_INTERVAL` (default: `25000` = 25sec.)\n  - `VITE_APP_SOCKETIO_PING_TIMEOUT` (default: `20000` = 20sec.)\n  - `VITE_APP_THEME` (`system` | `light` | `dark`, default: `system`) [Reference](https://github.com/nanawel/our-shopping-list/issues/48)\n  - `VITE_APP_TITLE` (default: `Our Shopping List`)\n  - `VITE_APP_USE_ITEM_QUICK_SYNTAX` (default: `0`) [Reference](https://github.com/nanawel/our-shopping-list/issues/20)\n\n### Robots.txt\n\nBy default, the embedded `robots.txt` prevents search engines from browsing the application:\n\n```\nUser-agent: *\nDisallow: /\n```\n\nYou can change this behavior by mounting the `robots.txt` of your choice at `/app/robots.txt` in the container.\n\n### 🗒 Notes for reverse-proxy (SSL offloading)\n\nOSL uses a WebSocket to allow server-to-client communication. So using a\nreverse-proxy to forward the connection implies the presence of the following\nsections below in the corresponding virtual host.\n\nReplace `127.0.0.1` and `8080` with the IP of the OSL host if your RP is not\nthe host itself and/or if you're using another port.\n\n#### Apache\n\n```\n\u003cProxy *\u003e\n    Allow from all\n\u003c/Proxy\u003e\nProxyPass         /  http://127.0.0.1:8080/\nProxyPassReverse  /  http://127.0.0.1:8080/\nProxyPreserveHost On\n\nRewriteEngine On\nRewriteCond %{HTTP:Upgrade} =websocket [NC]\nRewriteRule /(.*)           ws://127.0.0.1:8080/$1 [P,L]\nRewriteCond %{HTTP:Upgrade} !=websocket [NC]\nRewriteRule /(.*)           http://127.0.0.1:8080/$1 [P,L]\n```\n\n#### Nginx\n\n```\nlocation / {\n    proxy_set_header    Host $host;\n    proxy_set_header    X-Real-IP $remote_addr;\n    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header    X-Forwarded-Proto $scheme;\n    proxy_pass          http://localhost:8080;\n\n    proxy_http_version  1.1;\n    proxy_set_header    Upgrade $http_upgrade;\n    proxy_set_header    Connection \"Upgrade\";\n    \n    proxy_redirect      http://localhost:8080 https://ourshoppinglist.myhost;\n}\n```\n\n### ⚠ Notes when serving multiple instances on different web roots\n\nRemember to set the `BASE_URL` variable to the matching web root on each instance.\n\nMake sure you set `VITE_APP_LOCALSTORAGE_KEY_PREFIX` to a unique value too, otherwise clients switching from\none instance to another might corrupt the internal cache in their browser.\n\nExample:\n\n- 1st instance on https://my.host/public-osl\n  - `BASE_URL` = `public-osl/`\n  - `VITE_APP_LOCALSTORAGE_KEY_PREFIX` = `OSL1_`\n- 2nd instance on https://my.host/private-osl\n  - `BASE_URL` = `private-osl/`\n  - `VITE_APP_LOCALSTORAGE_KEY_PREFIX` = `OSL2_`\n- etc.\n\n### Debugging on server side\n\nYou can use the [standard `DEBUG`](https://dev.to/aderchox/what-is-the-debug-environment-variable-in-nodejs-and-how-to-use-it-3fal)\nenvironment variable to enable the verbose mode of the server:\n\nExample to log all operations related to **socket-io** (WebSocket) and the **URL rewrite** process\n(when using a custom `BASE_URL`):\n\n```\nDEBUG=socket.io:server,express-urlrewrite\n```\n\nOr if you need to log everything:\n\n```\nDEBUG=*\n```\n\n## Upgrade MongoDB to 7.x\n\nFrom the original release until june 2024, the stack was shipped with `mongo:4` but this version\nof MongoDB is deprecated and you can safely upgrade to MongoDB 7 while keeping your existing data.\n\nUse the provided automated script as follows:\n\n```shell\n# Make a backup with mongodump first!\ndocker compose exec -T mongodb mongodump -d osl --archive \u003e osl-backup.archive\n\nbash doc/update-mongo7.sh\n```\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=nanawel/our-shopping-list\u0026type=date\u0026legend=top-left)](https://www.star-history.com/#nanawel/our-shopping-list\u0026type=date\u0026legend=top-left)\n\n## 👷 Developer installation\n\n\u003e 🐋 This method also uses Docker, but with the local source files mounted\n\u003e into the `node` container.\n\nFirst of all, clone this project in the directory of your choice. Then from it:\n\n```shell\nmake dev-pull\nmake dev-init\nmake dev-upd\n```\n\nNow start the Webpack Development Server with\n\n```shell\nmake dev-watch\n```\n\n\u003e If you don't, you'll get 504 errors in the console on `/sockjs-node/*` requests\n\u003e and you won't get hot reloading on changes.\n\nIf you want to enter the container, just use\n\n```shell\nmake dev-shell\n```\n\n###  Translation\n\nTranslations can be very easily added and improved using the files from the `client/src/locales/`\ndirectory.\n\nIf you want to translate OSL in a new language, feel free to add your contribution using\n[Weblate](https://weblate.org/).  \nRegister on Weblate and go to https://hosted.weblate.org/projects/our-shopping-list/client-src-locales/\n\n### Special cases\n\nIn development mode, the service worker is not enabled.\nTo workaround this limitation, you may want to ponctually build the JS bundle\nin \"production\" mode.\n\nHere's how:\n\n```shell\nmake dev-shell\n\ncd client/\nNODE_ENV=production yarn build\n```\n\nThen reload the page in your browser and the SW should be activated.\nYou have to make sure you are running the app **with TLS enabled**. Use the\n`ENABLE_TLS` variable to use the embedded TLS proxy if needed.\n\n### Upgrade MongoDB to 7.x\n\nUse the provided automated script as follows:\n\n```shell\nexport COMPOSE_FILE=docker-compose.dev.yml\nexport DOCKER_COMPOSE_FILE=docker-compose.dev.yml\nbash doc/update-mongo7.sh\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnanawel%2Four-shopping-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnanawel%2Four-shopping-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnanawel%2Four-shopping-list/lists"}