Giter VIP home page Giter VIP logo

xipona's Introduction

Xipona

Docker Image Version (latest semver) Docker Image Version (latest semver)

Description

With Xipona you can create shopping lists, manage your bought items and collect your favorite recipes. Thanks to queuing and retry logic, you don't have to worry about losing internet connection while grocery shopping - the app will sync all changes of your shopping list once you're online again.

Go Shopping

Your items are sorted conveniently by the store's section in which they are located, so that you can take your usual stroll through the aisles and see at one glance what you need to pick up. To make it even easier, you can hide all items in the basket to only see what's left to buy.
One of the items you needed was out of stock? No problem, the shopping list will transfer all items that you haven't marked as "in basket" to the next shopping list upon finishing the current one.

Shopping list with items in basket and items not in basket

Manage items

You can create simple items ...

Editor where you can define an item's name, category, manufacturer and availability

... or register multiple types per item, so you don't have to create a separate item for every individual type.

Editor where you can define an item's name, category, manufacturer and types. You can again define the availabilities per type

(Modifying an item will alter the current revision, e.g. when you made a typo in the name. Updating the item will create a new revision of it, e.g. when the price changes. With this concept, you keep the item prices for previous shopping lists)

Create Recipes

Save your best recipes along with all the ingredients and instructions

A recipe for lasagna

And more

And that was just the general overview. Because not everyone wants to have certain items permanently show up for shopping, you can also create temporary items. These will only be available for this one store until you finish the shopping list with said item in the basket or remove it from the list

The price change dialog that's opend directly on the shopping list

Depending on the prices you saved for the items, the shopping lists predicts the estimated costs of your shopping errand. But because prices change, you can quickly adjust them from the shopping list without having to laboriously search for & open the item in the item editor.

The price change dialog that's opend directly on the shopping list

Search for recipes not only by their name, but also by their tag. You'd like to eat vegetarian? Great! Search by the tag select the recipe you want to cook.

Recipe search by the tag 'vegetarian'

But what if you're missing some ingredients? It's tedious to add all of them to the shopping lists individually. That's why you can add with one click all of the ones that you're lacking to the respective store's shopping list.

Recipe search by the tag 'vegetarian'

And there is more on the horizon! Check out the GitHub Milestones to get a glimps at what's coming soon ๐Ÿ‘€

Setup in Docker

To run all required services in containers, Dockerfiles and docker-compose files are provided. Since v0.7.0 Docker Secrets are being used and thus the services must be started via a stack deploy on a Docker Swarm. Starting via docker-compose is not supported anymore.

Prerequisits

Prepare the following things:

  • Docker Volumes
    • Api
      • ph-xipona-api-logs
      • ph-xipona-api-config
    • Frontend
      • ph-xipona-frontend-config
    • Database
      • ph-xipona-database
  • Docker Secrets
    • ph-xipona-db-username
    • ph-xipona-db-password
    • ph-xipona-db-root-pwd

Api

  • The appsettings file (Api/Xipona.Api.WebApp/appsettings.*.json) will not be delivered with the docker image and must be placed inside the ph-xipona-api-config volume. Specify the following things there:
    • The DB's address and port
    • The frontend's address as an allowed origin for CORS (e.g. https://localhost:5000)

Frontend

  • Configure the webserver address & the frontend's environment in xipona.conf under Frontend/Docker and copy it into the root directory of the ph-xipona-frontend-config.
  • Set the api's address in the respective appsettings file (Frontend/Xipona.Frontend.WebApp/wwwroot/appsettings.*.json) and copy it into a directory of your choice on your host.

yml files

  • Under Docker/Compose/ is a compose yml file. You have to replace the {CONFIG_FOLDER_PATH} placeholder with the absolute path of the directory where your frontend's appsettings file is
  • Start the containers via e.g. docker stack deploy --compose-file docker-compose.yml ph-xipona

And now you're done. Happy shopping!

Optional Setup

https

If you don't want to run the application behind a reverse proxy that handles the certificate for you, you can also configure the application for https.

Api

  1. Create the docker volume ph-xipona-api-tls and uncomment the line in the docker compose file where it's mapped as a volume.
  2. Generate the certificate and copy the files (<cert-name>.crt & <cert-key-name>.key) into the root directory of the ph-xipona-api-tls volume.
  3. Replace the existing kestrel http endpoint in your appsettings.{env}.json with an https configuration like the following or any other valid one. Just make sure the certificate's folder matches the one to which the tls volume is mapped (Default: ssl).
    "Kestrel": {
      "Endpoints": {
        "HttpsInlineCertAndKeyFile": {
          "Url": "https://localhost:5002",
          "Certificate": {
            "Path": "ssl/<cert-name>.crt",
            "KeyPath": "ssl/<cert-key-name>.key"
          }
        }
      }
    }
    

Frontend

  1. Create the docker volume ph-xipona-frontend-tls and uncomment the line in the docker compose file where it's mapped as a volume.
  2. Generate the certificate and copy the files (<cert-name>.crt & <cert-key-name>.key) into the root directory of the ph-xipona-frontend-tls volume.
  3. Replace the xipona.conf (under Frontend/Docker) with:
    server {
        listen 80 default_server;
        server_name <webserver-address>; # set your webserver address here (without port)
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl;
        server_name <webserver-address>; # set your webserver address here (without port)
        
        ssl_certificate /etc/nginx/ssl/<cert-name>.crt;
        ssl_certificate_key /etc/nginx/ssl/<cert-key-name>.key;
    
        add_header blazor-environment "Development"; # set this to Development or Production
    
        location / {
            root /usr/share/nginx/html/wwwroot;
            index index.html index.htm;
        }
    }
    

Frontend Logging

It is possible to collect client-side logs (e.g. exceptions). The compose files have an additional service LogCollector that must be uncommented (plus the two corresponding docker volumes). Additionally, you have to enable the LogCollector in the frontend's appsettings (CollectRemoteLogs section; disabled by default) and set the LogCollector's address.

Authentication & Authorization

In order to only grant access to this application for certain users, it's possible to enable authentication & authorization with OIDC. This must be done in both frontend and api. It's disabled by default.
Currently, there is only one user role that decides over full access or no access for authenticated users. By default, it's called User but can be overridden by the UserRoleName setting in the frontend & api's Auth section. This role must be returned by the role claim in the ID and access token.

Frontend

Set the Auth section in the respective appsettings file (Frontend/Xipona.Frontend.WebApp/wwwroot/appsettings.*.json) to "Enabled": true and fill the Provider and User sections.

API

Set the Auth section in the respective appsettings file (Api/Xipona.Api.WebApp/appsettings.*.json) to "Enabled": true and fill the remaining properties.

Key Vault

Instead of providing the database credentials via docker secrets, it's also possible to retrieve them from a HashiCorp Vault. To do so, you need the following setup (this assumes that you already have a running Vault):

  • Remove the api's two DB environment variables (PH_XIPONA_DB_USERNAME_FILE & PH_XIPONA_DB_PASSWORD_FILE) and both username/password docker secrets from the docker compose file
  • Create new docker secrets that contain the username/password with which the api will authenticate agains the vault:
    • ph-xipona-vault-api-username
    • ph-xipona-vault-api-password
  • Import both secrets in the docker compose file and replace the api's two DB environment variables with
    • PH_XIPONA_VAULT_USERNAME_FILE: /run/secrets/ph-xipona-vault-api-username
    • PH_XIPONA_VAULT_PASSWORD_FILE: /run/secrets/ph-xipona-vault-api-password
  • Set the vault's URI in the api's appsettings files (Api/Xipona.Api.WebApp/appsettings.*.json)
  • The default mount point (ph-xipona) & secret name (database) are defined in the same appsettings file and can be changed at will. But the key names inside the secret must be "username" and "password" (all lowercase) and can not be changed. Define the username and password of the user with which you want to authenticate against the database.

Local Development Setup

To get everything running at your dev machine, at least a running dev DB is necessary. However, it's recommended to start the whole dev stack in Docker. You'll then be able to start the api & frontend locally where the frontend connects to the api and the api to the dev database.

API

Database connection

To mimic Docker Secrets, there are two variables in the Api/Xipona.Api.WebApp/Properties/launchSettings.json: PH_XIPONA_DB_USERNAME_FILE & PH_XIPONA_DB_PASSWORD_FILE. Create two files with only username and password respectively and specify their full absolute file path in mentioned variables. A normal .txt is enough. [If you want to use the Vault, create PH_XIPONA_VAULT_USERNAME_FILE & PH_XIPONA_VAULT_PASSWORD_FILE variables instead in the launchSettings.json file, remove the other two and specify the location of the files holding the key vault username & password. Then, set the Vault's URI in the Api/Xipona.Api.WebApp/appsettings.Local.json.]

Also, set the DB's address and port in your Api/Xipona.Api.WebApp/appsettings.Local.json.

xipona's People

Contributors

velociraptor45 avatar

Stargazers

 avatar Tim Kersey avatar Attila Hajdrik avatar Chad M. Crowell avatar

Watchers

 avatar

Forkers

krishna412

xipona's Issues

Dockerfiles

Add Dockerfiles for building backend and frontend images.

Write missing unit tests

Some (actually a lot) of the command handlers, query handlers, services, etc. don't have unit tests. Write them.

Distinguish between api response codes

When the api requests throws an exception, distinguish between connection errors and 400, 500, etc.
If it's no connection error, don't retry to execute the request.

Replace extension methods with converters

Replace extension methods that convert domain objects, entities, read models, contracts into each other with dedicated converter classes. This'll also enable a global usage of factories for creating domain models.

Implement ItemTypes

Different ItemTypes should represent the same kind of product from the same manufacturer but with difference in e.g. flavor or size.

ShoppingListConverter expects an item in every section

The ShoppingListConverter expects that every section contains at least one item when it tries to do
var items = itemMapsPerSection[section.Id].Select(map => CreateItem(map, source));

This must be changed to be also able to convert sections that contain no items.

Exception when creating new store

When creating a new store via the frontend, an exception occurs while accessing the store's sections (for displaying the default section) because there are no sections yet.

Implement convenient way to switch between DBs when applying migrations

Currently, all connection strings to DBs are hard coded in every ContextFactory. This should just be done in the AppSettings and depending on a system variable, the corresponding DB should be updated.
There is also an update script in Api/Scripts that should be split in two scripts: update-dev and update-prd system

Multiple new store sections can't be distinguished

If you add multiple new sections to a store (no matter if you create a new or edit an existing one), the dropdown for the default section and the backend can't distinguish between them because they all have the same ID '0'.

Create READMEs for important folders

To explain the project's folder structure better, every important (sub) folder should have its own README explaining what's going on in there.

Summary before finishing shopping list

When clicking on the "Finish list" button, a summary should show up that shows:

  • completion date
  • total price

It should then have a "Cancel" and "Finish" button to cancel or confirm the action.

Change specifying default section of a store in DB

With the current circular reference between store and sections, it is impossible for EF Core to insert a new store and new sections.
Change the DB design as following:

  • Remove the DefaultSectionId column in table Stores
  • Add column IsDefaultSection in table Sections

Display ongoing retry

Display something to indicate that there's an ongoing retry in the background and not all changes are saved.

Reorganize solution

Reorganize solution by

  • introducing a ranked sub-folder for every layer
  • splitting Infrastructure projects into sub-domains
  • review whether the Transaction folder belongs to Infrastructure or ApplicationServices
  • rename test folders to reflect layer rank
  • move all fixtures into the corresponding TestKit project

Research VPN container

The plan is to be able to connect to the docker container that runs ProtonVPN, so that all devices (inside the network [+ from outside(?) ]) can connect to the container and have its traffic channeled through the VPN to ensure privacy.

Item sections

Item sections allow users to group items into logical parts (e.g. like sections of the supermarket) to easily access items that are next to each other.

Ensure DDD

An aggregate root shouldn't contain entities that don't belong to it but only their IDs as reference. Thus, all domain models must be adapted to this constraint
Also:

  • Make Sub-models read-only

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.