This is the self-serve portal for UID2 participants. It enables a range of operations for participants around key management, sharing, and so on.
- A recent version of Node. Recommended: 16.14 or later. See package.json for the required version.
- Docker Desktop.
- VS Code (or equivalent). Note that if you don't use VS Code, you will need to find equivalent extensions for things like linting.
Recommended VS Code extensions:
Extension | Details | Required? |
---|---|---|
ESLint | Lints your code. We expect PRs to be free of linter errors, and preferably free of warnings as well. | Yes |
i18n Ally | Checks your front-end code for accessibility rules. We expect PRs to maintain a high standard of A11y. | Yes |
Prettier - Code formatter | Formats your code. We want PRs to contain functionality changes, not whitespace fixes and linebreak changes. Prettier makes us all use the same code style so we can focus on the things which matter. | Yes |
Stylelint | Same as ESLint, but for your style files. | Yes |
Code Spell Checker | Popular extension by Street Side Software - checks your spelling. | Yes, or similar alternative |
Wallaby.js | Live, in-your-IDE, as-you-type test runner. It is free for open source projects, but please read the license and satisfy yourself that you're in compliance if you use the free version. | No |
Docker | Helps you manage docker containers straight from VS Code. | No |
Auto Rename Tag | Fixes your closing tags as you edit opening tags | No |
Toggle Quotes | You can hit ctrl-' to cycle between quote styles (', ", and `) for the string you're editing. |
No |
When you first check the repo out, run:
docker compose up
This will pull the needed docker images and start the stack. IMPORTANT: The first time you run this, the mssql database container will take a while to start. If you interrupt it during this process, the container may end up in a bad state. If this happens, you'll need to docker compose down
and then manually delete the persistent volume first, then start over.
If you get errors like Login failed for user 'sa'. Reason: Failed to open the explicitly specified database 'keycloak'
, the Keycloak container probably tried to start before the database was ready. Run the following command to try again:
docker compose restart keycloak
Keep in mind that the first time you start the stack, mssql will take ~5 minutes to launch, so you might need to be patient.
We use knex for migrations and seed data. Once your Docker environment is running, you can use the following commands:
npm run knex:migrate:latest
- Update your schema to the latest.
npm run knex:migrate:rollback
- Rollback the most recent update to your schema.
npm run knex:seed:run
- Generate some helpful seed data for a dev or test environment (n.b. this is only for seeding dev/test data).
If you're working on database changes, you can run:
npm run knex:migrate:make [migration-name]
- Generates a new migration file. This file includes a timestamp and the name you specify after the command.
npm run knex:seed:make [seed-name]
- Generates a new seed file for providing test data. This file is named based on the name you supply.
See the Knex migrations documentation for more details.
When creating a database, use camelCase
table and column names to match the casing in the TypeScript entity classes.
Tables should be created as the plural of the thing being stored. For example, if you're storing a list of possible participant types, the table should be called participantTypes
.
Linking tables should contain the names of the tables being linked, joined by the word 'To' - but avoid unnecessary duplication. For example, if you're creating a linking table for a many-to-many relationship between participants
and participantTypes
, it's reasonable to name the table participantsToTypes
.
All tables should have an auto-incrementing number column named id
. When creating references to other tables, prefer to use the column name 'Id', where thing is the thing being referred to. For example, when creating a column which references a participant, you should usually use the column name participantId
.
- This project was bootstrapped with Create React App.
- We are making use of the Radix-UI headless component library. Please prefer components from this library if you need to introduce a new component. You should review the documentation, especially RE: accessibility.
- Styling is done using Sass. It's very close to plain CSS and is very widely used.
- Storybook. See the section below on how we use Storybook.
- See
/adrs/2022-12-21-Tech_stack.md
for more info.
All components below the page level should be props-driven - data fetching should only happen at the routing level. This allows use of upcoming React features such as progressive rendering, and also enables rapid-iteration development using Storybook.
When developing new components, you should create new stories in Storybook for the key states to allow easy review of both visuals and functionality.
Please add tests to your changes where possible! We don't have a minimum coverage level because we feel responsible developers should be able to decide what's important to test, and what's not worth testing. Continuing down this path requires us all to be responsible developers and write tests!
Focus on testing functionality, not implementation. For example, if you have a button which waits 1 second and then displays a dialog, do not simulate a click and then assert that setTimeout(...)
was called. Instead, simulate a click, advance the timer, and make sure the dialog was displayed! Refer to the Testing Library Guiding Principles and the section of the docs on Query Priority.
- Start database and Keycloak server by running
docker compose up -d
. Now Keycloak will be up and running, and the realm will be configured - To access keycloak admin console, you can find the username and password in the
docker-compose.yml
- If you set an email address for the admin account, you will need to use that email address to log into the Keycloak admin console
For more advanced setup, see Keycloak Advanced Setup.
For logging, we use Loki and Grafana to store and query logs. We use the winston-express helper for express in order to log to winston from the browser. It helps format and label our log outputs for ingestion into Loki.
For development purposes, we can can spawn docker images for Loki/Grafana/Promtail to test and validate our loggings.
To do this, an optional docker file is provided docker-compose.log-stack.yml
in the root folder. This ensures that typical development workflows (that don't need logger stack) don't spawn these additional containers unnecessarily.
To instantiate the logging stack, use the following command:-
docker compose -f docker-compose.yml -f docker-compose.log-stack.yml up
This will spawn 3 additional containers for Promtail, Loki and Grafana.
Once running, log onto the Grafana UI from here. Use the username admin
and password admin
.
Add the Loki datasource in Grafana with the following Loki data-source url: http://host.docker.internal:3100
. Note: this url should match the value of SSP_LOKI_HOST
in your .env
file.
The logs should now be available in the Explore tab to query - you may need to trigger some API requests in the UI to generate some logs. You can then debug requests by specifying the app name along with a traceId, for example:
{app="ssportal-dev"} |= `ae44989e-7654-4e7f-ae7c-8987a829a622`
Note: the name of the app should match the SSP_APP_NAME
in your .env
file.
To add a new email template to the project, follow the steps below:
-
Locate the
emailTemplates
folder in the project's directory structure. If the folder doesn't exist, create it at the root level of the project. -
Create a new file for your email template with the following naming convention:
{{templateName}}.hbs
. Replace{{templateName}}
with a descriptive name for your template. For example, if your template is for a welcome email, you could name the filewelcome.hbs
.Before creating a new template, check if the desired template name already exists in the
templateMapping.json
file located in the/src/api
directory. If it exists, choose a different template name to avoid overriding an existing template. -
Open the newly created file in a text editor and write your email template using Handlebars syntax. Handlebars allows you to include placeholders, conditionals, and loops in your template to make it dynamic and personalized.
To ensure accurate email rendering, it is important to synchronize the Handlebars email templates with SendGrid. The synchronization process involves updating the SendGrid templates based on the files present in the emailTemplates
folder. Follow the steps below:
-
Trigger the Sync Handlebars Template with SendGrid action located in the repository's Actions tab.
-
Click on the Run workflow button to start the synchronization process.
This action should be triggered after adding or updating any templates and before building and publishing Docker images. It ensures that the latest email templates are reflected in SendGrid.
Note: If you only need to update an existing template, you can simply modify the corresponding
.hbs
file and trigger the Sync Handlebars Template with SendGrid action. There is no need to redeploy or rebuild Docker images in this case.
In the project directory, you can run:
Installs the dependencies for the project. You will need to run this before running any of the following commands.
Starts both the API and the React front-end side-by-side. This is probably the best way to get up and running in dev mode.
Starts Storybook. This is a great system for working on self-contained components and reviewing appearance and functionality of components across the site. It's also useful as a way for people to view or work on components (or even whole pages) without having the full environment set up.
Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build
folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed! Note that builds for deployment are not made on developer machines - those happen in our CI pipeline.
The following steps describe the minimal steps required to successfully log in to the portal UI. If you require a fully-functional portal, please perform the following steps as well as the steps described below in Connecting to local admin service.
-
Set up Docker, as described above: Docker
-
Ensure your
SSP_KK_SECRET
matches the value in the Keycloak admin console. If it does not, please try Reset your keycloak realm. If all else fails, manually generate your own secret by following: Generating SSP_KK_SECRET -
Run the following to install dependencies:
npm install
-
Run the following to start the API and React front-end:
npm run dev
Successfully running this will result in the self-serve-portal opening in the browser.
-
Run the following to build the database schema:
npm run knex:migrate:latest
-
Run the following to populate test data:
npm run knex:seed:run
-
Create an account in the UI by clicking
Create Account
. You can use a fake email address since we use MailHog to capture emails and store them locally. -
Go to local MailHog at http://localhost:18025/ and you will see an email from
test@self-serve-portal.com
with the subjectVerify email
-
Open the email and Click
Verify Email
-
Fill in the form however you want and submit the form
-
Connect to the database server
localhost,11433
using the credentials in docker-compose.yml -
In the
uid2_selfserve
database, observe thatdbo.users
now contains a row with with the details you just filled out. -
Approve your account by updating the
status
of the row indbo.participants
that corresponds to your new user, i.e.declare @email as nvarchar(256) = '<Enter your email here>' update p set status = 'approved' from dbo.participants p left join dbo.users u on p.id = u.participantId where u.email = @email
-
Assign yourself the
api-participant-member
role by following these steps: Assign Role to a Particular User -
Return to the UI and you should be good to go!
Functionality relating to Sharing Permissions will require the admin service to be running locally. Perform the following steps to standup the admin service to develop and test admin-related functionality on the portal.
- Run
uid2-admin
locally by following the README: https://github.com/IABTechLab/uid2-admin - Ensure that the site ids of your participants exist in admin. That goes for the current participant you are logged in to, as well as the participants you are interacting (e.g. sharing) with. You can check the existing ids by looking at
sites.json
inuid2-admin
or by going to http://localhost:8089/adm/site.html and hittingList Sites
, given the service is running locally. - Ensure that you have a key in
admins.json
inuid2-admin
with theSHARING_PORTAL
role, and that key is in your.env
asSSP_ADMIN_SERVICE_CLIENT_KEY
.- You should be able to use an existing key in
admins.json
, rather than having to create a new one. - You will need to restart the api (i.e.
npm run api
) after updating your.env
file.
- You should be able to use an existing key in