Skip to content

Staff interface for Kulttuurin kummilapset / Culture Kids

License

Notifications You must be signed in to change notification settings

City-of-Helsinki/kukkuu-admin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

codecov Build & Staging

Staff interface for Kulttuurin kummilapset / Culture Kids

👶 Staff interface for Kulttuurin kummilapset / Culture Kids 🎻

Service architecture

The Culture kids service consists of:

  • Kukkuu API: The API backend service - The primary source of data.
  • Admin UI: (This service). A restricted UI where the events are maintained and published.
  • Public UI: The frontend service where the kids can view and enrol in culture events.
  • Headless CMS: Content Management Service that provides dynamic pages and dynamic content for the public UI. It also provides content for the header and the footer. A React component library can be found from https://github.com/City-of-Helsinki/react-helsinki-headless-cms.
  • Notification Service API: A service used by the Kukkuu API to send SMS messages.
  • Mailer: A service used by the Kukkuu API to send emails.

Environments

The admin client environments (this service):

The API environments:

The public client environments:

The headless CMS environments:

Frameworks and Libraries

This project is built using the following key frameworks and libraries:

  • Vite: A modern frontend build tool that provides a fast and efficient development experience. It offers features like instant server start, hot module replacement, and optimized builds.
  • React: A JavaScript library for building user interfaces. It allows for the creation of reusable UI components and efficient management of application state.
  • React Admin: A framework for building admin applications on top of React. It provides a set of reusable components and utilities for common admin tasks, such as creating data grids, forms, and navigation menus. React Admin simplifies the development of admin interfaces by providing a structured and opinionated approach.

Development

Getting started

  1. Clone the repo.
  2. cp .env.example .env
  3. Use file .env.local to modify environment variables if needed. For more info, check this.
  4. Run either
    • yarn start to run the app normally or
    • docker compose up to run the app in a Docker container. In the future, when there are changes that need rebuilding the container, run docker compose up --build instead.
  5. Open http://localhost:3001 to view the app in the browser.

Authorizing login to kukkuu-admin and integrating to Kukkuu API

You need to authorize the user you are trying to log in with to Kukkuu-Admin. In order to log in and get the staff / admin privileges, an authorization service is needed.

NOTE: The Kukkuu API needs to be configured to use the same authorization service as the Kukkuu Admin UI is using, because only then the authorization can be verified.

Setup authorization service

Setup authorization service:

Setup Kukkuu API backend

You can use the public Kukkuu API from the test environment or set up a local Kukkuu API. It should be noted that in the public test environment, the data is shared with other users. If you want to test with your own data and have an isolated system, you need to set up a local API.

Choose the environment:

  • Use a public test environment API: Check that your environment variables are set correctly. The examples are given in .env.example.
  • Setup Kukkuu API locally: See Use Kukkuu API locally.
Using local Kukkuu API backend

If you're using a local Kukkuu API backend (VITE_API_URI=http://localhost:8081/graphql), you can easily grant staff privileges to your user account. Here's how:

  1. Start the backend: Ensure your local Kukkuu API backend is running.

  2. Access the Django admin interface:

    • Open the Django admin interface: http://localhost:8081/admin/
    • Log in with the default credentials: username admin, password admin. If you don't have an admin user yet, you can create one with python manage.py createsuperuser.
  3. Grant superuser privileges:

    • Attempt to log in to Kukkuu-admin (http://localhost:3001/login) using your desired user account. This will create the user in the backend if it doesn't exist.
    • In the Django admin interface, locate the user you just created and grant them admin or superuser privileges.

You should now be able to log in to Kukkuu-admin with that user.

Using remote Kukkuu API backend

If you're using a remote Kukkuu backend (e.g., the test environment; VITE_API_URI=https://kukkuu.api.test.hel.ninja/graphql), you'll need to grant staff privileges to your user account. Here's how:

  1. Obtain Django admin credentials:

    • Contact the administrator of the remote backend to get the credentials.
    • If you have access to the backend pod, you can create a superuser by running python manage.py createsuperuser in the pod's terminal.
  2. Access the Django admin interface:

    • Open the Django admin interface for the remote backend (e.g., https://kukkuu.api.test.hel.ninja/admin).
    • Log in using the credentials from step 1.
  3. Grant superuser privileges:

    • Attempt to log in to Kukkuu-admin (http://localhost:3001/login). This will create a user account in the backend if one doesn't exist.
    • In the Django admin interface, find the user you just created and grant them superuser privileges.

You should now be able to log in to Kukkuu-admin with your user account.

JWT issuance for browser tests

This section describes how JSON Web Tokens (JWT) are issued for browser tests.

In browser tests, we want to bypass the regular authentication flow and directly issue JWTs for testing user roles and permissions. This is achieved by mocking the authentication service and providing pre-generated JWTs with specific claims.

How it works:

  • clientUtils: Contains helper functions that run within the Testcafe browser environment. These functions utilize Testcafe's ClientFunction to interact with the browser and manage JWTs.
  • mocks: Provides functions to intercept network requests to the authentication service and replace them with mocked responses containing the test JWTs. This prevents actual authentication and allows us to control the user context during tests.
  • config: Holds configuration settings for the JWT library used in browser tests.
  • jwt: Contains utilities to create and sign JWTs symmetrically. The API needs to be configured with the same secret key to verify these tokens.
  • oidc: Adapts the generated JWTs to a format compatible with the OpenID Connect (OIDC) client used in the application.
  • services: Includes helper functions for managing test data, such as selecting an admin project for the test user. These functions make actual API calls (not mocked) to prepare the test environment.

Key points:

  • The API and the Admin UI must share the same secret key (BROWSER_TESTS_JWT_SIGN_SECRET) for JWT verification.
  • The BROWSER_TESTS_JWT_AD_GROUP environment variable defines the Active Directory group used for the test user, which should have admin privileges in the API.
  • Several environment variables are used to configure the JWT mocking and testing environment.

Husky Git Hooks

This project uses Husky to manage Git hooks. Husky is configured to run specific scripts before committing changes to ensure code quality and consistency.

Pre-commit Hook

The pre-commit hook is configured to run the following commands:

yarn doctoc .
yarn lint-staged
  • yarn doctoc .: This command updates the table of contents in your markdown files.
  • yarn lint-staged: This command runs linting on staged files to ensure they meet the project's coding standards. The lint-staged configuration can be found from .lintstagedrc.json.

NOTE: doctoc and husky does not work seamlessly together, since the doctoc does update the TOCs of the markdown files, but does not reject the pre-commit hook execution, and only leaves the refactored files as unstaged in Git.

Commit-msg Hook

The commit-msg hook is configured to run the following command:

npx --no-install commitlint --edit "$1"
  • npx --no-install commitlint --edit "$1": This command uses Commitlint to lint commit messages based on the project's commit message conventions. This repo follows the Conventional Commits.

Available Scripts

In the project directory, you can run:

yarn start

Runs the app in development mode. Open http://localhost:3001 to view it in the browser.

The page will reload if you make edits. You will also see any lint errors in the console.

yarn build

Builds the app for production to the build directory. 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!

See the section about building for production and CLI guide for more information.

yarn generate:graphql

Fetches the GraphQL schema from the backend and updates typing information. The configuration is written in codegen.ts. Check that the environment variables are set properly to match with your API.

yarn test

Launches the vitest test runner. See the section about Getting started for more information.

yarn test:browser

Runs browser tests against your local version of the application (assumes port 3001).

  • The yarn test:browser:ci variant of this command is meant to run in the CI, and it targets the staging server. It uses headless mode and may therefore behave differently compared to the local test runner.
  • The deployment pipelines are running the browser tests as automated actions. They are run against PR and staging environments when after they have been built and deployed.
  • See also JWT issuance for browser tests

To run browser tests locally, you need to configure the browser testing environment:

  1. Run a local Kukkuu API instance with the browser testing JWT features set on. This allows the UI client to issue new JWTs for authorization by itself.
  2. Run a local Kukkuu Admin UI.
  3. Carefully double-check that the UI instance is configured to use the local API. The browser test JWT token configurations also need to match in order to successfully verify the newly issued tokens. You can navigate through the UI manually to see that everything is working as expected.
  4. Run the browser test with yarn test:browser or yarn test:browser:ci.

For configuration, check the following environment variables:

  1. BROWSER_TESTS_JWT_SIGN_SECRET needs to be a valid 256 bits token and it needs to be configured the same in both the API and the Admin UI in order to verify the self-issued JWT for browser testing.
  2. BROWSER_TESTS_JWT_AD_GROUP defines the AD group that should be used while running the browser tests. This value is used while issuing a JWT for an admin user. The AD group should be made in the API so that it gives admin permissions for the newly created user with this AD group for the (year) project that is created for browser testing. These AD groups and user groups can be managed from the API.
  3. BROWSER_TESTS_ENV_URL tells Testcafe where the testable UI is located.
  4. VITE_API_URI defines the Kukkuu API GraphQL endpoint. It's important in browser testing configuration for JWT mocking reasons.
  5. VITE_OIDC_KUKKUU_API_CLIENT_ID OIDC config that is needed in JWT mocking.
  6. VITE_OIDC_CLIENT_ID OIDC config that is needed in JWT mocking.
  7. VITE_OIDC_AUTHORITY OIDC config that is needed in JWT mocking.

NOTE: There is an .env.test.local.example that can be copied to a file named .env.test.local. If the .env.test.local is present, it will be used during the local Testcafe runs.

Releases, changelogs and deployments

The used environments are listed in Service environments.

The application uses automatic semantic versions and is released using Release Please.

Release Please is a GitHub Action that automates releases for you. It will create a GitHub release and a GitHub Pull Request with a changelog based on conventional commits.

Each time you merge a "normal" pull request, the release-please-action will create or update a "Release PR" with the changelog and the version bump related to the changes (they're named like release-please--branches--master--components--kukkuu-admin).

To create a new release for an app, this release PR is merged, which creates a new release with release notes and a new tag. This tag will be picked by Azure pipeline and trigger a new deployment to staging. From there, the release needs to be manually released to production.

When merging release PRs, make sure to use the "Rebase and merge" (or "Squash and merge") option, so that Github doesn't create a merge commit. All the commits must follow the conventional commits format. This is important, because the release-please-action does not work correctly with merge commits (there's an open issue you can track: Chronological commit sorting means that merged PRs can be ignored ).

See Release Please Implementation Design for more details.

And all docs are available here: release-please docs.

Conventional Commits

Use Conventional Commits to ensure that the changelogs are generated correctly.

Releasable units

Release please goes through commits and tries to find "releasable units" using commit messages as guidance - it will then add these units to their respective release PR's and figures out the version number from the types: fix for patch, feat for minor, feat! for major. None of the other types will be included in the changelog. So, you can use for example chore or refactor to do work that does not need to be included in the changelog and won't bump the version.

Configuration

The release-please workflow is located in the release-please.yml file.

The configuration for release-please is located in the release-please-config.json file. See all the options here: release-please docs.

The manifest file is located in the release-please-manifest.json file.

When adding a new app, add it to both the release-please-config.json and release-please-manifest.json file with the current version of the app. After this, release-please will keep track of versions with release-please-manifest.json.

Troubleshoting release-please

If you were expecting a new release PR to be created or old one to be updated, but nothing happened, there's probably one of the older release PR's in pending state or action didn't run.

  1. Check if the release action ran for the last merge to main. If it didn't, run the action manually with a label.
  2. Check if there's any open release PR. If there is, the work is now included on this one (this is the normal scenario).
  3. If you do not see any open release PR related to the work, check if any of the closed PR's are labeled with autorelease: pending - ie. someone might have closed a release PR manually. Change the closed PR's label to autorelease: tagged. Then go and re-run the last merge workflow to trigger the release action - a new release PR should now appear.
  4. Finally check the output of the release action. Sometimes the bot can't parse the commit message and there is a notification about this in the action log. If this happens, it won't include the work in the commit either. You can fix this by changing the commit message to follow the Conventional Commits format and rerun the action.

Important! If you have closed a release PR manually, you need to change the label of closed release PR to autorelease: tagged. Otherwise, the release action will not create a new release PR.

Important! Extra label will force release-please to re-generate PR's. This is done when action is run manually with prlabel -option

Sometimes there might be a merge conflict in release PR - this should resolve itself on the next push to main. It is possible run release-please action manually with label, it should recreate the PR's. You can also resolve it manually, by updating the release-please-manifest.json file.

Fix merge conflicts by running release-please -action manually

  1. Open release-please github action
  2. Click Run workflow
  3. Check Branch is master
  4. Leave label field empty. New label is not needed to fix merge issues
  5. Click Run workflow -button

There's also a CLI for debugging and manually running releases available for release-please: release-please-cli

Deployments

When a Release-Please pull request is merged and a version tag is created (or a proper tag name for a commit is manually created), this tag will be picked by Azure pipeline, which then triggers a new deployment to staging. From there, the deployment needs to be manually approved to allow it to proceed to the production environment.

The tag name is defined in the azure-pipelines-release.yml.

License

This project is licensed under the MIT License.