diff --git a/.dockerignore b/.dockerignore index 49ef68257..f88a2a24b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,7 +6,7 @@ .idea .vscode -__pycache__/ +**/__pycache__/ *.py[cod] *$py.class *.so @@ -25,9 +25,11 @@ venv */node_modules */dist +/dist/ */data/db */mealie/test */mealie/.temp +/mealie/frontend/ model.crfmodel diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 09f8f5695..b890608ff 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -20,20 +20,6 @@ --> -## What type of PR is this? - -_(REQUIRED)_ - - - -- feature -- bug -- documentation -- cleanup -- dev (Internal development) - ## What this PR does / why we need it: _(REQUIRED)_ diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 48d020811..df3e5b3a2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -3,8 +3,15 @@ on: workflow_call: jobs: + build-package: + name: "Build Python package" + uses: ./.github/workflows/partial-package.yml + with: + tag: e2e + test: timeout-minutes: 60 + needs: build-package runs-on: ubuntu-latest defaults: run: @@ -18,11 +25,18 @@ jobs: cache-dependency-path: ./tests/e2e/yarn.lock - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Retrieve Python package + uses: actions/download-artifact@v4 + with: + name: backend-dist + path: dist - name: Build Image uses: docker/build-push-action@v5 with: file: ./docker/Dockerfile context: . + build-contexts: | + packages=dist push: false load: true tags: mealie:e2e diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fdf1c00c2..e2558c4bc 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -21,7 +21,7 @@ jobs: uses: ./.github/workflows/partial-backend.yml frontend-tests: - name: "Frontend and End-to-End Tests" + name: "Frontend Tests" uses: ./.github/workflows/partial-frontend.yml build-release: diff --git a/.github/workflows/partial-backend.yml b/.github/workflows/partial-backend.yml index b0772d181..89d809d16 100644 --- a/.github/workflows/partial-backend.yml +++ b/.github/workflows/partial-backend.yml @@ -1,4 +1,4 @@ -name: Backend Test/Lint +name: Backend Lint and Test on: workflow_call: diff --git a/.github/workflows/partial-builder.yml b/.github/workflows/partial-builder.yml index c6362ba3b..573325da1 100644 --- a/.github/workflows/partial-builder.yml +++ b/.github/workflows/partial-builder.yml @@ -16,7 +16,14 @@ on: required: true jobs: + build-package: + name: "Build Python package" + uses: ./.github/workflows/partial-package.yml + with: + tag: ${{ inputs.tag }} + publish: + needs: build-package runs-on: ubuntu-latest steps: - name: Checkout repository @@ -35,18 +42,22 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Override __init__.py - run: | - echo "__version__ = \"${{ inputs.tag }}\"" > ./mealie/__init__.py - - uses: depot/setup-action@v1 + - name: Retrieve Python package + uses: actions/download-artifact@v4 + with: + name: backend-dist + path: dist + - name: Build and push Docker image, via Depot.dev uses: depot/build-push-action@v1 with: project: srzjb6mhzm file: ./docker/Dockerfile context: . + build-contexts: | + packages=dist platforms: linux/amd64,linux/arm64 push: true tags: | diff --git a/.github/workflows/partial-frontend.yml b/.github/workflows/partial-frontend.yml index bbebe4cca..00f8a2673 100644 --- a/.github/workflows/partial-frontend.yml +++ b/.github/workflows/partial-frontend.yml @@ -1,4 +1,4 @@ -name: Frontend Build/Lin +name: Frontend Lint and Test on: workflow_call: @@ -41,37 +41,3 @@ jobs: - name: Run tests ๐Ÿงช run: yarn test:ci working-directory: "frontend" - - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout ๐Ÿ›Ž - uses: actions/checkout@v4 - - - name: Setup node env ๐Ÿ— - uses: actions/setup-node@v4.0.0 - with: - node-version: 16 - check-latest: true - - - name: Get yarn cache directory path ๐Ÿ›  - id: yarn-cache-dir-path - run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT - - - name: Cache node_modules ๐Ÿ“ฆ - uses: actions/cache@v4 - id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) - with: - path: ${{ steps.yarn-cache-dir-path.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - - name: Install dependencies ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป - run: yarn - working-directory: "frontend" - - - name: Run Build ๐Ÿšš - run: yarn build - working-directory: "frontend" diff --git a/.github/workflows/partial-package.yml b/.github/workflows/partial-package.yml new file mode 100644 index 000000000..1ee258562 --- /dev/null +++ b/.github/workflows/partial-package.yml @@ -0,0 +1,102 @@ +name: Package build + +on: + workflow_call: + inputs: + tag: + required: true + type: string + +jobs: + build-frontend: + name: Build frontend + runs-on: ubuntu-latest + + steps: + - name: Checkout ๐Ÿ›Ž + uses: actions/checkout@v4 + + - name: Setup node env ๐Ÿ— + uses: actions/setup-node@v4.0.0 + with: + node-version: 16 + check-latest: true + + - name: Get yarn cache directory path ๐Ÿ›  + id: yarn-cache-dir-path + run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT + + - name: Cache node_modules ๐Ÿ“ฆ + uses: actions/cache@v4 + id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป + run: yarn + working-directory: "frontend" + + - name: Run Build ๐Ÿšš + run: yarn generate + working-directory: "frontend" + + - name: Archive built frontend + uses: actions/upload-artifact@v4 + with: + name: frontend-dist + path: frontend/dist + retention-days: 5 + + build-package: + name: Build Python package + needs: build-frontend + runs-on: ubuntu-latest + + steps: + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + virtualenvs-create: true + virtualenvs-in-project: true + plugins: | + poetry-plugin-export + + - name: Retrieve built frontend + uses: actions/download-artifact@v4 + with: + name: frontend-dist + path: mealie/frontend + + - name: Override __init__.py + run: | + echo "__version__ = \"${{ inputs.tag }}\"" > ./mealie/__init__.py + + - name: Build package and requirements.txt + env: + SKIP_PACKAGE_DEPS: true + run: | + task py:package + + - name: Archive built package + uses: actions/upload-artifact@v4 + with: + name: backend-dist + path: dist + retention-days: 5 diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index ad2fa13e3..1cddb2d52 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -19,7 +19,7 @@ jobs: uses: ./.github/workflows/partial-backend.yml frontend-tests: - name: "Frontend and End-to-End Tests" + name: "Frontend Tests" uses: ./.github/workflows/partial-frontend.yml container-scanning: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9fbb398cc..55b0ec5d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: uses: ./.github/workflows/partial-backend.yml frontend-tests: - name: "Frontend and End-to-End Tests" + name: "Frontend Tests" uses: ./.github/workflows/partial-frontend.yml build-release: diff --git a/.gitignore b/.gitignore index f853ecb97..3dbf0a6bd 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,7 @@ pnpm-debug.log* env/ build/ develop-eggs/ - +/dist/ downloads/ eggs/ .eggs/ @@ -66,6 +66,9 @@ wheels/ .installed.cfg *.egg +# frontend copied into Python module for packaging purposes +/mealie/frontend/ + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2e8de8afb..1dfd0a074 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,7 +12,7 @@ repos: exclude: ^tests/data/ - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.8.2 + rev: v0.9.7 hooks: - id: ruff - id: ruff-format diff --git a/.vscode/settings.json b/.vscode/settings.json index e4bfdeb9d..b842cd45e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -60,5 +60,9 @@ }, "[vue]": { "editor.formatOnSave": false + }, + "[python]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "charliermarsh.ruff" } } diff --git a/Taskfile.yml b/Taskfile.yml index 70f6f23dd..8c017a286 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -41,14 +41,25 @@ tasks: setup:ui: desc: setup frontend dependencies dir: frontend + run: once cmds: - yarn install + sources: + - package.json + - yarn.lock + generates: + - node_modules/** setup:py: desc: setup python dependencies + run: once cmds: - poetry install --with main,dev,postgres - poetry run pre-commit install + sources: + - poetry.lock + - pyproject.toml + - .pre-commit-config.yaml setup:model: desc: setup nlp model @@ -131,6 +142,63 @@ tasks: - poetry run coverage html - open htmlcov/index.html + py:package:copy-frontend: + desc: copy the frontend files into the Python package + internal: true + deps: + - ui:generate + cmds: + - rm -rf mealie/frontend + - cp -a frontend/dist mealie/frontend + sources: + - frontend/dist/** + generates: + - mealie/frontend/** + + py:package:generate-requirements: + desc: Generate requirements file to pin all packages, effectively a "pip freeze" before installation begins + internal: true + cmds: + - poetry export -n --only=main --extras=pgsql --output=dist/requirements.txt + # Include mealie in the requirements, hashing the package that was just built to ensure it's the one installed + - echo "mealie[pgsql]=={{.MEALIE_VERSION}} \\" >> dist/requirements.txt + - poetry run pip hash dist/mealie-{{.MEALIE_VERSION}}-py3-none-any.whl | tail -n1 | tr -d '\n' >> dist/requirements.txt + - echo " \\" >> dist/requirements.txt + - poetry run pip hash dist/mealie-{{.MEALIE_VERSION}}.tar.gz | tail -n1 >> dist/requirements.txt + vars: + MEALIE_VERSION: + sh: poetry version --short + sources: + - poetry.lock + - pyproject.toml + - dist/mealie-*.whl + - dist/mealie-*.tar.gz + generates: + - dist/requirements.txt + + py:package:deps-parallel: + desc: Run py:package dependencies in parallel + internal: true + deps: + - setup:py + - py:package:copy-frontend + + py:package:deps: + desc: Dependencies of py:package, skippable by setting SKIP_PACKAGE_DEPS=true + internal: true + cmds: + - task: py:package:deps-parallel + status: + - '{{ .SKIP_PACKAGE_DEPS | default "false"}}' + + py:package: + desc: builds Python packages (sdist and wheel) in top-level dist directory + deps: + - py:package:deps + cmds: + - poetry build -n --output=dist + - task: py:package:generate-requirements + py: desc: runs the backend server cmds: @@ -160,6 +228,14 @@ tasks: cmds: - yarn build + ui:generate: + desc: generates a static version of the frontend in frontend/dist + dir: frontend + deps: + - setup:ui + cmds: + - yarn generate + ui:lint: desc: runs the frontend linter dir: frontend @@ -184,6 +260,16 @@ tasks: cmds: - yarn run dev + docker:build-from-package: + desc: Builds the Docker image from the existing Python package in dist/ + deps: + - py:package + cmds: + - docker build --tag mealie:dev --file docker/Dockerfile --build-arg COMMIT={{.GIT_COMMIT}} --build-context packages=dist . + vars: + GIT_COMMIT: + sh: git rev-parse HEAD + docker:prod: desc: builds and runs the production docker image locally dir: docker diff --git a/docker/Dockerfile b/docker/Dockerfile index bdee7416e..f08261129 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,8 +1,11 @@ -FROM node:16 as builder +############################################### +# Frontend Build +############################################### +FROM node:16 AS frontend-builder -WORKDIR /app +WORKDIR /frontend -COPY ./frontend . +COPY frontend . RUN yarn install \ --prefer-offline \ @@ -26,14 +29,10 @@ ENV PYTHONUNBUFFERED=1 \ PIP_NO_CACHE_DIR=off \ PIP_DISABLE_PIP_VERSION_CHECK=on \ PIP_DEFAULT_TIMEOUT=100 \ - POETRY_HOME="/opt/poetry" \ - POETRY_VIRTUALENVS_IN_PROJECT=true \ - POETRY_NO_INTERACTION=1 \ - PYSETUP_PATH="/opt/pysetup" \ - VENV_PATH="/opt/pysetup/.venv" + VENV_PATH="/opt/mealie" -# prepend poetry and venv to path -ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH" +# prepend venv to path +ENV PATH="$VENV_PATH/bin:$PATH" # create user account RUN useradd -u 911 -U -d $MEALIE_HOME -s /bin/bash abc \ @@ -41,31 +40,81 @@ RUN useradd -u 911 -U -d $MEALIE_HOME -s /bin/bash abc \ && mkdir $MEALIE_HOME ############################################### -# Builder Image +# Backend Package Build ############################################### -FROM python-base as builder-base +FROM python-base AS backend-builder RUN apt-get update \ && apt-get install --no-install-recommends -y \ curl \ + && rm -rf /var/lib/apt/lists/* + +ENV POETRY_HOME="/opt/poetry" \ + POETRY_NO_INTERACTION=1 + +# prepend poetry to path +ENV PATH="$POETRY_HOME/bin:$PATH" + +# install poetry - respects $POETRY_VERSION & $POETRY_HOME +ENV POETRY_VERSION=2.0.1 +RUN curl -sSL https://install.python-poetry.org | python3 - + +# install poetry plugins needed to build the package +RUN poetry self add "poetry-plugin-export>=1.9" + +WORKDIR /mealie + +# copy project files here to ensure they will be cached. +COPY poetry.lock pyproject.toml ./ +COPY mealie ./mealie + +# Copy frontend to package it into the wheel +COPY --from=frontend-builder /frontend/dist ./mealie/frontend + +# Build the source and binary package +RUN poetry build --output=dist + +# Create the requirements file, which is used to install the built package and +# its pinned dependencies later. mealie is included to ensure the built one is +# what's installed. +RUN export MEALIE_VERSION=$(poetry version --short) \ + && poetry export --only=main --extras=pgsql --output=dist/requirements.txt \ + && echo "mealie[pgsql]==$MEALIE_VERSION \\" >> dist/requirements.txt \ + && poetry run pip hash dist/mealie-$MEALIE_VERSION-py3-none-any.whl | tail -n1 | tr -d '\n' >> dist/requirements.txt \ + && echo " \\" >> dist/requirements.txt \ + && poetry run pip hash dist/mealie-$MEALIE_VERSION.tar.gz | tail -n1 >> dist/requirements.txt + +############################################### +# Package Container +# Only role is to hold the packages, or be overriden by a --build-context flag. +############################################### +FROM scratch AS packages +COPY --from=backend-builder /mealie/dist / + +############################################### +# Python Virtual Environment Build +############################################### +# Install packages required to build the venv, in parallel to building the wheel +FROM python-base AS venv-builder-base +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ build-essential \ libpq-dev \ libwebp-dev \ # LDAP Dependencies libsasl2-dev libldap2-dev libssl-dev \ gnupg gnupg2 gnupg1 \ - && rm -rf /var/lib/apt/lists/* \ - && pip install -U --no-cache-dir pip + && rm -rf /var/lib/apt/lists/* +RUN python3 -m venv --upgrade-deps $VENV_PATH -# install poetry - respects $POETRY_VERSION & $POETRY_HOME -ENV POETRY_VERSION=1.3.1 -RUN curl -sSL https://install.python-poetry.org | python3 - +# Install the wheel and all dependencies into the venv +FROM venv-builder-base AS venv-builder -# copy project requirement files here to ensure they will be cached. -WORKDIR $PYSETUP_PATH -COPY ./poetry.lock ./pyproject.toml ./ +# Copy built package (wheel) and its dependency requirements +COPY --from=packages * /dist/ -# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally -RUN poetry install -E pgsql --only main +# Install the wheel with exact versions of dependencies into the venv +RUN . $VENV_PATH/bin/activate \ + && pip install --require-hashes -r /dist/requirements.txt --find-links /dist ############################################### # CRFPP Image @@ -96,39 +145,25 @@ RUN apt-get update \ # create directory used for Docker Secrets RUN mkdir -p /run/secrets -# copying poetry and venv into image -COPY --from=builder-base $POETRY_HOME $POETRY_HOME -COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH - +# copy CRF++ and add it to the library path ENV LD_LIBRARY_PATH=/usr/local/lib COPY --from=crfpp /usr/local/lib/ /usr/local/lib COPY --from=crfpp /usr/local/bin/crf_learn /usr/local/bin/crf_learn COPY --from=crfpp /usr/local/bin/crf_test /usr/local/bin/crf_test -# copy backend -COPY ./mealie $MEALIE_HOME/mealie -COPY ./poetry.lock ./pyproject.toml $MEALIE_HOME/ +# Copy venv into image. It contains a fully-installed mealie backend and frontend. +COPY --from=venv-builder $VENV_PATH $VENV_PATH -# venv already has runtime deps installed we get a quicker install -WORKDIR $MEALIE_HOME -RUN . $VENV_PATH/bin/activate && poetry install -E pgsql --only main -WORKDIR / # Grab CRF++ Model Release -RUN python $MEALIE_HOME/mealie/scripts/install_model.py +RUN python -m mealie.scripts.install_model VOLUME [ "$MEALIE_HOME/data/" ] ENV APP_PORT=9000 EXPOSE ${APP_PORT} -HEALTHCHECK CMD python $MEALIE_HOME/mealie/scripts/healthcheck.py || exit 1 - -# ---------------------------------- -# Copy Frontend - -ENV STATIC_FILES=/spa/static -COPY --from=builder /app/dist ${STATIC_FILES} +HEALTHCHECK CMD python -m mealie.scripts.healthcheck || exit 1 ENV HOST 0.0.0.0 diff --git a/docker/entry.sh b/docker/entry.sh index 3acb00efc..cccc2ba9d 100644 --- a/docker/entry.sh +++ b/docker/entry.sh @@ -32,13 +32,51 @@ init() { cd /app # Activate our virtual environment here - . /opt/pysetup/.venv/bin/activate + . /opt/mealie/bin/activate +} + +load_secrets() { + # Each of these environment variables will support a `_FILE` suffix that allows + # for setting the environment variable through the Docker Compose secret + # pattern. + local -a secret_supported_vars=( + "POSTGRES_USER" + "POSTGRES_PASSWORD" + "POSTGRES_SERVER" + "POSTGRES_PORT" + "POSTGRES_DB" + "POSTGRES_URL_OVERRIDE" + + "SMTP_HOST" + "SMTP_PORT" + "SMTP_USER" + "SMTP_PASSWORD" + + "LDAP_SERVER_URL" + "LDAP_QUERY_PASSWORD" + + "OIDC_CONFIGURATION_URL" + "OIDC_CLIENT_ID" + "OIDC_CLIENT_SECRET" + + "OPENAI_BASE_URL" + "OPENAI_API_KEY" + ) + + # If any secrets are set, prefer them over base environment variables. + for var in "${secret_supported_vars[@]}"; do + file_var="${var}_FILE" + if [ -n "${!file_var}" ]; then + export "$var=$(<"${!file_var}")" + fi + done } change_user init +load_secrets # Start API HOST_IP=`/sbin/ip route|awk '/default/ { print $3 }'` -exec python /app/mealie/main.py +exec mealie diff --git a/docs/docs/contributors/developers-guide/building-packages.md b/docs/docs/contributors/developers-guide/building-packages.md new file mode 100644 index 000000000..5fe45e13c --- /dev/null +++ b/docs/docs/contributors/developers-guide/building-packages.md @@ -0,0 +1,40 @@ +# Building Packages + +Released packages are [built and published via GitHub actions](maintainers.md#drafting-releases). + +## Python packages + +To build Python packages locally for testing, use [`task`](starting-dev-server.md#without-dev-containers). After installing `task`, run `task py:package` to perform all the steps needed to build the package and a requirements file. To do it manually, run: +```sh +pushd frontend +yarnpkg install +yarnpkg generate +popd +rm -r mealie/frontend +cp -a frontend/dist mealie/frontend +poetry build +poetry export -n --only=main --extras=pgsql --output=dist/requirements.txt +MEALIE_VERSION=$(poetry version --short) +echo "mealie[pgsql]==${MEALIE_VERSION} \\" >> dist/requirements.txt +poetry run pip hash dist/mealie-${MEALIE_VERSION}-py3-none-any.whl | tail -n1 | tr -d '\n' >> dist/requirements.txt +echo " \\" >> dist/requirements.txt +poetry run pip hash dist/mealie-${MEALIE_VERSION}.tar.gz | tail -n1 >> dist/requirements.txt +``` + +The Python package can be installed with all of its dependencies pinned to the versions tested by the developers with: +```sh +pip3 install -r dist/requirements.txt --find-links dist +``` + +To install with the latest but still compatible dependency versions, instead run `pip3 install dist/mealie-$VERSION-py3-none-any.whl` (where `$VERSION` is the version of mealie to install). + +## Docker image +One way to build the Docker image is to run the following command in the project root directory: +```sh +docker build --tag mealie:dev --file docker/Dockerfile --build-arg COMMIT=$(git rev-parse HEAD) . +``` + +The Docker image can be built from the pre-built Python packages with the task command `task docker:build-from-package`. This is equivalent to: +```sh +docker build --tag mealie:dev --file docker/Dockerfile --build-arg COMMIT=$(git rev-parse HEAD) --build-context packages=dist . +``` diff --git a/docs/docs/documentation/community-guide/bring-api.md b/docs/docs/documentation/community-guide/bring-api.md new file mode 100644 index 000000000..41214bb0c --- /dev/null +++ b/docs/docs/documentation/community-guide/bring-api.md @@ -0,0 +1,8 @@ +!!! info +This guide was submitted by a community member. Find something wrong? Submit a PR to get it fixed! + +Mealie supports adding the ingredients of a recipe to your [Bring](https://www.getbring.com/) shopping list, as you can +see [here](https://docs.mealie.io/documentation/getting-started/features/#recipe-actions). +However, for this to work, your Mealie instance needs to be exposed to the open Internet so that the Bring servers can access its information. If you don't want your server to be publicly accessible for security reasons, you can use the [Mealie-Bring-API](https://github.com/felixschndr/mealie-bring-api) written by a community member. This integration is entirely local and does not require any service to be exposed to the Internet. + +This is a small web server that runs locally next to your Mealie instance, and instead of Bring pulling the data from you, it pushes the data to Bring. [Check out the project](https://github.com/felixschndr/mealie-bring-api) for more information and installation instructions. diff --git a/docs/docs/documentation/getting-started/authentication/oidc-v2.md b/docs/docs/documentation/getting-started/authentication/oidc-v2.md index 35f67369e..ee8c3ba9b 100644 --- a/docs/docs/documentation/getting-started/authentication/oidc-v2.md +++ b/docs/docs/documentation/getting-started/authentication/oidc-v2.md @@ -10,7 +10,7 @@ Mealie supports 3rd party authentication via [OpenID Connect (OIDC)](https://openid.net/connect/), an identity layer built on top of OAuth2. OIDC is supported by many Identity Providers (IdP), including: - [Authentik](https://goauthentik.io/integrations/sources/oauth/#openid-connect) -- [Authelia](https://www.authelia.com/configuration/identity-providers/open-id-connect/) +- [Authelia](https://www.authelia.com/integration/openid-connect/mealie/) - [Keycloak](https://www.keycloak.org/docs/latest/securing_apps/#_oidc) - [Okta](https://www.okta.com/openid-connect/) diff --git a/docs/docs/documentation/getting-started/faq.md b/docs/docs/documentation/getting-started/faq.md index 5484c718a..365663a62 100644 --- a/docs/docs/documentation/getting-started/faq.md +++ b/docs/docs/documentation/getting-started/faq.md @@ -1,164 +1,308 @@ + # Frequently Asked Questions -## How do I enable "smart" ingredient handling? +## Features and Functionality -You might have noticed that scaling up a recipe or making a shopping list doesn't by default handle the ingredients in a way you might expect. Depending on your settings, scaling up might yield things like `2 1 cup broth` instead of `2 cup broth`. And, making shopping lists from recipes that have shared ingredients can yield multiple lines of the same ingredient. **But**, Mealie has a mechanism to intelligently handle ingredients and make your day better. How? -### Set up your Foods and Units -Do the following just **once**. Doing this applies to your whole group, so be careful. +??? question "How do I enable 'smart' ingredient handling?" -1. Click on your name in the upper left corner to get to your settings -2. In the bottom right, select `Manage Data` -3. In the Management page, make sure that a little orange button says `Foods` -4. If your Foods database is empty, click `Seed` and choose your language. You should end up with a list of foods. (Wait a bit for seeding to happen, and try not to seed more than once or you will have duplicates) -5. Click the little orange `Foods` button and now choose `Units`. -6. Click `Seed` and choose your language. You should end up with a list of units (e.g. `tablespoon`) + ### How do I enable "smart" ingredient handling? -Initial seeding of Units is pretty complete, but there are many Foods in the world. You'll probably find that you need to add Foods to the database during parsing for the first several recipes. Once you have a well-populated Food database, there are API routes to parse ingredients automatically in bulk. But this is not a good idea without a very complete set of Foods. + You might have noticed that scaling up a recipe or making a shopping list doesn't by default handle the ingredients in a way you might expect. Depending on your settings, scaling up might yield things like `2 1 cup broth` instead of `2 cup broth`. And, making shopping lists from recipes that have shared ingredients can yield multiple lines of the same ingredient. **But**, Mealie has a mechanism to intelligently handle ingredients and make your day better. How? -### Set up Recipes to use Foods and Units -Do the following for each recipe you want to intelligently handle ingredients. +

Set up your Foods and Units

+ Do the following just **once**. Doing this applies to your whole group, so be careful. -1. Go to a recipe -2. Click the Edit button/icon -3. Click the Recipe Settings gear and deselect `Disable Ingredient Amounts` -4. Save -5. The ingredients should now look a little weird (`1 1 cup broth` and so on) -6. Click the Edit button/icon again -7. Scroll to the ingredients and you should see new fields for Amount, Unit, Food, and Note. The Note in particular will contain the original text of the Recipe. -8. Click `Parse` and you will be taken to the ingredient parsing page. -9. Choose your parser. The `Natural Language Parser` works very well, but you can also use the `Brute Parser`, or the `OpenAI Parser` if you've [enabled OpenAI support](./installation/backend-config.md#openai). -10. Click `Parse All`, and your ingredients should be separated out into Units and Foods based on your seeding in Step 1 above. -11. For ingredients where the Unit or Food was not found, you can click a button to accept an automatically suggested Food to add to the database. Or, manually enter the Unit/Food and hit `Enter` (or click `Create`) to add it to the database -12. When done, click `Save All` and you will be taken back to the recipe. Now the Unit and Food fields of the recipe should be filled out. + 1. Click on your name in the upper left corner to get to your settings + 2. In the bottom right, select `Manage Data` + 3. In the Management page, make sure that a little orange button says `Foods` + 4. If your Foods database is empty, click `Seed` and choose your language. You should end up with a list of foods. (Wait a bit for seeding to happen, and try not to seed more than once or you will have duplicates) + 5. Click the little orange `Foods` button and now choose `Units`. + 6. Click `Seed` and choose your language. You should end up with a list of units (e.g. `tablespoon`) -Scaling up this recipe or adding it to a Shopping List will now smartly take care of ingredient amounts and duplicate combinations. + Initial seeding of Units is pretty complete, but there are many Foods in the world. You'll probably find that you need to add Foods to the database during parsing for the first several recipes. Once you have a well-populated Food database, there are API routes to parse ingredients automatically in bulk. But this is not a good idea without a very complete set of Foods. -## Is it safe to upgrade Mealie? +

Set up Recipes to use Foods and Units

-Yes. If you are using the v1 branches (including beta), you can upgrade to the latest version of Mealie without performing a site Export/Restore. This process was required in previous versions of Mealie, however we've automated the database migration process to make it easier to upgrade. Note that if you were using the v0.5.x version, you CANNOT upgrade to the latest version automatically. You must follow the migration instructions in the documentation. + Do the following for each recipe you want to intelligently handle ingredients. -- [Migration From v0.5.x](./migrating-to-mealie-v1.md) + 1. Go to a recipe + 2. Click the Edit button/icon + 3. Click the Recipe Settings gear and deselect `Disable Ingredient Amounts` + 4. Save + 5. The ingredients should now look a little weird (`1 1 cup broth` and so on) + 6. Click the Edit button/icon again + 7. Scroll to the ingredients and you should see new fields for Amount, Unit, Food, and Note. The Note in particular will contain the original text of the Recipe. + 8. Click `Parse` and you will be taken to the ingredient parsing page. + 9. Choose your parser. The `Natural Language Parser` works very well, but you can also use the `Brute Parser`, or the `OpenAI Parser` if you've [enabled OpenAI support](./installation/backend-config.md#openai). + 10. Click `Parse All`, and your ingredients should be separated out into Units and Foods based on your seeding in Step 1 above. + 11. For ingredients where the Unit or Food was not found, you can click a button to accept an automatically suggested Food to add to the database. Or, manually enter the Unit/Food and hit `Enter` (or click `Create`) to add it to the database + 12. When done, click `Save All` and you will be taken back to the recipe. Now the Unit and Food fields of the recipe should be filled out. -## How can I change the theme? - -You can change the theme by settings the environment variables. - -- [Backend Config - Themeing](./installation/backend-config.md#themeing) - -## How can I change the login session timeout? - -Login session can be configured by setting the `TOKEN_TIME` variable on the backend container. - -- [Backend Config](./installation/backend-config.md) - -## Can I serve Mealie on a subpath? - -No. Due to limitations from the JavaScript Framework, Mealie doesn't support serving Mealie on a subpath. - -## Can I install Mealie without docker? - -Yes, you can install Mealie on your local machine. HOWEVER, it is recommended that you don't. Managing non-system versions of python, node, and npm is a pain. Moreover, updating and upgrading your system with this configuration is unsupported and will likely require manual interventions. - -## What is fuzzy search and how do I use it? -Mealie can use fuzzy search, which is robust to minor typos. For example, searching for "brocolli" will still find your recipe for "broccoli soup". But fuzzy search is only functional on a Postgres database backend. To enable fuzzy search you will need to migrate to Postgres: - -1. Backup your database and download the .zip file (same as when [migrating](./migrating-to-mealie-v1.md)) -2. Set up a [Postgres](./installation/postgres.md) instance of Mealie -3. Upload the backup .zip and click to apply it (as as migration) - -## How can I attach an image or video to a Recipe? - -Mealie's Recipe Steps and other fields support markdown syntax and therefore support images and videos. To attach an image to the recipe, you can upload it as an asset and use the provided copy button to generate the html image tag required to render the image. For videos, Mealie provides no way to host videos. You'll need to host your videos with another provider and embed them in your recipe. Generally, the video provider will provide a link to the video and the html tag required to render the video. For example, YouTube provides the following link that works inside a step. You can adjust the width and height attributes as necessary to ensure a fit. - -```html - -``` - -## How can I unlock my account? - -If your account has been locked by bad password attempts, you can use an administrator account to unlock another account. Alternatively, you can unlock all accounts via a script within the container. - -```shell -docker exec -it mealie bash - -python /app/mealie/scripts/reset_locked_users.py -``` - -## How can I change my password? - -You can change your password by going to the user profile page and clicking the "Change Password" button. Alternatively you can use the following script to change your password via the CLI if you are locked out of your account. - -```shell -docker exec -it mealie bash - -python /app/mealie/scripts/change_password.py -``` - -## I can't log in with external auth. How can I change my authentication method? - -Follow the [steps above](#how-can-i-change-my-password) for changing your password. You will be prompted if you would like to switch your authentication method back to local auth so you can log in again. - -## How do private groups, households, and recipes work? - -Managing private groups and recipes can be confusing. The following diagram and notes should help explain how they work to determine if a recipe can be shared publicly. - -- Private links that are generated from the recipe page using the `Share` button bypass all group and recipe permissions -- Private groups block all access to recipes, including those that are public, except as noted above. -- Private households, similar to private groups, block all access to recipes, except as noted above. -- Households with "Allow users outside of your group to see your recipes" disabled block all access to recipes, except as noted above. -- Private recipes block all access to the recipe from public links. This does not affect Private Links. - -```mermaid -stateDiagram-v2 - r1: Request Access - p1: Using Private Link? - p2: Is Group Private? - p3: Is Household Private? - p4: Is Recipe Private? - s1: Deny Access - n1: Allow Access + Scaling up this recipe or adding it to a Shopping List will now smartly take care of ingredient amounts and duplicate combinations. - r1 --> p1 - p1 --> p2: No - p1 --> n1: Yes +??? question "How do I enable Nutritional Values?" - p2 --> s1: Yes - p2 --> p3: No + ### How do I enable Nutritional Values? - p3 --> s1: Yes - p3 --> p4: No + Mealie can store Nutritional Information for Recipes. Please note that the values you enter are static for the recipe and no scaling is being done when changing Servings / Yield. - p4 --> s1: Yes - p4 --> n1: No -``` + Do the following to enable Nutritional Values on individual Recipes, or to modify your Household Recipe Preferences -For more information on public access, check out the [Permissions and Public Access guide](./usage/permissions-and-public-access.md). For more information on groups vs. households, check out the [Groups and Households](./features.md#groups-and-households) section in the Features guide. + **Show Nutritional Values on a Single Recipe** -## Can I use fail2ban with Mealie? -Yes, Mealie is configured to properly forward external IP addresses into the `mealie.log` logfile. Note that due to restrictions in docker, IP address forwarding only works on Linux. + 1. Go to a recipe + 2. Click the Edit button/icon + 3. Click the Recipe Settings gear and select `Show Nutritional Values` + 4. Scroll down to manually fill out the Nutritional Values + 5. Save -Your fail2ban usage should look like the following: -``` -Use datepattern : %d-%b-%y %H:%M:%S : Day-MON-Year2 24hour:Minute:Second -Use failregex line : ^ERROR:\s+Incorrect username or password from -``` + **Show Nutritional Values by default** -## Why an API? -An API allows integration into applications like [Home Assistant](https://www.home-assistant.io/) that can act as notification engines to provide custom notifications based on Meal Plan data to remind you to defrost the chicken, marinate the steak, or start the CrockPot. Additionally, you can access nearly any backend service via the API giving you total control to extend the application. To explore the API spin up your server and navigate to http://yourserver.com/docs for interactive API documentation. + 1. Click your username in the top left + 2. Click the 'Household Settings' button + 3. Under 'Household Recipe Preferences', click to select 'Show nutrition information' + 4. Click 'Update' -## Why a database? -Some users of static-site generator applications like ChowDown have expressed concerns about their data being stuck in a database. Considering this is a new project, it is a valid concern to be worried about your data. Mealie specifically addresses this concern by providing automatic daily backups that export your data in json, plain-text markdown files, and/or custom Jinja2 templates. **This puts you in control of how your data is represented** when exported from Mealie, which means you can easily migrate to any other service provided Mealie doesn't work for you. -As to why we need a database? +??? question "Why Link Ingredients to a Recipe Step?" -- **Developer Experience:** Without a database, a lot of the work to maintain your data is taken on by the developer instead of a battle-tested platform for storing data. -- **Multi User Support:** With a solid database as backend storage for your data, Mealie can better support multi-user sites and avoid read/write access errors when multiple actions are taken at the same time. + ### Why Link Ingredients to a Recipe Step? -## Why is there no "Keep Screen Alive" button when I access a recipe? -You've perhaps visited the Mealie Demo and noticed that it had a "Keep Screen Alive" button, but it doesn't show up in your own Mealie instance. -There are typically two possible reasons for this: -1. You're accessing your Mealie instance without using HTTPS. The Wake Lock API is only available if HTTPS is used. Read more here: https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API -2. You're accessing your Mealie instance on a browser which doesn't support the API. You can test this here: https://vueuse.org/core/useWakeLock/#demo + Mealie allows you to link ingredients to specific steps in a recipe, ensuring you know exactly when to add each ingredient during the cooking process. -Solving the above points will most likely resolve your issues. However, if you're still having problems, you are welcome to create an issue. Just remember to add that you've tried the above two options first in your description. + **Link Ingredients to Steps in a Recipe** + + 1. Go to a recipe + 2. Click the Edit button/icon + 3. Scroll down to the step you want to link ingredients to + 4. Click the ellipsis button next to the step and click 'Link Ingredients' + 5. Check off the Ingredient(s) that you want to link to that step + 6. Optionally, click 'Next step' to continue linking remaining ingredients to steps, or click 'Save' to Finish + 7. Click 'Save' on the Recipe + + You can optionally link the same ingredient to multiple steps, which is useful for prepping an ingredient in one step and using it in another. + +??? question "What is fuzzy search and how do I use it?" + + ### What is fuzzy search and how do I use it? + + Mealie can use fuzzy search, which is robust to minor typos. For example, searching for "brocolli" will still find your recipe for "broccoli soup". But fuzzy search is only functional on a Postgres database backend. To enable fuzzy search you will need to migrate to Postgres: + + 1. Backup your database and download the .zip file (same as when [migrating](./migrating-to-mealie-v1.md)) + 2. Set up a [Postgres](./installation/postgres.md) instance of Mealie + 3. Upload the backup .zip and click to apply it (as as migration) + +??? question "How can I attach an image or video to a Recipe?" + + ### How can I attach an image or video to a Recipe? + + Mealie's Recipe Steps and other fields support markdown syntax and therefore support images and videos. To attach an image to the recipe, you can upload it as an asset and use the provided copy button to generate the html image tag required to render the image. For videos, Mealie provides no way to host videos. You'll need to host your videos with another provider and embed them in your recipe. Generally, the video provider will provide a link to the video and the html tag required to render the video. For example, YouTube provides the following link that works inside a step. You can adjust the width and height attributes as necessary to ensure a fit. + + ```html + + ``` + +## Customization and Configuration + +??? question "How can I change the theme?" + + ### How can I change the theme? + + You can change the theme by settings the environment variables. + + - [Backend Config - Themeing](./installation/backend-config.md#themeing) + + +??? question "How can I change the login session timeout?" + + ### How can I change the login session timeout? + + Login session can be configured by setting the `TOKEN_TIME` variable on the backend container. + + - [Backend Config](./installation/backend-config.md) + + +??? question "Can I serve Mealie on a subpath?" + + ### Can I serve Mealie on a subpath? + + No. Due to limitations from the JavaScript Framework, Mealie doesn't support serving Mealie on a subpath. + + +??? question "Can I install Mealie without docker?" + + ### Can I install Mealie without docker? + + Yes, you can install Mealie on your local machine. HOWEVER, it is recommended that you don't. Managing non-system versions of python, node, and npm is a pain. Moreover, updating and upgrading your system with this configuration is unsupported and will likely require manual interventions. + + +## Account Management + +??? question "How can I unlock my account?" + + ### How can I unlock my account? + + If your account has been locked by bad password attempts, you can use an administrator account to unlock another account. Alternatively, you can unlock all accounts via a script within the container. + + ```shell + docker exec -it mealie bash + + python /app/mealie/scripts/reset_locked_users.py + ``` + + +??? question "How can I reset admin privileges for my account?" + + ### How can I reset admin privileges for my account? + + If you've lost admin privileges and no other admin can restore them, you can use the Command Line Interface (CLI) to grant admin access. + + ```shell + docker exec -it mealie bash + + python /app/mealie/scripts/make_admin.py + ``` + + +??? question "How can I change my password?" + + ### How can I change my password? + + You can change your password by going to the user profile page and clicking the "Change Password" button. Alternatively you can use the following script to change your password via the CLI if you are locked out of your account. + + ```shell + docker exec -it mealie bash + + python /app/mealie/scripts/change_password.py + ``` + + +??? question "I can't log in with external auth. How can I change my authentication method?" + + ### I can't log in with external auth. How can I change my authentication method? + + Follow the [steps above](#how-can-i-change-my-password) for changing your password. You will be prompted if you would like to switch your authentication method back to local auth so you can log in again. + + +## Collaboration and Privacy + +??? question "How do private groups, households, and recipes work?" + + ### How do private groups, households, and recipes work? + + Managing private groups and recipes can be confusing. The following diagram and notes should help explain how they work to determine if a recipe can be shared publicly. + + - Private links that are generated from the recipe page using the `Share` button bypass all group and recipe permissions + - Private groups block all access to recipes, including those that are public, except as noted above. + - Private households, similar to private groups, block all access to recipes, except as noted above. + - Households with "Allow users outside of your group to see your recipes" disabled block all access to recipes, except as noted above. + - Private recipes block all access to the recipe from public links. This does not affect Private Links. + + ```mermaid + stateDiagram-v2 + r1: Request Access + p1: Using Private Link? + p2: Is Group Private? + p3: Is Household Private? + p4: Is Recipe Private? + s1: Deny Access + n1: Allow Access + + + r1 --> p1 + p1 --> p2: No + p1 --> n1: Yes + + p2 --> s1: Yes + p2 --> p3: No + + p3 --> s1: Yes + p3 --> p4: No + + p4 --> s1: Yes + p4 --> n1: No + ``` + + For more information on public access, check out the [Permissions and Public Access guide](./usage/permissions-and-public-access.md). For more information on groups vs. households, check out the [Groups and Households](./features.md#groups-and-households) section in the Features guide. + + +## Security and Maintenance + +??? question "How can I use Mealie externally?" + + ### How can I use Mealie externally + + Exposing Mealie or any service to the internet can pose significant security risks. Before proceeding, carefully evaluate the potential impacts on your system. Due to the unique nature of each network, we cannot provide specific steps for your setup. + + There is a community guide available for one way to potentially set this up, and you could reach out on Discord for further discussion on what may be best for your network. + + +??? question "Can I use fail2ban with Mealie?" + + ### Can I use fail2ban with Mealie? + + Yes, Mealie is configured to properly forward external IP addresses into the `mealie.log` logfile. Note that due to restrictions in docker, IP address forwarding only works on Linux. + + Your fail2ban usage should look like the following: + ``` + Use datepattern : %d-%b-%y %H:%M:%S : Day-MON-Year2 24hour:Minute:Second + Use failregex line : ^ERROR:\s+Incorrect username or password from + ``` + + +??? question "Is it safe to upgrade Mealie?" + + ### Is it safe to upgrade Mealie? + + Yes. If you are using the v1 branches (including beta), you can upgrade to the latest version of Mealie without performing a site Export/Restore. This process was required in previous versions of Mealie, however we've automated the database migration process to make it easier to upgrade. Note that if you were using the v0.5.x version, you CANNOT upgrade to the latest version automatically. You must follow the migration instructions in the documentation. + + - [Migration From v0.5.x](./migrating-to-mealie-v1.md) + + +## Technical Considerations + + +??? question "Why setup Email?" + + ### Why setup Email? + + Mealie uses email to send account invites and password resets. If you don't use these features, you don't need to set up email. There are also other methods to perform these actions that do not require the setup of Email. + + Email settings can be adjusted via environment variables on the backend container: + + - [Backend Config](./installation/backend-config.md) + + Note that many email providers (e.g., Gmail, Outlook) are disabling SMTP Auth and requiring Modern Auth, which Mealie currently does not support. You may need to use an SMTP relay or third-party SMTP provider, such as SMTP2GO. + +??? question "Why an API?" + + ### Why an API? + + An API allows integration into applications like [Home Assistant](https://www.home-assistant.io/) that can act as notification engines to provide custom notifications based on Meal Plan data to remind you to defrost the chicken, marinate the steak, or start the CrockPot. Additionally, you can access nearly any backend service via the API giving you total control to extend the application. To explore the API spin up your server and navigate to http://yourserver.com/docs for interactive API documentation. + + +??? question "Why a database?" + + ### Why a database? + + Some users of static-site generator applications like ChowDown have expressed concerns about their data being stuck in a database. Considering this is a new project, it is a valid concern to be worried about your data. Mealie specifically addresses this concern by providing automatic daily backups that export your data in json, plain-text markdown files, and/or custom Jinja2 templates. **This puts you in control of how your data is represented** when exported from Mealie, which means you can easily migrate to any other service provided Mealie doesn't work for you. + + As to why we need a database? + + - **Developer Experience:** Without a database, a lot of the work to maintain your data is taken on by the developer instead of a battle-tested platform for storing data. + - **Multi User Support:** With a solid database as backend storage for your data, Mealie can better support multi-user sites and avoid read/write access errors when multiple actions are taken at the same time. + + +## Usability + +??? question "Why is there no 'Keep Screen Alive' button when I access a recipe?" + + ### Why is there no "Keep Screen Alive" button when I access a recipe? + + You've perhaps visited the Mealie Demo and noticed that it had a "Keep Screen Alive" button, but it doesn't show up in your own Mealie instance. + There are typically two possible reasons for this: + 1. You're accessing your Mealie instance without using HTTPS. The Wake Lock API is only available if HTTPS is used. Read more here: https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API + 2. You're accessing your Mealie instance on a browser which doesn't support the API. You can test this here: https://vueuse.org/core/useWakeLock/#demo + + Solving the above points will most likely resolve your issues. However, if you're still having problems, you are welcome to create an issue. Just remember to add that you've tried the above two options first in your description. diff --git a/docs/docs/documentation/getting-started/features.md b/docs/docs/documentation/getting-started/features.md index 8e4aa6258..a068ceea5 100644 --- a/docs/docs/documentation/getting-started/features.md +++ b/docs/docs/documentation/getting-started/features.md @@ -139,6 +139,9 @@ Below is a list of all valid merge fields: - ${id} - ${slug} - ${url} +- ${servings} +- ${yieldQuantity} +- ${yieldText} To add, modify, or delete Recipe Actions, visit the Data Management page (more on that below). diff --git a/docs/docs/documentation/getting-started/installation/backend-config.md b/docs/docs/documentation/getting-started/installation/backend-config.md index 6884bd6f7..819629979 100644 --- a/docs/docs/documentation/getting-started/installation/backend-config.md +++ b/docs/docs/documentation/getting-started/installation/backend-config.md @@ -31,27 +31,27 @@ ### Database -| Variables | Default | Description | -| --------------------- | :------: | ----------------------------------------------------------------------- | -| DB_ENGINE | sqlite | Optional: 'sqlite', 'postgres' | -| POSTGRES_USER | mealie | Postgres database user | -| POSTGRES_PASSWORD | mealie | Postgres database password | -| POSTGRES_SERVER | postgres | Postgres database server address | -| POSTGRES_PORT | 5432 | Postgres database port | -| POSTGRES_DB | mealie | Postgres database name | -| POSTGRES_URL_OVERRIDE | None | Optional Postgres URL override to use instead of POSTGRES\_\* variables | + | Variables | Default | Description | + | ------------------------------------------------------- | :------: | ----------------------------------------------------------------------- | + | DB_ENGINE | sqlite | Optional: 'sqlite', 'postgres' | + | POSTGRES_USER[†][secrets] | mealie | Postgres database user | + | POSTGRES_PASSWORD[†][secrets] | mealie | Postgres database password | + | POSTGRES_SERVER[†][secrets] | postgres | Postgres database server address | + | POSTGRES_PORT[†][secrets] | 5432 | Postgres database port | + | POSTGRES_DB[†][secrets] | mealie | Postgres database name | + | POSTGRES_URL_OVERRIDE[†][secrets] | None | Optional Postgres URL override to use instead of POSTGRES\_\* variables | ### Email -| Variables | Default | Description | -| ------------------ | :-----: | ------------------------------------------------- | -| SMTP_HOST | None | Required For email | -| SMTP_PORT | 587 | Required For email | -| SMTP_FROM_NAME | Mealie | Required For email | -| SMTP_AUTH_STRATEGY | TLS | Required For email, Options: 'TLS', 'SSL', 'NONE' | -| SMTP_FROM_EMAIL | None | Required For email | -| SMTP_USER | None | Required if SMTP_AUTH_STRATEGY is 'TLS' or 'SSL' | -| SMTP_PASSWORD | None | Required if SMTP_AUTH_STRATEGY is 'TLS' or 'SSL' | +| Variables | Default | Description | +| ----------------------------------------------- | :-----: | ------------------------------------------------- | +| SMTP_HOST[†][secrets] | None | Required For email | +| SMTP_PORT[†][secrets] | 587 | Required For email | +| SMTP_FROM_NAME | Mealie | Required For email | +| SMTP_AUTH_STRATEGY | TLS | Required For email, Options: 'TLS', 'SSL', 'NONE' | +| SMTP_FROM_EMAIL | None | Required For email | +| SMTP_USER[†][secrets] | None | Required if SMTP_AUTH_STRATEGY is 'TLS' or 'SSL' | +| SMTP_PASSWORD[†][secrets] | None | Required if SMTP_AUTH_STRATEGY is 'TLS' or 'SSL' | ### Webworker @@ -72,21 +72,21 @@ Use this only when mealie is run without a webserver or reverse proxy. ### LDAP -| Variables | Default | Description | -| -------------------- | :-----: | ----------------------------------------------------------------------------------------------------------------------------------- | -| LDAP_AUTH_ENABLED | False | Authenticate via an external LDAP server in addidion to built-in Mealie auth | -| LDAP_SERVER_URL | None | LDAP server URL (e.g. ldap://ldap.example.com) | -| LDAP_TLS_INSECURE | False | Do not verify server certificate when using secure LDAP | -| LDAP_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) | -| LDAP_ENABLE_STARTTLS | False | Optional. Use STARTTLS to connect to the server | -| LDAP_BASE_DN | None | Starting point when searching for users authentication (e.g. `CN=Users,DC=xx,DC=yy,DC=de`) | -| LDAP_QUERY_BIND | None | Optional bind user for LDAP search queries (e.g. `cn=admin,cn=users,dc=example,dc=com`). If `None` then anonymous bind will be used | -| LDAP_QUERY_PASSWORD | None | Optional password for the bind user used in LDAP_QUERY_BIND | -| LDAP_USER_FILTER | None | Optional LDAP filter to narrow down eligible users (e.g. `(memberOf=cn=mealie_user,dc=example,dc=com)`) | -| LDAP_ADMIN_FILTER | None | Optional LDAP filter, which tells Mealie the LDAP user is an admin (e.g. `(memberOf=cn=admins,dc=example,dc=com)`) | -| LDAP_ID_ATTRIBUTE | uid | The LDAP attribute that maps to the user's id | -| LDAP_NAME_ATTRIBUTE | name | The LDAP attribute that maps to the user's name | -| LDAP_MAIL_ATTRIBUTE | mail | The LDAP attribute that maps to the user's email | +| Variables | Default | Description | +| ----------------------------------------------------- | :-----: | ----------------------------------------------------------------------------------------------------------------------------------- | +| LDAP_AUTH_ENABLED | False | Authenticate via an external LDAP server in addidion to built-in Mealie auth | +| LDAP_SERVER_URL[†][secrets] | None | LDAP server URL (e.g. ldap://ldap.example.com) | +| LDAP_TLS_INSECURE | False | Do not verify server certificate when using secure LDAP | +| LDAP_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) | +| LDAP_ENABLE_STARTTLS | False | Optional. Use STARTTLS to connect to the server | +| LDAP_BASE_DN | None | Starting point when searching for users authentication (e.g. `CN=Users,DC=xx,DC=yy,DC=de`) | +| LDAP_QUERY_BIND | None | Optional bind user for LDAP search queries (e.g. `cn=admin,cn=users,dc=example,dc=com`). If `None` then anonymous bind will be used | +| LDAP_QUERY_PASSWORD[†][secrets] | None | Optional password for the bind user used in LDAP_QUERY_BIND | +| LDAP_USER_FILTER | None | Optional LDAP filter to narrow down eligible users (e.g. `(memberOf=cn=mealie_user,dc=example,dc=com)`) | +| LDAP_ADMIN_FILTER | None | Optional LDAP filter, which tells Mealie the LDAP user is an admin (e.g. `(memberOf=cn=admins,dc=example,dc=com)`) | +| LDAP_ID_ATTRIBUTE | uid | The LDAP attribute that maps to the user's id | +| LDAP_NAME_ATTRIBUTE | name | The LDAP attribute that maps to the user's name | +| LDAP_MAIL_ATTRIBUTE | mail | The LDAP attribute that maps to the user's email | ### OpenID Connect (OIDC) @@ -94,23 +94,22 @@ Use this only when mealie is run without a webserver or reverse proxy. For usage, see [Usage - OpenID Connect](../authentication/oidc-v2.md) -| Variables | Default | Description | -|---------------------------------------------------|:-------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| OIDC_AUTH_ENABLED | False | Enables authentication via OpenID Connect | -| OIDC_SIGNUP_ENABLED | True | Enables new users to be created when signing in for the first time with OIDC | -| OIDC_CONFIGURATION_URL | None | The URL to the OIDC configuration of your provider. This is usually something like https://auth.example.com/.well-known/openid-configuration | -| OIDC_CLIENT_ID | None | The client id of your configured client in your provider | -| OIDC_CLIENT_SECRET
:octicons-tag-24: v2.0.0 | None | The client secret of your configured client in your provider | -| OIDC_USER_GROUP | None | If specified, only users belonging to this group will be able to successfully authenticate. For more information see [this page](../authentication/oidc-v2.md#groups) | -| OIDC_ADMIN_GROUP | None | If specified, users belonging to this group will be able to successfully authenticate *and* be made an admin. For more information see [this page](../authentication/oidc-v2.md#groups) | -| OIDC_AUTO_REDIRECT | False | If `True`, then the login page will be bypassed and you will be sent directly to your Identity Provider. You can still get to the login page by adding `?direct=1` to the login URL | -| OIDC_PROVIDER_NAME | OAuth | The provider name is shown in SSO login button. "Login with " | -| OIDC_REMEMBER_ME | False | Because redirects bypass the login screen, you cant extend your session by clicking the "Remember Me" checkbox. By setting this value to true, a session will be extended as if "Remember Me" was checked | -| OIDC_USER_CLAIM | email | This is the claim which Mealie will use to look up an existing user by (e.g. "email", "preferred_username") | -| OIDC_NAME_CLAIM | name | This is the claim which Mealie will use for the users Full Name | -| OIDC_GROUPS_CLAIM | groups | Optional if not using `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP`. This is the claim Mealie will request from your IdP and will use to compare to `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP` to allow the user to log in to Mealie or is set as an admin. **Your IdP must be configured to grant this claim** | -| OIDC_SCOPES_OVERRIDE | None | Advanced configuration used to override the scopes requested from the IdP. **Most users won't need to change this**. At a minimum, 'openid profile email' are required. | -| OIDC_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) | +| Variables | Default | Description | +| ----------------------------------------------------------------------------------- | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| OIDC_AUTH_ENABLED | False | Enables authentication via OpenID Connect | +| OIDC_SIGNUP_ENABLED | True | Enables new users to be created when signing in for the first time with OIDC | +| OIDC_CONFIGURATION_URL[†][secrets] | None | The URL to the OIDC configuration of your provider. This is usually something like https://auth.example.com/.well-known/openid-configuration | +| OIDC_CLIENT_ID[†][secrets] | None | The client id of your configured client in your provider | +| OIDC_CLIENT_SECRET[†][secrets]
:octicons-tag-24: v2.0.0 | None | The client secret of your configured client in your provider | +| OIDC_USER_GROUP | None | If specified, only users belonging to this group will be able to successfully authenticate, regardless of the `OIDC_ADMIN_GROUP`. For more information see [this page](../authentication/oidc.md#groups) | +| OIDC_ADMIN_GROUP | None | If specified, users belonging to this group will be made an admin. For more information see [this page](../authentication/oidc.md#groups) | +| OIDC_AUTO_REDIRECT | False | If `True`, then the login page will be bypassed an you will be sent directly to your Identity Provider. You can still get to the login page by adding `?direct=1` to the login URL | +| OIDC_PROVIDER_NAME | OAuth | The provider name is shown in SSO login button. "Login with " | +| OIDC_REMEMBER_ME | False | Because redirects bypass the login screen, you cant extend your session by clicking the "Remember Me" checkbox. By setting this value to true, a session will be extended as if "Remember Me" was checked | +| OIDC_SIGNING_ALGORITHM | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) | +| OIDC_USER_CLAIM | email | This is the claim which Mealie will use to look up an existing user by (e.g. "email", "preferred_username") | +| OIDC_GROUPS_CLAIM | groups | Optional if not using `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP`. This is the claim Mealie will request from your IdP and will use to compare to `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP` to allow the user to log in to Mealie or is set as an admin. **Your IdP must be configured to grant this claim** | +| OIDC_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) | ### OpenAI @@ -119,17 +118,13 @@ For usage, see [Usage - OpenID Connect](../authentication/oidc-v2.md) Mealie supports various integrations using OpenAI. For more information, check out our [OpenAI documentation](./open-ai.md). For custom mapping variables (e.g. OPENAI_CUSTOM_HEADERS) you should pass values as JSON encoded strings (e.g. `OPENAI_CUSTOM_PARAMS='{"k1": "v1", "k2": "v2"}'`) -| Variables | Default | Description | -| ---------------------------- | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| OPENAI_BASE_URL | None | The base URL for the OpenAI API. If you're not sure, leave this empty to use the standard OpenAI platform | -| OPENAI_API_KEY | None | Your OpenAI API Key. Enables OpenAI-related features | -| OPENAI_MODEL | gpt-4o | Which OpenAI model to use. If you're not sure, leave this empty | -| OPENAI_CUSTOM_HEADERS | None | Custom HTTP headers to add to all OpenAI requests. This should generally be left empty unless your custom service requires them | -| OPENAI_CUSTOM_PARAMS | None | Custom HTTP query params to add to all OpenAI requests. This should generally be left empty unless your custom service requires them | -| OPENAI_ENABLE_IMAGE_SERVICES | True | Whether to enable OpenAI image services, such as creating recipes via image. Leave this enabled unless your custom model doesn't support it, or you want to reduce costs | -| OPENAI_WORKERS | 2 | Number of OpenAI workers per request. Higher values may increase processing speed, but will incur additional API costs | -| OPENAI_SEND_DATABASE_DATA | True | Whether to send Mealie data to OpenAI to improve request accuracy. This will incur additional API costs | -| OPENAI_REQUEST_TIMEOUT | 60 | The number of seconds to wait for an OpenAI request to complete before cancelling the request. Leave this empty unless you're running into timeout issues on slower hardware | +| Variables | Default | Description | +| ------------------------------------------------- | :-----: | ---------------------------------------------------------------------------------------------------------------------- | +| OPENAI_BASE_URL[†][secrets] | None | The base URL for the OpenAI API. If you're not sure, leave this empty to use the standard OpenAI platform | +| OPENAI_API_KEY[†][secrets] | None | Your OpenAI API Key. Enables OpenAI-related features | +| OPENAI_MODEL | gpt-4o | Which OpenAI model to use. If you're not sure, leave this empty | +| OPENAI_WORKERS | 2 | Number of OpenAI workers per request. Higher values may increase processing speed, but will incur additional API costs | +| OPENAI_SEND_DATABASE_DATA | True | Whether to send Mealie data to OpenAI to improve request accuracy. This will incur additional API costs | ### Theming @@ -154,24 +149,80 @@ Setting the following environmental variables will change the theme of the front ### Docker Secrets -Setting a credential can be done using secrets when running in a Docker container. -This can be used to avoid leaking passwords through compose files, environment variables, or command-line history. -For example, to configure the Postgres database password in Docker compose, create a file on the host that contains only the password, and expose that file to the Mealie service as a secret with the correct name. -Note that environment variables take priority over secrets, so any previously defined environment variables should be removed when migrating to secrets. +### Docker Secrets + +> Starting in version `2.4.2`, any environment variable in the preceding lists with a dagger +> symbol next to them support the Docker Compose secrets pattern, below. +[Docker Compose secrets][docker-secrets] can be used to secure sensitive information regarding the Mealie implementation +by managing control of each secret independently from the single `.env` file. This is helpful for users that may need +different levels of access for various, sensitive environment variables, such as differentiating between hardening +operations (e.g., server endpoints and ports) and user access control (e.g., usernames, passwords, and API keys). + +To convert any of these environment variables to a Docker Compose secret, append `_FILE` to the environment variable and +connect it with a Docker Compose secret, per the [Docker documentation][docker-secrets]. + +If both the base environment variable and the secret pattern of the environment variable are set, the secret will always +take precedence. + +For example, a user that wishes to harden their operations by only giving some access to their database URL, but who +wish to place additional security around their user access control, may have a Docker Compose configuration similar to: + ```yaml services: mealie: - ... - environment: - ... - POSTGRES_USER: postgres secrets: - - POSTGRES_PASSWORD + # These secrets will be loaded by Docker into the `/run/secrets` folder within the container. + - postgres-host + - postgres-port + - postgres-db-name + - postgres-user + - postgres-password + environment: + DB_ENGINE: postgres + POSTGRES_SERVER: duplicate.entry.tld # This will be ignored, due to the secret defined, below. + POSTGRES_SERVER_FILE: /run/secrets/postgres-host + POSTGRES_PORT_FILE: /run/secrets/postgres-port + POSTGRES_DB_FILE: /run/secrets/postgres-db-name + POSTGRES_USER_FILE: /run/secrets/postgres-user + POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password + +# Each of these secrets are loaded via these local files. Different patterns are available. See the Docker Compose +# documentation for more information. secrets: - POSTGRES_PASSWORD: - file: postgrespassword.txt + postgres-host: + file: ./secrets/postgres-host.txt + postgres-port: + file: ./secrets/postgres-port.txt + postgres-db-name: + file: ./secrets/sensitive/postgres-db-name.txt + postgres-user: + file: ./secrets/sensitive/postgres-user.txt + postgres-password: + file: ./secrets/sensitive/postgres-password.txt +``` +In the example above, a directory organization and access pattern may look like the following: +```text +. +โ”œโ”€โ”€ docker-compose.yml +โ””โ”€โ”€ secrets # Access restricted to anyone that can manage secrets + โ”œโ”€โ”€ postgres-host.txt + โ”œโ”€โ”€ postgres-port.txt + โ””โ”€โ”€ sensitive # Access further-restricted to anyone managing service accounts + โ”œโ”€โ”€ postgres-db-name.txt + โ”œโ”€โ”€ postgres-password.txt + โ””โ”€โ”€ postgres-user.txt ``` +How you organize your secrets is ultimately up to you. At minimum, it's highly recommended to use secret patterns for +at least these sensitive environment variables when working within shared environments: + +- `POSTGRES_PASSWORD` +- `SMTP_PASSWORD` +- `LDAP_QUERY_PASSWORD` +- `OPENAI_API_KEY` + +[docker-secrets]: https://docs.docker.com/compose/use-secrets/ +[secrets]: #docker-secrets [unicorn_workers]: https://www.uvicorn.org/deployment/#built-in diff --git a/docs/docs/documentation/getting-started/installation/installation-checklist.md b/docs/docs/documentation/getting-started/installation/installation-checklist.md index f941a7e0d..16277a4dd 100644 --- a/docs/docs/documentation/getting-started/installation/installation-checklist.md +++ b/docs/docs/documentation/getting-started/installation/installation-checklist.md @@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do: 1. Take a backup just in case! -2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v2.3.0` +2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v2.6.0` 3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access. 4. Restart the container diff --git a/docs/docs/documentation/getting-started/installation/postgres.md b/docs/docs/documentation/getting-started/installation/postgres.md index b4a9d35d5..f845bd74f 100644 --- a/docs/docs/documentation/getting-started/installation/postgres.md +++ b/docs/docs/documentation/getting-started/installation/postgres.md @@ -7,7 +7,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In ```yaml services: mealie: - image: ghcr.io/mealie-recipes/mealie:v2.3.0 # (3) + image: ghcr.io/mealie-recipes/mealie:v2.6.0 # (3) container_name: mealie restart: always ports: @@ -45,6 +45,7 @@ services: environment: POSTGRES_PASSWORD: mealie POSTGRES_USER: mealie + PGUSER: mealie healthcheck: test: ["CMD", "pg_isready"] interval: 30s diff --git a/docs/docs/documentation/getting-started/installation/sqlite.md b/docs/docs/documentation/getting-started/installation/sqlite.md index f1b22bcb9..a5dc2e5cf 100644 --- a/docs/docs/documentation/getting-started/installation/sqlite.md +++ b/docs/docs/documentation/getting-started/installation/sqlite.md @@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th ```yaml services: mealie: - image: ghcr.io/mealie-recipes/mealie:v2.3.0 # (3) + image: ghcr.io/mealie-recipes/mealie:v2.6.0 # (3) container_name: mealie restart: always ports: diff --git a/docs/docs/news/surveys/2024-october/Question2.png b/docs/docs/news/surveys/2024-october/Question2.png new file mode 100644 index 000000000..c68aef572 Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question2.png differ diff --git a/docs/docs/news/surveys/2024-october/Question3.png b/docs/docs/news/surveys/2024-october/Question3.png new file mode 100644 index 000000000..b46cf99c6 Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question3.png differ diff --git a/docs/docs/news/surveys/2024-october/Question4.png b/docs/docs/news/surveys/2024-october/Question4.png new file mode 100644 index 000000000..e2682aed7 Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question4.png differ diff --git a/docs/docs/news/surveys/2024-october/Question5.png b/docs/docs/news/surveys/2024-october/Question5.png new file mode 100644 index 000000000..7cd3f4bbc Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question5.png differ diff --git a/docs/docs/news/surveys/2024-october/Question6.png b/docs/docs/news/surveys/2024-october/Question6.png new file mode 100644 index 000000000..80a03ee9f Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question6.png differ diff --git a/docs/docs/news/surveys/2024-october/Question7.png b/docs/docs/news/surveys/2024-october/Question7.png new file mode 100644 index 000000000..8bd281ffd Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question7.png differ diff --git a/docs/docs/news/surveys/2024-october/Question8.png b/docs/docs/news/surveys/2024-october/Question8.png new file mode 100644 index 000000000..d9f48c134 Binary files /dev/null and b/docs/docs/news/surveys/2024-october/Question8.png differ diff --git a/docs/docs/news/surveys/2024-october/overview.md b/docs/docs/news/surveys/2024-october/overview.md new file mode 100644 index 000000000..6c691ee13 --- /dev/null +++ b/docs/docs/news/surveys/2024-october/overview.md @@ -0,0 +1,126 @@ +# October 2024 Survey + +It's been a while since a Mealie survey was done, and the community was much smaller back then. So much has changed in 2024, and we wanted to gauge the community's thoughts. +Our v2.0 release gave us a platform to ask people to take a few minutes to share their thoughts. + +A massive thanks to everyone who took the time to fill out this survey. We had 525 respondents! We're overwhelmed with the support. + +Also, thanks to ChristianB-F from our Discord community for putting the following images together, and to everyone who has taken the time to raise either an issue or pull request on our GitHub repository! + +For each question, we've created a GitHub discussion and we invite you to share any interesting insights or thoughts you have from the survey results! +If you see a specific idea that resonates with you, please check if there's already a feature request, and if not, please raise one and add your perspective. + +The questions (bar question 1) that are free text are on separate pages you'll need to click into, as there's just too much content to include on this page. + +For the written response sections, we have removed some of the more indifferent responses (e.g., "N/A") to save you reading time. If you'd like to see all the raw responses, they're in [this GitHub commit](https://github.com/mealie-recipes/mealie/pull/4666/commits/1287bc1635d9c2560b10db3a92a0d6644bc81571). + +## Structured Questions + +### Mealie Version (pre-v2) + +This question was free text input and it was mandatory. + +The responses to this were so varied and not overly informative/indicative of anything, so we've decided not to publish them - both to save space and your time. + +### Database Type + +This question was a single select and it was optional. + +Key insight: SQLite is the predominant database, but Postgres maintains an admirable share and must remain front of mind for any changes we make. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4640) + +![Question 2](Question2.png) + +### Time Using Mealie + +How long have you been using Mealie? This question was a single select and it was mandatory. + +Key insight: Most users have been using Mealie less than a year, with another 25% in the 1-2 year range. These users will have seen a lot of change in the product over that time. +Thanks to the long term users! + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4641) + +![Question 3](Question3.png) + +### Engagement with Mealie, the Project, and the Community + +This question was multiple choice and it was optional. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4642) + +![Question 4](Question4.png) + +### Number of Active Users + +This question was a single select and it was mandatory. + +Key insight: ~85% of instances have 2 users or fewer. This is assumed to be a couple of adults living together. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4643) + +![Question 5](Question5.png) + +### Number of Active Groups + +This question was a single select and it was mandatory. + +Key insight: Similar to the above question, one group being the most common backs the theory of one "family" using the Mealie instance. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4644) + +![Question 6](Question6.png) + +### Using Mealie on Mobile + +Do you access Mealie on a mobile? Using your browser or with it installed as an app (a Progressive Web App/PWA)? This question was a multiple select and it was mandatory. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4645) + +![Question 7](Question7.png) + +### Feature Usage + +Please select all the features you actively/regularly use, or consider important. This question was a multiple select and it was optional. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4646) + +![Question 8](Question8.png) + +## Suggestions/Feedback + +Some of you will spot feature suggestions that you know to already exist in Mealie. We'd love it if you could help us improve the documentation so more people can know about them! All pull requests are much appreciated. The [features](https://docs.mealie.io/documentation/getting-started/features/) page, or the [FAQ](https://docs.mealie.io/documentation/getting-started/faq/) could be appropriate places to add documentation. + +### Shopping List Suggestions + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4647) + +[Question 9](q9.md) + +### Meal Planner Suggestions + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4648) + +[Question 10](q10.md) + +### Recipe Timeline Suggestions + +Key insight: Looks like a lot of people would be fine with this not existing, or at least being hidden. + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4649) + +[Question 11](q11.md) + +### Recipe Suggestions + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4650) + +[Question 12](q12.md) + +### Other Suggestions + +There are so many kind words in this section in particular. Thanks so much, it means a lot to the whole team and all our contributors to see the impact Mealie has on people's lives! + +[GitHub Discussion](https://github.com/mealie-recipes/mealie/discussions/4651) + +[Question 13](q13.md) diff --git a/docs/docs/news/surveys/2024-october/q10.md b/docs/docs/news/surveys/2024-october/q10.md new file mode 100644 index 000000000..97ae6fbd9 --- /dev/null +++ b/docs/docs/news/surveys/2024-october/q10.md @@ -0,0 +1,227 @@ +[Back to the overview](overview.md) + +# Question 10: Any suggestions for how to improve the Meal Planner? + +> again mostly visual, I think it works well as is for my needs but the interface could use some improvements + +> The ability to open a recipe in a new tab from Edit mode. You can do this in the View only mode, but when editing the meal plan, it would be nice to easily get to a recipe to see what ingredients there are. I am often checking recipes to see if I already have the ingredients in my cupboard, as part of making a plan for my weekly meal plan. Not being able to quickly see the recipe is a little annoying. + +> If Not fixed jet, integrate Portions e.g. 200g sugger and 2egg for two people and 400g sugger and 4eggs for 4 people + +> I live alone, so I almost always have leftovers from a meal. Would love for the meal planner to be able to see how many portions a recipe makes, and if its more than the number of people eating it automatically makes leftover meals for the next days. I know you can create notes manually currently, but that's a lot of work. + +> Option for "friendly mode" when selecting a date, I.e. "next Tuesday" or "two Wednesday's from today" + +> Add a label with the name of the user who added a meal to the planner in case of two or more users in the same household don't share the same dish. + +> editing is a separate button/step. It would be nice if that would be more intuitive/user friendly + +> - two week view, month view - drag & drop - mass add to shopping list + +> It would be very helpful if the meal planner had an option that helps the user to find recipes with some of the similar ingredients, so that it's easier to use all of the groceries bought. + +> Allow to set the same food every day of the week if needed + +> Synchronize Meal Plan via ics calendar + +> Add a button to automatically fill the whole week (or a predetermined number of days). (Wasn't that an option before?) Add the choice of having the full week (Monday to Sunday) stay in place until the new week. Now the meal planner changes to the current day and adds the chosen number of days to display, which always creates a new empty day. + +> Improve import + +> A better sliding window of plans. I've found looking back to previous weeks clunky. Most of the time, we only care about this upcoming week but once in a while we'll plan a couple weeks out. I know you can expand the view to be more than 7 days; however, beyond planning, I typically only care about a few days in advance once the plan has been set. + +> We create meal plans for the next 7 days but are not fixed to what meals have to be made on which dates. It's more flexible in practice. The Meal Planner as-is is a bit in-flexible in this aspect. Being able to check-off meals as they have been made. As above, are meal plans have to be flexible so being able to mark meals as 'made' or done, makes it easier to see what is left for the rest of the week. + +> So the meal planner I find it to be the weakest yet the most important point of Mealie. My main issue is that there are only 4 fixed meals. There are some diet plans that have some intermediate snacks and stuff like that, so the best thing would be to have free control on how many meals each day can have, and perhaps have some rules like "mondays have the standard 4 meals" and "tuesdays have these 4 snacks in middle of the meals" or "wednesdays have these customs meals", so I can set as many meals each day with its custom names on them. The logic would be that I have a "meals" database so I create the object like "morning snack" and then I can apply rules like having a fruit on my morning snack and a power bar on my "afternoon snack". - Also would be cool to have a randomizer for the whole week or month after proper rules were established that autofills the meals set for each day, so I can plan my groceries in advance and save a good amount of repetitive clicking. - In the case of each day's random meal, its strange that there is a button for 2 different meals, but dinner and side have their own buttons. They should have eiother their own button each, or be all toghether in one menu - The possibilty of marking special days like birthdays so these days wont autofill with the suggested randomizer, ignore the rules, and instead would require user input for planning these special meals + +> So far it works. It could use some UX changes to improve the flow, certain sizing on mobile would be nice. I am using it with a couple of rules, and made a feature request about this already. + +> Create an option to create singular list, that does not tie recipe to specific date. When I create a meal plan, my idea is to use it as a todo list, not deciding upfront what will be done on each day. Currently I am not using meal planner at all, because it really cumbersome for me. + +> 1. have a check box so a week could be automatically selected. maybe use the week of the year, ie check box next to Week 47 that would select Sunday - Saturday 2. to be able to click and drag the recipes between the days of the week. so if i didn't want make it on Monday but Tuesday instead i can just drag the recipe cards to the new days. 3. having a Today button in the drop down calendar in case you plan a few weeks ahead + +> Being able to go back to previous dates and batch edit the meal plan without having to set the dates after each single edit + +> A wizard for creating a meal plan for a given period + +> Easy integration of daily meal image into Home assistant. eg a HACS addon? + +> More options to auto create e.g. based on ingredients such as pick recipes that total 500g minced beef or 2 meals that include pulled pork. Include macro tracking e.g. total planned calories and average calories + +> I was very excited about a "Meal Planner" feature when I first saw it, but it was not what I was expecting. I wanted to be able to collect several recipes into a single "meal", e.g., a soup, a starter, a main, and a desert; or combine my home made steak sauce recipe with my grilled steak recipe for a more complete meal without having to duplicate recipes in multiple records. This would be particularly helpful for large holiday gatherings or dinner parties. Once collected, it could provide a master ingredients list and help with organizing the sequencing of the cooking. + +> Ability to reorder meals without switching to edit mode. (Very minor) + +> It could be here that you pick the number of people a recipe is for when you add it to a plan. Currently, to double a recipe we have to add it twice to the meal planner and list. Also, drag n drop doesn't work great when editing plans on a tablet (android). + +> No I like the meal planner. Integration with the shopping list would be awesome. As in, add the ingredients from recipes on the planner to the shopping list. + +> Allow a default view instead of "today forward. (For example, "x previous days" or "this week") Remove the modes and integrate editing with viewing Default to "today" (or "first blank dinner/etc slot") when adding entries. + +> As per previous shopping list comments. Really appreciate and like the planner. It makes managing the week's meals and shopping so much easier! + +> Add https://github.com/mealie-recipes/mealie/discussions/1761, it would make it easier for me to make many recipes of like tacos or pizzas with base seasoning mixes/dough mixes and individual recipe customizations on top. + +> Please add more entry type/food type on planner. In Poland the main dish is at 1-4 P.M. It's called obiad but it's related to lunch. But because it's main meal, we usually have 2 dishes: soup (zupa) and the second dish (drugie danie). It would be great to have separate entry type for soups and the second dished. So in generally, please allow to define own entry types in planner (like in Tandoor Recipes). + +> On the meal planner screen, I feel like there should be a button for immediately adding or randomizing a meal for any given day that is blank. Thereโ€™s something about having to go into edit mode first when youโ€™re creating a meal plan on a blank day that seems unintuitive. To my brain โ€œEditโ€ means to change something that exists, not to create from scratch. Not a big issue obviously but I notice it every time. + +> It could be that Iโ€™m missing something, but excluding meals from categories when using random selection. For example, let me disable adding foods labeled โ€œDessertโ€ when randomizing. + +> Same here. Make it removable via env. + +> Mealie has done a great job. If you have to ask questions, I hope to support the