Uesio is a low-code application development platform.
- Install homebrew (for macOS user)
- Install git
- Install GitHub Desktop GitHub Desktop
- Install nvm (for ensuring that your version of Node.js matches the version used in the repo):
nvm install
- Install Go
- Install the following brew packages:
hurl
(for integration tests):brew install hurl
jq
(for JSON manipulation in Shell):brew install jq
wget
(for fetching URLs):brew install wget
- Start dependencies here.
- Build
- Run.
- Set up SSL here. If you don't set up SSL locally and you still want to run multiple sites locally in addition to the ues.io studio, you will need to set the
UESIO_ALLOW_INSECURE_COOKIES
environment variable totrue
- Set up local DNS here This is also necessary if you want to run multiple sites locally in addition to the ues.io studio. By default, you can access the studio at
http://localhost:3000
- Install VS Code and plugins (ESLint, Prettier, Go, GitLens). Do enable
format on save
in conjunction with thePrettier
. Set up thecode
environment variable. - Install the following Google Chrome plugins :
React Developers Tools
,Redux DevTools
. - Install Oh My Zsh
- Add a SSH key to your github account
- Install the
nx
cli globally:npm i -g nx
- An alternative to installing
nx
globally is to set an alias in your~/.zshrc
file or equivalent:alias nx="npx nx"
. This way your global nx version will always be the correct version.
npm run dev
- Optional. Create a file called
launch.json
located inapps/.vscode
for the uesio server debugger in Go and paste the following :
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceRoot}",
"env": {},
"args": ["serve"]
}
]
}
- Download and install the npm module dependencies
npm install
npm run build-all
cd ./libs/apps/uesio/studio && uesio pack
// or
npm run nx -- build apps-uesio-studio
// or, if you have nx installed globally (or aliased)
nx build apps-uesio-studio
While developing you may want the entire monorepo to rebuild changed files. You can do this with:
npm run watch-all
If you'd like to use the Uesio CLI that you have built elsewhere on your machine without having to explicitly reference the binary in dist/cli
:
- Mac OS/Linux: create a symlink for the Uesio CLI into your bin (NOT an alias, which won't work with
nx
):sudo ln -s <absolute project root path>/dist/cli/uesio /usr/local/bin
- Windows: add
<absolute project root path>/dist/cli
to your PATH
- Launch all local dependencies (e.g. Postgres) with Docker Compose:
docker compose up -d
- Seed your local Postgres database with everything Uesio needs for local development
npm run migrations
npm run seeds
npm start
open http://localhost:3000
If you have SSL and local DNS configured, you can access the Studio via the following "local" DNS:
open https://studio.uesio-dev.com:3000
To run the app in Docker locally:
npm run in-docker
open https://studio.uesio-dev.com:3000
SSL is optional for local development. It is enabled using by setting the environment variable UESIO_USE_HTTPS=true
npm run setup-ssl
This script should create the certificate.crt
and private.key
files in the apps/platform/ssl
directory.
On Windows/Linux, you will need to manually trust this self-signed certificate. On Mac OS, this is done automatically.
- Windows: double-click certificate.crt in the File Explorer. Click "Install Certificate..." Then place the certificate in the "Trusted Root Certification Authorities".
If you just want to work in the Uesio Studio site, local DNS setup is not necessary, you can just access "http://localhost:3000".
However, to simmulate how Uesio routes DNS domains and subdomains to Uesio sites, you need to configure your OS to properly route "local" DNS domains (e.g. "uesio-dev.com") to the Uesio app server running on localhost.
There are two ways to do this, you'll need to pick one:
-
Modify /etc/hosts directly
On Mac/Linux, modify the
/etc/hosts
file to resolve local subdomains to 127.0.0.1bash ./scripts/seed-etc-hosts.sh
-
Use DNSMasq
brew install dnsmasq
The installation process will output several commands that you can use to start Dnsmasq automatically with a default configuration. I used the following commands but you should use whichever commands brew tells you to:
sudo brew services start dnsmasq
There are a number of worker jobs which Uesio runs in production, to handle things such as usage event aggregation, daily invoice generation, and potentially other future use cases (such as scheduled bots).
To run the worker process, use npm run nx -- worker platform
(Or nx worker platform
if you have nx installed globally):
> nx run platform:worker
{"message":"Running Uesio worker process","severity":"INFO"}
{"message":"Scheduling job Invoices with schedule: @daily","severity":"INFO"}
{"message":"Scheduling job Usage with schedule: * * * * *","severity":"INFO"}
{"message":"Finished loading all jobs, starting scheduler now...","severity":"INFO"}
{"message":"Cron job Invoices (1) next run will be at: Mar 22 00:00:00","severity":"INFO"}
{"message":"Cron job Usage (2) next run will be at: Mar 21 20:09:00","severity":"INFO"}
The following environment variables can optionally be configured in your Shell (e.g. in ~/.zshenv
if you are using Zsh)
Environment Variable | Description | Default | Examples, Values, and Help |
UESIO_USE_HTTPS | Whether or not to serve with TLS | false | true / false |
HOST | Host to use for HTTP server | "" | Set to "localhost" for local development |
UESIO_PRIMARY_DOMAIN | The primary domain to use for site identification purposes (e.g. for ues.io cloud, this is "ues.io") | localhost (or "uesio-dev.com" if `UESIO_DEV=true`) | If running ues.io on your own infrastructure, set to a 2-part TLD that you own. |
UESIO_SESSION_STORE | Allows you to specify the storage location for user sessions | redis | redis, filesystem, "" |
UESIO_USERFILES_BUCKET_NAME | The Bucket in AWS / local folder where user-uploaded files will be stored. | "" | |
UESIO_BUNDLES_BUCKET_NAME | The Bucket in AWS / local folder where bundles will be stored. | "" | |
UESIO_STATIC_ASSETS_HOST | Host from which to serve static files, including vendored JS (React) and Uesio assets | "" | By default, assets are served from the local filesystem / Docker container. Alternately, set this to a valid URL where Uesio static assets live, e.g. "https://www.ues.io" |
UESIO_ALLOW_INSECURE_COOKIES | Allows cookies without the secure flag | true | Useful in local docker development |
UESIO_PLATFORM_FILESOURCE_TYPE | Controls where user-uploaded files are stored | uesio.local | Either "uesio.local" (filesystem) or "uesio.s3" (store in AWS S3) |
UESIO_PLATFORM_FILESOURCE_CREDENTIALS | The name of the Uesio credential to use for saving user-uploaded files | uesio/core.aws | Must be a fully-qualified Uesio credential name |
UESIO_PLATFORM_BUNDLESTORE_TYPE | Controls where Uesio bundles are stored | uesio.local | Either "uesio.local" (filesystem) or "uesio.s3" (store in AWS S3) |
UESIO_PLATFORM_BUNDLESTORE_CREDENTIALS | The name of the Uesio credential to use for saving bundlestore files | uesio/core.aws | Must be a fully-qualified Uesio credential name |
UESIO_DEV | Enable various features for use in local development of Uesio | false | Set to "localhost" for local development |
UESIO_DEBUG_SQL | Enable detailed SQL query debugging | false | If enabled, all Wire loads will return a `debugQueryString` property containing the SQL queries made |
UESIO_MOCK_AUTH | Enables you to login with mock user accounts (which can be specified with `UESIO_MOCK_AUTH_USERNAMES`) | false | Only for local dev / unit tests |
UESIO_MOCK_AUTH_USERNAMES | A comma-separated list of usernames to use for mock authentication (requires `UESIO_MOCK_AUTH=true`) | ben,abel,wessel,baxter,zach,uesio | Only for local dev / unit tests |
UESIO_GRACEFUL_SHUTDOWN_SECONDS | The number of seconds to wait before terminating the Uesio app / worker process | 5 | Should be less than whatever the ECS / Kubernetes / etc shutdown window is (usually 30) |
UESIO_USAGE_JOB_RECURRENCE_MINUTES | The number of minutes to wait between runs of the Usage worker job | 10 | Usage data (stored in Redis) will only be aggregated and committed to Postgres as often as this job is run by the worker process. Set to a lower window for more frequent checks. |
UESIO_WORKER_MODE | Determines whether the batch job worker will run as part of the serve command or as a separate process. | separate | separate: The worker will run as a separate process. combined: The worker will run as part of the serve command. |
UESIO_USAGE_MODE | Determines whether to handle usage in memory on the web server, or to use redis for multiple web servers. | redis | redis, memory |
UESIO_PLATFORM_CACHE | Determines whether to handle the platform cache in memory on the web server, or to use redis for multiple web servers. | redis | redis, memory |
REDIS_HOST | The host to connect to Redis | ||
REDIS_PORT | The port to connect to Redis | 6739 | |
REDIS_USER | The Redis Username (If Necessary) | ||
REDIS_PASSWORD | The Redis Password (If Necessary) | ||
REDIS_TTL | Redis TTL Seconds | 86400 | Default is one day. |
REDIS_TLS | Whether or not to use TLS Mode | false | true or false |
UESIO_DB_USER | |||
UESIO_DB_PASSWORD | |||
UESIO_DB_DATABASE | |||
UESIO_DB_HOST | |||
UESIO_DB_PORT | 5432 | ||
UESIO_DB_SSLMODE | disable | disable, allow, prefer, require, etc. |
In addition, all Uesio Secrets can have their default value set by setting a corresponding UESIO_SECRET_<namespace>_<name>
environment variable. Any value set for these secrets in a Site/Workspace will override the environment variable default, but it can often be useful, especially for local development, to configure a default value, so that you don't have to populate these secrets in every site. (Note: there is no corresponding feature for Config Values, because you can define a Config Value's default directly in the metadata definition).
For example, the uesio/appkit.resend_key
secret's default value can be configured with export UESIO_SECRET_UESIO_APPKIT_RESEND_KEY=your-resend-key
As mentioned in the monorepo section, a single package.json
file describes the npm dependencies for the whole monorepo.
All npm modules we used are installed as development
dependency since uesio is not intended to be released as standalone npm module.
We use golang-migrate
package for running SQL migrations. This package maintains the current state of migration runs via a schema_migrations
table.
Migrations can be run against your local using npm run migrations
, or you can use ./uesio migrate [up|down] [NUMBER]
to manually run a specific number of migrations, e.g. to undo the most recent migration, you can run ./uesio migrate down 1
.
To run migrations in ECS, create a new one-off Task, using the latest Task Definition for "uesio", and modify the command to be ./uesio,migrate
(or ./uesio,migrate,down,1
) to undo one migration)
New migrations can be created using npm run migrate:create -- <SOME_NAME>
To forcibly set the migration version to latest (currently 4), you can either use pgcli
or some other DB tool to manually run the command update schema_migrations set version = 4, dirty = false
against your database, or use this (assuming you install golang-migrate
with brew):
brew install golang-migrate
export CONN_STR="postgres://postgres:mysecretpassword@localhost:5432/postgresio?sslmode=disable"
migrate -path apps/platform/migrations -database "$CONN_STR" force 4
This will skip running any migrations but update schema_migrations
table to think you've run them all up through 4
To test running migrations (against a separate pgtest
database alongside your main postgresio
database for dev), do the following (run from THIS top-level directory!):
docker compose up -d
bash apps/platform/migrations_test/test_migrations.sh
![IMPORTANT] The default behavior for all tests is to run against
https://studio.uesio-dev.com:3000
so you must ensure that SSL and local DNS have been configured.
To run the various test suites, there are a number of commands available:
npm run tests
- Runs all Unit tests
npm run tests-all
- Runs all Unit, Integration and E2E tests against your local Uesio app.
- Use this when writing and debugging tests locally
npm run tests-docker
- This is what we run in Github Actions CI builds for integration & E2E tests. It builds the latest code, spins up all dependencies, and a Dockerized version of the Uesio app, runs integration and E2E tests against the app, and then spins down all Docker containers.
npm run tests-integration
- Runs just the Integration Tests (against your local app).
npm run tests-e2e
- Runs just the E2E Tests (against your local app).
npm run tests-init
- Deletes the
uesio/tests
app if it exists and then creates theuesio/tests
app with related workspaces and sites and loads seed data. All of the above scripts execute this script automatically so there is not typically a need to run it. However, if you want to run individual tests (via hurl, cypress, etc.) separate from one of the above scripts which runs an entire suite, you will need to run this script to prepare for test execution.
- Deletes the
npm run tests-cleanup
- Removes the
uesio/tests
app (if it exists). Similar totests-init
, the automated test suite scripts will execute this script prior to completion. However, if a test run terminates abnormally and/or if you rantests-init
manually, you can execute this script to remove the test relateduesio/tests
app.
- Removes the
npm run tests-cypress-open
- Runs the cypress visual UI where you can run E2E tests from. See E2E testing with cypress for details.
npm run tests-cypress-run
- Runs the cypress in headless mode, helpful when you want to run individual tests. See E2E testing with cypress for details.
TO run just an individual E2E or Integration test, see the sections below.
Note
You must manually run npm run tests-init
in order to run individual tests. Depending on the test, you may need to re-run this script prior to every test execution. Additionally, ensure that UESIO_DEV=true
environment variable is set prior to starting the server and for each test so that mock logins can be used.
We use Cypress for writing end-to-end tests of the Uesio app. All E2E tests are defined in apps/platform-e2e
directory.
E2E tests are the most expensive and most brittle, and as such should be used sparingly.
If you're running Uesio locally, you can use npm run tests-cypress-open
to launch Cypress' visual UI for running tests, or npm run tests-e2e
to just run all the tests in a headless runner. Note that when running using the visual UI or when running individual tests as per the below, you must have the UESIO_DEV=true
environment variable set and have run npm run tests-init
.
If you want to visually run a single spec, use the Cypress visual UI and then select the individual spec.
Or, use npm run tests-cypress-run -- --spec <path to spec>
to run a specific file in a headless Electron instance, e.g.
npx run tests-cypress-run -- --spec apps/platform-e2e/cypress/e2e/builder.cy.ts
We use Hurl for running integration tests against Uesio APIs, and for performing load testing against APIs. Hurl provides a powerful text-based abstraction over curl
suitable for defining suites of HTTP requests and assertions to make upon the responses.
To run API integration tests locally against your running Uesio container, use npm run tests-integration
The easiest way to run a single Integration Test is to go into the scripts/tests/start-integration-tests.sh
file and comment out the lines where we run all tests, and uncomment the lines here and then run npm run tests-integration
:
# npx hurl --very-verbose -k --variable host=$UESIO_TEST_HOST_NAME --variable domain=$UESIO_TEST_DOMAIN --variable port=$UESIO_TEST_PORT apps/platform-integration-tests/hurl_specs/wire_collection_dependencies.hurl
You could run the individual test from the CLI, but you would have to make sure that you have the test app created and the right environment variables set up. If you would like to run via the CLI:
npm run tests-init # initialize test app/workspace/site/data/etc.
source scripts/tests/setup-env.sh # setup environment variables used in tests
npx hurl --very-verbose -k --variable host=$UESIO_TEST_HOST_NAME --variable domain=$UESIO_TEST_DOMAIN --variable port=$UESIO_TEST_PORT apps/platform-integration-tests/hurl_specs/wire_collection_dependencies.hurl
We use GitHub Actions for automated builds. All of our workflows live in ./github/workflows
.
We use Github Releases to manage releases of:
(a) the Uesio web/worker app - as a Docker image (b) the Uesio CLI - as a platform-specific binary
Here are the steps to create a new release:
- In Github, go to Draft a new release
- Enter a new tag name, using Semver names (e.g.
v0.5.0
) - Click Generate release notes
- Click Publish release
That's it! This will kick off the "Release" Github Action, which will download the corresponding Docker image from AWS ECR and re-publish it to Github Container Registry with the corresponding version tag, as well as the latest
tag. It will also generate CLI binaries for Linux, Windows, and Mac OS.
As much as possible, our code style and format is codified with eslint and Prettier. We cherry-picked some rules from the Airbnb JavaScriopt Style Guide, Airbnb React/JSX Style Guide and the React+TypeScript Cheatsheets.
For Redux, we follow the Redux Style Guide with some exceptions. More details on that here.
For Go package naming, we follow this guideline.
- Cobra. CLI for Go application.
- gorilla/mux. Web framework in Go.
- goja. JavaScript engine implemented in Go.
- Node.js. For package management, building process, and development.
- TypeScript. For strong typing of JavaScript code.
- React. Framework for UI components.
- Redux. State store for the application's frontend data.
- Redux-toolkit. Bootstrap for Redux.
- We're pinning monaco to version 0.50.0 for now because of this bug
nx
and its plugins need to be pinned to specific versions as the version of all of them must match per their docs. Running npx nx migrate will ensure that all are kept in-sync.- When running
npm install
there are errors related to[email protected]
,[email protected]
,[email protected]
,[email protected]
that all are dependencies of jest and its related tooling. There is a jest@next package (currently v30.0.0-alpha.6) that should address most (and hopefully) all of these. See: - Unable to update to
eslint-config-prettier
v10 due to@nx/eslint-plugin
not supporting it yet (https://github.com/nrwl/nx/blob/master/packages/eslint-plugin/package.json#L29) - Unable to update to
cypress
v14 due to@nx/cypress
not supporting it yet (https://github.com/nrwl/nx/blob/master/packages/cypress/package.json#L47)