2021 April 7
eatplants.app is a plant-based food tracking app without the food tracking
The goal of this exercise is to go from conceptual stage (ie. "just an idea") to an actual working prototype in a day. It's not going to be perfect but it's nice to just build stuff sometimes without necessarily worrying that it's the perfect design.
What do I want this app to do for me? What problem am I solving for myself?
Requirements:
This is by far the worse part of any project. I need to gather and setup all the software components before even starting.
Here's the stack I will use:
Now that everything is setup, it's time to see how the requirements above will map to a database structure that is easy to query.
All tables will have these:
created_at timestamptz default now(),
updated_at timestamptz default now()
-- updated_at triggers for each table
create or replace function app_private.set_updated_at ()
returns trigger
as $$
begin
new.updated_at := now();
return new;
end;
create table app_private.person (
id smallint primary key generated always as identity,
email text not null unique check (email ~* '^.+@.+\..+$'),
username text unique, -- for sharing and page links
password_hash text not null,
role_name text not null
);
create table app.food_group (
id smallint primary key generated always as identity,
-- don't think we'll need more than 32767 food groups lol
name text
);
create table app.food (
id integer primary key generated always as identity,
food_group_id integer references app.food_group (id),
long_description text,
short_description text,
common_name text
);
create table app.nutrient (
id integer primary key generated always as identity,
unit text, -- g, mg, ml etc...
name text -- protein
);
create table app.food_nutrient (
id integer primary key generated always as identity,
nutrient_id integer references app.nutrient (id),
food_id integer references app.food (id),
value_per_g real,
value_per_kcal real,
unique (nutrient_id, food_id)
);
create table app.food_measure_weight (
id integer primary key generated always as identity,
food_id integer references app.food (id),
num_measures real, -- -->1<-- cup,
measure text, -- 1 -->cup<--, this might be another table since we'll have tons of 'cup', 'tbsp' entries here. let's wait and see
weight_in_g real -- weight in grams
);
create table app.recipe (
id integer primary key generated always as identity,
name text,
description text
);
Note: I know I will have to implement an ordering system because recipes need to list ingredients in the order they are used while cooking. It's going to be annoying to code so I'll put it off until I actually get to creating recipes
create table app.recipe_food_item (
id integer primary key generated always as identity,
recipe_id integer references app.recipe (id),
food_id integer references app.food (id),
amount_in_g real, -- this I'm not 100% sure about yet. we'll probably need something a bit more sophisticated than this
-- we can store it in grams but in the UI, show the nicer looking "1 cup" by using the food_measure_weight table
unique (recipe_id, food_id)
);
Just throwing this here but I won't implement this yet for version 1
Users can repeat for now
create table app.recipe_recipe_item (
-- TBD
);
create table app.collection (
id integer primary key generated always as identity,
name text,
description text
);
create table app.collection_food_item (
id integer primary key generated always as identity,
food_id integer references app.food (id),
collection_id integer references app.collection (id),
unique (food_id, collection_id)
);
create table app.collection_recipe_item (
id integer primary key generated always as identity,
recipe_id integer references app.recipe (id),
collection_id integer references app.collection (id),
unique (recipe_id, collection_id)
);
create table app.collection_collection_item (
id integer primary key generated always as identity,
collection_id integer references app.collection (id)
);