# QE Platform
QE is a multilingual SaaS platform that allows you to develop software as a service without having to go through the difficult steps of software as a service development.
- [QE website](http://qepal.com)
## QE is based on:
1. HTML, CSS, tailwind, [daisyui](https://daisyui.com/llms.txt)
2. [Nodejs](https://nodejs.org/en)
3. [Nextjs](https://nextjs.org/)
4. [Python 3.12.8](https://www.python.org/downloads/release/python-3128)
5. [Go Lang](https://go.dev/)
## QE Quick start:
1. Login to the [QE website](https://qepal.com)
2. Click on the Menu in the top right of the screen.
3. Select Services (4th Item on menu)
4. Select MongoDB Service and get it.
5. Click on the `Date` part of a service to open it's settings.
6. Clone a service and answer the technical questions while cloning a service.
7. Download `Development files` and then extract it on your computer. Note: development files only works on windows.
8. Install the latest version of [Nodejs](https://nodejs.org).
9. Open a terminal in the `explore` path of the downloaded files.
10. Type `yarn` then press enter.
11. Type `yarn manage` and press enter.
12. Now go back to the [QE website](https://qepal.com)
13. Open the `explore` settings by click on `date` now you should see many options to select for developing SaaS on the QE platform.
## QE Structure:
- The QE provides ability for some users (that privileged as developers) to create projects for a specific purpose.
- Each project on QE is named `explore`.
- The user that makes a `explore` is the `topuser` of the project and has highest access level to it. in the other word the `explore` is a project that will be created and tuned by a QE user that is names `topuser`.
- Any other user of QE (based on the `explore` settings) can make a derivative from from the `explore`.
- the derivative that is made from `explore` is named `service`.
- the user that make the derivative of the `explore` is named `middleuser`.
- the `middleuser` owns the `service`.
- making `service` and using it may has some costs based on the `explore` settings for the `middleuser` and it will be payed to the `topuser` (that made and owns the `exlore`)
- QE uses a communication network named `nexus`.
- All users and blocks in QE can communicate with each other by the `nexus` network.
## QE Users
### We have 3 user types on QE Platform:
1. `topuser` the user that creates and owns an `explore` and has highest access to the whole project.
2. `middleuser` the user that buys (or gets for free based on the `explore`'s settings) one instance of the `explore` that is named `service`. in the other word the `middleuser` owns a `service` that is derivative of the top user's `explore`
3. `enduser`: the user that uses the software in the `xwebsite` block it only exists in `xwebsite` block.
## QE `explore`
QE `explore` is actually a project that `topuser` make it.
### Where is the explore list on QE?
every project is indexed in the `https://qepal.com/[langcode]/explore` and `[langcode]` here is the language code of user. for example `https://qepal.com/en/explore` is the `explore` page for English users and `https://qepal.com/fa/explore` is the `explore` page for Persian language users.
### How to make an explore?
Making an explore is pretty easy just navigate to the [QE Explore page](https://qepal.com/fa/explore) and open a random explore there. click on the `date` part and click `clone` and answer the questions and your `explore` project is ready.
### `explore` Specifications
Every explore has some specifications that `topuser` will set and these specs will determine the `explore` and derivative `service` behavior.
- `app`: a unique string among all `explore`s. it will be use to communicate by `nexus` and a very important factor for building `block`s. The `topuser` will set it. it should be started by letter `e` and all after that should be lower case English letters, no number or special characters allowed in the `app` string.
- `mongourl`: every explore needs a `mongodb` database for working. the `topuser` should make a cloud `mongodb` and set it's connection string to the `explore`.
- `giturl`: every explore needs a [Github](https://github.com) repository that maintain the project. the `topuser` should set the `giturl` with the Github repository address of the project.
- `gittoken`: QE is a platform. it means it can publish and be a host for making the `explore` project `block`s online (by Docker technology). QE will get the project from `giturl` and clone it to it's server. but some projects are private on github. QE use a github token to access these private repositories to publish and make them online. thus it's a necessary part of every explore.
- `title1`: It is the main name (depends on user language) of the explore. it can contains some words to introduce the explore.
- `title2`: Its the secondary name (depends on user language) of the explore. it can contains some words to introduce the explore.
- `title0`: It's a very short (1 or 2 word) name of the explore.
- `icon`: It is a URL of an image for the `explore` icon. the image size should be lower or equal to 128x128 pixels and it should be square and recommended that be be in `PNG` or `webp` format and be lower than 10kb. it can be different in any language.
- `poster`: It is a URL of an image for the `explore` icon. the image size should be equal to 1024x768 pixels and it should be square and recommended that be in `PNG` or `webp` format and lower than 50kb. it can be different in any language.
## QE Blocks
1. Each project that is made may contains some `block`s
2. We have 5 type of blocks on the QE: `microservice`, `nodejs-worker` , `python-worker`, `golang-worker` and `xwebsite`.
### The `microservice` and `xwebsite` blocks:
#### Description:
- The `microservice` is the simplest way for the `middleuser` to communicate with the `service` and it runs on an IFrame inside [QE Website](https://qepal.com).
- The `xwebsite` is similar to the `microservice` but it can be run separately without an IFrame of [QE Website](https://qepal.com).
- Both of them are based on `Nextjs` but it's very customized and `topuser` must use and obey the design rules while designing it.
- Both of them uses `mongodb` database that is connected to the `explore`.
- `xwebsite` block has an extra database that is owned by `middleuser` and it is set to the `service`.
- Both of them use `SSR` part of the `Nextjs` framework but it is customized as well.
7. `microservice` can only be runned on an IFrame inside the [QE website](https://qepal.com). QE gives it a secret key from the service that is derivative from `explore` via Query string and by this way the `microservice` can identify that who is connected to it and which service is running on it.
8. `xwebsite` runs separately and it use two secret codes (locally by .env files and globally by env variables) one is explore secret, second is service secret. both of these codes will placed on project files by `yarn manage` automatically.
#### Custom Tags:
- In `microservice` and `xwebsite` front-end e have some `custom tags` that are actually custom HTML tags and they are fully defined on `global.css` and we use them for building our fully customized apps. here is the custom tags list:
##### Button custom tags:
- `b-100`: it is a button with `height: 30px`, it's `display: flex` and `min-width: 100px`
- we also have `b-30`, `b-50`, `b-150`,`b-200`, `b-300`, `b-400` and they are different in `min-width`. their `min-width` respectively are: `30px`, `50px`, `150px`, `200px`, `300px`, `400px`.
- the `b-[num]` that we mentioned above are useful for responsive design.
For example:
```html
button1button1button1
```
in the above code, if page's width is greater than 300px the 3 buttons will align horizontally but if page's width gets smaller they will be placed on new lines below together.
##### Font size custom tags:
all font size custom tags that we show here has below CSS properties:
``` CSS
text-align: justify;
word-spacing: -0.5px;
margin-block-start: 0px;
margin: 0;
padding: 0;
```
the custom font size tags format is like `f-[num]`, and `[num]` indicates the font size and starts from 5 to 40. for example we have `` to `` tags here is some examples:
```html
HelloHiWow im a font with 18px font-size
```
##### Horizontal spacing custom tags:
Horizontal spacing custom tags are for making horizontal space between two elements. for example assume that we have two images and we need some horizontal space between them.
The Horizontal spacing custom tags format is `sp-[num]` and `[num]` can be `1` for `10px` , `2` for `5px` , `3` for `3px` or `4` for `1px`.
Here is an example:
```html
```
##### Vertical spacing custom tags:
Vertically spacing custom tags are for making vertical space between two elements. for example assume that we have two images and we need some vertical space between them.
The vertical spacing custom tags format is `br-[num]` and `[num]` can be `1` for `10px` , `2` for `5px` , `3` for `3px` or `4` for `1px`.
Here is an example:
```html
```
##### Flex custom tags:
We have 3 group of useful custom tags that has `display:flex` CSS property. The format of these groups are `f-[n][m]` , `w-[n][m]` , `c-[n][m]` while `[n]` , `[m]` is parametric and depends on other CSS properties.
- The first group `f-[n][m]` has `flex-direction: row` .
- The second group `w-[n][m]` has `flex-direction: row` and `flex-wrap: wrap`.
- The third group `c-[n][m]` has `flex-direction: column`.
- We use first group when we need to place some children horizontally.
- We use second group when we need to place some children horizontally but we also need it to be responsive and children go to next line while parent's width is lower that sum of children's sum with.
- We use third group when we need to lace some children vertically.
Now lets explain `[n]` and `[m]` parameters:
- `[n]` actually determine the `align-item` and it can be 4 values:
-- `x` for `align-item: stretch`
-- `s` for `align-item: start`
-- `e` for `align-item: end`
-- `c` for `align-item: center`
Now lets explain `[m]` parameter:
- `[m]` actually determine the `justify-content` and it can be 4 values:
-- `s` for `justify-content: start`
-- `e` for `justify-content: end`
-- `c` for `justify-content: center`
-- `sa` for `justify-content: space-around`
-- `sb` for `justify-content: space-between`
-- `se` for `justify-content: space-evenly`
Now lets do some examples:
**Example 1**: Assume that we need a 100px x 100px rectangle with a `Hi` in the center of it.
**Answer 1**: There is two way to make it by flex custom tags, one of them is to use `f-cc` or `w-cc` and another way is to use `c-cc`.
First way:
``` html
Hi
```
or
``` html
Hi
```
in the above examples `f-cc` indicates `display:flex; align-item:center; justify-content:center` and it is all we need to place `Hi` in the center of it.
Second way:
``` html
Hi
```
in the above examples `c-cc` indicates `display:flex; flex-direction: column; align-item:center; justify-content:center` and it is all we need to place `Hi` in the center of it.
---
**Example 2**: Assume that we need a 100px x 100px rectangle with a `Hi` and `Bye` with 15px font-size. and both inside this rectangle and be horizontally beside each other and both be in the center of the parent.
**Answer2**:
``` html
HiBye
```
---
**Example 3**: Assume that we need a 100px x 100px rectangle with 3 Hi with the font size as: (the first one 15px, the second one 18px and the last one 20px) and we want all he horizontally besides together and maximum space between them.
**Answer 3**: For this question we need 3 elements to be be vertically centered and horizontally space-between so we need `display:flex; flex-diretion: row` so we have to use `f-[n][m]` and `align-items: center` to be vertically center aligned so `[n]-> c` and horizontally space between them so `[m] -> sb` finally we should use `` to solve this question below is the code:
``` html
HiHiHi
```
---
**Example 4**: Convert below code to the QE custom tags version:
``` html
```
**Answer 4**: Here is the QE custom tags equivalent:
```html
```
---
**Example 5**: Convert below code to the QE custom tags version:
``` html
```
**Answer 5**: Here is the QE custom tags equivalent:
```html
```
**Example 6**: Convert below code to the QE custom tags version:
``` html
HiHi
```
**Answer 6**: Here is the QE custom tags equivalent:
```html
HiHi
```
---
**Example 7**: Convert below code to the QE custom tags version:
``` html
```
**Answer 7**: Here is the QE custom tags equivalent:
```html
```
---
**Example 8**: Convert below code to the QE custom tags version:
``` html
```
**Answer 8**: Here is the QE custom tags equivalent:
```html
```
---
**Example 9**: Convert below code to the QE custom tags version:
``` html
```
**Answer 9**: Here is the QE custom tags equivalent:
```html
```
---
**Example 10**: Convert below code to the QE custom tags version:
``` html
```
**Answer 10**: Here is the QE custom tags equivalent:
```html
```
---
**Example 11**: Convert below code to the QE custom tags version:
``` html
```
**Answer 11**: Here is the QE custom tags equivalent:
```html
```
---
**Example 12**: Convert below code to the QE custom tags version:
``` html
```
**Answer 12**: Here is the QE custom tags equivalent:
```html
```
---
**Example 13**: Convert below code to the QE custom tags version:
``` html
Hi Bye Hi
```
**Answer 13**: Here is the QE custom tags equivalent:
```html
HiByeHi
```
#### QE Components
We have some `QE Components` that are actually `Nextjs` components and we store them in `frontend/components/qecomps`. we use these components as much as we can instead of building new components. here is detail explanations for each of them:
#### Pages:
1. Both `microservice` and `xwebsite` has pages to communicate with the `middleuser` (on `microservice`) and `enduser` (on `xwebsite`) The first page is placed on `./pages/[lang]/index.tsx` in this path `[lang]` will determinate the `middleuser` 's (on `microservice`) and `enduser` (on `xwebsite`) language that they selected.
2. Below code is the minimum code for a page to run:
3.
```jsx
import Component, { PageEl } from '@/frontend/components/qecomps/Component'
import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
//front-end function:
export default p => Component(p, Page);
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
return
}
//backend-part:
export const getServerSideProps: GetServerSideProps = async (context: GetServerSidePropsContext) => {
(global.Startup != "OK") ? (await (await import('@/startup.ts')).Starter()) : null
var session = await global.SSRVerify(context)
var { lang, path, pageid } = session;
let keys = ["region", "dir", "ff", "ffb", "support", "code", "textw", "txtmt"]
let nlangs = {}
for (let l of Object.keys(global.langs[lang])) {
if (keys.includes(l))
nlangs[l] = global.langs[lang][l]
}
// doint the server side operations for serving the page
let obj = await Prosper({
props: {
query: context.query,
nlangs,
path,
session,
title: "test title",
description: "test description",
pageid,
},
}, context)
return obj
}
```
#### Page's main parts:
In the `Page` function of front-end we have `props` , `refresh` , `getProps` , `onLoad` , `onConnected` , `dies`, `isFront` .
##### props (front-end):
1. The `props` in `microservice` and `xwebsite`'s front-end is a javascript Object (mutable) and it consists of the back-end data that is send by `props` inside `Prosper` function.
2. The `props` in the front-end also used for storing data that needs to be maintained during `refresh` in the front-end.
##### refresh:
1. `refresh` is something like `setState` in the `Nextjs` while the `state` is the `props` on QE. In the other word, When `refresh` is called on front-end the page will be `re-rendered` while all values that needs to be maintained during rendering must be assigned to the `props` Here is an example:
```jsx
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
return
{props.sayhi}
}
```
in the above example after clicking on the button, "hi" will be showed on the page.
2. assigning values to the `props` in the `refresh` is also possible as below example:
```jsx
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
return
{props.sayhi}
}
```
##### getProps:
it is a function that runs before rendering the page and it will be used for assigning necessary variables on `props` or getting something from another source before showing the page.
Here is an example:
```jsx
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
getProps(async (isFront)=>{
let json = await api("https://example.com/api/test");
props.sayhi = json.sayhi
})
return
{props.sayhi}
}
```
in the above example we get information from the URL and assign it to the `props.sayhi` for rendering. it's notable that we have an optional parameter in `onLoad` named `isFront` and it show that is it rendering on client (browser) or not. the `isFront` is equal to the `typeof window != "undefined"` in `Nextjs`.
##### onLoad:
The `onLoad` function will be called after page is loaded completely. it is equal to the `useEffect(()=>{},[])` in the `Nextjs` but it gets an async function instead of sync one in the `useEffect(()=>{},[])`.
Here is an example:
```jsx
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
onLoad(async ()=>{
props.sayhi = "hi"
refresh()
})
return
{props.sayhi}
}
```
in the above example after loading the page, the `onLoad` will be called and then "hi" will be assigned to the props and we refresh the page to show the `props.sayhi`'s value on the page.
##### onConnected
The `onConnected` function will be called after the `nexus` is connected. thus when we want to do something with `nexus` on front-end of `microservice` or `xwebsite` we should wait until this functions is called.
Here is an example:
```jsx
export default p => Component(p, Page);
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
onConnected(async () => {
let r = await nexus.api({ app: "etest", cmd: "ping" })
refresh({sayhi: r.sayhi})
})
return
{props.sayhi}
}
```
in the above example when nexus is connected on front-end. we will send a ping request by `nexus-api-request` to a block that is based on an explore named `etest` and wait for it's reply that contains a `sayhi` key and after that we will refresh page and put the value on the `props` and show it.
##### dies
The `dies` function will be called when the QE component (That is actually something like `Nextjs` component) is dying. it's something equivalent to the `Nextjs`s `useEffect(()=>{} return ()=>{}),[])` and can be usefull when we want to stop something that is running while component is alive.
Here is an example:
```jsx
export default p => Component(p, Page);
const Page: PageEl = (props, refresh, getProps, onLoad, onConnected, dies, isFront, z) => {
onLoad(async () => {
if(!props.counter)
props.counter = 0
props.c = setInterval(() => {
props.counter++
refresh()
}, 1000);
})
dies(async () => {
clearInterval(props.c)
})
return
{props.counter}
}
```
in the above example we want to have a counter that when page fully loaded starts counting. so we have `onLoad` function that is called when page is loaded completely and we start a `setInterval` function with 1000ms interval and when we route to another page or component dies it has to be stop counting and so we use `clearInterval` function in `dies` function to stop it.
##### z
`z` is an object in the `microservice` and `xwebsite` front-end and it's very useful for something like identifying user or getting styles or even it has some language variables (variables that changes by selected user's language). it has different children at `microservice` and `xwebsite` and we will explain it below:
- `z.crossstyles`: it has some keys for controlling some styles. for example QE form styles is controlled by this.
- `z.lang`: it has all language key/values for using on multilingual pages. for example if we have `z.lang.hi` defined on the database when user chooses English language the `z.lang.hi`'s value will be `Hi` and else if user chooses Persian language the `z.lang.hi`'s value will be `سلام`.
- `z.qestyles`: it has some styles for the QE components.
- `z.root`: it has root path string based on selected user language for example if user selected English language, then `z.root` will be `/en` and else if user chooses Persian it will be `/fa` it's useful for routing pages.
- `z.styles`: it has developers styles from CSS file that is placed on `[PROJECT ROOT]/styles/styles.module.css`
- `z.middleuser`: it contains information about the `middleuser`.
-- `z.middleuser.uid` indicated the `middleuser`'s unique ID. It is got from the QE 's user's database. in the back-end it's actually ObjectId type but here in the front-end it's the equivalent hex string.
-- `z.middleuser.name` indicated the `middleuser`'s name. It is got from the QE 's user's database.
-- `z.middleuser.image` indicated the `middleuser`'s image. It is got from the QE 's user's database.
-- `z.middleuser.email` indicated the `middleuser`'s email. It is got from the QE 's user's database.
-- `z.middleuser.phone` indicated the `middleuser`'s phone. It is got from the QE 's user's database. it's notable that this field does not contain country code.
-- `z.middleuser.lang` indicated the `middleuser`'s language code. (it's a two character string language code, for example `en` for `English`, `fr` for `French`, `fa` for `Farsi (Persian)` and `zh` for `Chinese`).
-- `z.middleuser.cchar` indicated the `middleuser`'s country code . It is got from the QE 's user's database. For example `US` for `United states` and `UK` for `United Kingdom`, etc.
-- `z.middleuser.ccode` indicated the `middleuser`'s country phone code . It is got from the QE 's user's database. For example `+1` for `United states` and `+98` for `Iran`, etc.
-- `z.middleuser.unit` is a string and indicated the `middleuser`'s money unit . It is got from the QE 's user's database. For example `usd` for `United states Dollars` and `usdt` for `Tether`, `toman` for `Iranian Toman` or `aud` stands for `Australian dollar`, etc.
-- `z.middleuser.status` is a string and indicated the `middleuser`'s `service`'s status. it can have values `approved` , `rejected`, `waiting` based on the `service` condition.
-- `z.middleuser.mongourl` is `mongodb` connection string for `service`. note that it's different than `explore`'s `mongodb` connection string. the `z.middleuser.mongourl` is owned by `middleuser` while the `explore`'s `mongourl` is owned by `topuser`.
-- `z.middleuser.role` is a string array (string[]) and indicated the `middleuser`'s roles. it is set by `topuser` and specifies the `middleuser` accessibility in the `microservice` (that is created by `topuser` in fact).
-- `z.middleuser.quota` is a number that indicated the `service` quota. if it's equal to zero, `middleuser` can use service unlimited and if it's a positive number it must be lower than `z.middleuser.usedquota` so `middleuser` can use any block of the service.
-- `z.middleuser.usedquota` indicates the used quota of the `service` and if `z.middleuser.quota` is greater than zero and `z.middleuser.usedquota` >= `z.middleuser.quota` then the `service` will be unusable because `out-of-quota`.
-- `z.middleuser.quotaunit` is a string that shows the `z.middleuser.quota`'s unit.
-- `z.middleuser.rolecheck`: is a function that takes a role's string array and check if `middleuser` has any kind of the input roles.
-- `z.middleuser.servid`: is `unique service id` in the back-end it's actually an ObjectId but here in the front-end it is a string.
-- `z.middleuser.servsecret`: is a string that provide access to the `service` and it's owned by `middleuser`.
-- `z.middleuser.tempsecret`: is a javascript Object that provide Multi-factor authentication for some kind of applications like uploader it contains `z.middleuser.tempsecret.generate` and `z.middleuser.tempsecret.verify`.
--`z.middleuser.tempsecret.generate`: is a async function that returns a Multi-Factor authenticatin code (a 6-digit code).
--`z.middleuser.tempsecret.verify`: is a async function that checks a Multi-Factor authenticatin code (a 6-digit code) and if it is valid returns true otherwise false.
- `z.topuser`: it contains some limited information about the `topuser`.
-- `z.topuser.uid` indicated the `topuser`'s unique ID. It is got from the QE 's user's database. in the back-end it's actually ObjectId type but here in the front-end it's the equivalent hex string.
-- `z.topuser.name` indicated the `topuser`'s name. It is got from the QE 's user's database.
-- `z.topuser.image` indicated the `topuser`'s image. It is got from the QE 's user's database.
-- `z.topuser.email` indicated the `topuser`'s email. It is got from the QE 's user's database.
-- `z.topuser.phone` indicated the `topuser`'s phone. It is got from the QE 's user's database. it's notable that this field does not contain country code.
-- `z.topuser.lang` indicated the `topuser`'s language code. (it's a two character string language code, for example `en` for `English`, `fr` for `French`, `fa` for `Farsi (Persian)` and `zh` for `Chinese`).
-- `z.topuser.cchar` indicated the `topuser`'s country code . It is got from the QE 's user's database. For example `US` for `United states` and `UK` for `United Kingdom`, etc.
-- `z.topuser.ccode` indicated the `topuser`'s country phone code . It is got from the QE 's user's database. For example `+1` for `United states` and `+98` for `Iran`, etc.
-- `z.topuser.unit` is a string and indicated the `topuser`'s money unit . It is got from the QE 's user's database. For example `usd` for `United states Dollars` and `usdt` for `Tether`, `toman` for `Iranian Toman` or `aud` stands for `Australian dollar`, etc.
- `z.enduser`: [NOTE: It is only available on `xwebsite` block ] It contains information about the `enduser`.
-- `z.enduser.uid` indicated the `enduser`'s unique ID. It is got from the QE 's user's database. in the back-end it's actually ObjectId type but here in the front-end it's the equivalent hex string.
-- `z.enduser.name` indicated the `enduser`'s name. It is got from the QE 's user's database.
-- `z.enduser.image` indicated the `enduser`'s image. It is got from the QE 's user's database.
-- `z.enduser.email` indicated the `enduser`'s email. It is got from the QE 's user's database.
-- `z.enduser.phone` indicated the `enduser`'s phone. It is got from the QE 's user's database. it's notable that this field does not contain country code.
-- `z.enduser.lang` indicated the `enduser`'s language code. (it's a two character string language code, for example `en` for `English`, `fr` for `French`, `fa` for `Farsi (Persian)` and `zh` for `Chinese`).
-- `z.enduser.cchar` indicated the `enduser`'s country code . It is got from the QE 's user's database. For example `US` for `United states` and `UK` for `United Kingdom`, etc.
-- `z.enduser.ccode` indicated the `enduser`'s country phone code . It is got from the QE 's user's database. For example `+1` for `United states` and `+98` for `Iran`, etc.
-- `z.enduser.unit` is a string and indicated the `enduser`'s money unit . It is got from the QE 's user's database. For example `usd` for `United states Dollars` and `usdt` for `Tether`, `toman` for `Iranian Toman` or `aud` stands for `Australian dollar`, etc.
-- `z.middleuser.role` is a string array (string[]) and indicated the `enduser`'s roles. it is set by `middleuser` and specifies the `enduser` accessibility in the `xwebsite` (that is created by `middleuser` in fact).
-- `z.middleuser.rolecheck`: is a function that takes a role's string array and check if `enduser` has any kind of the input roles.
-- `z.middleuser.tempsecret`: is a javascript Object that provide Multi-factor authentication for some kind of applications like uploader it contains `z.middleuser.tempsecret.generate` and `z.middleuser.tempsecret.verify`.
--`z.middleuser.tempsecret.generate`: is a async function that returns a Multi-Factor authentication code (a 6-digit code).
--`z.middleuser.tempsecret.verify`: is a async function that checks a Multi-Factor authentication code (a 6-digit code) and if it is valid returns true otherwise false.
### The `nodejs-worker` block:
#### Description
Some tasks need to be separately done. For example assume that when we need to run a command on another system we cannot do it directly using `microservice`. or assume that we need a process to be run on 10 separate system due to load-balancing. in such cases we send data and commands to a worker block (like `nodejs-worker` or `python-worker`, etc) and it do the job and send the result back.
#### How to start
when the `topuser` make a project, they can download the development files. after extracting them they should run `yarn manager` and after that they can go to the `explore`'s settings and you will see multiple blocks consists of `w[app]` with a `Nodejs` icon on it. for example is the app's name was `test` you should see `wtest` icon on the `explore`'s settings. you should also see a blue icon for `vscode`. for beginning you should click on the `vscode` icon in the `explore`'s settings and if `yarn manager` connects successfully you should have `Visual Studio Code` runned on the `explore`'s path on your system. after that click on `w[app]` folder and open `run.ts` in the `vscode`. the minimum code for running a worker is below:
```ts
import { App } from './libs/bridge';
(async () => {
console.clear()
await App.Init(false);
await App.initUDB();
await App.Connect({ //if process args not available use this
resource: process.env.RESOURCE || "default",
image: "/files/app/robot.webp",
})
console.log("[nexus] connected.")
App.on("ping", async (specs) => {
console.log("ping request from:", specs.uid)
return { code: 0, pong: true }
})
})();
```
after that in the `explore`'s settings click on the `w[app]`'s (with nodejs icon) and it will be run on your system locally.
in the above code, the worker is connected to the `nexus` network with the `resource` from `process.end.RESOURCE` and if this environment variable doesn't exists it uses `default` as resource. It will also initiate a mongodb database object that is globally available via `global.udb` or simply `udb`. on the above code we see:
```ts
App.on("ping", async (specs) => {
console.log("ping request from:", specs.uid)
return { code: 0, pong: true }
})
```
this is a `nexus api` code and here we have a `ping` api on this worker. this part of code is necessary due to health check of the worker and it's communications through `nexus api`. further information about `nexus` and it's parts are available at the `nexus` part.
#### MongoDB Database on `nodejs-worker`
Every block that runs from explore by `topuser` has access to the `explore`'s mongodb database. for example assume that we want to add a test object into mycollection of the database in `nodejs-worker` here is the full code:
```ts
import { App } from './libs/bridge';
(async () => {
console.clear()
await App.Init(false);
await App.initUDB();
await App.Connect({ //if process args not available use this
resource: process.env.RESOURCE || "default",
image: "/files/app/robot.webp",
})
console.log("[nexus] connected.")
await udb.collection("mycollection").insertOne({mykey:"test value"})
App.on("ping", async (specs) => {
console.log("ping request from:", specs.uid)
return { code: 0, pong: true }
})
})();
```
Note that every job on the worker must be after the `await App.Connect(...)` part of the code not before that because the initialization of every part of this worker is only ready when this fully executed.
in the above example as we said before the `udb` object is the `explore`'s mongodb object and we can easily use it to do every database operation we want.
### The `python-worker` block:
#### Description
Some tasks need to be separately done. For example assume that when we need to run a command on another system we cannot do it directly using `microservice`. or assume that we need a process to be run on 10 separate system due to load-balancing. in such cases we send data and commands to a worker block (like `nodejs-worker` or `python-worker`, etc) and it do the job and send the result back.
#### How to start
when the `topuser` make a project, they can download the development files. after extracting them they should run `yarn manager` and after that they can go to the `explore`'s settings and you will see multiple blocks consists of `wpy[app]` with a python icon on it. for example is the app's name was `test` you should see `wpytest` icon on the `explore`'s settings. you should also see a blue icon for `vscode`. for beginning you should click on the `vscode` icon in the `explore`'s settings and if `yarn manager` connects successfully you should have `Visual Studio Code` runned on the `explore`'s path on your system. after that click on `wpy[app]` folder and open `run.ts` in the `vscode`. the minimum code for running a worker is below:
```python
import asyncio
from libs.bridge import APISpecs, App as app, MessageSpecs, SetInterval
from libs.startup import startup
startup()
App = app(
resource="python", image="/files/app/robot.webp", public=True
)
async def api(specs: APISpecs):
if specs.cmd == "ping":
return {"pong": True}
App.xmpp.onapi = api
loop = asyncio.get_event_loop()
loop.run_forever()
```
in the above code it will connect to the `nexus` network with a `ping` api and we can run every code that we need after below part of code:
```python
App = app(
resource="python", image="/files/app/robot.webp", public=True
)
```
### The `golang-worker` block:
#### Description
Some tasks need to be separately done. For example assume that when we need to run a command on another system we cannot do it directly using `microservice`. or assume that we need a process to be run on 10 separate system due to load-balancing. in such cases we send data and commands to a worker block (like `nodejs-worker` or `python-worker`, etc) and it do the job and send the result back.
#### How to start
The `golang` worker is under development.
### The `xwebsite` block:
#### Description
When we need to work with the made software by `topuser` as explore. the only way to communicate with the software, workers and any other block is to use `microservice`. But `microservice` can only be runned as an IFreame in the [QE Website](https://qepal.com) but what if we need a website that use QE 's facilities but runs directly on browser and not as an IFrame inside QE? The answer is `xwebsite` block. by this we can run a user-interface to the software we build separately on s subdomain of QE, and we can have a `xwebsite` on `[app]-[xwebsite block name]-[resource].qepal.com` for example if we have an explore with `app` equal to `etest` and we have a block named `xtest` then the subdomain will be `etest-xtest-xservice.qepal.com`
#### How to start
when the `topuser` make a project, they can download the development files. after extracting them they should run `yarn manager` and after that they can go to the `explore`'s settings and you will see multiple blocks consists of `x[app]` with a globe icon on it. for example is the app's name was `test` you should see `xtest` icon on the `explore`'s settings. you should also see a blue icon for `vscode`. for beginning you should click on the `vscode` icon in the `explore`'s settings and if `yarn manager` connects successfully you should have `Visual Studio Code` runned on the `explore`'s path on your system. after that click on `x[app]` folder and open `run.ts` in the `vscode`. the minimum code for running a worker is exactly the same as `microservice` 's minimum code that is available at `pages/[lang]/index.tsx`.
## QE Comminications (Nexus):
### Description
Nexus is a XMPP based system for comminucating between all users and blocks in QE system. every block that get's online will connect by it so they can communicate with each other. when a block connects to the `nexus` network it will have a JID as below format:
```
[app]-[userUID]-[role]@qepal.com/[resource]
```
in above format:
- `app` is the `explore`'s `app` and determine that the connected `block` belongs to what `explore` .
- userUID is the connected user by that `block`. let's make some clearification about this. assume that `userA` makes an `explore` and runs a `nodejs block`