diff --git a/.github/workflows/push-trigger.yml b/.github/workflows/push-trigger.yml index ba16458e..9ebac5f5 100644 --- a/.github/workflows/push-trigger.yml +++ b/.github/workflows/push-trigger.yml @@ -39,7 +39,6 @@ jobs: SERVICE_NAME: 'admin-ui' NPM_BUILD: true BUILD_ARTIFACT: 'admin-ui' - SQUASH_LAYERS: '11' fail-fast: false name: ${{ matrix.SERVICE_NAME }} uses: mosip/kattu/.github/workflows/docker-build.yml@master @@ -48,7 +47,6 @@ jobs: SERVICE_NAME: ${{ matrix.SERVICE_NAME }} NPM_BUILD: ${{ matrix.NPM_BUILD }} BUILD_ARTIFACT: ${{ matrix.BUILD_ARTIFACT }} - SQUASH_LAYERS: ${{ matrix.SQUASH_LAYERS }} secrets: DEV_NAMESPACE_DOCKER_HUB: ${{ secrets.DEV_NAMESPACE_DOCKER_HUB }} ACTOR_DOCKER_HUB: ${{ secrets.ACTOR_DOCKER_HUB }} @@ -187,4 +185,3 @@ jobs: JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..75d9aa29 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,108 @@ +# AGENTS.md + +This file provides guidance to AI agents when working with code in this repository. + +## Project Overview + +MOSIP Admin Portal — an Angular 8 SPA used by privileged administrative personnel to manage master data (Registration Centers, Devices, Machines, Users), run key management operations, check packet/RID status, and perform bulk uploads. It is the **authoritative interface** for post-deployment master data updates in a MOSIP deployment; changes should go through the portal (not raw DB scripts) to enforce business rule constraints. + +The repo has two independently buildable modules: +- `admin-ui/` — the Angular frontend +- `uitest-admin/` — a Selenium + TestNG automation test suite (Java 21, Maven) + +--- + +## Commands + +### Frontend (`admin-ui/`) + +```bash +cd admin-ui +npm install # install dependencies +ng serve # dev server at http://localhost:4200 (auto-reloads) +ng build # development build → dist/ +ng build --prod # production build (AOT, minified) +ng test # unit tests via Karma +ng lint # lint +ng e2e # end-to-end tests via Protractor +``` + +### UI Test Suite (`uitest-admin/`) + +```bash +cd uitest-admin +mvn clean install # build and package the fat JAR + +# Run tests against a deployed environment +java -Dpath=https://admin..mosip.net/ \ + -DKeyclockURL=https://iam..mosip.net \ + -Denv.user=api-internal. \ + -Denv.endpoint=https://api-internal..mosip.net \ + -jar target/uitest-admin-1.3.0-jar-with-dependencies.jar +``` + +Control test execution via `src/main/resources/TestData.json`: +- `setExcludedGroups`: comma-separated group tags to skip (e.g. `"BL,CT"`) +- `headless`: `"yes"` for headless Chrome + +--- + +## Architecture + +### Runtime Configuration + +The app does **not** use Angular `environment.ts` for the API base URL. At startup, `AppConfigService` fetches `assets/config.json` and exposes it globally. `app.constants.ts` reads `config.baseUrl` at module load time. This means API targets are set at deploy time, not build time. Key config fields: `baseUrl`, `primaryLangCode`, `locationHierarchyLevel`, `supportedLanguages`, `countryCode`, `filterValueMaxRecords`. + +### Module & Routing Structure + +Hash routing (`useHash: true`) with `PreloadAllModules`. The root route redirects to `/admin`, which is guarded by `LanguageGuard` (initialises i18n) and `AuthguardService` (Keycloak token check). + +All feature areas are **lazy-loaded modules** under `/admin`: + +| Route | Module | Roles | +|---|---|---| +| `/admin/resources` | ResourcesModule | GLOBAL_ADMIN, ZONAL_ADMIN, MASTERDATA_ADMIN | +| `/admin/masterdata` | MasterdataModule | GLOBAL_ADMIN, ZONAL_ADMIN, MASTERDATA_ADMIN | +| `/admin/bulkupload` | BulkuploadModule | all roles | +| `/admin/keymanager` | KeymanagerModule | KEY_MAKER | +| `/admin/packet-status`, `/admin/rid-status`, `/admin/lost-rid-status` | — | REGISTRATION_ADMIN | + +Menu item visibility is driven by `RolesService` reading Keycloak roles from the JWT. + +### HTTP & Auth + +`AuthInterceptor` (registered in `CoreModule`) attaches the Keycloak bearer token to every outgoing request and handles 401/403 redirects. All API calls go through Angular's `HttpClient` — never `fetch` or XHR directly. + +API paths are constructed in `app.constants.ts` as ` + + /search` (POST with filter/sort/pagination payloads). The search pattern is uniform across all master data entities. + +### Core Services + +- **`DataStorageService`** — in-memory cache for filter values, languages, and lookup data to avoid redundant API calls across components. +- **`AuditService`** — logs every significant user action with MOSIP audit event IDs (ADM-002 through ADM-085+). Every feature interaction should call this. +- **`CommonService`** — shared utility calls (language list, zone tree, etc.). +- **`CanDeactivateGuard`** — prevents navigation away from forms with unsaved changes. + +### MOSIP Domain Concepts (relevant to code decisions) + +- **Zone hierarchy**: Admins are assigned to a zone; `ZONAL_ADMIN` can only see/edit resources within their zone. Zone filtering is applied server-side via the masterdata APIs. +- **Master data search API**: All list/search pages POST to `.../search` with a `{ filters: [], sort: [], pagination: {} }` body — not GET with query params. +- **Language support**: All master data entities have language-specific fields. The UI sends `langCode` in payloads. Supported: `eng`, `ara`, `fra`, `tam`, `kan`, `hin`. i18n strings live in `admin-ui/src/assets/i18n/.json`. +- **Deactivation vs deletion**: Master data records are deactivated (`isActive: false`), not deleted. UI should reflect this. + +### UI Test Suite Structure + +15 test classes run in parallel (8 threads) via TestNG, one per master-data entity/feature. `KnownIssueListener` cross-references `Known_Issues.txt` to suppress known failures. Test reports go to `admintest/Reports/` (ExtentReports) and `testng-report/`. + +--- + +## CI/CD + +`.github/workflows/push-trigger.yml` triggers on push to `develop`, `release-*`, `master`, `1.*`, and on PRs. Pipeline jobs in order: + +1. `build-admin-ui` — npm build +2. `build-docker-admin-ui` — Docker image +3. `sonar-analysis` — SonarCloud (skipped on PRs) +4. `build-maven-uitest-admin` → `build-uitest-admin-local` → `build-docker-uitest-admin` +5. `sonar-analysis-uitest-admin` + +Helm chart publishing is triggered by changes under `helm/**` via `chart-lint-publish.yml`. diff --git a/README.md b/README.md index fce08ca1..c4438972 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,27 @@ # Admin Portal -[![Maven Package upon a push](https://github.com/mosip/keymanager/actions/workflows/push_trigger.yml/badge.svg?branch=release-1.2.0.1)](https://github.com/mosip/admin-ui/actions/workflows/push_trigger.yml) +[![admin-ui build upon a push](https://github.com/mosip/admin-ui/actions/workflows/push-trigger.yml/badge.svg?branch=develop)](https://github.com/mosip/admin-ui/actions/workflows/push-trigger.yml) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?branch=develop&project=mosip_admin-ui&metric=alert_status)](https://sonarcloud.io/dashboard?branch=develop&id=mosip_admin-ui) ## Overview -See [overview and portal user guide](https://docs.mosip.io/1.2.0/modules/administration/admin-portal-user-guide). +An admin application is a web-based application used by a privileged group of administrative personnel to manage various master data sets. The various resources that an Admin can manage are: + +* Center (Registration centers) +* Device +* Machine +* Users (Admin, Registration staff) + +Along with the resource and data management, the admin can generate master keys, check registration status, retrieve lost RID, and resume processing of paused packets. To start using the Admin portal, an admin user must be assigned to a zone. + Refer [overview and portal user guide](https://docs.mosip.io/1.2.0/modules/administration/admin-portal-user-guide). This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.3. +### Local Setup (for Development or Contribution) +The project can be set up in two ways: + +1. [Local Setup (for Development or Contribution)](#local-setup-for-development-or-contribution) +2. [Local Setup with Docker (Easy Setup for Demos)](#local-setup-with-docker-easy-setup-for-demos) + +### Local Setup (for Development or Contribution) ## Development server Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. @@ -27,7 +42,44 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github. Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). -## Deployment in K8 cluster with other MOSIP services: +### Local Setup with Docker (Easy Setup for Demos) +#### Build Docker Images Locally + +Recommended for contributors or developers who want to modify or build the services from source. + +1. Clone and build the project: + +```text +git clone +``` +```text +cd admin-ui +``` +2. Navigate to each service directory and build the Docker image: +```text +cd admin-ui/ +``` +```text +docker build -t . +``` +#### Running the Services + +Start each service using Docker: + +```text +docker run -d -p : --name +``` +#### Verify Installation + +Check that all containers are running: + +```text +docker ps +``` +Access the services at `http://localhost:` using the port mappings listed above. + +## Deployment +### Kubernetes ### Pre-requisites * Set KUBECONFIG variable to point to existing K8 cluster kubeconfig file: * ``` @@ -48,11 +100,17 @@ Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protrac $ cd deploy $ ./restart.sh ``` +### Product Documentation +To learn more about admin services from a functional perspective and use case scenarios, refer to our main documentation: [Click here](https://docs.mosip.io/1.2.0/id-lifecycle-management/support-systems/administration). + +## Contribution & Community +* To learn how you can contribute code to this application, [click here](https://docs.mosip.io/1.2.0/community/code-contributions). -## Further help +* If you have questions or encounter issues, visit the [MOSIP Community](https://community.mosip.io/) for support. +* For any GitHub issues: [Report here](https://github.com/mosip/admin-ui/issues) -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.3. ## License -This project is licensed under the terms of [Mozilla Public License 2.0](../LICENSE). +This project is licensed under the terms of [Mozilla Public License 2.0](LICENSE) \ No newline at end of file diff --git a/deploy/admin-ui/install.sh b/deploy/admin-ui/install.sh index 2041c0cc..ab13f362 100755 --- a/deploy/admin-ui/install.sh +++ b/deploy/admin-ui/install.sh @@ -44,4 +44,4 @@ set -o errexit ## set -e : exit the script if any statement returns a non-true set -o nounset ## set -u : exit the script if you try to use an uninitialised variable set -o errtrace # trace ERR through 'time command' and other functions set -o pipefail # trace ERR through pipes -installing_admin_ui # calling function \ No newline at end of file +installing_admin_ui # calling function diff --git a/deploy/admin-uitestrig/install.sh b/deploy/admin-uitestrig/install.sh index a4a916a3..fb137033 100644 --- a/deploy/admin-uitestrig/install.sh +++ b/deploy/admin-uitestrig/install.sh @@ -94,4 +94,4 @@ set -o errexit ## set -e : exit the script if any statement returns a non-true set -o nounset ## set -u : exit the script if you try to use an uninitialised variable set -o errtrace # trace ERR through 'time command' and other functions set -o pipefail # trace ERR through pipes -installing_uitestrig # calling function \ No newline at end of file +installing_uitestrig # calling function diff --git a/helm/admin-ui/.gitignore b/helm/admin-ui/.gitignore index ee3892e8..1654d0dc 100644 --- a/helm/admin-ui/.gitignore +++ b/helm/admin-ui/.gitignore @@ -1 +1,2 @@ charts/ +Chart.lock \ No newline at end of file diff --git a/helm/admin-ui/templates/deployment.yaml b/helm/admin-ui/templates/deployment.yaml index 22838e00..d8ee4ee4 100644 --- a/helm/admin-ui/templates/deployment.yaml +++ b/helm/admin-ui/templates/deployment.yaml @@ -33,6 +33,7 @@ spec: {{- if .Values.hostAliases }} hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} {{- end }} + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds | default 60 }} {{- if .Values.affinity }} affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.affinity "context" $) | nindent 8 }} {{- else }} @@ -104,10 +105,8 @@ spec: {{- end }} {{- end }} {{- if .Values.extraEnvVarsSecret }} - {{- range .Values.extraEnvVarsSecret }} - secretRef: - name: {{ . }} - {{- end }} + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} {{- end }} volumeMounts: - name: conf-file diff --git a/helm/admin-ui/values.yaml b/helm/admin-ui/values.yaml index 767506ce..82937905 100644 --- a/helm/admin-ui/values.yaml +++ b/helm/admin-ui/values.yaml @@ -12,23 +12,18 @@ ## commonLabels: app.kubernetes.io/component: mosip - ## Add annotations to all the deployed resources ## commonAnnotations: {} - ## Kubernetes Cluster Domain ## clusterDomain: cluster.local - ## Extra objects to deploy (value evaluated as a template) ## extraDeploy: [] - ## Number of nodes ## replicaCount: 1 - service: type: ClusterIP port: 80 @@ -48,12 +43,10 @@ service: ## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip ## externalTrafficPolicy: Cluster - image: registry: docker.io repository: mosipqa/admin-ui tag: develop - ## Specify a imagePullPolicy ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images @@ -65,10 +58,8 @@ image: ## # pullSecrets: # - myRegistryKeySecretName - ## Port on which this particular spring service module is running. springServicePort: 8080 - ## Configure extra options for liveness and readiness probes ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes ## @@ -83,7 +74,6 @@ startupProbe: timeoutSeconds: 5 failureThreshold: 30 successThreshold: 1 - livenessProbe: enabled: true httpGet: @@ -94,7 +84,6 @@ livenessProbe: timeoutSeconds: 5 failureThreshold: 6 successThreshold: 1 - readinessProbe: enabled: true httpGet: @@ -105,7 +94,6 @@ readinessProbe: timeoutSeconds: 5 failureThreshold: 6 successThreshold: 1 - ## # existingConfigmap: @@ -113,12 +101,10 @@ readinessProbe: ## command: [] args: [] - ## Deployment pod host aliases ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ ## hostAliases: [] - ## ref: http://kubernetes.io/docs/user-guide/compute-resources/ ## resources: @@ -132,37 +118,31 @@ resources: requests: cpu: 100m memory: 500Mi - additionalResources: ## Specify any JAVA_OPTS string here. These typically will be specified in conjunction with above resources ## Example: java_opts: "-Xms500M -Xmx500M" javaOpts: "-Xms750M -Xmx750M" - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container ## Clamav container already runs as 'mosip' user, so we may not need to enable this containerSecurityContext: enabled: false runAsUser: mosip runAsNonRoot: true - ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod ## podSecurityContext: enabled: false fsGroup: 1001 - ## Pod affinity preset ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity ## Allowed values: soft, hard ## podAffinityPreset: "" - ## Pod anti-affinity preset ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity ## Allowed values: soft, hard ## podAntiAffinityPreset: soft - ## Node affinity preset ## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity ## Allowed values: soft, hard @@ -184,32 +164,26 @@ nodeAffinityPreset: ## - e2e-az2 ## values: [] - ## Affinity for pod assignment. Evaluated as a template. ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity ## affinity: {} - ## Node labels for pod assignment. Evaluated as a template. ## ref: https://kubernetes.io/docs/user-guide/node-selection/ ## nodeSelector: {} - ## Tolerations for pod assignment. Evaluated as a template. ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ ## tolerations: [] - ## Pod extra labels ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ ## podLabels: {} - ## Annotations for server pods. ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ ## podAnnotations: {} - ## pods' priority. ## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ ## @@ -217,16 +191,22 @@ podAnnotations: {} ## lifecycleHooks for the container to automate configuration before or after startup. ## -lifecycleHooks: {} +lifecycleHooks: + preStop: + exec: + command: + - sh + - -c + - sleep 30 +## Termination grace perios : the maximum amount of time (in seconds) Kubernetes will wait for a container to gracefully shut down +terminationGracePeriodSeconds: 60 ## Custom Liveness probes for ## customLivenessProbe: {} - ## Custom Rediness probes ## customReadinessProbe: {} - ## Update strategy - only really applicable for deployments with RWO PVs attached ## If replicas = 1, an update can get "stuck", as the previous pod remains attached to the ## PV, and the "incoming" pod can never start. Changing the strategy to "Recreate" will @@ -234,7 +214,6 @@ customReadinessProbe: {} ## updateStrategy: type: RollingUpdate - ## Additional environment variables to set ## Example: ## extraEnvVars: @@ -242,14 +221,12 @@ updateStrategy: ## value: "bar" ## extraEnvVars: [] - ## ConfigMap with extra environment variables ## extraEnvVarsCM: - global - config-server-share - artifactory-share - ## Secret with extra environment variables ## extraEnvVarsSecret: [] @@ -257,11 +234,9 @@ extraEnvVarsSecret: [] ## Extra volumes to add to the deployment ## extraVolumes: [] - ## Extra volume mounts to add to the container ## extraVolumeMounts: [] - ## Add init containers to the pods. ## Example: ## initContainers: @@ -273,7 +248,6 @@ extraVolumeMounts: [] ## containerPort: 1234 ## initContainers: {} - ## Add sidecars to the pods. ## Example: ## sidecars: @@ -285,7 +259,6 @@ initContainers: {} ## containerPort: 1234 ## sidecars: {} - persistence: enabled: false ## If defined, storageClassName: @@ -307,7 +280,6 @@ persistence: existingClaim: # Dir where config and keys are written inside container mountDir: - ## Init containers parameters: ## volumePermissions: Change the owner and group of the persistent volume mountpoint to runAsUser:fsGroup values from the securityContext section. ## @@ -341,12 +313,10 @@ volumePermissions: ## cpu: 100m ## memory: 128Mi ## - ## Specifies whether RBAC resources should be created ## rbac: create: true - ## Specifies whether a ServiceAccount should be created ## serviceAccount: @@ -355,7 +325,6 @@ serviceAccount: ## If not set and create is true, a name is generated using the fullname template ## name: - ## Prometheus Metrics ## metrics: @@ -365,9 +334,7 @@ metrics: ## podAnnotations: prometheus.io/scrape: "true" - endpointPath: /v1/admin/actuator/prometheus - ## Prometheus Service Monitor ## ref: https://github.com/coreos/prometheus-operator ## @@ -394,7 +361,6 @@ metrics: ## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#prometheusspec ## additionalLabels: {} - ## Custom PrometheusRule to be defined ## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart ## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions @@ -412,13 +378,11 @@ metrics: # labels: # severity: error rules: [] - ## The url below is to access Admin API services. ## CAUTION: Domain name to acess Admin UI must be secure/internal/over vpn. ## Slash is important! admin: apiUrl: https://api-internal.sandbox.mosip.net/v1/ - ## Admin UI swagger should have only internal access. Hence linked to internal gateway ## We create a gateway for admin specific URL(s) listed under `hosts` istio: diff --git a/uitest-admin/pom.xml b/uitest-admin/pom.xml index e18fdbe9..9de8ca45 100644 --- a/uitest-admin/pom.xml +++ b/uitest-admin/pom.xml @@ -2,7 +2,7 @@ 4.0.0 io.mosip.testrig.adminui uitest-admin - 1.2.1-SNAPSHOT + 1.4.0-SNAPSHOT uitest-admin Parent project of uitest-admin https://github.com/mosip/admin-ui @@ -41,7 +41,7 @@ 3.0.7 6.11 1.13 - uitest-admin-1.2.1-SNAPSHOT-jar-with-dependencies + uitest-admin-1.4.0-SNAPSHOT-jar-with-dependencies 21 @@ -57,7 +57,7 @@ io.mosip.kernel kernel-bom - 1.2.1-SNAPSHOT + 1.4.0-SNAPSHOT pom import