A single-page application (SPA) built with Angular 19, TailwindCSS and Node/Express SSR that allows SNOMED International managed-service customers to raise structured requests that are turned into Jira tickets.
- Overview
- Architecture
- Prerequisites
- Getting Started
- NPM Scripts
- Project Structure
- Styling & Design
- Internationalisation (i18n)
- Coding Standards & Best Practices
- Branching & Commit Conventions
- Features
- CI/CD & Quality Gates
- Deployment
- Security
- Contributing
- License
The portal offers a user-friendly dashboard for creating, tracking and managing requests. When a form is submitted the server creates a corresponding Jira issue via the internal API.
Key characteristics:
- Modern Angular application with Server-Side Rendering (SSR).
- Responsive UI powered by TailwindCSS.
- Multi-language support through ngx-translate and JSON translation bundles.
- Strict TypeScript configuration and RxJS best practices.
- Designed for containerised deployment.
+--------------+ SSR build +-------------------+
| Angular App | ---------------> | Node/Express |
| (browser) | <--------------- | CommonEngine SSR |
+--------------+ HTML stream +-------------------+
At build time Angular CLI outputs both browser and server bundles. server.ts starts an Express server that uses @angular/ssr's CommonEngine to render pages. Static assets are served from the browser folder with long-term caching.
- Node.js 22.7.0+ (aligned with
@types/nodeinpackage.json). - npm 10.8.2 or pnpm 8+ (the repository is npm-centric but compatible with pnpm).
- Angular CLI 19+ installed globally for convenience:
npm i -g @angular/cli. - Jira credentials (service account) and other secrets exported as environment variables for production deployment.
# 1. Clone
$ git clone https://github.com/ihtsdo/request-management-portal-ui.git
$ cd request-management-portal-ui
# 2. Install dependencies
$ npm ci # reproducible install
# or: pnpm i
# 3. Start the dev server (HMR, no SSR)
$ npm start # alias for `ng serve` -> http://localhost:4200/
# 4. Lint & unit tests in watch mode (optional)
$ npm run lint
$ npm t -- --watch# Build browser + server bundles in development mode
npm run build
# Start node server (auto reload via nodemon is recommended)
node dist/request-management-portal-ui/server/main.mjs
# -> http://localhost:4000| Variable | Purpose | Default |
|---|---|---|
PORT |
Port Express listens on | 4000 |
JIRA_BASE_URL |
Jira REST API endpoint | – |
JIRA_USERNAME |
Service-account user | – |
JIRA_TOKEN |
API token/password | – |
Create a .env file for local experiments; never commit secrets.
| Command | Description |
|---|---|
npm start |
Alias for ng serve (dev, no SSR) |
npm run build |
Production build incl. SSR (default configuration) |
npm run build:prod |
Explicit production build with budgets enforced |
npm run watch |
Rebuild on file changes (development config) |
The Angular CLI configuration resides in
angular.json. Adjust or extend build targets there.
├── src/
│ ├── app/ # Angular feature & shared modules
│ │ ├── components/ # Presentational and container components
│ │ ├── services/ # Singleton providers (REST, auth, etc.)
│ │ ├── interceptors/ # HTTP interceptors
│ │ ├── pipes/ # Pure pipes
│ │ └── models/ # TypeScript interfaces
│ ├── public/ # Static assets (copied verbatim)
│ ├── styles.scss # Tailwind & global styles
│ └── main.ts # Browser bootstrap
├── server.ts # Express entry point (SSR)
└── angular.json # Angular CLI project config
The repository follows the feature-based folder structure recommended by the Angular Style Guide.
- TailwindCSS 4 provides utility-first classes.
- Global SCSS variables/mixins can be placed in
src/stylesand imported via@use. - Follow the BEM methodology for any custom component styles.
Translations reside in public/i18n/{lang}.json and are loaded via ngx-translate. Add new keys in English first, then provide translations for other languages. Use the dedicated TranslatePipe rather than hard-coded strings.
- Angular Style Guide: Prefer stand-alone components,
OnPushchange detection, and@Inputimmutability. - TypeScript:
strictmode is enabled; avoid theanytype. - RxJS: use
takeUntiland the async pipe to manage subscriptions; avoid manualsubscribewhere possible. - State management: co-locate component state; introduce a dedicated library (NgRx, NGXS, etc.) only when complexity demands it.
- Routing: lazy-load feature routes; keep modules shallow.
develop– default integration branch.master– production releases.- feature/
xyz, bugfix/xyz, hotfix/xyz– short-lived topic branches.
Commits follow Conventional Commits:
feat(auth): add OIDC login flow
fix(request): correct date validation
chore(ci): upgrade node version in pipeline
This enables automatic changelog generation and semantic versioning.
The portal provides the following key capabilities:
- Dashboard overview – see
src/app/components/dashboard - Request submission forms –
src/app/components/request - Request management list & filters –
src/app/components/request-management - SNOMED navigation bar with language switching –
src/app/components/snomed-navbar - Authentication & session handling –
src/app/services/authentication - Language & i18n service –
src/app/services/language - Authoring service for creating requests –
src/app/services/authoring - IMS integration service –
src/app/services/ims - HTTP interceptors for auth and headers –
src/app/interceptors - Notification system via Toastr – implementation across components (see example in each
*.component.ts)
A GitHub Actions workflow runs on every PR:
- Install dependencies with cache
- Lint & format check
- Run unit tests & collect coverage
- Build production artefacts
- Upload results to SonarCloud (security, coverage, smells)
A green build is required before merging.
- Build:
npm run build:prod - Copy
dist/request-management-portal-uito your server/container image. - Start:
node server/main.mjs(or viapm2,docker-compose, etc.)
A Dockerfile/Helm chart will be added in a future iteration.
- Keep dependencies updated (
npm audit --production). - Sanitize all form inputs on both client and server.
- Use HTTPS & HSTS in production (configure the reverse proxy, not Express).
- Secrets are injected via environment variables / vault – never commit them.
We welcome contributions! Please:
- Open an issue to discuss the enhancement.
- Create a branch from
develop. - Follow the coding standards and add tests.
- Submit a draft PR early; add the
ready-for-reviewlabel when finished.
Apache-2.0 © SNOMED International. See LICENSE.md for details.