Skip to content

Instantly share code, notes, and snippets.

@zetekla
Last active December 16, 2018 08:07
Show Gist options
  • Save zetekla/c0cabe176f7c14d45a3e17ad67818a88 to your computer and use it in GitHub Desktop.
Save zetekla/c0cabe176f7c14d45a3e17ad67818a88 to your computer and use it in GitHub Desktop.
yml
first SPRINT:
- evaluate where we are in term of infrastructure & DevOps work
- ensure consistency across dev env and ensure the codebases to follow architecture and development guidelines.
e.g. 2-spaces indentation, naming and everything to follow the set of guidelines.
- set out the baseline
- allow intial ground work to help form the fundamentals.
Expect:
- extension of cloudAPI and initial testing.
- reference to data design/Schema structure in this yml and the implemented CloudAPI for the development of user, foodieUser and its associated Schemas and their query transactions (either in the form of ORM or query statements).
Goal1: 2 set of CRUD operations with supporting Schemas to be working and fully functional. foodieUser CRUD should be ready.
Goal2: (2 story points) for an API endpoint for server response of status/health check
/ping -> JSON response: 'pongaroo' :) ... there is a ticket for this already.
- menu navbar, sass-css, Semantics-UI, Font-Awesome to be in-place, working and fully functional across multiple devices and viewports.
- UI hyperlink and modal component to be crafted for User login & registration function.
+ create a simple hyperlink, on-clicking it populating a Modal Component.
+ That component contains 3 Buttons: Sign In, Cancel, and Register. and 1 hyperlink for "forgot password?".
+ Integrate Redux-Logic as an outline for state-procedure and store management.
+ Create a UI for Register, and its service for POSTing data to the server.
- Run 2 instances of the UI. One falls into the main use of cloudAPI and the other is to test Java backend server. Observe. and Log bugs (could be either UI, Java side and tangents between Java server and cloudAPI, all should be logged into OpenProject).
- Report of testing progress and assessment of where we are to resolve bugs/issues and achieve a smooth workflow. The Testing and Validation phase is very important.
- layer as a support for the workload of next Sprint.
second Sprint:
- CloudAPI: by this Sprint, CloudAPI should be full-complete, moved to the server and ready for full-blown testing; unless minor changes and relational/field validations need to take place for enhancements.
- evaluate where we are in term of infrastructure & DevOps work
- ensure consistency across dev env and ensure the codebases follow architecture and development guidelines.
e.g. 2-spaces indentation, naming and everything to follow the set of guidelines.
- set out the baseline
- Backend: reference to data design/Schema structure in this yml and the implemented CloudAPI for the development of the next set of CRUD operations. The set is for business logic concerning: businessChain, businessUnit, businessHour and openingTime schemas
- UI: + create a new UI for updating user profile for logged-on user.
+ create a new UI for admin user to view list of user. Think and Leave room for improvements on admin's mass-configurating of users.
+ create a new UI for admin user to manage single user.
+ create a new UI for a user to reset their password with questions and answers.
Sprint 3:
- check, validate and ensure DevOps CI/CD and pipelining works fine.
- health-check on deployed servers.
- evaluate where we are in term of infrastructure, roadmap and our progressing in the application development process.
- Backend: continue with listing, foodieMenu, foodieDish, foodieIngredient and foodieAllergents.
- UI: + listing view of business chains a user has.
+ listing view of all business units per businessChains/{_id}
+ detail view of a business unit with inner ol of business hour and opening time windows.
+ detail view of a single openingTime and its serving menu.
Given there are 4-5 web services
web1.com
web2.com
web3.com
web4.com
We need a middle-tier NodeJS layer to handle JWT & passport for oAuth.
We need it for proxy and interact with all of those web services; so we don't have to hardcode the links on the UI, easier for UI dev as well.
nodejsWeb20.com will be making requests to web1,web2,web3,web4 accordingly
Nginx takes care of load-balancer for nodejsWeb20; also for each of the microservices.
need Docker+ Nginx for NodeJS as a container
need Docker+ Nginx for each of those microservices. Eventually for 4 microservices will have 4 Docker containers.
Altogether 4+1 containers to be managed by Kubernetes or Docker Swarm.
Then, scale the 4+1 containers by x5 (would be 25 Kubernetes stackes of containers) or x10 times (would be 50 Kubernetes stackes of containers) to have more persistence.
Each set can be deployed to the right locale for improving performance.
Passport, Bcryp, JWT & oAuth:
https://stackoverflow.com/questions/6951563/storing-passwords-with-node-js-and-mongodb
https://www.mongodb.com/blog/post/password-authentication-with-mongoose-part-1
---
uuid
https://github.com/strongloop/loopback-connector-postgresql/issues/61
JSON https://github.com/strongloop/loopback-connector-postgresql/issues/31#issuecomment-310563011
https://strongloop.com/strongblog/postgresql-node-js-apis-loopback-connector/
http://loopback.io/doc/en/lb3/PostgreSQL-connector.html#postgresql-types-to-loopback
https://github.com/strongloop/loopback-connector-postgresql
https://github.com/strongloop/loopback-example-ssl
POSGRES CLI:
\du : list all databases and users with privileges per database.
\l and \list : list all databases
\c foodie : use database foodie
\d+ appuser : describe appuser schema
TABLE appuser : foodie# show all appuser records
psql -U postgres
create database demo;
CREATE USER admin WITH PASSWORD 'password';
grant all on database demo to admin;
GRANT ALL PRIVILEGES ON DATABASE "chatApp" to "admin";
ALTER DATABASE db RENAME TO newdb;
More POSTGRE-CLI https://gist.github.com/mikeumus/03626d5cd3e1aa42918f
POSTGRE-JSON type reference http://www.postgresqltutorial.com/postgresql-json/
User:
type: "food-consumer | food-truck-owner | food-restaurant-owner | food-truck-and-restaurant-owner | food-event-organizer | food-marketing-campaigner | food-value-chain-promoter | food-value-chain-distributor | food-value-chain-analyst | food-value-chain-donator | food-app-investor
marketplace-buyer | marketplace-seller | marketplace-eVendor | marketplace-investor
common-payment-service-provider | common-investor
"
marketplace-eVendor:is the vendors who help sell your items with a commission fee.
Listing: ( 1 listing record represents 1 product or service: furniture, book, food, janitorial service )
## FOREWORD: ##
# atomic, cross-relational data structure. It is user-driven.
# 'foodie' : appName and a reference point.
# singular means the general; also a single record.
# plurals or [] stand for array/collection of records
# [] means new Schema is required when scaling up to that point
# see 'matching' annotation for relational.
# an object in YML is called a Dictionary. You can learn more about YML: http://docs.ansible.com/ansible/latest/YAMLSyntax.html
# story:
# 1 user has a foodieUser profile and foodieUserTransaction if user.type includes foodie
# 1 businessChain (owner: usedId) has Many businessUnits.
# e.g. chain restaurants. businessChain: McDonald, businessUnits: many McDonald franchise businesses.
# likewise, if a foodtruck business owner has many trucks of his own. The same (businessChain and businessUnits 1:m) story works.
# a businessUnit has foodieProfile if businessUnit.type includes foodie. If doesn't, do NOT query foodieProfile
# a businessUnit has
# many foodiePromotion
# many businessHour
# a Promotion is linked to a Dish on 1:1 relationship
# a Dish has
# many Meal types
# many Promotions
# many Ingredients
# a listing has a foodieMenu. That is because a listing record is dependent on businessUnit and openingTime. 1 openingTime has 1 listing.
# The listing is kept generic. While, the foodieMenu is to extend listing Schema for the foodieApp specifically.
# an Ingredient has Many Allergens
# In this design, Patronage is not a Schema. It can be figured through algorithm for list of users has type of 'foodie' and has favorited the restaurants / foodtrucks
####################################
####################################
## MICROSERVICE 1 user info ##
## user ##
user: # user<Schema>
_id: uuid
type: JSON # build this string as a string list of comma-separated types base on the number of apps a user joins. A user can be both owner/consumer, buyer/seller: 'foodie-consumer, foodie-truck-owner', patronage/buyer
apps:
- appName: String
appId: uuid # reference to the App. if,
userId: uuid # backward reference to the user _id above
realm: String # provider where they join: Google, Twitter, Facebook, etc.
email: String # default to abc@gmail.com
emailVerified: Boolean
required: JSON # "email,name,userName,birthDay,gender, password"
userName: String
name:
userId: uuid
firstName: String
middleName: String
lastName: String
suffixName: String
career: String
jobTitle: String
company: String
gender: String
ethnicity: String
origin: String
addresses: # multiple addresses
- address1: String
address2: String
city: String
state: String
zip: String
country: String
mainAddress: Boolean # hometown, e.g. Orange CA
currentAddress: Boolean # place of residence, e.g. Quincy MA
password: String
questions: JSON # storing questions for password reset
answers: JSON # storing answers for password reset. User input of answer for questions[0] must match answers[0], likewise for the other two.
birthDate: Date
phoneNumber1: String
phoneNumber2: String
createdAt: Date
updatedAt: Date
lastSeenAt: Date
# foodieUser<Schema> extends user<Schema>
foodieUser:
_id: uuid # for purpose of tracking how many foodie users. There can be users using other Apps, only the one active on this App has this uuid pertaining to the foodie for extra security
type: JSON # inherits from the generic user type, foodie-app specific type
usedId: uuid # matching user _id
foodiePreferences: [] # String JSON "['burger', 'burrito', 'tapaz', 'taco', 'salad']", allow user to sort their preference
foodieAllergences: [] # String JSON
favoriteRestaurants: []
favoriteFoodtrucks: []
favoriteIngredients: []
favoriteLocations: [] # list of their neighborhoods or cities
favoriteDishes: [] # list of restaurant|foodtruck to try, { foodtruckId, foodtruckName, dishes: []}
favoriteRecipes: [] # data-mining for kitchen & cookware business
wishList: [] # survey purpose, polls, wish to have several more dishes of salmon salad at a place X, wish to have more sushi in my area.
coupons: []
accumPromoPoint: Number
role: String # admin | tech-support | regular-user
status: String # active | disable | gone | banned | locked, locked if not activated.
# extension <foodieUserTransaction schema>
_id: uuid
appUserId: uuid # matching user _id
credit: String # buy-in credits
inAppPurchases: []
####################################
####################################
## MICROSERVICE 2 locale, i18n, oAuth, openAM/openDJ ##
####################################
####################################
## MICROSERVICE 3 business Chain ##
## businessChain Schema (reusable & independent from foodie app) ##
businessChain: # businessChain<Schema>
_id: uuid
userId: String # references to the owning user. The owner Id shall help determine how many restaurants and foodtrucks a 'merchant' user has.
name: String
desc: String
createdAt: Date # entry createdAt
updatedAt: Date # entry updatedAt
license: String
motto: String
keywords: String # comma-separated string
status: Boolean # active | disable | out-of-business
promotionType: JSON # determine the type of promotions as per credit use for a unit
## businessUnits as a collection ##
businessUnits: # businessUnit<Schema>
- _id: uuid
businessChainId: uuid # fk
type: JSON # comma-separated string,means business operation type(s)
# the field determines whether it contains business operation type of 'foodie'
street: String
city: String
state: String
zip: String
franchise: String
storeNumber: String
longitude: String # decimal ?
latitude: String # decimal
taxId: String
status: String
updatedAt: Date
## A single businessUnit ##
businessUnit:
businessHour: # businessHour<Schema>
_id: uuid
businessUnitId: uuid # matching businessUnit._id
openingTimes: # openingTime<Schema>
- _id: uuid # time window uuid
name: String # naming for this time window "early-morning | morning | noon | early-afternoon | late-afternoon | evening | festive-season | holiday | weekend | weekday"
openingHour: String
closingHour: String
listing: [] # see listing in MICROSERVICE 4
startedAt: Date # when to apply this time window and its catering menu
endedAt: Date # when to stop applying prune if it was 4 months old.
createdAt: Date # date the user created this time window
updatedAt: Date # date the user updated this time window
foodieProfile: # foodieProfile<Schema>
_id: uuid
businessUnitId: uuid # fk
hasFoodTruck: Boolean
foodiePromotion: # foodiePromotion<Schema>
_id: uuid # promotion uuid
businessUnitId: uuid # matching businessUnit._id
dishId: uuid # matching dish._id
createdAt: Date
expiredAt: Date
promoPoint: Number
####################################
####################################
## MICROSERVICE 4 the listing of menu of categories of dishes of ingredients and allergences ##
# listing Schema (reusable & independent from foodie app) ##
# the goal is to try to be generic as much as possible
# listing document can be reused for eCommerce products.
listing: # listing<Schema>
_id: uuid
openingTimeId: uuid # matching openingTime._id
businessUnitId: uuid # reference to restaurant profile Schema
description: String # further description of this listing
keywords: String # comma-separated string
## foodieMenu Schema ##
foodieMenu: # foodieMenu<Schema>
_id: uuid
listingId: uuid # matching listing._id
mealType: String
# Korean BBQ, Mongo-Grilling, Mediterranean Grill, Japanese shabu, Japanese bar, Japanese sushi, American Burger, American Salad, German Hotdog, Italian pasta, Italian pizza
foodieCategories: # foodieDishCategory<Schema>
- _id: uuid
foodieMenuId: uuid # matching foodieMenu._id
name: String # category name " appertizer/entree | main course | dessert | any "
# as per category, there will be dishes
foodieDishes: # foodieDish<Schema>
- _id: uuid
foodieCategoryId: uuid
name: String
price: Currency # can be Number perhaps? unless Postgre supports Currency type. Or, we can just leave it as Real or Decimal and let the UI handles parsing to display currency properly, which is used in most cases, whereas we need to support different currencies.
createdAt: Date # date the user created this dish
updatedAt: Date # date the user updated this dish
# it seems unnecessary to have to include businessUnitId
foodieDish:
foodieIngredient: # foodieIngredient<Schema>
_id: uuid
foodieDishId: uuid # matching foodieDish._id
name: String
type: String # just an ingredientType
flavor: String # brief description of how it tastes
foodieAllergence: # foodieAllergence<Schema>
_id: uuid
foodieIngredientId: uuid # matching foodieIngredient._id
type: String # allergenType
####################################
CREATE EXTENSION "uuid-ossp";
-- or CREATE EXTENSION "pgcrypto";
create table entity(
entity_id uuid primary key default uuid_generate_v4(),
-- or entity_id uuid primary key default gen_random_uuid(),
attribute text not null
);
https://stackoverflow.com/questions/43039653/mongo-to-postgres-migration-convert-mongo-hexa-id-field-to-shorter-integer
https://www.postgresql.org/docs/9.2/static/ddl-constraints.html
https://stackoverflow.com/questions/15037349/creating-postgresql-tables-relationships-problems-with-relationships-one-t
http://www.postgresqltutorial.com/postgresql-foreign-key/
http://blog.bguiz.com/2017/postgres-many2many-sql-non-relational/
--
Rancher to get started with Kubernetes: http://rancher.com/
Docker GUI: Rancher, Portainer, Docker Swarm
// PhotonOS is a minimal Linux container host
https://github.com/vmware/photon
https://vmware.github.io/photon/
## FOREWORD: ##
# atomic, cross-relational data structure. It is user-driven.
# 'foodie' : appName and a reference point.
# singular means the general; also a single record.
# plurals or [] stand for array/collection of records
# [] means new Schema is required when scaling up to that point
# see 'matching' annotation for relational.
# an object in YML is called a Dictionary. You can learn more about YML: http://docs.ansible.com/ansible/latest/YAMLSyntax.html
# story:
# 1 user has a foodieUser profile and foodieUserTransaction if user.type includes foodie
# 1 businessChain (owner: usedId) has Many businessUnits.
# e.g. chain restaurants. businessChain: McDonald, businessUnits: many McDonald franchise businesses.
# likewise, if a foodtruck business owner has many trucks of his own. The same (businessChain and businessUnits 1:m) story works.
# a businessUnit has foodieProfile if businessUnit.type includes foodie. If doesn't, do NOT query foodieProfile
# a businessUnit has
# many foodiePromotion
# many businessHour
# a Promotion is linked to a Dish on 1:1 relationship
# a Dish has
# many Meal types
# many Promotions
# many Ingredients
# an Ingredient has Many Allergens
# In this design, Patronage is not a Schema. It can be figured through algorithm for list of users has type of 'foodie' and has favorited the restaurants / foodtrucks
## generic user Schema ##
user:
_id: uuid
type: JSON # build this string as a string list of comma-separated types base on the number of apps a user joins. A user can be both owner/consumer, buyer/seller: 'foodie-consumer, foodie-truck-owner', patronage/buyer
apps:
- appName: String
appId: uuid # reference to the App. if,
userId: uuid # backward reference to the user _id above
realm: String # provider where they join: Google, Twitter, Facebook, etc.
email: String # default to abc@gmail.com
emailVerified: Boolean
required: JSON # "email,name,userName,birthDay,gender, password"
userName: String
name:
firstName: String
middleName: String
lastName: String
suffixName: String
career: String
jobTitle: String
company: String
gender: String
ethnicity: String
origin: String
addresses: # multiple addresses
- address1: String
address2: String
city: String
state: String
zip: String
country: String
mainAddress: Boolean # hometown, e.g. Orange CA
currentAddress: Boolean # place of residence, e.g. Quincy MA
password: String
questions: JSON # storing questions for password reset
answers: JSON # storing answers for password reset. User input of answer for questions[0] must match answers[0], likewise for the other two.
birthDate: Date
phoneNumber1: String
phoneNumber2: String
createdAt: Date
updatedAt: Date
lastSeenAt: Date
# Annotation for user.type, user can take 1 or as many of the following types, by comma-separated:
# "foodie-consumer | foodie-truck-owner | foodie-restaurant-owner | foodie-truck-and-restaurant-owner | foodie-event-organizer | foodie-marketing-campaigner | foodie-value-chain-promoter | foodie-value-chain-distributor | foodie-value-chain-analyst | foodie-value-chain-donator | foodie-app-investor | foodie-app-patronage
# marketplace-buyer | marketplace-seller | marketplace-eVendor | marketplace-investor
# common-payment-service-provider | common-investor"
# if user.type.indexOf('foodie') insert fields foodiePreference
## foodieUser Schema ##
# extends the generic user schema.
# generic for restaurantOwner & consumer
foodieUser:
_id: uuid # for purpose of tracking how many foodie users. There can be users using other Apps, only the one active on this App has this uuid pertaining to the foodie for extra security
type: JSON # inherits from the generic user type,
usedId: uuid # matching user _id
foodiePreferences: []
foodieAllergences: []
favoriteRestaurants: []
favoriteFoodtrucks: []
favoriteIngredients: []
favoriteLocations: [] # list of their neighborhoods or cities
favoriteDishes: [] # list of restaurant|foodtruck to try, { foodtruckId, foodtruckName, dishes: []}
favoriteRecipes: [] # data-mining for kitchen & cookware business
wishList: [] # survey purpose, polls, wish to have several more dishes of salmon salad at a place X, wish to have more sushi in my area.
coupons: []
accumPromoPoint: Number
role: String # admin | tech-support | regular-user
status: String # active | disable | gone | banned | locked, locked if not activated.
## foodieUserTransaction Schema ##
# extends the foodieUser schema.
foodieUserTransaction:
_id: uuid
userId: uuid # matching user _id
credit: String # buy-in credits
inAppPurchases: []
## businessChain Schema (reusable & independent from foodie app) ##
businessChain:
_id: uuid
userId: String # references to the owning user. The owner Id shall help determine how many restaurants and foodtrucks a 'merchant' user has.
name: String
desc: String
createdAt: Date # entry createdAt
updatedAt: Date # entry updatedAt
license: String
motto: String
keywords: String # comma-separated string
status: Boolean # active | disable | out-of-business
promotionType: JSON # determine the type of promotions as per credit use for a unit
# promotionType is a field for query efficiency
# if promotionType is empty, ignore query to promotion Schema,
# otherwise use this to find only the matching results from the collection of promotion records.
## businessUnit Schema (reusable & independent from foodie app) ##
## extends businessUnit Schema ##
businessUnit:
_id: uuid
businessChainId: uuid # fk
type: JSON # comma-separated string,means business operation type(s)
# the field determines whether it contains business operation type of 'foodie'
street: String
city: String
state: String
zip: String
franchise: String
storeNumber: String
longitude: String # decimal ?
latitude: String # decimal
taxId: String
status: String
updatedAt: Date
## foodieProfile Schema ##
## extends businessUnit Schema ##
foodieProfile:
_id: uuid
businessUnitId: uuid # fk
hasFoodTruck: Boolean
## foodiePromotion Schema ##
foodiePromotion:
_id: uuid # promotion uuid
businessUnitId: uuid # matching businessUnit._id
dishId: uuid # matching dish._id
createdAt: Date
expiredAt: Date
promoPoint: Number # the point to give out
## businessUnit Schema (reusable & independent from foodie app) ##
businessHour:
_id: uuid
businessUnitId: uuid # matching businessUnit._id
openingTimes:
- _id: uuid # time window uuid
name: String # naming for this time window "early-morning | morning | noon | early-afternoon | late-afternoon | evening | festive-season | holiday | weekend | weekday"
openingHour: String
closingHour: String
listings: []
startAt: Date # when to apply this time window and its catering menu
endAt: Date # when to stop applying prune if it was 4 months old.
createdAt: Date # date the user created this time window
updatedAt: Date # date the user updated this time window
## listing Schema (reusable & independent from foodie app) ##
# the goal is to try to be generic as much as possible
# listing document can be reused for eCommerce products.
listing:
_id: uuid
openingTimeId: uuid # matching openingTime._id
businessUnitId: uuid # reference to restaurant profile Schema
description: String # further description of this listing
keywords: String # comma-separated string
## foodieMenu Schema ##
foodieMenu: # foodieMenu<Schema>
_id: uuid
listingId: uuid # matching listing._id
mealType: String
# Korean BBQ, Mongo-Grilling, Mediterranean Grill, Japanese shabu, Japanese bar, Japanese sushi, American Burger, American Salad, German Hotdog, Italian pasta, Italian pizza
foodieCategory:
_id: uuid
foodieMenuId: uuid # matching foodieMenu._id
name: String # category name " appertizer/entree | main course | dessert | any "
foodieDish:
_id: uuid
foodieCategoryId: uuid
price: Currency # can be Number perhaps? unless Postgre supports Currency type. Or, we can just leave it as Real or Decimal and let the UI handles parsing to display currency properly, which is used in most cases, whereas we need to support different currencies.
createdAt: Date # date the user created this dish
updatedAt: Date # date the user updated this dish
# it seems unnecessary to have to include businessUnitId
foodieIngredient:
_id: uuid
foodieDishId: uuid # matching foodieDish._id
name: String
type: String # just an ingredientType
flavor: String # brief description of how it tastes
foodieAllergence:
_id: uuid
foodieIngredientId: uuid # matching foodieIngredient._id
type: String # allergenType
### EXTRA ###
queryScenarios:
findListOfFoodTruckAndRestaurantsPerUser: Query businessUnit Schema, { userId: userId }
findListOfFoodTruckPerUser: Query businessUnit Schema, { userId: userId, type: 'truck' }
findListOfRestaurantPerUser: Query businessUnit Schema, { userId: userId, type: 'restaurant' }
@zetekla
Copy link
Author

zetekla commented Mar 5, 2018

Composite ID ?

@zetekla
Copy link
Author

zetekla commented Mar 9, 2018

@zetekla
Copy link
Author

zetekla commented Mar 12, 2018

python manage.py createsuperuser

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment