- Manually create an umbrella folder e.g. "~/LyttleBit/code/01-adopt-a-drain/"
- Clone your repo in the umbrella folder e.g. "git clone "
- Update your .env with LB_GIT={"name":"adopt-a-drain","branch":"#21.refactor.reorganize.folders", "owner":"Wilfongjt"}
git clone https://github.com/Wilfongjt/adopt-a-drain.git
cd adopt-a-drain/
git checkout
- set LB_
LB_PROJECT={"name":"adopt-a-drain", "prefix":"aad", "owner":"Wilfongjt", "branch":"#21.refactor.reorganize.folders"}
# LB_PROJECT={"name":"register", "prefix":"reg", "owner":"Wilfongjt"}
# LB_GIT={"name":"register","branch":"#05.refactor.api", "owner":"Wilfongjt"}
######### DATABASE
LB_PROJECT_prefix=reg
# Model Users
LB_JWT_MODEL={"username":"jwt@register.com","email":"jwt@register.com","password":"PASSWORD.must.BE.AT.LEAST.32.CHARS.LONG","role":"jwt"}
LB_REGISTER_GUEST_MODEL={"username":"anonymous@register.com","email":"anonymous@register.com","password":"g1G!gggg","role":"anonymous"}
LB_REGISTER_REGISTRANT_MODEL={"username":"registrant@register.com","email":"registrant@register.com","password":"g1G!gggg","role":"registrant"}
LB_REGISTER_EDITOR_MODEL={"username":"editor@register.com","email":"editor@register.com","password":"g1G!gggg","role":"editor"}
LB_REGISTER_REGISTRAR_MODEL={"username":"registrar@register.com","email":"registrar@register.com","password":"g1G!gggg","role":"registrar"}
LB_TEST_USER={"type":"app", "app-name":"my-app","version": "1.0.0", "username":"testuser@register.com","email":"test@register.com","password":"g1G!gggg"}
LB_WEB_GUEST={"name":"anonymous@web.com","password":"g1G!gggg","role":"anonymous"}
######### PASSWORDS
LB_JWT_MODEL_password=PASSWORD.must.BE.AT.LEAST.32.CHARS.LONG
LB_WEB_PASSWORD=w1W!wwww
LB_WEB_GUEST_PASSWORD=g1G!gggg
LB_ADMIN_PASSWORD=a1A!aaaa
LB_ADMIN_GUEST_PASSWORD=g1G!gggg
LB_ADMIN_REGISTRAR_PASSWORD=r1R!rrrr
Setup Postgres rest development environment
- registrant-token indentifies the user to the system
- api-token is specific to a set of api methods
- user-token is specific to an application, limits access to api
- app-token ?? this the same as the api-token
Allow multiple applications to use the same API
- Provide an application registry by version
- Provide an app-token for each application by version
- Provide application specific user registry
- Provide a user-token for each user session
desc | role | params | success/fail | example |
---|---|---|---|---|
app registration | anonymous | app(JSONB) | {"results":"1"} {"results":"-1"} | app('{"app-name":"my-app", "version":"1.0.0", "username": "aaa@bbb.com", "password":"<password>"}') |
get app-token | anonymous | token(JSONB) | {"results":"<app-token>"} {"results":"-1"} | token('{"app-key":"my-app@1.0.0", "username":"aaa@bbb.com", "password":"<password>"}') |
user registration | anonymous | user(TEXT, JSONB) | {"results":"1"} {"results":"-1"} | user('{"app-token":"<app-token-string>", "user-name":"xxx@yyy.com", "password":"<password>"}') |
get user-token | anonymous | token(JSONB) | {"results":"<user-token>"} {"results":"-1"} | token('{"app-token":"<app-token-string>", "user-name":"xxx@yyy.com", "password":"<password>"}') |
token-anonymous {"username":"anonymous@register.com", "type":"app", "role":"anonymous"} select ((current_setting('app.lb_register_anonymous')::JSONB - 'password') || ('{"type":"app"}'::JSONB));
models are environment variables
- anonymous-model = {"username":"anonymous@register.com",
"email":"anonymous@register.com", "password":"g1G!gggg", "role":"anonymous"} - registrar-model = {"registrar-name":"registrar@register.com", "email":"registrar@register.com", "password":"g1G!gggg", "role":"registrar", "app_id":"<>.1.0.0"}
- testregistrar-model = {"type":"app", "app_id":"my-app@1.0.0", "username":"testuser@register.com", "email":"testuser@register.com", "password":"g1G!gggg", "role":"registrar"} testuser-model = {"type":"app", "app_id":"my-app@1.0.0", "username":"testuser@register.com", "email":"testuser@register.com", "password":"g1G!gggg", "role":"user"}
Tokens are JSON Web Tokens
- anonymous-token-content = {"username":"anonymous@register.com", "role":"anonymous"}
- app-token-content = {"registrar-name":"registrar@register.com", "role":"registrar"}
- user-token-content = {"username":"<>@<>.<>", "role":"user", "app_id": "<>@<>.<>"}
A form is client submitted set of attributes
- app-form = {"app-name":"", "type":"", "version":"1.0.0", "username":"", "password":""}
- user-form = {"username": "", "type": "user", "password": ""}
-
add application, app(app-form TEXT) return {"username":"anonymous@register.com", "type":"app", "token":"aaaaaa"}
-
add application, app(anonymous-token TEXT, app-form JSONB)
-
get app-token, app(anonymous-token TEXT, app_id TEXT) returns {"username":"anonymous@register.com", "type":"app", "token":"aaaaaa"}
-
add user, user(app-token, user-form)
-
get user, user(app-token, user-credentials) returns {"username":"anonymous@register.com", "type":"user", "token":"uuuuu"}
Admin-application is the starting point,
- register applications
- get anonymous token Client Application
- create users
- update user
app function: Insert an application record parameters anonymous-token TEXT app-form JSONB returns {}
app function: Select an application record parameters: anonymous-token TEXT app-form JSONB return {}
Get anonymous-token from admin application
app(form JSONB)
BEGIN
-- make token
_token = maketoken
return app(_token, form)
END
app(token TEXT, form JSONB)
BEGIN
-- role is
-- validate token
if not is_valid_token(token, expected_role) then
return '{"result":"0"}'::JSONB;
-- validate form attributes
if not(form ? 'app-name') then return '{"results":"-1"}';
if not(form ? 'version') then return '{"results":"-2"}';
if not(form ? 'username') then return '{"results":"-3"}';
if not(form ? 'password') then return '{"results":"-4"}';
if id in form:
UPDATE
else
-- stop versions
-- validation checks
INSERT
END;
* id(UUID), obj (JSONB), created(TIMESTAMP), updated(TIMESTAMP)
- id, type, attributes, created, updated id:uuid, type:'app', object:{"type":"app", "name": "", "version":"1.0.0", "username":"", "password":""} id:uuid, type:'user', object:{"type":"user","name": "", "username":"", "password":""}
* id(integer), uuid(UUID), obj (JSONB), created(TIMESTAMP), updated(TIMESTAMP)
* id(integer), key(UUID), obj (JSONB), created(TIMESTAMP), updated(TIMESTAMP)
* store application name, user-name, and encrypted password
* generate and store a reusable application token (app-token)
* an app-token changes when you update your password
* changing your password for a specific application version will
* old tokens are still valid so you wont need to change the app configuration when you change your password
* do this once and use it for your web app
* configure your application to use the token >> Devlopment use .env
>> api-token
*
- register new user,
- signin and get a user-token
we have at least two applications (an admin-app and a primary-app) so account needs to handle multiple applications
>> credential({username, password})
> upsert credentials
> add registrant-role
> return a registrant-token [ id, username, role:[roles] ]
>> register(registrant-token, {name, version})
> upsert application
> add 'owner:<registrant-id>'
>
>> credential(app-token, {username, password})
- registrant-token contains user-identifer, user-access [register-write, register-read]
- api-token contains application-identifer []
- user-token contains user-identifier, application-identifer, user-access
- app-token contains application-identifier,
- credentials (id, username, password, row, created, updated)
- register (id, name, row, created, updated )
create credentials john@some.com [registrant] register the "my-app" application john@some.com [registrant, apps:{app1:[,,...], app2:[,,...]]
credentials are username and password version is follows major.minor.patch pattern applicaton-name is a unique combination of a name, version number, ownername, and password (e.g. @) app-token is a token that grants application specific access to the api
administration-application primary-app admin-app
- An uncredentialed person adds the application-name and personal credentials to the register
- Establishes a unique application identity
- Pairs up the application and an owner
- Pairs up the Application and the API
- Establishes the person as the application owner
- An owner has rights to update the application's registration
- Creates an app-token for the application
- The app-token grants the right to create an application account, or signin to an application
- An uncredentialed person adds their credentials to access the api that supports the application
- Registration allows the person to request an a user specific api-token aka user-token
- A registered person is known as a registrant
send Form >> 'id' not in Form >> sync Form values to table field values
>> remove password
>> insert
>> id exists then update table fields found in object
three states of a value
- Undefined means not available eg crud="ru" doesnt provide insert
- Lowercase means optional e.g., "c"
- Uppercase means required e.g., "C" requires field on insert
Imutable ("I") values can be created/inserted but not changed/updated. Imutables are passed as part of the json object to the API. Imutables are checked to ensure they have not been changed. The differnce between "I" and "U", "I" declares imutability whereas the absense of "U", less obviously, implies imutability. "I" also has the sideeffect of making the API confirm the value has not changed.
- "C" in crud = "C" defines a required insert field value
- "c" in crud = "c" defines an optionally insertable table field value
- "c" in crud = "U" defines a required update table field value
- crud = "u" defines an optionally updateable table field value
- "I" in crud defines an imutable attribute, it can be created and is required for update but cant be updated
- "F" in crud defines a form field, F and C are mutually exclusive, F and U are mutually exclusive, F implies a C, F implies a U, forms are not passed in a form, a form is assembled, only one Form per record
- Forms are JSON objects.
- Forms are interfaces between client and backend
- Forms
- The list of Attributes apply to API input objects
- "C" in json is a required attribute on insert defines a required insertable input Form attribute
- "c" in json defines an optional insertable input Form attribute
- if no "C" or "c" then value cannot be inserted
- "U" in json defines a required updatable input attribute
- "u" in json defines an optional updatable input attribute
- if no "U" or "u" then value cannot be updated
- "I" in json defines an imutable attribute, same as "U" except it cant be upbdated
- "I" in json defines an imutable attribute, it can be created and is required for update but cant be updated
- "D" in json defines an attribute that is not stored in the Form, these are automatically removed from Form
https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/
- json = "P" defines a required partition key
- json = "S" defines a required sort key
- json = "p" defines an optional secondary partition key
- json = "s" defines an optional secondary sort key
- default = ""
- default =
- default = ""
- default = "()"
- default = "(_)"
- default =
- default =
[[update_combos_format]] update statements, all possible combinations of optional fields
[[required_update_inputs]]
[[required_insert_inputs]]
[[required_insert_inputs]]
[[insert - values]]
[[insert - columns]]
[[insert - sync - json - values]]
[[set - defaults]]
[[declare - upsert]]
[[where - clause]]
[[set - clause]]
[[required - insert - attributes]]
[[insert - parameter - types]]
[[select - parameter - types]]
[[update - parameter - types]]
[[delete-parameter-types]]
[[select - columns]]
[[update - columns]]
[[insert - parameters]]
[[db-extensions]]
[[tbl-fields]] table column definitions
Register your application and get an application-token
app_form = {
"type": "app",
"app-name": "my-app",
"version": "1.0.0",
"username": "abc@xyx.com",
"password": <your-password>"
}
register(app_form)
Register a user and create a user token
# retrieve your application token manually from register table
app_token = '<application-token>'
app_form = {
"app-name": "my-app",
"version": "1.0.0",
"username": "abc@xyx.com",
"password": "<your-password-here>"
}
user(app_token, form)
Signin and get a user-token