Giter VIP home page Giter VIP logo

kcal's Introduction

kcal – the personal food nutrition journal

License: MPL 2.0 CI Status Coverage Status

Track nutritional information about foods and recipes, set goals, and record a food journal to help along the way. Kcal is a personal system that focuses on direct control of inputs (as opposed to unwieldy user generated datasets) and a minimal, easy to use recipe presentation for preparing meals.

Screenshots

kcal mobile screenshot kcal desktop screenshot

Functionality

Kcal's primary functionality includes three main content categories -- journal, recipes, and foods -- and two per-user configurations -- goals and meals. Users can customize meals (up to eight per day) for meal planning, set multiple goals for tracking calories and macros (fat, carbohydrates, protein), enter food data with calories and macros, create recipes based on foods and other recipes, and record foods and recipes in a journal tracked against goals.

Foods

Foods are shared between all users.

Foods are the basis for recipes and calorie and macro calculations throughout the app. They can be added directly to journal entries and included in recipes that roll-up nutritional data per serving.

Food servings can be recorded using U.S. measure units (teaspoon, tablespoon, cup) and use a weight basis of grams. These units and weights are commonly used in the United States and required by law for most packaged foods. Kcal tries to make data entry as easy as possible by organization field order and units to match nutritional label configurations.

Food data does not (currently) make use of any API or service for retrieving information about food. While this may change in the future, there are a couple of reason this feature has been left out of kcal:

  • There is a very large volume of data in most food databases such that organizing, categorizing, and searching for the right food can be daunting.

  • Food databases that allow and include input from large groups of users can be inaccurate and counter-productive for users with calorie and/or macro goals.

  • Kcal's self-hostable nature is in part for privacy-conscious users so limiting interactions with third-party services is desirable (though adding APIs as an optional enhancement is not a major concern here).

Foods are taggable and tags can be used to filter and search for foods quickly.

kcal foods edit and show screenshot

Recipes

Recipes are shared between all users. They (currently) cannot be shared externally, but a feature enhancement to support optional, per-recipe public link creation is planned.

Configurable recipe metadata includes servings, weight, volume, timing, image, description, ingredients, and steps.

The recipe view is meant to be as uncluttered as possible, to support browser "reader mode", and to still provide nutritional metadata at a glance.

Recipes are taggable and tags can be used to filter and search for recipes quickly.

kcal foods edit and show screenshot

Journal entries

Journal entries are private. Each user has and can only see their own entries.

Planning and tracking calories and macros is the primary focus of journal entries. The journal section aggregates this information by day and by meal.

Recipes and foods can be added to journal entries in various quantities and configurations (depending on the associated serving data). Manual entries can also be used to record data for foods and recipes not in the kcal's database.

Journal entries are not editable. The calorie and macro information for each entry is recorded with the entry. This allows for recoding and maintaining journal entry data even as foods and recipes are updated.

kcal journal entries edit and show screenshot

Goals

Goals are private. Each user can create and see only their own goals.

Goals reflect daily calories and macros and are therefore closely related to journal entries.

Goals can be configured as "default" for specific days of the week but can also be overridden for individual days in the journal section.

There is no limit to the number of goals a user can create.

kcal goals edit and show screenshot

Meals

Meals are private. Each user can rename, arrange, and enable or disabled their own meals.

Meals are used to aggregate data within a day in the journal section and can be used for both meal planning and goal tracking.

There is a pre-configured maximum of eight meals for each user.

kcal meals edit and show screenshot

Use cases

Kcal's primary focus is tracking nutrition (recipe management is the most important secondary focus), so it should be a useful tool for anyone looking to implement a specific diet. Below are some (very) broad diet types and information about how kcal can be helpful. Kcal intentionally does not provide any specific dieting guidance or recommend any particular diet or type of diet. Individual users are expected to research and make their own plans and goals -- kcal is here to help record and organize the data.

Hypocaloric diets

Hypocaloric diets use calorie restriction for weight loss or other dietary management. Kcal users can create low calorie (relative to personal regular calorie) intake goals and use the detailed nutritional data of food and recipes and to plan meals and record caloric intake using journal entries.

Hypercaloric diets

Hypercaloric diets are used for weight gain and can be especially useful for building muscle in weight training. Kcal users can create calorie goals that exceed expected calorie burn on a day-to-day basis. For the weight training example users can create a goal for training days and separate, lower goal for rest days. The goals can be automated based on the day of the week and journal entries can be used to ensure that a proper macro balance is maintained. More meals may also be helpful on a hypercaloric diet and kcal supports up to eight meals per day.

Plant based diets (vegetarian, vegan, etc.)

Diets that exclude animal-based products may require special attention to ensure a proper balance of nutrients (particularly when transitioning). Kcal's goals and food nutritional data can help to make sure that appropriate fat, carbohydrate, and protein needs are met.

Low-X diets

Any diet that focuses on lowering a particular nutrient can be trackable with kcal. In addition to the macronutrients (fat, carbohydrates, and protein) foods support cholesterol and sodium data as well. Support for other common nutrients like saturated fats, trans fats, fiber, sugar, etc. may also be available in future iterations.

Deployment

Docker is the recommended deployment method. See kcal-app/kcal-docker.

General requirements for any deployment are:

  • PHP 8.x with Composer 2.x and PHP extensions: bcmath, curl, gd, intl, mbstring, xml, zip.
  • Web server/proxy (Apache, nginx, etc.)
  • Database (MySQL/MariaDB, PostgreSQL, etc.)

Optional but useful additions are:

Docker

There is a Dockerfile and automated build process to create builds at kcalapp/kcal on Docker Hub. See the kcal-app/kcal-docker repository for a Docker Compose based template and instructions.

Manual

This deployment process has been tested with an Ubuntu 20.04 LTS instance with 2GB of memory which should be enough to host the app for a few regular users. The memory is primarily needed for Elasticsearch -- See the Search section for other options if lower memory support is needed.

  1. Add PHP 8.x repository.

    sudo apt-get install software-properties-common
    sudo add-apt-repository ppa:ondrej/php
    
  2. Add Elasticsearch 7.x repository.

    wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
    echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-7.x.list
    
  3. Update available packages.

    sudo apt-get update
    
  4. Install dependencies.

    sudo apt-get install elasticsearch mysql-server-8.0 nginx-full php8.2 php8.2-bcmath php8.2-cli php8.2-curl php8.2-gd php8.2-intl php8.2-mbstring php8.2-mysql php8.2-redis php8.2-xml php8.2-zip redis php8.2-fpm
    
  5. Start Elasticsearch and configure to run at start up.

    sudo systemctl start elasticsearch
    sudo systemctl enable elasticsearch
    
  6. Install Composer.

    🚨 This command runs code from a remote location as root. See Download Composer for alternative install options.

    curl -s https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin/ --filename=composer
    
  7. Clone the app repository.

    cd /var/www
    sudo mkdir kcal
    sudo chown $USER:`id -gn $USER` kcal
    cd kcal
    git clone https://github.com/kcal-app/kcal.git .
    
  8. Configure nginx to serve the app public files.

    sudo vim /etc/nginx/conf.d/kcal.conf
    <edit config, see example below>
    sudo service nginx restart
    

    Example config:

    server {
        listen 80;
        server_name kcal.example.com;
        root /var/www/kcal/public;
        
        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-Content-Type-Options "nosniff";
        
        index index.php;
        
        charset utf-8;
        
        location / {
           try_files $uri $uri/ /index.php?$query_string;
        }
        
        location = /favicon.ico { access_log off; log_not_found off; }
        location = /robots.txt  { access_log off; log_not_found off; }
        
        error_page 404 /index.php;
        
        location ~ \.php$ {
           fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
           fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
           include fastcgi_params;
        }
        
        location ~ /\.(?!well-known).* {
           deny all;
        }
    }
    
  9. Create database user.

    sudo mysql -u root
    CREATE DATABASE `kcal`;
    CREATE USER 'kcal'@'localhost' IDENTIFIED BY RANDOM PASSWORD;
    GRANT ALL ON `kcal`.* TO 'kcal'@'localhost';
    FLUSH PRIVILEGES;
    

    πŸ”’ Save the generated password output by the CREATE USER statement.

  10. Install dependencies and generate an app key to use in the next step.

    composer install --optimize-autoloader --no-dev
    php artisan --no-ansi key:generate --show
    
  11. Copy environment config file and adjust as desired.

    cp .env.example .env
    

    At a minimum:

    • Set APP_KEY to the value generated in the previous step.
    • Set APP_URL to match the host configured in nginx configuration.
    • Set the DATABASE_ values to the configured credentials.
  12. Run initial app installation/bootstrap commands.

    php artisan migrate
    php artisan elastic:migrate
    php artisan config:cache
    php artisan route:cache
    php artisan view:cache
    php artisan user:add --admin
    
  13. Allow web server to access required directories.

    sudo chown -R $USER:www-data {storage,public}
    sudo chmod g+s {storage,public}
    
  14. Visit the APP_URL and log in!

Configuration

Media Storage

Recipes and users can have associated media (images) that by default are stored on a local disk under the path {app}/public/media. If a local disk solution is not feasible, an AWS S3 bucket can be used instead.

AWS S3

Use the general guidance below to create an AWS S3 bucket and IAM user for media storage in AWS S3.

  1. Create a bucket that allows objects to be configured with public access.

  2. Create an IAM user with access to the bucket.

    Use this example policy to grant necessary permissions to a specific bucket:

    {
        "Version": "2012-10-17",
        "Statement": [
           {
              "Sid": "VisualEditor0",
              "Effect": "Allow",
              "Action": [
                  "s3:GetBucketPublicAccessBlock",
                  "s3:GetBucketPolicyStatus",
                  "s3:GetAccountPublicAccessBlock",
                  "s3:ListAllMyBuckets",
                  "s3:GetBucketAcl",
                  "s3:GetBucketLocation"
              ],
              "Resource": "*"
           },
           {
              "Sid": "VisualEditor1",
              "Effect": "Allow",
              "Action": "s3:ListBucket",
              "Resource": "arn:aws:s3:::REPLACE_WITH_S3_BUCKET_NAME"
           },
           {
              "Sid": "VisualEditor2",
              "Effect": "Allow",
              "Action": ["s3:*Object", "s3:*ObjectAcl*"],
              "Resource": "arn:aws:s3:::REPLACE_WITH_S3_BUCKET_NAME/*"
           }
        ]
    }
    
  3. Set necessary environment variables (via .env or some other mechanism).

    MEDIA_DISK=s3-public
    AWS_ACCESS_KEY_ID=REPLACE_WITH_IAM_KEY
    AWS_SECRET_ACCESS_KEY=REPLACE_WITH_IAM_SECRET
    AWS_DEFAULT_REGION=REPLACE_WITH_S3_BUCKET_NAME
    AWS_BUCKET=REPLACE_WITH_S3_BUCKET_REGION
    

Search πŸ”

The "ingredient" (food or recipe) search for journal entries and recipe ingredients supports three different backends using the SCOUT_DRIVER environment variable. In all cases, always ensure that the SCOUT_DRIVER environment variable is only set once in kcal's .env file.

Currently, the food and recipe list searches do not take advantage of these search drivers. Support for those searches will be added if the Laravel JSON:API adds support for Scout (see: laravel-json-api/laravel#32).

Algolia (algolia)

  1. Create and/or log in to an Algolia account.

  2. Create an application for kcal.

  3. Navigate to the application's "API Keys" section.

  4. Using the Application ID and Admin API Key values, update kcal's .env file:

    SCOUT_DRIVER=algolia
    ALGOLIA_APP_ID=<APPLICATION_ID>
    ALGOLIA_SECRET=<ADMIN_API_KEY>
    

ElasticSearch (elastic)

  1. Determine the ElasticSearch service host and port.

  2. Update kcal's .env file.

    SCOUT_DRIVER=elastic
    ELASTIC_HOST=<HOST:PORT>
    ELASTIC_PORT=<PORT>
    

    Note: The ELASTIC_PORT variable is a convenience option specifically for Docker Compose configurations and is not strictly required.

  3. Run Elastic's migrations.

    php artisan elastic:migrate
    

Fallback (null)

The fallback driver is a simple WHERE ... LIKE clause search on a couple of key fields. Results will not be ordered by relevance, and some fields will not be searched (e.g. the tags fields). Using one of the other options is highly recommended.

Set SCOUT_DRIVER=null in kcal's .env file to use the fallback driver.

Development

Dev Container

Clone the project in an IDE with Dev Container support and build the container.

Laravel Sail

Prerequisites

Steps

  1. Clone the repository.

    git clone https://github.com/kcal-app/kcal.git
    cd kcal
    
  2. Install development dependencies.

    composer install
    
  3. Create a local .env file.

    cp .env.example .env
    
  4. Generate an app key.

    php artisan key:generate
    

    Verify that the APP_KEY variable has been set in .env. If has not, run php artisan key:generate --show and copy the key and append it to the APP_KEY= line manually.

  5. Run it! β›΅

    vendor/bin/sail up
    
  6. (On first run) Run migrations.

    vendor/bin/sail artisan migrate
    vendor/bin/sail artisan elastic:migrate
    
  7. (On first run) Seed the database.

    vendor/bin/sail artisan db:seed
    

    The default username and password is kcal / kcal.

Navigate to http://127.0.0.1:8080 to log in!

Create a docker-compose.override.yml file to override any of the default settings provided for this environment.

Custom console commands

dev:cache-clear

Executes the various cache clearing artisan commands:

  • cache:clear
  • config:clear
  • route:clear
  • view:clear

dev:reset

Resets and seeds the database by executing the following artisan commands:

  • db:wipe
  • migrate
  • db:seed

Testing

Ensure that Sail is running (primarily to provide ElasticSearch):

vendor/bin/sail up -d

Execute tests.

vendor/bin/sail artisan dev:cache-clear
vendor/bin/sail artisan test --parallel --recreate-databases

kcal's People

Contributors

cdubz avatar megawubs avatar ryderforreal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

kcal's Issues

Remove unused tags

Tags that are no longer used remain in the system forever and should instead be purged.

Add SECURITY.md

Hey there!

I belong to an open source security research community, and a member (@0xAmal) has found an issue, but doesn’t know the best way to disclose it.

If not a hassle, might you kindly add a SECURITY.md file with an email, or another contact method? GitHub recommends this best practice to ensure security issues are responsibly disclosed, and it would serve as a simple instruction for security researchers in the future.

Thank you for your consideration, and I look forward to hearing from you!

(cc @huntr-helper)

SQLSTATE[22003]: Numeric value out of range:

Trying to edit a recipe and adding above 99 grams of something gives error:

SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'amount' at row 1 (SQL: update ingredient_amounts set amount = 100, ingredient_amounts.updated_at = 2021-10-31 15:03:27 where id = 7)

SQL error causing 500 Internal Server Error on both /recipes and /foods

When I browse to both /recipes and /food, I get the 500 SERVER ERROR page and see an accompanying error and stack trace in the Laravel logs. I've included both that stack trace and my redacted .env file.

Expand .env file
APP_NAME=kcal
APP_ENV=production
APP_KEY=[REDACTED]
APP_DEBUG=false
APP_URL=https://[REDACTED]
APP_PORT=80
APP_SERVICE=app
APP_TIMEZONE=UTC
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=kcal
DB_USERNAME=kcal
DB_PASSWORD=[REDACTED]
REDIS_HOST=localhost
REDIS_PORT=6379
SCOUT_DRIVER=algolia
ALGOLIA_APP_ID=[REDACTED]
ALGOLIA_SECRET=[REDACTED]
MEDIA_DISK=media
QUEUE_CONVERSIONS_BY_DEFAULT=false
Expand stacktrace
[2023-12-12 00:57:20] production.ERROR: SQLSTATE[42000]: Syntax error or access violation: 1055 'kcal.tags.name' isn't in GROUP BY (SQL: select `id`, `name`, count(*) as total from `tags` inner join `taggables` on `taggables`.`tag_id` = `id` where `taggables`.`taggable_type` = App\Models\Food group by `id` order by json_unquote(json_extract(`name`, '$."en"')) asc) {"userId":12,"exception":"[object] (Illuminate\\Database\\QueryException(code: 42000): SQLSTATE[42000]: Syntax error or access violation: 1055 'kcal.tags.name' isn't in GROUP BY (SQL: select `id`, `name`, count(*) as total from `tags` inner join `taggables` on `taggables`.`tag_id` = `id` where `taggables`.`taggable_type` = App\\Models\\Food group by `id` order by json_unquote(json_extract(`name`, '$.\"en\"')) asc) at /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Connection.php:760)
[stacktrace]
#0 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Connection.php(720): Illuminate\\Database\\Connection->runQueryCallback()
#1 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Connection.php(405): Illuminate\\Database\\Connection->run()
#2 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2705): Illuminate\\Database\\Connection->select()
#3 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2694): Illuminate\\Database\\Query\\Builder->runSelect()
#4 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(3230): Illuminate\\Database\\Query\\Builder->Illuminate\\Database\\Query\\{closure}()
#5 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2693): Illuminate\\Database\\Query\\Builder->onceWithColumns()
#6 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(710): Illuminate\\Database\\Query\\Builder->get()
#7 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(694): Illuminate\\Database\\Eloquent\\Builder->getModels()
#8 /var/www/kcal/app/Models/Traits/Ingredient.php(59): Illuminate\\Database\\Eloquent\\Builder->get()
#9 /var/www/kcal/app/Http/Controllers/FoodController.php(21): App\\Models\\Food::getTagTotals()
#10 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): App\\Http\\Controllers\\FoodController->index()
#11 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(43): Illuminate\\Routing\\Controller->callAction()
#12 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Route.php(259): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#13 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\\Routing\\Route->runController()
#14 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php(798): Illuminate\\Routing\\Route->run()
#15 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#16 /var/www/kcal/app/Http/Middleware/DisableBrowserCache.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#17 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): App\\Http\\Middleware\\DisableBrowserCache->handle()
#18 /var/www/kcal/vendor/spatie/laravel-csp/src/AddCspHeaders.php(13): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#19 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Spatie\\Csp\\AddCspHeaders->handle()
#20 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#21 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
#22 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php(44): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#23 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Auth\\Middleware\\Authenticate->handle()
#24 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(78): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#25 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle()
#26 /var/www/kcal/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#27 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle()
#28 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#29 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(64): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest()
#30 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Session\\Middleware\\StartSession->handle()
#31 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#32 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle()
#33 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#34 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle()
#35 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#36 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php(797): Illuminate\\Pipeline\\Pipeline->then()
#37 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php(776): Illuminate\\Routing\\Router->runRouteWithinStack()
#38 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php(740): Illuminate\\Routing\\Router->runRoute()
#39 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php(729): Illuminate\\Routing\\Router->dispatchToRoute()
#40 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(190): Illuminate\\Routing\\Router->dispatch()
#41 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#42 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#43 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#44 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#45 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#46 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#47 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#48 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#49 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#50 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#51 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#52 /var/www/kcal/vendor/fruitcake/laravel-cors/src/HandleCors.php(38): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#53 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Fruitcake\\Cors\\HandleCors->handle()
#54 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#55 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#56 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#57 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(165): Illuminate\\Pipeline\\Pipeline->then()
#58 /var/www/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(134): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#59 /var/www/kcal/public/index.php(51): Illuminate\\Foundation\\Http\\Kernel->handle()
#60 {main}

I'm happy to help debug further, but I don't know any of the frameworks in use or even PHP.

Recipes api returns 500 error. Other queries seem fine.

192.168.1.102 - - [28/Sep/2023:18:58:10 +0000] "GET /api/v1/foods?page[number]=1&page[size]=12 HTTP/1.1" 200 11706 "http://192.168.1.238/foods" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0" 192.168.1.102 - - [28/Sep/2023:18:58:13 +0000] "GET /recipes HTTP/1.1" 200 15598 "http://192.168.1.238/foods" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0" 192.168.1.102 - - [28/Sep/2023:18:58:13 +0000] "GET /api/v1/recipes?page[number]=1&page[size]=12 HTTP/1.1" 500 6628 "http://192.168.1.238/recipes" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0"

Navigation seems to be fine; however, the api is returning 500 causing recipes page to spool endlessly. Trying to dig up more details, but I'm just now diggin in.

Restarting host & containers doesn't seem to resolve.

Host details:
Operating System: Ubuntu 20.04.5 LTS
Kernel: Linux 5.4.0-163-generic
Architecture: x86-64

Appreciate any help!

Add fragments and history state to list pages

The recipe and food listings are annoying to navigate beyond a single filter and the first page. These views should be modified to use URL fragments and update history state for easier back-and-forth navigation and link sharing.

Capital letters inconsistent

Word capitalisation is inconsistent, some instances always display lowercase, some display capitals depending if another field is not empty (details for food), some are captialised such as the journal.

An option to disable all changes and display as entered would be much appreciated, if not a setting to choose.

Add multiples of food to journal

Adding multiple serves of a food is possible, but has to be done one at a time. Having a quantity dropdown next to the meal selector would allow more effective use of servings

Recommendation by meal

Is it possible to have the search results filter by common foods logged for that meal?

For example if I have a shake for breakfast, could the results begin with common foods logged at the meal first so they could be quickly selected, rather than searching 'shake' and then scrolling through options.

installation issue

Hello,

I have not been successful installing kcal manual type on an Ubuntu Server 22.04.4 LTS with Apache.

There is an issue on step 12 second line

... php artisan elastic:migrate ...

which yields the following error message:

Migrating: 2021_03_04_193043_create_foods_index

In 2021_03_04_193043_create_foods_index.php line 9:

Interface "ElasticMigrations\MigrationInterface" not found

Any hep would be appreciated.

Blank user edit page when profile image is uploaded

Once a user has an image uploaded and is saved the edit page becomes blank, both refreshing and backing out both result in the same behavior. Attempted on multiple users and the edit page is only blank after uploading an image, works flawlessly without it

Options to add, hide, convert, and reorder nutrition units

In Australia dietary information is standardised (online and on packaging examples included) so having the option to change the formatting to match would save a lot of time.

Add: Some other units may be applicable on a user by user basis. For example: Saturated and Trans fats (in addition to Total fat), Sugars, Dietary Fibre, Caffeine, Vitamins, etc.

Reorder: For example the order is ALWAYS Energy>Protein>Fat>Carbs>Sugars>Fibre>Sodium so being able to reorganise them in a settings page would allow copying the values straight over.

Convert: Energy in Australia is often showed in kilojoules and only is sometimes converted to calories on the packaging, 1 calorie is 4.184 Kilojoules so having an option that switches the input to the opposite unit and does the math would save a lot of time.

Hide: Cholesterol is not included on these nutritional fact sheets so having the option to hide this section would clean the interface.

image
image

Improve journal UX

The journal UX is clunky. Two key changes that would help a lot β€”

  1. Immediate feedback on day macros effect of making a change.
  2. Ability to quickly edit existing entries.

The current system was designed to be flexible with respect to added data for multiple days at once but that seems like an edge case that isn’t worth building for. Implementing these improvements should be easier if that feature can be sacrificed (or at least deprioritized).

SQL error

I use mariadb database and got such exception.

Illuminate\Database\QueryException:
SQLSTATE[42000]: Syntax error or access violation: 1055 'kcal.tags.name' isn't in GROUP BY (SQL: select `id`, `name`, count(*) as total from `tags` inner join `taggables` on `taggables`.`tag_id` = `id` where `taggables`.`taggable_type` = App\Models\Recipe group by `id` order by json_unquote(json_extract(`name`, '$."en"')) asc)

  at /home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Connection.php:760
  at Illuminate\Database\Connection->runQueryCallback()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Connection.php:720)
  at Illuminate\Database\Connection->run()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Connection.php:405)
  at Illuminate\Database\Connection->select()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2705)
  at Illuminate\Database\Query\Builder->runSelect()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2694)
  at Illuminate\Database\Query\Builder->Illuminate\Database\Query\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:3230)
  at Illuminate\Database\Query\Builder->onceWithColumns()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2693)
  at Illuminate\Database\Query\Builder->get()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:710)
  at Illuminate\Database\Eloquent\Builder->getModels()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:694)
  at Illuminate\Database\Eloquent\Builder->get()
     (/home/taurus/develop/kcal/app/Models/Traits/Ingredient.php:59)
  at App\Models\Recipe::getTagTotals()
     (/home/taurus/develop/kcal/app/Http/Controllers/RecipeController.php:29)
  at App\Http\Controllers\RecipeController->index()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Controller.php:54)
  at Illuminate\Routing\Controller->callAction()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:43)
  at Illuminate\Routing\ControllerDispatcher->dispatch()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Route.php:259)
  at Illuminate\Routing\Route->runController()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Route.php:205)
  at Illuminate\Routing\Route->run()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php:798)
  at Illuminate\Routing\Router->Illuminate\Routing\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/app/Http/Middleware/DisableBrowserCache.php:27)
  at App\Http\Middleware\DisableBrowserCache->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/spatie/laravel-csp/src/AddCspHeaders.php:13)
  at Spatie\Csp\AddCspHeaders->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php:50)
  at Illuminate\Routing\Middleware\SubstituteBindings->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Auth/Middleware/Authenticate.php:44)
  at Illuminate\Auth\Middleware\Authenticate->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:78)
  at Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php:49)
  at Illuminate\View\Middleware\ShareErrorsFromSession->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:121)
  at Illuminate\Session\Middleware\StartSession->handleStatefulRequest()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:64)
  at Illuminate\Session\Middleware\StartSession->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php:37)
  at Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:67)
  at Illuminate\Cookie\Middleware\EncryptCookies->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116)
  at Illuminate\Pipeline\Pipeline->then()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php:797)
  at Illuminate\Routing\Router->runRouteWithinStack()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php:776)
  at Illuminate\Routing\Router->runRoute()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php:740)
  at Illuminate\Routing\Router->dispatchToRoute()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Routing/Router.php:729)
  at Illuminate\Routing\Router->dispatch()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:190)
  at Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:141)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21)
  at Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php:31)
  at Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php:21)
  at Illuminate\Foundation\Http\Middleware\TransformsRequest->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php:40)
  at Illuminate\Foundation\Http\Middleware\TrimStrings->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php:27)
  at Illuminate\Foundation\Http\Middleware\ValidatePostSize->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php:86)
  at Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/fruitcake/laravel-cors/src/HandleCors.php:38)
  at Fruitcake\Cors\HandleCors->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php:39)
  at Illuminate\Http\Middleware\TrustProxies->handle()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:180)
  at Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:116)
  at Illuminate\Pipeline\Pipeline->then()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:165)
  at Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter()
     (/home/taurus/develop/kcal/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:134)
  at Illuminate\Foundation\Http\Kernel->handle()
     (/home/taurus/develop/kcal/public/index.php:51)      

For myself I fixed it here

    public static function getTagTotals(string $locale = null): DatabaseCollection {
        $locale = $locale ?? app()->getLocale();
        return Tag::query()->join('taggables', 'taggables.tag_id', '=', 'id')
            ->select(['id', 'name', DB::raw('count(*) as total')])
            ->where('taggables.taggable_type', '=', static::class)
            ->groupBy(['id', 'name'])
            ->orderBy("name->{$locale}")
            ->get();
    }

Error means when you use GROUP BY you can select only aggregate columns or columns from GROUP BY.

HTTPS behind another reverse proxy

Hello, I have deployed your app in a proxmox container and set it up behind a reverse proxy (nginx proxy manager) with SSL connection but when I go on the link, the CSS and the JS doesn't load... if I go directly on the ip adress this works perfectly. There is a screenshot of the chromium error logs in attached files. Can you help me ?
unknown

Shopping List + Journal expansion

Hi, it's me again with some suggestions:

  • While kcal is currently more leaning towards a diet tracker, I think that adding shopping list functionality would be great. E.g. a "add to shopping list" button on recipes which then adds the ingredients to the shopping list.
  • Adding a food "schedule" functionality to the journal would be a great feature as well. (from what I've seen in my short time using kcal, you can "skip forward in time" on your journal, but something like an "add to schedule" on recipes button that opens a date selector GUI and then adds the recipe to that day's schedule would be great)

Sorry if this sounds unstructured/whatever, it's 23:37 for me and my brain is half asleep. If you need clarifications, I'll gladly respond tomorrow.

Kcal with a HTTPS and a Reverse Proxy

Hi, I really like your app. However I have trouble getting it to work with a Reverse Proxy like NGINX and HTTPS. From issue I understand that this is because kcal doesn't know about the URL and is just "projecting" its js and css to the ip given in the .env file. I must say I am not a Frontend Dev by any means so please excuse my possible misunderstanding. Is there any workaround? Is it possible to implements such a solution such as offerd in link?
Screenshot from 2024-05-08 18-59-35

Copy food/meal feature

Would appreciate the feature to copy a meal to another day. For example I always have the same PM snack and I'd like to copy what I usually have to the next day instead of looking for it each day.

Recipe serving name wrong when food serving size is less than 1

The recipe ingredient list will use the food serving name if the food is entered using servings and the food serving size is less than one. E.g. food with 1/4 cup serving size added to a recipe as 1/2 serving will show up incorrectly as 1/2 cup no instead of 1/8 cup.

Related it #19. Seems a specific recipe summary method should be added to the Food model.

Unable to build on raspberry pi

Hi, thanks for making this service. I'm looking forward to using it. Has anyone built this on a raspberry pi? I'm unable to get it to work. The app container keeps crashes immediately after boot. I'm assuming it has something to do with the binary that's being run not being arm compatible.

I also had other issues getting redis, elasticsearch and mysql running on the raspberry pi, but I've been able to slowly work through them by using various different images. Here is the docker compose file that I'm currently using:

  kcal-app:
    image: kcalapp/kcal
    container_name: kcal-app
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    tty: true
    working_dir: /app
    env_file: ./kcal/.env
    volumes:
      - './kcal/app/public:/app/public/'
      - './kcal/etc/php/php.ini:/usr/local/etc/php/conf.d/local.ini'
    networks:
      - net
    depends_on:
      - kcal-db

  kcal-db:
    image: hypriot/rpi-mysql
    container_name: kcal-db
    restart: unless-stopped
    tty: true
    privileged: true
    security_opt:
      - no-new-privileges:true
    ports:
      - '${DB_PORT:-3306}:3306'
    environment:
      MYSQL_ROOT_PASSWORD: '${DB_PASSWORD:-kcal}'
      MYSQL_DATABASE: '${DB_DATABASE:-kcal}'
      MYSQL_USER: '${DB_USERNAME:-kcal}'
      MYSQL_PASSWORD: '${DB_PASSWORD:-kcal}'
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
    volumes:
      - './kcal/db/data:/var/lib/mysql/'
      - './kcal/etc/mysql/my.cnf:/etc/mysql/my.cnf'
    networks:
      - net

  kcal-web:
    image: nginx:alpine
    container_name: kcal-web
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped
    tty: true
    working_dir: /app
    volumes:
      - './kcal/app/public:/app/public/'
      - './kcal/etc/nginx/conf.d/:/etc/nginx/conf.d/'
    networks:
      - net
    depends_on:
      - kcal-app
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.kcal-web.rule=Host(`kcal.$DOMAIN`)"
      - "traefik.http.routers.kcal-web.entrypoints=https"

  kcal-elasticsearch:
    image: 'ind3x/rpi-elasticsearch'
    container_name: kcal-elasticsearch
    security_opt:
      - no-new-privileges:true
    environment:
      - xpack.security.enabled=false
      - discovery.type=single-node
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    cap_add:
      - IPC_LOCK
    volumes:
      - './kcal/elasticsearch/data:/usr/share/elasticsearch/data'
    ports:
      - '${ELASTIC_PORT:-9200}:9200'
    networks:
      - net

  kcal-redis:
    image: 'redis:latest'
    container_name: kcal-redis
    privileged: true
    security_opt:
      - no-new-privileges:true
    ports:
      - '${REDIS_PORT:-6379}:6379'
    volumes:
      - './kcal/redis/data:/data'
    networks:
      - net

I also tried cloning the kcal repo and building an image using the Dockerfile, but changing the php image, but I had no luck. The Dockerfile uses apk, so I had to use the alpine image specified in the file, however I ran into various issues with that while building.

Recipe image doesn't show

After uploading a recipe image, it does not show up and instead 404s (when accessing my installation via its local IP) or straight up doesn't display without any errors (when accessing my installation via the url defined in .env).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.