Skip to content

Commit

Permalink
Update bank for release (#73)
Browse files Browse the repository at this point in the history
This PR updates the bank demo app:
- Use the npm package, delete .npmrc.
- Update scripts and README to have clearer instructions on how to setup
the demo.
  • Loading branch information
qianl15 authored Oct 15, 2023
1 parent 77c72f3 commit 2970cb9
Show file tree
Hide file tree
Showing 17 changed files with 186 additions and 169 deletions.
30 changes: 9 additions & 21 deletions .github/workflows/bank.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ jobs:
# Service container for Postgres
services:
# Label used to access the service container.
postgres:
bankdb:
image: postgres:15.4
env:
# Specify the password for Postgres superuser.
POSTGRES_PASSWORD: dbos
# Set health checks to wait until postgres has started
options: >-
--name bankdb
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
Expand All @@ -42,10 +43,12 @@ jobs:
steps:
- name: "Setup postgres config"
run: |
docker exec -i ${{ job.services.postgres.id }} apt update
docker exec -i ${{ job.services.postgres.id }} apt install -y postgresql-15-wal2json
docker exec ${{ job.services.postgres.id }} sh -c 'echo "wal_level=logical" >> /var/lib/postgresql/data/postgresql.conf'
docker restart ${{ job.services.postgres.id }}
docker ps
docker exec bankdb psql -U postgres -c "CREATE USER bank WITH PASSWORD '${PGPASSWORD}';"
docker exec bankdb psql -U postgres -c "ALTER USER bank CREATEDB;"
docker exec bankdb psql -U postgres -c "CREATE DATABASE bank OWNER bank;"
env:
PGPASSWORD: bank
- name: Checkout demo app
uses: actions/checkout@v3
- name: Use Node.js 18
Expand All @@ -54,21 +57,6 @@ jobs:
node-version: 18
cache: npm
cache-dependency-path: 'bank/bank-backend/package-lock.json'

- name: Install psql
run: |
sudo apt-get update
sudo apt-get install -y postgresql-client coreutils
- name: Setup Postgres
working-directory: bank/
run: scripts/init_postgres.sh
env:
# The hostname used to communicate with the PostgreSQL service container
POSTGRES_HOST: localhost
# The default PostgreSQL port
POSTGRES_PORT: 5432
POSTGRES_PASSWORD: dbos
BANK_PORT: 8081
- name: Compile Bank Server
working-directory: bank/bank-backend/
run: |
Expand All @@ -84,4 +72,4 @@ jobs:
# The default PostgreSQL port
POSTGRES_PORT: 5432
BANK_PORT: 8081
NPM_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
BANK_SCHEMA: banktest
115 changes: 109 additions & 6 deletions bank/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,113 @@
# Bank of Operon
# Operon Bank Demo App

This is a simple bank application that uses [Operon](https://github.com/dbos-inc/operon) as the backend framework.
It requires node version 18.
This is a simplified bank application that uses [Operon](https://github.com/dbos-inc/operon) as the backend framework.
It requires Node 18.x or later and Docker.

### Start the backend
To compile and run the bank backend, enter the `bank-backend/` directory and follow the instructions [here](bank-backend/README.md).
In this tutorial, you will set up a Postgres `bank` database, start a Keycloak server for authentication, start two backend servers (we will run bank transactions across them), start a frontend server that connects to both backends, and optionally use Jaeger to visualize backend operations.
Especially, bank uses [Prisma](https://www.prisma.io/) to manage the user database.

## Run the Demo

### Pre-requisite

#### Install Dependencies

This demo includes two packages: the web frontend and the backend.
You need to run `npm install` under each of the [`bank-frontend/`](./bank-frontend/) and [`bank-backend/`](./bank-backend/) directories as a first step.

#### Start PostgreSQL
Now, let's set up a Postgres database. Please make sure you set `PGPASSWORD` environmental variable before you start!

We provide a convenient script to start a Postgres server in a docker container:
```shell
./scripts/start_postgres_docker.sh
```
This script sets up a new user `bank` that owns the database `bank`, and creates a `keycloak` schema in the `bank` database so we can proceed to our next step.

#### Start Keycloak
[Keycloak](https://www.keycloak.org/) is a popular Identity and Access Management solution.
We use Keycloak to manage user authentication for our bank application.
We provide a script to start a Keycloak server in a docker container:
```shell
./scripts/start_keycloak_docker.sh
```
You can visit `http://localhost:8083/` after the Keycloak server is started.
We import a default [dbos-realm](./scripts/dbos-realm.json) with the admin name and password (you can use it to log in Keycloak's admin console):
```
dbos-admin / dbos-pass
```

For more information about Keycloak, please visit [Keycloak guides](https://www.keycloak.org/guides#server).

### Start two backend servers
Each backend server must run in its own terminal window because we will configure different environmental variables for them.
Especially, you need to set `PGPASSWORD` to the one you used to create the `bank` database, and set `BANK_SCHEMA` to the namespace you wish to use for the specific bank server.
In this tutorial, let's set `export BANK_SCHEMA=bank1` for the first server, and in a separate terminal, set `export BANK_SCHEMA=bank2` for the second server.

In the terminal with `BANK_SCHEMA=bank1`, enter the `bank-backend/` directory, set up the database with Prisma, compile, and start the server at port `8081`:
```bash
# Create tables under the bank1 schema.
npx prisma migrate dev --name initbank1

npm run build
npx operon start -p 8081
```

In the terminal with `BANK_SCHEMA=bank2`, enter the `bank-backend/` directory, set up the database with Prisma, and start the server at port `8082`:
```bash
# Create tables under the bank2 schema.
npx prisma migrate dev --name initbank2

npx operon start -p 8082
```

Now both backend servers are up, let's move to the bank frontend!

### Start the frontend
We build a bank frontend using Angular. To start the frontend, enter the `bank-frontend/` directory and follow the instructions [here](bank-frontend/README.md).

We build a simple bank frontend using [Angular](https://angular.io/). To start the frontend, enter the `bank-frontend/` directory and run:
```bash
npm start
```

## Demo Walkthrough

Once you finish all previous steps, navitage to http://localhost:8089/
You will be presented with a welcome page.
Press the `Login` button and the webpage should redirect to a login page from Keycloak.

We pre-populate two example users so you can use the following emails and passwords to login:
```
[email protected] / 123 # This has an "appUser" role.
[email protected] / pass # This has an "appAdmin" role
```

Once you successfully log in, the frontend should re-direct you to the home page of the bank user.
The drop-down menu at the top allows you switch between two bank servers (bank1 at port 8081 and bank2 at port 8082) we just started.
There are three buttons in the middle:
- "New Greeting Message" fetches a greeting message from the backend and displays it in the "Message from Bank" banner above.
- "Create a New Account" creates a new checking account for the current user. If you logged in as `[email protected]`, pressing this button would fail because this user lacks the "appAdmin" permission to create a new account.
- "Refresh Accounts" refreshes the list of accounts of the current user.

Now, log in as `[email protected]`.
Once you click "Create a New Account" several times in both bank1 and bank2, you will see a list of accounts displayed with their `Account ID`, `Balance`, `Type`, and `Actions`. Initially, all accounts have zero balance.
Select the "Choose an Action" drop-down menu next to each account, you will see several options:
- "Transaction History" displays a list of past transactions from latest to oldest.
- "Deposit" allows you to make a deposit from either cash or from an account in another bank backend.
- "Withdraw" allows you to make a withdrawal to either cash or to an account in another bank backend.
- "Internal Transfer" allows you to transfer between your own accounts within the same bank backend.

Sometimes the JWT token would expire and cause failures. You can refresh the page and try again. Refreshing the webpage obtains a new token.

### (Optional) Visualize Tracing
We use [Jaeger Tracing](https://www.jaegertracing.io/) to visualize traces of Operon operations. We provide a script to automatically start it in a docker container:
```bash
./scripts/start_jaeger_docker.sh
```
Once it starts, you will see traces via the Jaeger UI: http://localhost:16686/

## Under the Covers

> Note, this section assumes you have read at least the [Operon Getting Started docs](https://docs.dbos.dev/category/getting-started).
(Coming soon!)
2 changes: 0 additions & 2 deletions bank/bank-backend/.npmrc

This file was deleted.

59 changes: 0 additions & 59 deletions bank/bank-backend/README.md

This file was deleted.

3 changes: 2 additions & 1 deletion bank/bank-backend/operon-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ telemetry:
localRuntimeConfig:
port: 8081
application:
bankname: 'localbank'
bankname: "Operon Bank - ${BANK_SCHEMA}"
bankport: '8081'
bankschema: ${BANK_SCHEMA}
5 changes: 3 additions & 2 deletions bank/bank-backend/operon-test-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ telemetry:
localRuntimeConfig:
port: 8081
application:
bankname: 'localbank'
bankport: '8081'
bankname: "testbank - ${BANK_SCHEMA}"
bankport: '8091'
bankschema: ${BANK_SCHEMA}
14 changes: 7 additions & 7 deletions bank/bank-backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bank/bank-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"license": "ISC",
"private": true,
"dependencies": {
"@dbos-inc/operon": "0.5.32-preview",
"@dbos-inc/operon": "0.5.34-preview",
"@koa/bodyparser": "^5.0.0",
"@koa/cors": "^4.0.0",
"@koa/router": "^12.0.0",
Expand Down
2 changes: 1 addition & 1 deletion bank/bank-backend/prisma/.env
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgresql://bank:bank@localhost:5432/bank?schema=prisma"
DATABASE_URL=postgresql://bank:${PGPASSWORD}@localhost:5432/bank?schema=${BANK_SCHEMA}
9 changes: 7 additions & 2 deletions bank/bank-backend/src/bank.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import { convertTransactionHistory } from "./router";

describe("bank-tests", () => {
let testRuntime: OperonTestingRuntime;
let bankSchema: string;

beforeAll(async () => {
bankSchema = process.env.BANK_SCHEMA ?? "";
if (!bankSchema) {
throw new Error("Env 'BANK_SCHEMA' not set!");
}
testRuntime = await createTestingRuntime([BankEndpoints, BankAccountInfo, BankTransactionHistory], "operon-test-config.yaml");
await testRuntime.queryUserDB<void>(`delete from prisma."AccountInfo" where "ownerName"=$1;`, "alice");
await testRuntime.queryUserDB<void>(`delete from ${bankSchema}."AccountInfo" where "ownerName"=$1;`, "alice");
});

afterAll(async () => {
Expand All @@ -28,7 +33,7 @@ describe("bank-tests", () => {
type: "saving",
});

const res = await testRuntime.queryUserDB<AccountInfo>(`select * from prisma."AccountInfo" where "ownerName" = $1;`, "alice");
const res = await testRuntime.queryUserDB<AccountInfo>(`select * from ${bankSchema}."AccountInfo" where "ownerName" = $1;`, "alice");
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
expect(res[0].ownerName).toBe("alice");
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Expand Down
2 changes: 1 addition & 1 deletion bank/bank-backend/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class BankEndpoints {
// eslint-disable-next-line @typescript-eslint/require-await
@GetApi("/api/greeting")
static async greeting(ctx: HandlerContext) {
return { msg: "Hello from DBOS Operon " + ctx.getConfig("bankname") };
return { msg: "Hello from " + ctx.getConfig("bankname") };
}

// Deposit.
Expand Down
4 changes: 4 additions & 0 deletions bank/bank-backend/src/runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ async function waitForMessageTest(command: ChildProcess, port: string) {

describe("runtime-tests", () => {
beforeAll(() => {
const bankSchema = process.env.BANK_SCHEMA;
if (!bankSchema) {
throw new Error("Env 'BANK_SCHEMA' not set!");
}
execSync('npm install');
execSync('npm run build');
});
Expand Down
12 changes: 0 additions & 12 deletions bank/bank-frontend/README.md

This file was deleted.

2 changes: 1 addition & 1 deletion bank/bank-frontend/src/environments/environment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const environment = {
// Put a list of actual bank servers here.
bankHosts: ['http://localhost:8081', 'http://localhost:8081'],
bankHosts: ['http://localhost:8081', 'http://localhost:8082'],
authUrl: `http://localhost:8083/realms/dbos/protocol/openid-connect`,
redirectUrl: "http://localhost:8089/"
}
Loading

0 comments on commit 2970cb9

Please sign in to comment.