# Introduction

All digital platforms require master data and actor (person/entity/thing) data related to that system be maintained for identification, validation, etc. For example, a property tax system needs to maintain master data about properties, land boundaries, tax codes, tax payers, inspection officers, etc. in a structured and validated fashion so as to help manage the property tax transaction in a seamless manner.

As the world becomes data rich, it is essential that various data about people, entities, geographies, resources, assets, etc. are made available in electronic registries with Open APIs for other applications to seamlessly validate and use attested and authenticated data. This is even more critical when it comes to people and entities where various claims can be electronically validated against such registries via open APIs avoiding paper-based validations, thus increasing trust while decreasing cost of validation.

Traditionally such data is owned and maintained within registers and kept frequently updated. But there are three big issues that are very common among most of these systems;

* **LIVE**: Due to its changing nature, such data often goes stale (not up-to-date), thus increasing the cost of collection and maintenance. For example, information about schools and teachers, their contact details, etc. get outdated, forcing departments to redo data collection every few years, and digitise, through time consuming processes.
* **REUSEABLE**: Even if such data is maintained by one system, it is not available to be reused by other systems forcing every department needing such data to repeat data collection and maintenance.
* **TRUSTWORTHY**: When data is exchanged between systems, trust of that data is established by ensuring the entire record itself is digitally signed and the fact that registry record comes with attestations along with the data. For example, a list of schools downloaded as a CSV file from a portal cannot be trusted by other systems since there is no guarantee that it is authentic and has not been edited subsequently.

The government, educational industry, and other ecosystems issue certificates, licenses, etc. Availability of these in paper form creates issues of low trust, lack of credibility, information asymmetry, time consuming physical verification, and non-portability amongst many others. Additionally, it is difficult to verify the legitimacy of these documents. Verification is a time-consuming and challenging procedure that frequently takes weeks or even months to complete. Moreover, Users have very little control over who has access to their personal information, where their papers are stored, and how they are used.

[Click here](/v1.0.0/help/comprehensive-overview-electronic-registries-and-verifiable-credentials) to learn more about electronic registries and verifiable credentials

#### *An interoperable and unified registry infrastructure needs to be built to enable "live", "reusable", and “trustworthy” registries as a “single source of truth” to address the above three core issues.*

**Sunbird RC** is a "low code" framework to enable organizations to rapidly build next generation electronic registries and verifiable credentials. Sunbird RC uses a set of configurations to rapidly build out registries, automatically generate CRUD (create/ read/ update/ delete) APIs without any coding, enable registry searches and access via open APIs, issue and manage verifiable credentials, manage user consent flows if required, manage attestation and verification flows, etc.

Sunbird RC is listed as a global Digital Public Good (DPG) within the [Digital Public Good Alliance (DPGA) registry](https://digitalpublicgoods.net/registry/). It meets the DPG standard of privacy and other applicable best practices, does no harm by design, and is of high relevance for attainment of the United Nations 2030 Sustainable Development Goals. Sunbird RC is the core engine within [DIVOC](https://divoc.dev/), a globally recognized DPG for vaccination and health credentialing. Sunbird RC is also part of India's massively adopted [DIKSHA](https://diksha.gov.in/) school education platform used at population scale.

Sunbird RC is open sourced under [MIT license](https://opensource.org/licenses/MIT). Any individual or organisation can leverage this building block for free for their purposes in accordance with the MIT license. We strongly encourage you to participate in the community and contribute back to help improve this project.

***“This website abides by the*** [***Terms of Use***](https://sunbird.org/terms-conditions) ***and*** [***Privacy Policy***](https://sunbird.org/privacy-policy) ***of*** [***www.sunbird.org***](http://www.sunbird.org)***.”***

*“Copyright © 2021 EkStep Foundation. This work is licensed under a* [*Creative Commons Attribution (CC-BY-4.0) International License*](https://creativecommons.org/licenses/by/4.0/) *unless otherwise noted.”*


# Sunbird RC Overview

**What is Sunbird RC?**

#### Video on "What is Sunbird RC?"

To understand Sunbird RC, listen to Dr Pramod Varma, CTO of EkStep foundation

{% embed url="<https://www.youtube.com/watch?feature=youtu.be&v=HsQK5uSUnDk>" %}
What is Sunbird RC? by Dr Pramod Varma
{% endembed %}

Sunbird RC (Registry and Credentials) is a "low code" framework to enable organizations to rapidly build next generation electronic registries and verifiable credentials. Sunbird RC uses a set of configurations to rapidly build out registries, automatically generate CRUD (create/ read/ update/ delete) APIs without any coding, enable registry searches and access via open APIs, issue and manage verifiable credentials, manage user consent flows if required, manage attestation and verification flows, etc.

Sunbird RC is listed as a global Digital Public Good (DPG) within the [Digital Public Good Alliance (DPGA) registry](https://digitalpublicgoods.net/registry/). Sunbird RC is the core engine within [DIVOC](https://divoc.dev/), a globally recognized DPG for vaccination and health credentialing. Sunbird RC is also part of India's massively adopted [DIKSHA](https://diksha.gov.in/) school education platform used at population scale.

This is an independently usable digital building block and is part of overall [Sunbird](https://sunbird.org/) open-source initiative. Similar to various projects under Sunbird, this is also open sourced under MIT license and you are free to adopt for your purposes. We strongly encourage you to contribute back, participate in the community to help improve this project.

One of the most significant advantages of Sunbird RC is its privacy-preserving feature. Sunbird RC uses advanced cryptographic methods, such as digital signatures and encryption, to protect personally identifiable information (PII) and other sensitive data from unauthorized access or disclosure. This is critical in today's data-driven world, where data privacy and security are of paramount importance.

Another significant benefit of the Sunbird RC is its modular and configurable design. This feature allows implementers to tailor the platform to their specific needs and requirements, enabling them to use the platform efficiently and effectively. Sunbird RC also supports multiple languages and multi-cloud environments, making it easy to deploy and facilitate rapid roll-out.

Sunbird RC also offers observability features that allow users to monitor the health and performance of the system. Basic telemetry and analytics are provided, enabling users to detect any issues or anomalies through audit and logs.

Sunbird RC is designed to handle large volumes of data and concurrent users, with the ability to sync and update data asynchronously, ensuring that the platform can scale as the data grows. See the Sunbird RC in action page for examples of where and how Sunbird RC is currently used.

**Features of Sunbird RC**

**1. Master Data Store:** Use the registry as a master data store of actors (people, entities or things)

* Vocabulary creation and modelling
* Employ flexible schema to define entity attributes and validations using JSON, JSON-LD
* Attach rules for data validation, lifecycle operations and relationships

**2. Data operations:** Issue data into, as well as read data from Registry

* Secure API driven CRUD operations
* Data operations via secure, open APIs for data publishing and access, data discovery and search
* Key-value pair driven search, attribute search

**3. Data protection:** Encryption and data security

* Data encryption and masking
* Support for custom encryption services - open end points to replace the bundled in encryption services with services of the adopters choice
* Audit trails and logging

**4. Single source of truth:** Employing the registry as a single source of truth for reliable data

* Digital signatures for trust worthiness and non-repudiation
* Open end points to replace the bundled in encryption services with services of the adopters choice

**5. Business led Database choice:** Ability to make a business led choice of database to the registry

* Support for multiple databases employing out-of-the-box adapters for multiple DB support - including graphs DBs(Neo4j), RDBMS(Postgres)

[Click here](/v1.0.0/help/comprehensive-overview-electronic-registries-and-verifiable-credentials) to learn more about electronic registries and verifiable credentials

Use the GitHub [discussions board](https://github.com/Sunbird-RC/community/discussions) or [use this invite to join Discord community channel](https://discord.gg/Q5mvw2mGC8) to participate in the community and help improve. For feature requests and issues, use the [issue tracker](https://github.com/Sunbird-RC/community/issues). We also encourage you to help fix documentation and code by doing pull requests on the appropriate repos here.

“Copyright © 2021 EkStep Foundation. This work is licensed under a [Creative Commons Attribution (CC-BY-4.0) International License](https://creativecommons.org/licenses/by/4.0/) unless otherwise noted.”

##


# Why do we need Sunbird RC?

{% embed url="<https://www.youtube.com/watch?v=zWDyQWuB_lw>" %}

Sunbird RC can be used to quickly build numerous national registries of individuals, objects, and entities for a variety of domains. Adopters can rapidly build core electronic registries through configurable schemas and workflows. All needed APIs, workflows, and a default user experience are automatically created for key registry stakeholders.

Sunbird RC provides microservices to issue portable standard schema based [W3C](https://www.w3.org/TR/vc-data-model/) VC complaint credentials with attestation and verification flows. These credentials may be printed with QR codes, can be translated into many languages, and are instantly verifiable. Sunbird RC, facilitates enrollment, authentication, data ownership, search, issuance and management of verifiable credentials, claim attestation flows between user and attester, sharing of credentials with user consent, amongst others.

Sunbird RC is designed to be scalable, enabling organizations to handle large volumes of digital identities and credentials with ease. The system can handle both synchronous and asynchronous updates, making it easy to keep data up to date. It is built on open standards and protocols, making it interoperable with other systems and platforms. This ensures that organizations can easily integrate with other systems and applications without having to reinvent the wheel.

Overall, Sunbird Registry and Credentials provide a secure and scalable solution for managing and verifying digital identities and credentials, making it easier for organizations to manage access and permissions, and enabling individuals to have greater control over their data.


# Core Capabilities

<figure><img src="/files/XsPwSYrE4P2hYihT4dU2" alt=""><figcaption></figcaption></figure>

### Registry

A governing body/authority would be able to build registry that acts as a single source of truth

1. **Define Schema as per policy:**

* Define field and field types: Can create new fields in the registry to store specific types of information and can also specify the type of data that should be entered into each field. For example: if an adopter is building a student registry, they may define the fields for student name, father's name, mother's name, school name, and age, and may define that the age field should accept only numeric.
* Field level privacy: This feature allows the individuals/organizations to define different levels of privacy for different fields based on the sensitivity of the data contained within them. For example, in a patient registry, adopters may want to restrict access to certain fields containing patient health information to only authorized healthcare professionals, while other fields containing less sensitive information such as patient demographics may be accessible to a wider range of users.
* Consent framework at schema level

2. **Create entities:**

* Able to Bulk invite/onboard users via CSV
* Able to link to external systems
* Able to self-register
* Able to decide visibility of who can view the content at field level

3. **Define Ownership**

* Able to define which entities can login & how is authorization handled

4. **Discovery**: The visibility of discovery attributes can be controlled through access control mechanisms such as consent-based sharing, which allows users to control who can view their information. Specifically, users can define which discovery attributes are public (visible to all users), private (visible only to the user), or consent-based (visible to selected users or groups based on their consent).
5. **Analytics**: Basic Analytics for Registries

### Verifiable Credentials (VC)

1. **Define Attestation and Claim Workflow**:

* Tenants (users) can define an 'add-on' workflow, which means they can customize the steps in the workflow to suit their needs. Additionally, they can configure how claims will be approved, either automatically or manually.
* The system used for attestation can be an internal system like Sunbird RC or an external system that the tenant connects to.
* Multi-level attestation for a claim can be created i.e. the claim can be reviewed by multiple parties or levels of approval.
* Define Validity

2. **Consent:**

* Grant or Revoke Consent: Able to receive consent requests to grant or revoke the consent access.
* Consent Auditing

3. **Issuance services**

* W3C compliant
* Create and Issue Verifiable Credentials
* Updation and Revocation
* Unique ID generation

### VC Verification

* Offline verification of Verifiable Credentials:[ Reference SDK](https://docs.sunbirdrc.dev/vc-verification-module)
* Consent based access: Able to provide consent to another system/person to access Verifiable Credentials for the purpose of transaction/interaction.

### Digital Wallet

Citizen (credential owners/holders) can access Verifiable Credentials anytime anywhere.

1. Fetch and store personal verifiable credentials :With digital wallet, individuals can access their credentials anytime anywhere as the wallet can fetch and store the issued credentials from various entities.
2. Consent based sharing of verifiable credentials:The digital wallet also enables consent-based sharing of verifiable credentials with third parties, such as employers, service providers, or other organizations that require proof of identity ,qualifications, association etc. This means that the individuals can control who has access to their personal information and can choose to share only the necessary information for a specific purpose.


# Core Registry Verbs

<figure><img src="/files/rKTBR0TJQ1cVwfGSyPtw" alt=""><figcaption></figcaption></figure>


# Workflows

<figure><img src="/files/ZvMxcnqKPdb45RrYlbHb" alt=""><figcaption></figcaption></figure>

1. **User Registration/Onboarding**
   1. Self-Registration
   2. Register via Invitation
   3. Via integration with existing registries
2. **Verifiable Credentials Issuance:** Issuer of a verifiable credential creates the credential and digitally signs it using a cryptographic key that only the issuer can use.When the issuer digitally signs the credential, they generate a digital signature using their private key. The digital signature is attached to the credential and can be used by verifiers to confirm that the credential has not been altered since it was issued. The public key associated with the issuer's private key can also be included in the credential, allowing verifiers to verify the digital signature using the issuer's public key.
3. **Verifiable Credentials Storage:** Once a verifiable credential is issued, it is stored in the elockers/digital wallet or other digital storage system controlled by the credential holder. The digital wallet provides a secure and convenient way for the credential holder to manage and share their credentials with others.
4. **Verifiable Credentials Verification:** When a credential holder presents a verifiable credential to the accepting party/verifier, such as a potential employer, the verifier can verify the authenticity of the credential using cryptographic techniques. This involves verifying the digital signature of the issuer, which confirms that the credential has not been tampered with since it was issued.


# What Sunbird RC is and what it's not? (WIP)


# Possibilities

<figure><img src="/files/3tPbuAAmruEpMm08nPeV" alt=""><figcaption></figcaption></figure>

Sunbird Registry and Credentials provides a secure and scalable way to manage digital identities and credentials. Some of the use cases for Sunbird Registry and Credentials include:

1. Education: Sunbird Registry and Credentials can be used to manage educational credentials, such as degrees, certificates, and diplomas. This can help educational institutions to securely issue and verify digital credentials, while also providing students with a secure and portable way to share their achievements.
2. Healthcare: Sunbird Registry and Credentials can be used to manage healthcare credentials, such as medical licenses, certifications, and training records. This can help healthcare providers to ensure that their staff members are qualified and competent, while also enabling patients to verify the credentials of their healthcare providers.
3. Government Ecosystem: Sunbird Registry and Credentials can be used by governments to manage citizen identities and credentials, such as driver's licenses, passports, and voter registration. This can help to improve the efficiency and accuracy of government services, while also enhancing the security and privacy of citizen data.
4. Employment: Sunbird Registry and Credentials can be used to manage employment credentials, such as job certifications, training records, and performance reviews. This can help employers to ensure that their staff members are qualified and competent, while also enabling employees to securely share their credentials with potential employers.


# Demo Links

Discover Sunbird RC in action! Explore the demo links below to experience firsthand the features and use cases of our offerings. Click, explore, and see how our solutions can make a difference.

<table><thead><tr><th width="180">Solution</th><th width="365">Description</th><th>Link and Creds</th></tr></thead><tbody><tr><td>Education Ecosystem Registries</td><td>Education Ecosystem Registries (EER) are being envisioned as a means to empower end users with capabilities to manage their data and learning/skilling credentials in a digital format</td><td><a href="https://demo-education-registry.sunbirdrc.dev/
City-metro/abcd@123">https://demo-education-registry.sunbirdrc.dev/<br></a></td></tr><tr><td>Certificate Issuance Portal</td><td>The portal provides a centralized platform for managing digital certificates, empowering the organizations with capabilities to create and issue certificates to individuals. It allows issuers to select a template for their digital certificates and then issue them to individuals.</td><td><a href="https://sunbird-certificate-demo.sunbirdrc.dev/">https://sunbird-certificate-demo.sunbirdrc.dev/</a></td></tr><tr><td>eLocker</td><td>Sunbird eLocker is a digital platform that allows users to store and manage their credentials (academic, professional, skill etc.) in one central location. It is built on Sunbird RC and serves as a reference solution for developers to build their own digital eLocker platforms quickly and easily.</td><td><a href="https://elocker.xiv.in/">https://elocker.xiv.in/</a></td></tr><tr><td>Organ Donor Registry</td><td>Organ Registries are designed to facilitate the coordination and management of organ donation and transplantation. These registries serve as centralized databases that store information about both donors and recipients, allowing for efficient matching and allocation of organs.</td><td><a href="https://demo-donor-registry.sunbirdrc.dev/">https://demo-donor-registry.sunbirdrc.dev/</a></td></tr><tr><td>Unified Learner's Passport</td><td>Unified Learners Passport (ULP) is a single source of digital credentials for learners across levels, that will help them easily discover and avail opportunities for academic or professional growth</td><td><p><a href="https://dev-registration.uniteframework.io/">Issuance Portal Link</a></p><p><a href="https://dev-avsar.uniteframework.io/">Holder Portal Link</a></p><p><a href="https://verify.uniteframework.io/">Verifier Portal Link</a></p><p></p><p><br></p></td></tr><tr><td>Education Registry</td><td>Education Registry is a sample (a reference solution) built on Sunbird RC demonstrating registry of the common subjects involved in an educational system, and flows that allow attesting some of the most common claims like that of education history of students and teaching history of teachers.</td><td><a href="https://demo-education-registry.sunbirdrc.dev/">https://demo-education-registry.sunbirdrc.dev/</a></td></tr></tbody></table>


# Technical Overview

Here are the articles in this section:

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td></td><td>High Level Architecture</td><td></td><td><a href="/pages/L9RNkN4tYTlwKFHJFWW6">/pages/L9RNkN4tYTlwKFHJFWW6</a></td></tr><tr><td></td><td>Technical Specification Draft</td><td></td><td><a href="/pages/ICXMITolj3IAtWKRlvu8">/pages/ICXMITolj3IAtWKRlvu8</a></td></tr><tr><td></td><td>Tech Stack and requirements</td><td></td><td><a href="/pages/iABWwstbmxhNtnKdnyxs">/pages/iABWwstbmxhNtnKdnyxs</a></td></tr></tbody></table>


# High level architecture

<figure><img src="/files/NjreBzVe231T7LJJTJbc" alt=""><figcaption><p>High Level Architecture Diagram</p></figcaption></figure>

<figure><img src="/files/4DjljYpxK02yiTNnzC1a" alt=""><figcaption><p>Key Services</p></figcaption></figure>

The functionalities and purpose of various microservices built as part of Sunbird-RC are explained below.

#### Registry (Core)

This is the core service which enables the major functionalities of SunbirdRC. It exposes API that can be used to configure schemas and manage entities and workflows. It can also process creating entities synchronously or asynchronously. The registry is enabled to support various database providers, which are:

1. Graph database (Neo4J)
2. Relational databases (Postgresql, HSQLDB, H2, MariaDB, MySQL, MSSQLServer)
3. NoSQL databases (Cassandra)

The registry generates REST APIs for the schemas that are created dynamically. It also applies authentication and authorization on schema APIs based on the schema configuration. The registry service also provides discovery API, which can be used to search public data of a particular schema. Elasticsearch needs to be configured to the registry to enable the discovery of schemas.

#### Claim ms

This service needs to be enabled if attestation/workflows are required. This service is responsible for handling all the claims of an attestation.

#### Certificate Signer

This service needs to be enabled if verifiable credentials need to be generated for a schema. This service is capable of generating W3C based schemas. This service support configuring multi keys based on issuer. The service supports RSA & ED25519 based keys. The key [file](https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/services/certificate-signer/config.json) needs to be [mounted](https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/docker-compose.yml#L137) to the service.

#### Certificate API

This service needs to be enabled if a visual template for the verifiable credentials is required. This service is capable of generating a QR based template. The templates that are supported are SVG/HTML/PDF.

#### Notification ms

This service is required to send SMS or emails to the users. This service is used by the registry to send invite notifications to users. It is also used by keycloak to send OTP messages. This service can be configured with 3rd party plugins to send notifications.

#### Public key service

This service is used to expose public keys that are used to generate verifiable credentials. It has APIs that exposes all the public keys or issuer-based public key. This API will be used by the verification services to verify the issued verifiable credentials.

#### Metrics service

This service is used to handle all the events emitted by registry through kafka. The service stores this events in clickhouse. However the service can be used to connect different databases. Service also exposes an API which returns all the events emitted

#### Clickhouse

Clickhouse is a open source database. We are using clickhouse to store all the events that are emitted in this clickhouse

#### Context proxy service

This service will be used by verifying clients to proxy the context URLs that are used in the verifiable credentials. The public facing verifying clients needs to access the content of the context URLs that are present in the verifiable credentials. If the client is UI based application, the context URLs will be blocked due to CORS issues. This service can be used to overcome the CORS issue. The context URLs can be routed to this service which can proxy and return back the contents.

#### DB

The registry requires a main DB that is used as the main store for storing all data. The following DB providers can be used:

1. Graph database (Neo4J)
2. Relational databases (Postgresql, HSQLDB, H2, MariaDB, MySQL, MSSQLServer)
3. NoSQL databases (Cassandra)

#### Elastic Search

Elastic search is used to store all public data and it enables the discovery of data.

#### Keycloak

Keycloak is used to enable authentication and authorization of the users on using the APIs.

#### Nginx

The SunbirdRC package is also shipped with a custom modified Nginx image which is configured with all the reverse proxies for the services and also contains a generic verification page.

#### File Storage (minio)

S3 compatible object storage service is also shipped along with services which can be used to store files. It can be used by adopters who are running the services on private/bare metal servers.

#### Redis

The registry core service will require a Redis cache layer when the core service is scaled to multiple instances.

#### Kafka

Kafka service is required to create entities in an asynchronous fashion. If the system needs to handle high load and high availability the entity creation(with generating credentials) can be processed asynchronously using Kafka.

#### Bulk Issuance

Bulk issuance service will allow the issuers to upload their csv files and issue credentials to all those actors present in each row of a csv. The service also has the capability to return a file based reports which will download a csv file which will contain a column of errors that occurred for a that specific actors data

**Encryption**

Encryption service can be used to store private fields configured in a schema in encrypted form in db, which can only be decrypted by the encryption service. It requires to be enabled through appropriate environment variables.

**ID Gen**

ID Gen service can be used to generate IDs with given format for any fields in the schema. It requires format configurations to be provided in schema configurations. and enabled through environment variables.

{% embed url="<https://youtu.be/mZjYgdxu0gU>" %}


# Technical Specification Draft

***This is an early draft of the specification. You can give your feedback to improve the same via the*** [***Discussions area***](https://github.com/Sunbird-RC/community/discussions/categories/sunbird-rc-technical-specification-feedback)***.***

## **Introduction**

All digital platforms require master data and actors (person/entity/thing) data related to that system to be maintained for identification, validation, etc. For example, a property tax system needs to maintain master data about properties, land boundaries, tax codes, tax payers, inspection officers, etc. in a structured and validated fashion so as to help manage the property tax transaction in a seamless manner. As the world becomes data rich, it is essential that various data about people, entities, geographies, resources, assets, etc. are made available in electronic registries with Open APIs for other applications to seamlessly validate and use attested and authenticated data. This is even more critical when it comes to people and entities where various claims can be electronically validated against such registries via open APIs avoiding paper based validations, thus increasing trust while decreasing cost of validation.

## **Core principles**

* LIVE: Due to its changing nature, such data often goes stale (not up-to-date), thus increasing the cost of collection and maintenance. For example, information about schools and teachers, their contact details, etc. get outdated, forcing departments to redo data collection every few years, and digitise, through time consuming processes.
* REUSEABLE: Even if such data is maintained by one system, it is not available to be reused by other systems forcing every department needing such data to repeat data collection and maintenance.
* TRUSTWORTHY: When data is exchanged between systems, trust of that data is established by ensuring the entire record itself is digitally signed and the fact that registry record comes with attestations along with the data. For example, a list of schools downloaded as a CSV file from a portal cannot be trusted by other systems since there is no guarantee that it is authentic and has not been edited subsequently.

## **Terminology**

| Data                          | Electronic data of any type. It could be simple data or composite data.                                                                                                                                                                                                                                                                                                                   |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Database                      | A software system that stores and manages data.                                                                                                                                                                                                                                                                                                                                           |
| Schema                        | Machine readable definition of data.                                                                                                                                                                                                                                                                                                                                                      |
| Actor (Subject)               | A person, entity, or a thing who/which has been identified.                                                                                                                                                                                                                                                                                                                               |
| Transaction/ Interaction Data | Data representing details of an interaction/transaction that was done among one or more actors within a system.                                                                                                                                                                                                                                                                           |
| SoR (System of Record)        | A software system that is the primary system to enable a specific set of transactions/interactions through a set of workflows and user interfaces. Identities of actors participating in these transactions/interactions maybe linked to a registry.                                                                                                                                      |
| Registration                  | Act of registering/enrolling the actor into a system                                                                                                                                                                                                                                                                                                                                      |
| Claim                         | A statement that is made by an actor which can be verified.                                                                                                                                                                                                                                                                                                                               |
| Attestation                   | An act of verifying and authorizing specific data in a digitally signed fashion by an authorized individual/entity (whose identities are typically linked to some other registries).                                                                                                                                                                                                      |
| Discovery                     | An act of finding specific entries in a registry through a search/find mechanism.                                                                                                                                                                                                                                                                                                         |
| Assertion                     | An act of verifying a claim.                                                                                                                                                                                                                                                                                                                                                              |
| Consent                       | Approval of an actor given to another person/system to access the data of that actor for purposes of transaction/interaction.                                                                                                                                                                                                                                                             |
| Credential                    | Digitally represented verifiable artifacts containing a qualification, achievement, milestone, fact, etc issued to an actor for them to be able to make claims.                                                                                                                                                                                                                           |
| Registry                      | An Electronic Registry is a system, acting as a single source of truth that houses a set of common attributes of the actor in a trustable (attested) and non-repudiable (audited) fashion, made available in the control of the actor enabling actors to authenticate themselves and make claims about them with their consent which can be electronically verified by 3rd party systems. |
| Information Provider          | An authorized entity or a person who manages a SoR for enabling specific transactions/interactions among various actors. This entity using their systems of record then provides verifiable (digitally) credentials, documents, certificates, and transaction/interaction data etc. back to actors.                                                                                       |
| Information Users             | An entity that is accessing credentials/data of an actor with necessary consent of the actor for making assertions and providing various services/products.                                                                                                                                                                                                                               |

## **Workflow**

![](/files/xqXF7M1x1DDDFZLGHo2W)

## **Schema**

All registries have attributes pertaining to the entity or the fact in question either person or things. Schema defines the structure and constraints of the entity, Sunbird RC uses standard JSON-LD based schema.

In the example given below Place is Concept that registry is storing supporting name, city, addressRegion (state) and country.

#### Example:

```
{
 "$schema": "http://json-schema.org/draft-07/schema",
 "type": "object",
 "properties": {
   "Place": {
     "$ref": "#/definitions/Place"
   }
 },
 "required": [
   "Place"
 ],
 "title": "Place",
 "definitions": {
   "Place": {
     "$id": "#/properties/Place",
     "type": "object",
     "title": "The Place Schema",
     "required": [
       "name",
       "city",
       "addressRegion",
       "country"
     ],
     "properties": {
       "name": {
         "type": "string"
       },
       "city": {
         "type": "string"
       },
       "addressLocality": {
         "type": "string"
       },
       "addressRegion": {
         "type": "string"
       },
       "country": {
         "type": "string"
       },
       "postalCode": {
         "type": "string"
       },
       "contact": {
         "type": "string"
       }
     }
   }
 }}
```

## Configuration

In addition to JSON LD specific data types Sunbird RC supports various extension configurations under `\_osConfig`. Access, indexing, primary key etc are configurable using schema configuration.

#### Entity and Properties

#### Property data types and restrictions

Supported types:

String - Unicode text, additional regular expressions restrictions can be applied.

Enum - restricted list of values

Number - numeric data

#### List of attributes

Collection of data values are also supported as multiple data value might represent the entity property for example subjects taught : `["english","science, "mathematics"]`

### Visibility scope:

3 types of visibility on attributes.

1. Public
2. Private (privateFields)
3. Internal

Public data attributes are available in discovery by default any sort of permission / authorization is not needed by default.

Private attributes can be accessed by the owner by default, with consent 3rd party can access the data field.

Internal fields are system fields that only serve internal functionalities, these can never be accessed by any actors in the system.

#### Primary Keys for Entities

Primary keys from domain space will help enforce uniqueness of information and make it easily accessible. “uniqueIndexFields” can be used to configure the same.

Example:

```
"uniqueIndexFields": [ "identityValue", ... ]
```

### Index field set

Indexes can help in faster access to information, based on usage context index fields can be configured. Example:

`"indexFields": ["phoneNumber", ... ],`

### Validation Extensions

JSON LD schema allows defining basic type constraints like numeric type, text or list of items etc. Also it allows a list of possible values for given attributes (enum) and regular expressions based constraints for the value.

### Schema access api:

SunbirdRC supports following apis for accessing schema:

```
GET /api/docs/{entityName}.json
```

Swagger document is accessible at

```
GET /api/docs/swagger.json
```

## Attestation

### Configuration

Attestation on given set of fields is configurable with schema configuration. Below is the example for attestation requirement using DSL.

Example:

```
 "attestationPolicies": [
 {
     "property": "experience/\[\]",
     "paths": [ "experience" ],
     "attestorEntity": "Institute",
     "conditions": "\(ATTESTOR\#$.instituteName\#.contains\(REQUESTER\#$.institute\#\)\)"
 },
  ...
 ]
```

### Attestation API

#### Attestation Types

Since there will be mixed attestation requirements which need human verification and in some cases attestations can be completely digital, To begin with registries can allow both manual and automatic attestation types. A teacher rewarding and attesting the grades can be manual activity, identity claim can be attested digitally by identity provider like Aadhaar.

Manual Attestation

Manual attestation may need workflow, by default registry supports raising claim to pre-configured attestation requirement. The claim will be routed to appropriate authority / role based on the configuration. Once the claim gets approved / rejected it will show the status of respective fields in the claim as verified / invalid respectively.

Attestor configuration is controlled with “attestorEntity” configuration.

Automated attestation

Digital registries can inter-operate sharing the trusted claims and information among themselves. For doing so claim can be routed to automated registry verifier which will proxy for another registry and take care of verification and attestation. Such attestation can be time bound or one time attestation.

Example: Identity registry can be used to prove the identity of a subject without manual verification. Mobile OTP based consent flow can verify the identity and mark subjects name as verified. Eventually certificates issued by educational institutions can also get verified digitally.

```
POST /api/v1/{entityName}/{entityId}/attest/{propertyID}
{
  "action":"GRANT_CLAIM"
  ...
}
```

#### Custom extensions

Attestation workflow might need custom stages and transition rules based on the usecase. Attestation is extensible to add or customize these workflows and add custom rules based on the need.

## Enrolment / Signup

### Sign up

Enrolment/Signup API supports use cases related to self signup or bulk invites to register in the registry. One of the principles of registry is to avoid stale data loading from databases and give control to subjects in participating in registration and managing their data (Rather than someone else managing it for them).

```
POST /api/v1/{entityName}/invite
{
"name”:"Suresh",
"email":"suresh@example.com"
}
```

### Update information

```
PATCH /api/v1/{entityName}/{entityId}
{
  "fieldPaths":["/name"]
}
```

## Discovery

### Search API

```
POST /api/v1/search
{
  "email":"suresh@example.com"
}
```

### Directory

Example pincode lookup

```
POST /api/v1/search { "state":"Karnataka" }
```

## Consent API

### Authentication flow

![](/files/7KNAIj3H6Ftnb31ahKGW)

### Request scopes and sharing attributes

```
GET /partner/api/v1/{entityName}
```

## Use Cases

* Building a Blood donor registry
* Building simple pincode directory service
* Education registry
* Immunization
* Authentication and consent usage in learning application

## **Open for feedback**

***This is an early draft of the specification. You can give your feedback to improve the same via the*** [***Discussions area***](https://github.com/Sunbird-RC/community/discussions/categories/sunbird-rc-technical-specification-feedback)***.***


# Tech Stack and Requirements

## Architecture Diagram

<figure><img src="/files/YmHyYxnw8IVT8G9dTr4X" alt=""><figcaption></figcaption></figure>

## Tech Stack

| Software/Language | Recommended | Minimum Version |
| ----------------- | ----------- | --------------- |
| Java              | 1.8         | 1.8             |
| Node JS           | v18.12.1    | v18.12.1        |
| Go Lang           | 1.15        | 1.15            |
| Linux / Docker    | any         | any             |
| Postgre sql       | latest      | v8              |
| Redis             | latest      | 4               |
| ElasticSearch     | 6.8.23      | v6, v7          |
| Keycloak          | 14.0.0      | 14.0.0          |
| Minio             | latest      |                 |
| Kafka (Zookeeper) | latest      |                 |
| nginx             | latest      |                 |
| Angular           | 10          |                 |
| Kubernetes        | latest      |                 |
| Helm              | latest      |                 |
| Docker Compose    | latest      |                 |

## Stock Frontend Interface

Angular 8

## Deployment

On local machines, Docker is recommended.

For development, a single VM with docker will work.

The steps to setup the development environment is available here.

{% content-ref url="/pages/I9pXw6sQApabC3Lz7IUF" %}
[Installation Guide](/v1.0.0/use/getting-started/installation-guide)
{% endcontent-ref %}

For production, Kubernetes is recommended.

## Typical Requirement for production

* 1 node small (backed by CDN) 2 core 4 gb minimum (UI)
* 3 node kubernetes cluster with 4 core 8 gb RAM 200 GB storage
* 2 node for postgresql 4 core 8gb RAM 500 GB storage
* 1 node for elastic-search 4 core 8gb RAM 200 GB storage (if needed)
* Loadbalancer based on cloud provider


# Adopters

Sunbird RC has been leveraged to develop the following solutions:

<table><thead><tr><th width="126"> </th><th> </th></tr></thead><tbody><tr><td><img src="/files/0nMhdISWmgRJ7h2yXzUA" alt="" data-size="original"></td><td><p><strong>COVID Vaccination Credentials</strong></p><p>Sunbird RC is the core engine within <a href="https://divoc.dev/">DIVOC</a>, a globally recognized DPG for vaccination and health credentialing.  Utilizing Sunbird RC as a versatile building block, DIVOC has digitized the generation of vaccination certificates, available electronically and as printable copies from a centralized database. Governments, including those in India, Sri Lanka, the Philippines, have implemented DIVOC (built on Sunbird RC) to launch efficient digital vaccination platforms, showcasing the adaptability and effectiveness of Sunbird RC in advancing global vaccination efforts.</p></td></tr><tr><td><img src="/files/0nMhdISWmgRJ7h2yXzUA" alt="" data-size="original"></td><td><strong>COVID Test Certificates</strong></td></tr><tr><td><img src="/files/jBCwVZKFx24re0OWB3tl" alt="" data-size="original"></td><td><em>Sunbird RC</em> is part of India's massively adopted <a href="https://diksha.gov.in/">DIKSHA</a> school education platform used at population scale. Digital Infrastructure for Knowledge Sharing (DIKSHA) is the national school education platform of India and has been adopted by all 36 states and UTs across India thus impacting nearly every student and teacher in the country. It is one of the largest education platforms in the world. Student, teacher and school registries are core building block, and can be enabled by Sunbird- RC building block</td></tr><tr><td><img src="/files/HRtwfQsFXGa63GlB3H4m" alt="" data-size="original"></td><td> <strong>iGOT Karmayogi,</strong> a comprehensive online platform to guide individual civil service officials in their capacity building journey,  leveraged Sunbird RC to enable the issuance &#x26; verification of digitally verifiable certificates that are issued to civil servants as proof of training and served 2 crore officials by enabling lifelong learning through iGOT implementation.</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>Leveraging Sunbird RC , a leading multinational corporation has successfully built a powerful upskilling platform. More than 500,000+ learners onboarded, the platform offers 10,000+ courses, empowering students from various backgrounds. Focusing on vocational and soft skill development, participants gain expertise for emerging job opportunities. It enables learners to gain certifications, enhancing their career prospects. The platform have been issuing verifiable credentials and certificates, addressing the evolving challenges faced by learners and professionals using Sunbird RC.</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>Utilizing the Sunbird RC framework, a government health agency has created an Organ Pledge Registry, serving as a centralized repository for information on individuals in the country committed to donating organs. The Pledge Registry features a verification process for the authenticity of individuals pledging organs, ensuring only legitimate individuals are included in the organ donation registry, instilling trust in the system. These registries generate verifiable digital pledge certificates based on stakeholder registration data, with the added functionality of producing multilingual certificates for the diverse population across the country.</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>Utilizing the Sunbird RC framework, the Unified Learners Passport (ULP) was created, serving as a singular digital credential source for learners across levels. This platform facilitates easy discovery and access to opportunities for academic or professional growth. ULP offers learners a comprehensive platform to aggregate and display their educational achievements, skills, and experiences. The platform enables effortless sharing of credentials, streamlining the verification process for both learners and opportunity providers. A pilot for this initiative has been launched.</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>A successful PoC has been developed for eLocker, a digital wallet system. This platform allows users to securely manage digital documents, including government-issued IDs and academic certificates. Eliminating the need for physical storage, eLocker provide a safe and convenient solution, reducing the risk of loss or damage. The PoC demonstrates the efficiency and security of this innovative approach to digital document management</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>Utilizing the Sunbird RC framework, organizations are issuing proof of achievement credentials to participants who have taken part in a variety of events hosted by the organization.</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>Leveraging Sunbird RC, a successful PoC has been developed for Vehicle Registry. This enables the incorporation of verifiable credentials on both number plates and registration cards, ensuring a heightened level of trust and security within the automotive ecosystem. This not only streamlines the registration workflow, but also sets the stage for a future where seamless authentication and accountability redefine the standards of vehicle management</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>One of our adopter has utilized Sunbird RC to create a customizable and user-friendly platform. This solution facilitates the seamless registration, verification, and issuance of verifiable credentials, ensuring a trustworthy and efficient process. Through this utilization, the adopter aims to transform intricate procedures into user-friendly interactions, enhancing overall efficiency and reliability in credential management</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>One of Sunbird's building blocks involves utilizing Sunbird RC as a key component. This integration serves to enable registries of various involved actors, encompassing Volunteers, agencies, Needs, and Need Types. By incorporating Sunbird RC in this capacity, the system enhances the efficiency and organization of these registries.</td></tr><tr><td><img src="/files/1k5xoMsLdTtsJA6Tzc3R" alt="" data-size="original"></td><td>Leveraging Sunbird RC, a government agency is in the process of creating a platform to issue Verifiable Credentials (VCs) to farmers. Through this initiative, each farmer will receive a unique farmer ID along with a digitally verifiable credential. The farmer registry will be dynamically linked to their farmland plot records, laying the foundation for swift, efficient, and transparent service and scheme delivery by the government.</td></tr></tbody></table>


# Roadmap

The link to the RC roadmap is here:

<https://github.com/orgs/Sunbird-RC/projects/16/views/1>


# Getting started

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>Pre-requisites</td><td></td><td></td><td><a href="/pages/5W0gcXhXiudkxgZqNj1s">/pages/5W0gcXhXiudkxgZqNj1s</a></td></tr><tr><td>Installation Guide</td><td></td><td></td><td><a href="/pages/I9pXw6sQApabC3Lz7IUF">/pages/I9pXw6sQApabC3Lz7IUF</a></td></tr></tbody></table>


# Pre-requisites

## Prerequisites

### Terminal emulator

Linux and MacOS will have a terminal installed already. For Windows, it is recommended that you use `git-bash`, which you can install from [here](https://git-scm.com/download/win).

Type `echo Hi` in the terminal once it is installed. If installed correctly, you should see `Hi` appear when you hit enter.

### Git

Installation instructions for Git can be found [here](https://github.com/git-guides/install-git).

Run `git --version` in the terminal to check if `git` has been installed correctly:

```
$ git --version
git version 2.33.0
```

### Java

Installation instructions for Java 8 can be found [here](https://docs.oracle.comjavase/8/docs/technotes/guides/install/install_overview.html).

Run `java` in the terminal to check if `java` has been installed correctly:

```
$ java
Usage: java [-options] class [args...]
...
```

### NodeJS (Only needed for the Registry CLI)

Installation instructions for NodeJS can be found [here](https://nodejs.org/en/download/package-manager/).

Run `node -v` in the terminal to check if `node` has been installed correctly:

```
$ node -v
v16.11.0
```

### Docker

Installation instructions for Docker can be found [here](https://docs.docker.com/engine/install/).

Run `docker -v` in terminal to check if `docker` has been installed correctly:

```
$ docker -v
Docker version 20.10.9, build c2ea9bc90b
```

### Docker Compose

Installation instructions can be found [here](https://docs.docker.com/engine/install/).

Run `docker-compose -v` in terminal to check if `docker-compose` has been installed correctly:

```
$ docker-compose -v
Docker Compose version 2.0.1
```

## Downloading The Source Code

Run the following in terminal to download the registry's source code:

```
$ git clone https://github.com/sunbird-rc/sunbird-rc-core.git sunbird-rc/core
```

Move into the folder by typing:

```
$ cd sunbird-rc/core
```

## Compiling The Registry

Run the `configure-dependencies.sh` script in the root of the repo as follows:

```
$ sh configure-dependencies.sh
```

Then compile the registry (this will take some time when you are running it for the first time):

```
$ cd java
$ ./mvnw clean install -DskipTests
$ cd ..
```

This should create a JAR file in the `java/registry/target` folder.

## Configuring Schemas

Create `_schemas/` folder in `java/registry/src/main/resources/public/`

Place all your schema files in the `java/registry/src/main/resources/public/_schemas/` folder.

A sample set of schemas for a simple student-teacher registry can be found [here](https://github.com/Sunbird-RC/sunbird-rc-core/tree/main/tools/cli/src/templates/config/schemas). You can learn how to write your own schemas by following [this guide](/v1.0.0/use/developers-guide/schema-setup/schema-configuration).

## Configure And Start Dependent Services

Run the following in terminal to download [this](https://github.com/sunbird-rc/sunbird-rc-core/blob/main/tools/cli/src/templates/examples/student-teacher/docker-compose.yaml) Docker Compose file:

```
$ curl https://raw.githubusercontent.com/sunbird-rc/sunbird-rc-core/main/tools/cli/src/templates/examples/student-teacher/docker-compose.yaml > docker-compose.yml
```

To download a minimal keycloak configuration, run the following:

```
$ curl https://raw.githubusercontent.com/sunbird-rc/sunbird-rc-core/main/tools/cli/src/templates/examples/student-teacher/imports/realm-export.json > imports/realm-export.json
```

Then start Keycloak (`kc`), Postgres (`db`), Elastic Search (`es`) and the Claims Service (`cs`) by running the following command:

```
$ docker-compose up kc db es cs
```

## Configuring The Registry

Before we can start the registry, we need to regenerate and retrieve the client secret for the `admin-api` client in Keycloak. To do that, follow these steps:

* Go to <http://localhost:8080/auth/admin/master/console/#/realms>.
* Login using the username `admin` and password `admin`.
* Click `Sunbird RC`.
* Click `Clients` in the panel on the left.
* Click `admin-api`.
* Click the `Credentials` tab.
* Under `Client Secret`, click `Regenerate Secret`. Copy the secret that you see in the box and paste it in the `docker-compose.yml` file in place of `INSERT_SECRET_HERE` on line 42.

## Running The Registry

Once you have completed all the above steps, run the registry using the following command:

```
$ java -jar java/registry/target/registry.jar
```


# Installation Guide

The following steps will help you to setup SunbirdRC components for a local/development/production environment.

## For local/development environment

We have two methods of setting up the environment.

* **Registry CLI**

{% content-ref url="/pages/KOptdg53jEkYJbzU8Mdi" %}
[Registry CLI](/v1.0.0/use/getting-started/installation-guide/installation-guide)
{% endcontent-ref %}

* **Manually through docker-compose**

{% content-ref url="/pages/800jsm72BNwlYUJxY0oO" %}
[Manual installation through docker-compose](/v1.0.0/use/getting-started/installation-guide/manual-installation-through-docker-compose)
{% endcontent-ref %}

* **Production setup through helm charts**

{% content-ref url="/pages/DS86UyGEqwcVwzj9shkM" %}
[Production setup through Helm](/v1.0.0/use/getting-started/installation-guide/production-setup-through-helm)
{% endcontent-ref %}


# Registry CLI

The following steps will help you to setup SunbirdRC components for a local/development environment.

## System requirements

* 4 Cores
* 8 GB RAM
* Min 100 GB disk

## Video

{% embed url="<https://www.youtube.com/live/C-cmtsEuPU0?feature=share>" %}

## Prerequisites

> This guide assumes a some familiarity with basic linux commands. If not, [here](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) is a great place to start.

> Don't copy-paste the `$` signs, they indicate that what follows is a terminal command

### Terminal emulator

Linux and MacOS will have a terminal installed already. For Windows, it is recommended that you use `git-bash`, which you can install from [here](https://git-scm.com/download/win).

Type `echo Hi` in the terminal once it is installed. If installed correctly, you should see `Hi` appear when you hit enter.

### NodeJS

Installation instructions for NodeJS can be found [here](https://nodejs.org/en/download/package-manager/).

Run `node -v` in the terminal if `node` has been installed correctly:

```
$ node -v

```

### Docker

Installation instructions for Docker can be found [here](https://docs.docker.com/engine/install/).

Run `docker -v` in terminal to check if `docker` has been installed correctly:

```
$ docker -v
Docker version 20.10.9, build c2ea9bc90b
```

### Docker Compose

Installation instructions can be found [here](https://docs.docker.com/compose/install/).

Run `docker compose version` in the terminal to check if `docker compose` has been installed correctly:

```
$ docker compose version
Docker Compose version 2.0.1
```

## Installing the Registry CLI

To install the official Registry CLI, run:

```
```

>

To check if the Registry CLI has been installed correctly, run:

```
$ registry help
```

This should show you all the commands you can execute using the CLI.


# Setup A Registry Instance

#### Initialize registry

Now that you have the Registry CLI installed, we can create a new instance of a registry!

Run the following command in a directory where you wish to setup the registry. For this example, we will use `~/Registries/example/`. (`~` is short form for the user's home directory).

```bash
# Create and move into the ~/Registries/example directory
mkdir -p ~/Registries/example
cd ~/Registries/example
# Create a registry instance
registry init
```

This will present you with a set of questions to setup the registry. For the purpose of this getting started guide, you can hit enter and use the default values for the registry. Please follow the references below

* ***Registry Version***

<figure><img src="/files/HOElzK36J2TDplJwSqfi" alt=""><figcaption><p>registry version</p></figcaption></figure>

* ***Auxiliary Services***

The registry provides a set of auxiliary services that you can use in addition to the core registry. To select or deselect any of these services, use the ***SPACE BAR***.

Reference solutions for digital credentialing, including administration or issuance portals, are available in Auxiliary services.

<figure><img src="/files/w3JfD6dauY4R9GgJKoeh" alt=""><figcaption></figcaption></figure>

* ***Type of QR***

When VC Issuance is enabled, you'll be prompted to choose the type of QR code to generate on your certificates.

<figure><img src="/files/nwtUMrLmsOX1UQgGWk1O" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/rlgE9mD5p7mI5qPRgRYL" alt=""><figcaption><p>registry init - v1.0.0 </p></figcaption></figure>

#### Registry Status

Once the registry init is successfully initialized, the status of all the services can be checked using

```bash
registry status
```

The above command should return the status of all the services, like below

<figure><img src="/files/8UxqryYIEJ185sAfSmQL" alt=""><figcaption></figcaption></figure>

Make sure that the status of all the services is in the `running` state. If any of the services are in `exited` status you can restart only that particular service.

```bash
docker-compose restart <service-name>
```

To restart the registry use the below command

```sh
SCHEMA_DIR=config/schemas docker-compos up -d --force-recreate --no-deps registry
```

#### Registry Down

To stop the running services, you can use the below command

```
registry down
```

<figure><img src="/files/D0Txld13gT7SU7iUKfnP" alt=""><figcaption></figcaption></figure>


# Manual installation through docker-compose

The following steps will install SunbirdRC via docker compose file

## System requirements

* 4 Cores
* 8 GB RAM
* Min 100 GB disk

## Prerequisites

> This guide assumes a some familiarity with basic linux commands. If not, [here](https://ubuntu.com/tutorials/command-line-for-beginners#1-overview) is a great place to start.

> Don't copy-paste the `$` signs, they indicate that what follows is a terminal command

### Terminal emulator

Linux and MacOS will have a terminal installed already. For Windows, it is recommended that you use `git-bash`, which you can install from [here](https://git-scm.com/download/win).

Type `echo Hi` in the terminal once it is installed. If installed correctly, you should see `Hi` appear when you hit enter.

### Docker

Installation instructions for Docker can be found [here](https://docs.docker.com/engine/install/).

Run `docker -v` in terminal to check if `docker` has been installed correctly:

```
$ docker -v
Docker version 20.10.9, build c2ea9bc90b
```

### Docker Compose

Installation instructions can be found [here](https://docs.docker.com/compose/install/).

Run `docker compose version` in the terminal to check if `docker compose` has been installed correctly:

```
$ docker compose version
Docker Compose version 2.0.1
```

## Installation

* Download the latest docker-compose file <https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/docker-compose.yml>. Modify the values inside the compose file based on the requirements. More details on the configurations can be found [here](/v1.0.0/use/developers-guide/configuration).
* Download or create a `.env` file. <https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/.env>
* Add the below environment variables to `.env` file

| ENV              | Value   | Description                                                                                           |
| ---------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| RELEASE\_VERSION | v1.0.1  | Use the latest release version of SunbirdRC. <https://github.com/Sunbird-RC/sunbird-rc-core/releases> |
| SCHEMA\_DIR      | schemas | Relative path to the directory where schemas are created                                              |

* Create the [schema](/v1.0.0/use/developers-guide/schema-setup/introduction-to-schemas) files in the `schemas` directory
* Create a directory `imports`
* Download the [keycloak realm](https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/imports/realm-export.json) file in `imports` directory
* Download the [sample signing key](https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/imports/config.json) file in `imports` directory. Please note to update the signing keys before going to production.
* Steps to setup keycloak:

  * Start the database container

  `docker-compose up -d db`

  * Start the keycloak container

  `docker-compose up -d keycloak`

  * Open the keycloak admin console \`<http://localhost:8080/auth/>\`
  * Goto `Clients` -> `admin-api` -> `Credentials`
  * Click on `Regenerate Secret` and copy the new value
* Set `KEYCLOAK_SECRET` with the copied value in `.env` file
* Start all the services, `docker-compose up -d`
* Check if all the services are started using `docker-compose ps`
* Access the registry swagger json \`<http://localhost:8081/api/docs/swagger.json>\`\\


# Production setup through Helm

The below scripts will help the adopters to deploy SunbirdRC services in the Kubernetes environment.

## System requirements

Please note that the below numbers are only for reference, they will vary based on the business domain and scale.

1. Kubernetes cluster (any version above v1.26.3)
   * Master Node: 2 vCPU, 4 GB RAM, Disc Size: 50 GB, Nodes: 1
   * Worker Nodes: 4 vCPU, 8 GB RAM, Disc size: 100 GB, Nodes: 3
2. Bastion server: 2 vCPU, 4 GB RAM, Disc Size: 50GB
3. Postgres with a read replica: 4 vCPU 8 GB RAM, Disc Size: 100GB
4. ElasticSearch: 4 vCPU, 8 GB RAM, Disc Size: 100GB
5. API Gateway
6. Public domain
7. Server for Minio: 2 vCPU, 4 GB RAM, Disc Size: 100GB (Optional)
8. CDN / any other alternative for hosting UI

### Prerequisites

* Kubernetes Cluster with minimum 3 nodes
* [Helm](https://helm.sh/docs/intro/install/)
* kubectl
* Ingress (<https://kubernetes.github.io/ingress-nginx/deploy/>)
* Postgres DB (create a database for `keycloak` and `registry`)
* ElasticSearch (Optional)
* Kafka (Optional)
* Redis (Optional)
* Minio (Optional)
* Domain URL (domain url mapped to Kubernetes cluster)

The above optional services are not mandatory for SunbirdRC services. It can be installed based on the requirement of the project. For more details <https://docs.sunbirdrc.dev/learn/readme-1/high-level-architecture>

### Deployment steps

#### Clone the repo

```bash
git clone https://github.com/Sunbird-RC/sunbird-rc-core.git
cd infra
```

#### Pre-check

Make sure from the current directory you're able to run the below commands

```bash
kubectl cluster-info
kubectl get nodes
kubectl get ns
helm version
```

#### Create namespace

```bash
kubectl create ns demo-registry
```

***Feel free to use a different name for the namespace. Use the same name in the rest of the commands.***

#### Create secrets

Convert all the passwords/secrets into base64 format and update these values in `values.yaml` file

**Secrets**

* DB\_PASSWORD: Postgres database password
* KEYCLOAK\_ADMIN\_PASSWORD: Keycloak admin password used to login to admin console
* KEYCLOAK\_DEFAULT\_USER\_PASSWORD: Default password to be set for new users created by registry
* MINIO\_SECRET\_KEY: Minio secret key
* ELASTIC\_SEARCH\_PASSWORD: Elastic search connection password
* KEYCLOAK\_ADMIN\_CLIENT\_SECRET: Client secret of keycloak admin client for registry

`DB_PASSWORD, KEYCLOAK_ADMIN_PASSWORD and KEYCLOAK_DEFAULT_USER_PASSWORD are mandotry secrets to be set. Other secrets can be set to empty`

#### Modify configuration values

Configuration values like database address, elastic search address etc should be modified in `values.yaml` file.

#### Schemas

All schema files should be placed in the schemas directory located at `sunbird-rc-core/infra/helm_charts/charts/registry/schemas`.

#### Configure signing keys

The signing keys should be placed in the below directories

Both public and private keys for signing

`sunbird-rc-core/infra/helm_charts/charts/certificate-signer/keys`

Only public key for exposure to verifiers

`sunbird-rc-core/infra/helm_charts/charts/public-key-service/keys`

## Please note that by default a sample key is added. It is highly recommended to update this key before going to live.

#### Deploy helm charts

```bash
helm upgrade --install --namespace=demo-registry demo-registry helm_charts --create-namespace
```

**Output**

```
Release "demo-registry" does not exist. Installing it now.
NAME: demo-registry
LAST DEPLOYED: Thu May  4 17:02:08 2023
NAMESPACE: demo-registry
STATUS: deployed
REVISION: 1
```

**Check if all the pods are running**

```bash
kubectl get pods -n demo-registry
```

#### Import keycloak realm

* Goto keycloak admin console `<host>/auth/`
* Login with username `admin` and use the same password configured in secrets
* Click on `Master` and select `Add realm`
* Select `https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/imports/realm-export.json` file
* And click on `Create`

#### Configure keycloak secret

**Get the keycloak secret from the keycloak admin console**

* Goto keycloak admin console `<host>/auth/`
* Login with username `admin` and use the same password configured in the secrets
* Goto `clients` page and click on `admin-api`
* Goto `Credentials` tab and click on `Regenerate Secret`
* Copy the secret

**Configure secret in the registry**

* Get all secrets created

```bash
kubectl get secret -n demo-registry
```

* Encode the secret in base64 format

```bash
echo -n "secret copied from keycloak" | base64
```

* Open the secret in edit mode

```bash
kubectl edit secret rc-secret -n demo-registry
```

Replace empty string for `KEYCLOAK_ADMIN_CLIENT_SECRET` with the base64 encoded secret

* Restart registry

```bash
kubectl rollout restart deploy/demo-registry -n demo-registry
```

* Check the pods status

```bash
kubectl get pods -n demo-registry
```

#### Check registry APIs

Open the below url in the browser and check if you're able to get the swagger JSON `<host>/registry/api/docs/swagger.json`


# Developer's Guide


# Configurations

Registry provides following configuration properties

### **Registry Configurations**

| Properties                                       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **notification\_enabled**                        | boolean value which determines whether notification is to be sent or not                                                                                                                                                                                                                                                                                                                                                                                               |
| **notification\_url**                            | url which will be used to send notification url                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **notification\_async\_enabled**                 | to send out notifications in asynchronous manner                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **notification\_topic**                          | if notification\_async\_enabled is enabled, then kafka topic to which notification event will be sent                                                                                                                                                                                                                                                                                                                                                                  |
| **registry\_perRequest\_indexCreation\_enabled** | boolean value which determines if index needs to be created at database level                                                                                                                                                                                                                                                                                                                                                                                          |
| **external\_entities**                           | comma separated strings of external entities                                                                                                                                                                                                                                                                                                                                                                                                                           |
| **workflow\.enable**                             | boolean value to enable or disable the workflow i.e attestation policy                                                                                                                                                                                                                                                                                                                                                                                                 |
| **async\_enabled**                               | create entities asynchronously                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| **kafka\_create\_entity\_topic**                 | if async\_enabled, then this property defines the topic name to which new async requests are pushed                                                                                                                                                                                                                                                                                                                                                                    |
| **kafka\_post\_create\_entity\_topic**           | if async is enabled, then this property defines the topic name to which the response of create-entity is pushed                                                                                                                                                                                                                                                                                                                                                        |
| **search\_offset**                               | this is the default offset that will be used while searching,                                                                                                                                                                                                                                                                                                                                                                                                          |
| **search\_limit**                                | this is the default limit that will be used or the max value that can be used to as a limit in the search                                                                                                                                                                                                                                                                                                                                                              |
| **search\_expandInternal**                       | boolean value, if set true, all the search results will be expanded to include internal objects.                                                                                                                                                                                                                                                                                                                                                                       |
| **database\_provider**                           | this property states which database is to be used. Providers available are NEO4J, SQLG, CASSANDRA, ORIENTDB, TINKERGRAPH (in-memory)                                                                                                                                                                                                                                                                                                                                   |
| **connectionInfo\_uri**                          | url to connect to database. eg Postgres - jdbc:postgresql://localhost:5432/yourdb                                                                                                                                                                                                                                                                                                                                                                                      |
| **connectionInfo\_username**                     | username to be used to connect to database                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **connectionInfo\_password**                     | password to be used to connect to database                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **connectionInfo\_maxPoolSize**                  | Database connection pool size                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| **verify\_url**                                  | this url will be used to verify the issued VC. point it to {certification\_signer}/verify                                                                                                                                                                                                                                                                                                                                                                              |
| **certificate\_health\_check\_url**              | certificate api service's health check url                                                                                                                                                                                                                                                                                                                                                                                                                             |
| **template\_folder\_path**                       | path from which default template will be loaded if no external template is provided. File name should be the **`name_of_schema.appropriate_extention`** The location should be in resources folder                                                                                                                                                                                                                                                                     |
| **audit\_enabled**                               | This audit configuration will enable audit logging in the system                                                                                                                                                                                                                                                                                                                                                                                                       |
| **audit\_frame\_store**                          | <p>FILE : Store the audit log in files.<br>DATABASE : Store the audit log in the primary database configured and in elastic search if it's enabled</p>                                                                                                                                                                                                                                                                                                                 |
| **audit\_suffix**                                | suffix which is used for schema name to store audit information for a particular entity type                                                                                                                                                                                                                                                                                                                                                                           |
| **audit\_suffixSeparator**                       | separator between entity name and audit\_suffix                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **validation\_enabled**                          | boolean property to check for request body to be validated in specific format                                                                                                                                                                                                                                                                                                                                                                                          |
| **validation\_type**                             | type in which request body needs to be validated. eg JSON                                                                                                                                                                                                                                                                                                                                                                                                              |
| **service\_connection\_timeout**                 | Set the connection timeout in milliseconds for the underlying request configuration                                                                                                                                                                                                                                                                                                                                                                                    |
| **service\_connection\_request\_timeout**        | Set the timeout in milliseconds used when requesting a connection from the connection manager using the underlying request Configuration                                                                                                                                                                                                                                                                                                                               |
| **service\_read\_timeout**                       | Set the socket read timeout in milliseconds for the underlying request configuration                                                                                                                                                                                                                                                                                                                                                                                   |
| **http\_max\_connections**                       | maximum http connections                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| **taskExecutor\_index\_threadPoolName**          | Specify the prefix to use for the names of newly created threads.                                                                                                                                                                                                                                                                                                                                                                                                      |
| **taskExecutor\_index\_corePoolSize**            | Set the ThreadPoolExecutor's core pool size.                                                                                                                                                                                                                                                                                                                                                                                                                           |
| **taskExecutor\_index\_maxPoolSize**             | Set the ThreadPoolExecutor's maximum pool size.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **taskExecutor\_index\_queueCapacity**           | Set the capacity for the ThreadPoolExecutor's BlockingQueue.                                                                                                                                                                                                                                                                                                                                                                                                           |
| **auditTaskExecutor\_threadPoolName**            | Specify the prefix to use for the names of newly created threads.                                                                                                                                                                                                                                                                                                                                                                                                      |
| **auditTaskExecutor\_corePoolSize**              | Set the ThreadPoolExecutor's core pool size.                                                                                                                                                                                                                                                                                                                                                                                                                           |
| **auditTaskExecutor\_maxPoolSize**               | Set the ThreadPoolExecutor's maximum pool size.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **auditTaskExecutor\_queueCapacity**             | Set the capacity for the ThreadPoolExecutor's BlockingQueue.                                                                                                                                                                                                                                                                                                                                                                                                           |
| **elastic\_search\_connection\_url**             | url for elastic search connection if elastic search is enabled. Elastic search is enabled using search\_providerName                                                                                                                                                                                                                                                                                                                                                   |
| **search\_providerName**                         | <p>The search mechanism to use. Values could be either NativeSearchService or ElasticSearchService. If NativeSearchService, then every search API uses the same database as the writes. May not offer high speed reads. This is the default search service, if this config is not provided. If ElasticSearchService, then Elastic search is used.<br>Ex: (dev.sunbirdrc.registry.service.ElasticSearchService, dev.sunbirdrc.registry.service.NativeSearchService)</p> |
| **sunbird\_sso\_realm**                          | identity provider realm name to be used for authentication and authorization                                                                                                                                                                                                                                                                                                                                                                                           |
| **sunbird\_sso\_url**                            | identity provider connection url                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **sunbird\_sso\_admin\_client\_id**              | client id to be used as admin                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| **sunbird\_sso\_admin\_client\_secret**          | secret key of keycloak admin client set by using sunbird\_sso\_admin\_client\_id                                                                                                                                                                                                                                                                                                                                                                                       |
| **sunbird\_keycloak\_user\_set\_password**       | boolean value to default password for user/owner of entity in identity provider                                                                                                                                                                                                                                                                                                                                                                                        |
| **sunbird\_keycloak\_user\_password**            | if sunbird\_keycloak\_user\_set\_password is set to true, provide this value to set this as default user password                                                                                                                                                                                                                                                                                                                                                      |
| **identity\_user\_actions**                      | actions which will be trigger by identity provider example email actions: VERIFY\_EMAIL, UPDATE\_PROFILE, UPDATE\_PASSWORD,TERMS\_AND\_CONDITIONS etc. email details should be configured in identity provider realm settings                                                                                                                                                                                                                                          |
| **identity\_provider**                           | <p>name of the implementation of identity provider. below are the implemented identity providers in registry - </p><p><code>dev.sunbirdrc.auth.auth0.Auth0ProviderImpl</code> <code>dev.sunbirdrc.auth.genericiam.AuthProviderImpl</code></p><p><code>dev.sunbirdrc.auth.keycloak.KeycloakProviderImpl</code></p>                                                                                                                                                      |
| **oauth2\_resource\_uri**                        | identity provider resource url. i.e. <http://keycloak:8080/auth/realms/sunbird-rc>                                                                                                                                                                                                                                                                                                                                                                                     |
| **oauth2\_resource\_email\_path**                | email path in identity provider resource (jwt token). i.e. email                                                                                                                                                                                                                                                                                                                                                                                                       |
| **oauth2\_resource\_consent\_path**              | consent path in identity provider resource. i.e. consent                                                                                                                                                                                                                                                                                                                                                                                                               |
| **oauth2\_resource\_roles\_path**                | roles path in identity provider resource. i.e. realm\_access.roles                                                                                                                                                                                                                                                                                                                                                                                                     |
| **oauth2\_resource\_entity\_path**               | entity path in identity provider resource. i.e. entity                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **oauth2\_resource\_user\_id\_path**             | user id path in identity provider resource. i.e. sub                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **claims\_enabled**                              | default `false`. boolean value which determines whether attestation is to be done                                                                                                                                                                                                                                                                                                                                                                                      |
| **claims\_url**                                  | url in order to connect to claims service                                                                                                                                                                                                                                                                                                                                                                                                                              |
| **signature\_enabled**                           | boolean value which determines whether signature is to be created for a document                                                                                                                                                                                                                                                                                                                                                                                       |
| **sign\_url**                                    | url in order to connect to certificate signer to sign the document                                                                                                                                                                                                                                                                                                                                                                                                     |
| **sign\_health\_check\_url**                     | certificate signer health check url                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| **certificate\_enabled**                         | default `false`. boolean value which determines whether certificate is to be generated                                                                                                                                                                                                                                                                                                                                                                                 |
| **pdf\_url**                                     | url to fetch certificate from certificate api service                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **certificate\_health\_check\_url**              | certificate api health check url                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **template\_base\_url**                          | api endpoint to get default templates stored in sunbird-rc                                                                                                                                                                                                                                                                                                                                                                                                             |
| **filestorage\_enabled**                         | default `false`. boolean value which determines whether documents are to be stored                                                                                                                                                                                                                                                                                                                                                                                     |
| **filestorage\_connection\_url**                 | minio connection url to store files                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| **filestorage\_access\_key**                     | access key of minio                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| **filestorage\_secret\_key**                     | secret key of minio                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| **filestorage\_bucket\_key**                     | bucket name where to store the files in minio                                                                                                                                                                                                                                                                                                                                                                                                                          |
| **registry\_base\_apis\_enable**                 | if enabled the exisitng /add /update apis will be enabled. This is to enable backward compatibility                                                                                                                                                                                                                                                                                                                                                                    |
| **logging.level.root**                           | <p>The log level that will be used for logging. Default logging is INFO.<br>Values supported:<br>INFO<br>DEBUG<br>WARN<br>ERROR</p>                                                                                                                                                                                                                                                                                                                                    |
| **enable\_external\_templates**                  | boolean value which when set to true, one can retrieve the certificate pdf using external templates                                                                                                                                                                                                                                                                                                                                                                    |
| **authentication\_enabled**                      | boolean value to enable authentication in the system                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **kafka\_bootstrap\_address**                    | url for kafka connection                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| **webhook\_enabled**                             | boolean value to enable webhook if async\_enabled is true                                                                                                                                                                                                                                                                                                                                                                                                              |
| **webhook\_url**                                 | if async\_enabled and webhook\_enabled is set to true, the caller can retrieve information of the created entity once it is generated via this webhook url                                                                                                                                                                                                                                                                                                             |
| **redis\_host**                                  | redis connection url                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **redis\_port**                                  | port on which redis is running                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| **manager\_type**                                | if using a single instance of registry, set this value to DefinitionsManager else set to DistributedDefinitionsManager                                                                                                                                                                                                                                                                                                                                                 |
| **service\_retry\_maxAttempts**                  | The number of times an attempt must be made to reach to the service                                                                                                                                                                                                                                                                                                                                                                                                    |
| **service\_retry\_backoff\_delay**               | The fixed time interval, in milliseconds, between each such attempt.                                                                                                                                                                                                                                                                                                                                                                                                   |
| **event\_enabled**                               | boolean value that indicates whether events should be emitted or not. if enabled, registry will start emitting events                                                                                                                                                                                                                                                                                                                                                  |
| **event\_topic**                                 | kafka topic name to which events will be emitted                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **event\_providerName**                          | name of provider to be used for emitting events. For eg: if Kafka is used, the value should be `dev.sunbirdrc.registry.service.impl.KafkaEventService`. If file is to be used to store events the value should be \``dev.sunbirdrc.registry.service.impl.FileEventService.java`\`                                                                                                                                                                                      |
| **encryption\_enabled**                          | <p>default <code>false</code>. boolean value which determines whether to enable encryption to store private fields.<br><br><em>Note: External encryption service is required to encrypt/decrypt</em><br></p>                                                                                                                                                                                                                                                           |
| **encryption\_health\_check\_url**               | encryption service health check endpoint                                                                                                                                                                                                                                                                                                                                                                                                                               |
| **encryption\_uri**                              | encryption service encrypt api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                                |
| **encryption\_batch\_uri**                       | encryption service batch encrypt api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                          |
| **decryption\_uri**                              | encryption service decrypt api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                                |
| **decryption\_batch\_uri**                       | encryption service batch decrypt api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                          |
| **encryption\_method**                           | `Normal`/`Imp` or keys from map value provided in encryption service property `type.to.method.map`                                                                                                                                                                                                                                                                                                                                                                     |
| **encryption\_tenant\_id**                       | tenant id to use for encryption                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **idgen\_enabled**                               | `boolean` to enable/disable idgen feature                                                                                                                                                                                                                                                                                                                                                                                                                              |
| **idgen\_tenant\_id**                            | tenant id to use for id generation                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| **idgen\_health\_check\_url**                    | idgen service health check api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                                |
| **idgen\_generate\_url**                         | idgen service id generate api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| **idgen\_id\_format\_url**                       | idgen service id format api endpoint                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| **swagger\_enabled**                             | default `true`. boolean value to enable/disable swagger apis                                                                                                                                                                                                                                                                                                                                                                                                           |
| **swagger\_title**                               | to set custom title for swagger to be generated                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **swagger\_description**                         | to set custom description for swagger to be generated                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **swagger\_version**                             | to set a custom version for swagger                                                                                                                                                                                                                                                                                                                                                                                                                                    |

### Claims Service

| Properties         | Description                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------------------------------------- |
| **sunbirdrc\_url** | used by claim service to communicate with sunbirdrc. url which corresponds to registry deployed host and port |

### Certificate Api service

<table><thead><tr><th>Properties</th><th>Description</th><th data-hidden></th><th data-hidden></th></tr></thead><tbody><tr><td><strong>CUSTOM_TEMPLATE_DELIMITERS</strong></td><td>Delimeters to be used to parse credential/certificate template. By default <code>{{,}}</code></td><td></td><td></td></tr><tr><td><strong>QR_TYPE</strong></td><td>Types of QR codes that sunbird supports<br>1. W3C-VC<br>2. URL-W3C-VC (if VC needs to be sent as a URL)<br>3. URL (If only a URL needs to be part of the QR. The URL will only contain the entity name and osid.</td><td></td><td></td></tr><tr><td><strong>CERTIFICATE_DOMAIN_URL</strong></td><td>Base URL to be used when <code>QR_TYPE</code> is URL*</td><td></td><td></td></tr></tbody></table>

### Certificate signer service

<table><thead><tr><th>Properties</th><th>Description</th><th data-hidden></th></tr></thead><tbody><tr><td><strong>CACHE_CONTEXT_URLS</strong></td><td>Predefine a set of context urls to be cached to avoid runtime network access.</td><td></td></tr><tr><td><strong>CONFIG_BASE_PATH</strong></td><td>path to config.json file where all the signing keys are stored</td><td></td></tr><tr><td><strong>CUSTOM_TEMPLATE_DELIMITERS</strong></td><td>Delimeters to be used to parse credential/certificate template. By default <code>{{,}}</code></td><td></td></tr></tbody></table>

### Notification Service

| Properties                    | Description                                                            |
| ----------------------------- | ---------------------------------------------------------------------- |
| **KAFKA\_BOOTSTRAP\_SERVERS** | Kafka bootstrap servers (ex: host:port)                                |
| **SMS\_AUTH\_KEY**            | api url to send sms to provided mobile numbers                         |
| **SMS\_AUTH\_KEY**            | authorization key for sms api url                                      |
| **ENABLE\_SMS**               | flag to enable sending sms using sms api                               |
| **TRACK\_NOTIFICATIONS**      | boolean value to track all sent notifications and fetch them if needed |

### Metrics Service

| Properties                    | Description                                                                |
| ----------------------------- | -------------------------------------------------------------------------- |
| **CLICK\_HOUSE\_URL**         | clickhouse database url along with port on which clickhouse is hosted      |
| **CLICKHOUSE\_DATABASE**      | database name where the events will be stored                              |
| **KAFKA\_BOOTSTRAP\_SERVERS** | url along with port number on which kafka is running                       |
| **KAFKA\_METRICS\_TOPIC**     | topic name to which registry produces events                               |
| **DATABASE\_PROVIDER\_NAME**  | type of database being used. eg clickhouse                                 |
| **REDIS\_URL**                | url where redis is hosted                                                  |
| **CRON\_ENABLE**              | boolean value which will run the cron job and save the aggregates to redis |
| **SCHEDULE\_INTERVAL**        | days interval after which you want to run cron job to compute aggregates   |
| **SCHEDULE\_TIME**            | time at which you want to run cron job to compute aggregates               |

### Bulk Issuance

| Properties            | Description                              |
| --------------------- | ---------------------------------------- |
| REGISTRY\_BASE\_URL   | url on which registry is hosted          |
| DATABASE\_HOST        | host address of database                 |
| DATABASE\_PORT        | port on which database is running        |
| DATABASE\_USER        | username of database                     |
| DATABASE\_PASSWORD    | password for that user of the database   |
| DATABASE\_NAME        | database name                            |
| KEYCLOAK\_PUBLIC\_KEY | public key from keycloak                 |
| KEYCLOAK\_URL         | url for keycloak                         |
| KEYCLOAK\_REALM       | keycloak realm name                      |
| ROLES                 | roles which are allowed to issue in bulk |

### Digilocker Certificate API

| Properties                  | Description                                                                                                                                         |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| DIGILOCKER\_HMAC\_AUTHKEY   | A random generated string. This will be used to verify the HMAC from request and HMAC from the request body. This is the API Key of Digilocker      |
| DIGILOCKER\_AUTH\_KEYNAME   | Needed to fetch HMAC From Request. Its default value is `x-digilocker-hmac`                                                                         |
| DIGILOCKER\_DOC\_ID\_PREFIX | Document prefix which needs to be sent it in response in order to map it to correct document in digilocker. This is different for different issuers |
| KEYCLOAK\_TOKEN\_URL        | Keycloak connection url                                                                                                                             |
| KEYCLOAK\_CLIENT\_SECRET    | secret key of keycloak admin client set by using sunbird\_sso\_admin\_client\_id                                                                    |
| KEYCLOAK\_CLIENT\_ID        | client id to be used as admin                                                                                                                       |
| REGISTRY\_URL               | Registry url                                                                                                                                        |

### Encryption Service

To enable the encryption/decryption feature in registry set the environment variable in .env file `ENCRYPTION_ENABLED=true`

| Properties                        | Description                                                                                                                                                                                                                          |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| server.port                       | port on which encryption should run                                                                                                                                                                                                  |
| server.servlet.context-path       | context path for encryption to run on                                                                                                                                                                                                |
| spring.datasource.url             | url to connect to database. eg Postgres - jdbc:postgresql://localhost:5432/yourdb                                                                                                                                                    |
| spring.flyway.url                 | url to connect to database. eg Postgres - jdbc:postgresql://localhost:5432/yourdb                                                                                                                                                    |
| spring.flyway.baseline-on-migrate | boolean, to handle migration scripts versioning                                                                                                                                                                                      |
| egov.mdms.provider                | <p>implemented class to provide master data. It has two classes implemented.<br><code>org.egov.enc.masterdata.provider.DBMasterDataProvider</code><br><code>org.egov.enc.masterdata.provider.WebServiceMasterDataProvider</code></p> |

### ID Gen Service

To enable Id generation feature\
1\. Add environment variable in .env file `IDGEN_ENABLED=true`\
2\. Follow documentation for [unique identifier fields](/v1.0.0/use/developers-guide/schema-setup/schema-configuration#uniqueidentifierfields) in Schema Configuration to configure the schema

| Properties                        | Description                                                                                                                                                                                                                        |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| spring.datasource.url             | url to connect to database. eg Postgres - jdbc:postgresql://localhost:5432/yourdb                                                                                                                                                  |
| spring.flyway.baseline-on-migrate | boolean, to migration scripts versioning                                                                                                                                                                                           |
| autocreate.new\.seq               | boolean, set true to auto create sequences provided in schema configurations property `uniqueIdentifierFields`                                                                                                                     |
| idformat.from.mdms                | booean, set true to fetch id format from mdms                                                                                                                                                                                      |
| egov.mdms.provider                | <p>implemented class to provide master data. It has two classes implemented.<br><code>org.egov.id.masterdata.provider.DBMasterDataProvider</code><br><code>org.egov.id.masterdata.provider.WebServiceMasterDataProvider</code></p> |


# Frontend Configurations

Registry provides following configuration properties

Go to **config.json** file and update the value of of key as with your application details

```javascript
{
   "keycloak": {      // Add your keycloak configurations here
   "url": "domainUrl/auth",
   "clientId": "registry-frontend",
   "realm": "sunbird-rc"
   },
   "configFolder": "/assets/config/ui-config",
   "languageFolder": "/assets/i18n",
   "title": "Application name",  // Here you can change Application name
   "baseUrl": "domainUrl/registry/api/v1", // Replace with your API URL
   "domainName" : "https://demo-url.xiv.in", //Replace with Site Domain
   "schemaUrl": "domainUrl/registry/api/docs/swagger.json", // Replace with your schema api(swagger) url
   "footerText": "Organ donation registry", // Change Footer text
   "languages": [
   "en"   
   ],
   "appType": "attestation",
   "default_theme": {  // Here you can change theme  color and site logo
         "logoPath": "../../assets/images/logo.svg",
          - - - 
          - - - 
      }

```

* **Keycloak** : Add your keycloak configurations in this object
* **baseUrl**: Set the Api base url to this property
* **domainName** : Add your domain name to this property
* **schemaUrl** : Set the swagger api url to this property
* **footerText** : You can set footer label here
* **Languages** : If you wants to add multilingual support on your site, you need to add language code in this language property and also need to create respective files in [src](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src)/[assets](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src/assets)/[i18n](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src/assets/i18n)/global/ and [src](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src)/[assets](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src/assets)/[i18n](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src/assets/i18n)/[local](https://github.com/Sunbird-RC/demo-donor-registry/tree/main/donor-registry/src/assets/i18n/local)/ folder with specific language translations
* **Default\_theme** - In this object you can change your site color, logo etc


# Frontend - Proxy configuration

This setting is required when you want to run an application in a local environment.

To run an application in a local environment and avoid CORS issues, you can set up a proxy configuration. CORS (Cross-Origin Resource Sharing) is a security mechanism enforced by web browsers that restricts cross-origin requests. By configuring a proxy, you can bypass CORS restrictions during development.

Here are the steps to add a proxy configuration in your project:

1. Check if there is a `proxy.conf.json` file in the root folder . If the file doesn't exist, create a new file with that name.
2. Open the `proxy.conf.json` file and add the proxy configuration for your API endpoints. The configuration should be in the following format:

```json
{
  "/registry/api/docs": {
    "target": "https://domain_name/",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug"
  }
}
```

To run an application in a local environment and avoid CORS issues, you can set up a proxy configuration. CORS (Cross-Origin Resource Sharing) is a security mechanism enforced by web browsers that restricts cross-origin requests. By configuring a proxy, you can bypass CORS restrictions during development.

Here are the steps to add a proxy configuration in your project:

1. Check if there is a `proxy.conf.json` file in the root folder . If the file doesn't exist, create a new file with that name.
2. Open the `proxy.conf.json` file and add the proxy configuration for your API endpoints. The configuration should be in the following format:

```json
{
  "/registry/api/docs": {
    "target": "https://domain_name/",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug"
  }
}


```

* Replace `"/registry/api/docs"` with your API path.
* Set the `"target"` value to the domain name where your APIs are hosted.
* Set `"secure"` to `true` if your domain has SSL (HTTPS), or `false` if it doesn't.
* Set `"changeOrigin"` to `true` if your backend is not hosted on the localhost server.
* `"logLevel"` is used to check whether a proxy is working or not. Proxy log levels are info (the default), debug, warn, error, and silent.

3. In the `config.json` file, update the values of the `baseUrl` and `schemaUrl` properties with `http://localhost:4200/`.

```json
{
  "environment": "development",
  "keycloak": {
    "url": "https://demo-registry.xiv.in/auth",
    "clientId": "registry-frontend",
    "realm": "sunbirdrc-frontend"
  },
  "configFolder": "/assets/config/ui-config",
  "languageFolder": "/assets/i18n",
  "title": "Application name",
  "baseUrl": "http://localhost:4200/registry/api/v1",
  "schemaUrl": "http://localhost:4200/registry/api/docs/swagger.json",
  "footerText": "Organ donation registry",
    "domainName": "https://demo-url-registry.xiv.in",
  "languages": [
    "en"
  ]
}

```

4. Run the following command to start the application:

```sh
npm start
```


# Audit Configuration

The following document describes about how audit on registry schema can be enabled

Sunbird-RC enables audit logging of the schemas. Any operation like ADD/READ/UPDATE/DELETE/SEARCH on the schema will be added to the audit log.

Currently, Sunbird-RC supports two types of audit logging:

1. FILE\
   In file-based audit, the logs are appended to a log file which is present at `audit_logs/audit.log`. The log also has a rolling policy based on the size (30MB).
2. DATABASE\
   In database audit, the logs are added to the database and also to elastic search if it's enabled at the registry level. To store the audit logs in the database an audit schema needs to be created. The sample schema for the audit logs should be as per <https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/java/registry/src/main/resources/raw_audit_schema.json>. The audit schema should be placed in the schema's directory configured for the registry.


# Notifications Configuration

### Registry

Sunbird RC Provides a way to send out notifications to the owner of the entity. Whenever the entity under a particular schema is Invited/Created/Modified/Deleted/Revoked, the notifications can be sent out to owner of that entity.

The schema should be configured with the notification templates. [Here](/v1.0.0/use/developers-guide/schema-setup/schema-configuration#notification-templates) is the way to configure the schema to send out notifications. The configuration shows an example for create notification templates which will be sent on creating an entity. Following are the other type of operations that are supported by Sunbird RC to send out notifications

1. update for Updating entity
2. invite for Inviting an Entity
3. delete for Deleting an Entity
4. revoke for Revoking an Entity

This notification template is configured for One97 Messaging API. Sunbird RC can send out multiple notifications too. Here if you see, create key's value is a list of json objects, where each object represents one notification template. This list can have multiple such templates

Sunbird RC supports sending out notifications for email and sms both. subject is sent only for email content and body is required for both the ways.

There are two ways that Sunbird RC sends out notification

1. Asynchronous - Via Kafka
2. Synchronous - Via APIs

Registry can be configured to send notifications either by Kafka or through APIs. Refer to this [link](/v1.0.0/use/developers-guide/configuration#registry-configurations)

**Asynchronous -**

Registry creates a kafka message in the required format and puts that in the configured topic of messaging queue. Then, notification service, consumer of the topic, reads this message and then sents out notification to the phone number or the email address or both that is sent along with this kafka message

**Synchronous -**

Registry calls an API to the Notification Service. The controller in notification service then handles this request and sends out notification to the phone number or the email address or both that is sent in the request body.

### **Notification Service**

Notification service is the service responsible to send out notifications. The service expects configuration of SMS, SMTP Gateway and sends out notifications to the phone number or email address that it receives through kafka message or API request.

Here is the [link](/v1.0.0/use/developers-guide/configuration#notification-service) for configuration of notification service


# View Templates Configuration

Sunbird RC provides a functionality to transform the entity response body with different transformation templates

In SunbirdRC we can configure view templates (JSON transformers) which can be applied during runtime. It supports enabling/disabling properties in JSON responses. It also provides executing simple [JEXL](https://commons.apache.org/proper/commons-jexl/) expressions and also supports creating custom provider functions.

Below is an example of a view template:

```json
{
  "id": "personDefaultView1",
  "subject": "Person",
  "fields": [
    {
      "name": "firstName",
      "title": "NAME"
    },
    {
      "name": "lastName",
      "display": true
    },
    {
      "name": "nationalIdentifier",
      "title": "OS number",
      "display": false,
      "$comment": "This field is not displayable, but needed for internal referencing"
    },
    {
      "title": "Name in passport",
      "function": "#/functionDefinitions/concat($lastName, $firstName)",
      "$comment": "This is a virtual field not defined in the schema"
    },
    {
      "title": "Name as in DL",
      "function": "#/functionDefinitions/userDefinedConcat($firstName, $lastName)",
      "$comment": "This is a virtual field not defined in the schema"
    }
  ],
  "functionDefinitions": [
    {
      "name" : "concat",
      "result": "arg1 + \", \" + arg2",
      "$comment": "arg1 and arg2 will be populated with parameter values at runtime"
    },
    {
      "name" : "userDefinedConcat",
      "provider": "dev.sunbirdrc.provider.SampleViewFunctionProvider",
      "$comment" : "Complex operations that cannot be expressed easily in an in-line function definition can be implemented as a class. "
    }
  ]
}
```

When the above template is applied for the below response payload:

```json
{
  "Person": {
    "nationalIdentifier": "nid823",
    "firstName": "Ram",
    "lastName": "Moorthy",
    "gender": "MALE",
    "dob": "1990-12-10"
  }
}
```

The response will be transformed to:

```json
{
  "Person": {
    "NAME": "Ram",
    "lastName": "Moorthy",
    "Name in passport": "Moorthy, Ram",
    "Name as in DL": "Ram : Moorthy"
  }
}
```

The view templates support configuring what fields should be displayed, changing the field names, and also performing functionalities on top of the fields.

In the above template, a field called `firstName` which is present in the entity is been renamed to `NAME.`

```json
{
      "name": "firstName",
      "title": "NAME"
}
```

By default, all fields defined in the template are treated to be `"display": true`. If the fields are not supposed to be displayed then we can set `"display": false`

```json
{
      "name": "nationalIdentifier",
      "title": "OS number",
      "display": false,
      "$comment": "This field is not displayable, but needed for internal referencing"
}
```

We can also define expressions or custom functions to perform complex/custom transformations.

```json
{
      "name" : "concat",
      "result": "arg1 + \", \" + arg2",
      "$comment": "arg1 and arg2 will be populated with parameter values at runtime"
},
```

In the above example, a custom JEXL expression to concatenate two fields is inline defined in the view template.

```json
{
      "title": "Name in passport",
      "function": "#/functionDefinitions/concat($lastName, $firstName)",
      "$comment": "This is a virtual field not defined in the schema"
},
```

The above code illustrates on how to call the inline-defined functions for a specific field.

We can also write Java code which can be used to perform custom/complex operations and also execute that in the view template.

```json
{
      "name" : "userDefinedConcat",
      "provider": "dev.sunbirdrc.provider.SampleViewFunctionProvider",
      "$comment" : "Complex operations that cannot be expressed easily in an in-line function definition can be implemented as a class. "
}
```

The implementation of the above provider is here, <https://github.com/Sunbird-RC/sunbird-rc-core/blob/3dcca8a7ca6be355991808a0d1ebfc3a824c43c5/java/view-templates/src/main/java/dev/sunbirdrc/provider/SampleViewFunctionProvider.java>

A custom provider function should implement `IViewFunctionProvider`

Similarly, SunbirdRC is shipped with another provider functions that can be used for transformation,\
[RemovePathFunctionProvider](https://github.com/Sunbird-RC/sunbird-rc-core/blob/3dcca8a7ca6be355991808a0d1ebfc3a824c43c5/java/view-templates/src/main/java/dev/sunbirdrc/provider/RemovePathFunctionProvider.java)\
The above provider function will remove JSON paths from a nested object.\
Example to demonstrate how to use the above function,

```json
{
  "subject": "Reporter",
  "fields": [
    {
      "name": "name",
      "title": "name",
      "display": true
    },
    {
      "name": "address",
      "title": "address",
      "function": "#/functionDefinitions/removePath($address, $.line)",
      "display": true
    }
  ],
  "functionDefinitions": [
    {
      "name" : "removePath",
      "provider": "dev.sunbirdrc.provider.RemovePathFunctionProvider"
    }
  ]
}
```

The above template will transform the below response payload

```json
{
  "Person": {
    "nationalIdentifier": "nid823",
    "name": "Ram",
    "lastName": "Moorthy",
    "gender": "MALE",
    "dob": "1990-12-10",
    "address": {
      "line": "1st stree",
      "city": "bangalore"
    }
  }
}
```

to the below format

```json
{
  "Person": {
    "name": "Ram",
    "address": {
      "city": "bangalore"
    }
  }
}
```

The view templates can be applied to both the GET APIs. We need to pass a `viewTemplateId` the header which contains the value of the view template file to be applied.

{% content-ref url="/pages/IQtWkmPtyIiURZjzIncX" %}
[Get An Entity](/v1.0.0/api-reference/registry/get-an-entity)
{% endcontent-ref %}

{% content-ref url="/pages/WZeZc5g6OYgF5GMA6s6p" %}
[Get An Entity By Id](/v1.0.0/api-reference/registry/get-an-entity-by-id)
{% endcontent-ref %}

Example:

```powershell
curl --location 'localhost:8081/api/v1/StudentWithPassword/1-2ee0c034-0a81-4c7f-a971-058af35911cb' \
--header 'viewTemplateId: student_view_template.json' \
```

View templates can be used in search/discovery APIs. The respective template id needs to be part of the request body as below

```json
{
    "filters": {

    },
    "viewTemplateId": "student_view_template.json"
}
```

{% content-ref url="/pages/EZ7pbjtpHsVx6B20OfQs" %}
[Search An Entity](/v1.0.0/api-reference/discovery-api/search-an-entity)
{% endcontent-ref %}


# Schema Setup


# Introduction To Schemas

Each registry can store data as entities. The example registry we setup using CLI already has two types of entities: `Teacher` and `Student`. To view the schemas, run the following in the directory you setup the registry:

```
$ cat config/schemas/student.json
$ cat config/schemas/teacher.json
```

> Or you could view the schemas [on Github](https://github.com/sunbird-rc/sunbird-rc-core/tree/main/tools/cli/src/templates/config/schemas).

A teacher is represented by 5 fields: `name`, `phoneNumber`, `email`, `subject` and `school`, out of which `name`, `phoneNumber`, `email` and `school` are required fields. `subject` can be any one of Math, Hindi, English, History, Geography, Physics, Chemistry, and Biology.

A student is represented by 4 fields: `name`, `phoneNumber`, `email`, and `school`, all of which are required fields. When setting `school` field, you are making a 'claim' (i.e., that the student is from the specified school), which can be 'attested' (i.e., confirmed to be true) by a teacher from the same school.


# Creating Your Own Schemas

Each registry can store data as entities. An entity is defined by its schema. This guide demonstrates how to create a schema to define your own entity.

The following is an example schema for a student entity. The comments should guide you as to which fields are required, and what fields should be adjusted as per your needs.

> Note: Schema files cannot contain comments. The following example has been commented for your understanding only.

```json
{
	// This must be at the top of all schemas. See http://json-schema.org/understanding-json-schema/reference/schema.html#schema
	"$schema": "http://json-schema.org/draft-07/schema",
	// This is a schema object...
	"type": "object",
	// ...that declares a Student entity
	"properties": { "Student": { "$ref": "#/definitions/Student" } },
	// The actual definition of the Student entity
	"definitions": {
		// You can declare multiple entities in one schema file, just make sure you
		// add the entity name in the `properties` field above
		"Student": {
			// The path to the declaration in the schema entity
			"$id": "#/properties/Student",
			// A Student is an object...
			"type": "object",
			// ...with the following required fields
			"required": ["name", "phoneNumber", "email", "school"],
			// The `phoneNumber` field must be unique across all Student entities
			"uniqueIndexFields": ["phoneNumber"],
			// The fields a Student entity can have
			"properties": {
				// Full name (string)
				"name": { "type": "string" },
				// Phone number (string)
				"phoneNumber": { "type": "string" },
				// Email (string)
				"email": { "type": "string" },
				// What school they are going to (string)
				"school": { "type": "string" }
				// The password for the Student entity (string)
				"passwordToken": { "type": "string" }
			}
		}
	},
	// Sunbird-RC specific configuration
	"_osConfig": {
        // The following property is used as an access modifier. The fields mentioned 
        // here are accessible by the owner of the entity and other users via consent.  
        // By default all fields are public.
        "privateFields": ["$.phoneNumber"],
        // The following property is used as an access modifier. The fields mentioned 
        // here are accessible only by the owner of the entity.
        // By default all fields are public.
        "internalFields": ["$.school"],
        // The following property is used to add additional audit fields to entity, to know
        // who/when created/updated the entity. 
        "systemFields": [
        "osCreatedAt",
        "osUpdatedAt",
        "osCreatedBy",
        "osUpdatedBy"
        ],
        // The following field is used to define the role who will be allowed to use the POST /api/v1/<Schema> API
        // to create the entity. The role will be validated with jwt token passed with the API.
        // If API does not require any role validation, then it can be set to anonymous
        "roles": ["admin"],
        // The following field is used to define the role who will be allowed to use the POST /api/v1/<Schema>/invite API
        // to invite the entity. The role will be validated with jwt token passed with the API.
        // If API does not require any role validation, then it can be set to anonymous
        "inviteRoles": ["admin"],
      
        // The following field is only needed if the entity is a human that can
        // login, grant consent, and manually attest claims. It will (usually) not
        // be needed for something like a book or toy entity.
        // The following fields are used to create a corresponding user in Keycloak,
        // the authentication service used by Sunbird RC.
      
        "ownershipAttributes": [
            {
                // The path to the field to consider the email of the entity
                "email": "/email",
                // The path to the field to consider the phone number of the entity
                "mobile": "/phoneNumber",
                // The path to the field to consider as unique ID of the entity
                "userId": "/phoneNumber"
                // The path to the field to consider as the password of the entity
                "password": "/passwordToken"
            }
        ],
        "attestationPolicies": [
            // For each field mentioned in the `attestationAttributes` field, add
            // an object like so:
            {
              
                // The unique name for the attestation policy
                "name": "studentInstituteAttest",
                // The schema for the additional input to be captured that is not part of the schema/entity
                "additionalInput": {
                  "enrollmentNumber": {"type": "string"}
                },
                // The fields/properties to be used for attestation. The value of the below mentioned properties
                // will be extracted and sent for attestation.
                // The path to the field (dot-separate fields if the field is nested, $
                // is the root of the entity)
                "attestationProperties": {
                  "name": "$.name",
                  "educationDetails": "$.school"
                },
                // Set the attestation type to `MANUAL` if another entity needs to login
                // and verify the claim
                "type": "MANUAL",
                // What type of entity should be able to attest the claim OR the role an
                // entity should have (in Keycloak) for them to be able to attest the claim
                "attestorPlugin": "did:internal:ClaimPluginActor?entity=Teacher",
                // The condition for a certain entity to be able to attest the claim. In
                // this case, the attestor Teacher entity must be in the same school as
                // the Student entity to attest the claim
                "conditions": "(ATTESTOR#$.school#.contains(REQUESTER#$.school#))"
            }
        ],
        // This property holds the template to be used for generating the VC. It needs to be a template that follows
        // W3C standards. It can be an url or the template object can be defined inline. The signed data (VC) generated by this
        // template will be used to generate a QR Code.
        // Ex: inline: https://github.com/tejash-jl/ref-sunbirdrc-certificate/blob/main/schemas/TrainingCertificate.json#L52
        // Ex: external url: https://github.com/tejash-jl/ref-sunbirdrc-certificate/blob/main/schemas/SkillCertificate.json#L66
        "credentialTemplate": "",
        // This property holds the template to be used for generating visual certificate. The key can be used while 
        // downloading the certificate.
        "certificateTemplates": {
          "svg": "https://raw.githubusercontent.com/dileepbapat/ref-sunbirdrc-certificate/main/schemas/templates/TrainingCertificate.svg"
        }
    }
}
```

To add a new entity to the registry, place the JSON file defining its schema in the schemas folder. If you have setup the registry using the Registry CLI, place the JSON file in the `config/schemas` folder. If you are running the registry from its source, place the schemas in the `java/registry/src/main/resources/public/_schemas` folder. If you are using a `docker-compose.yaml` file to start the registry, the schema folder will be mentioned in the file under the `volumes` section in the registry container's configuration.

Then restart the registry by running the following:

```
# If using a docker-compose file:
$ docker compose up --force-recreate -d
# If using the Registry CLI:
$ registry restart
```

If you restarted the containers manually (without the CLI), then wait approximately 40 seconds for the containers to start. You can view the status of the registry by running the following:

```
# If using a docker-compose file:
$ docker compose ps
# If using the Registry CLI:
$ registry status
```

> `docker compose up --force-recreate -d` is only required when a change is made to the configuration (e.g.: an environment variable is updated in the `docker-compose.yaml` file, a new entity schema file was placed in the schemas folder). If you simply want to restart the registry process running in the container, a simple `docker compose restart` or `registry restart --soft` will suffice.


# Schema Configuration

## **Schema**

All registries have attributes pertaining to the entity or the fact in question either person or things. Schema defines the structure and constraints of the entity, Sunbird RC uses standard JSON-LD based schema.

In the example given below Place is Concept that registry is storing supporting name, city, addressRegion (state) and country.

#### Example:

```
{
 "$schema": "http://json-schema.org/draft-07/schema",
 "type": "object",
 "properties": {
   "Place": {
     "$ref": "#/definitions/Place"
   }
 },
 "required": [
   "Place"
 ],
 "title": "Place",
 "definitions": {
   "Place": {
     "$id": "#/properties/Place",
     "type": "object",
     "title": "The Place Schema",
     "required": [
       "name",
       "city",
       "addressRegion",
       "country"
     ],
     "properties": {
       "name": {
         "type": "string"
       },
       "city": {
         "type": "string"
       },
       "addressLocality": {
         "type": "string"
       },
       "addressRegion": {
         "type": "string"
       },
       "country": {
         "type": "string"
       },
       "postalCode": {
         "type": "string"
       },
       "contact": {
         "type": "string"
       },
       "email": {
         "type": "string"
       }
     }
   }
 }}
```

## Configuration

In addition to JSON LD specific data types SunbirdRC supports various extension configurations under “\_osConfig”. Access, indexing, primary key etc are configurable using schema configuration.

#### Entity and Properties

#### Property data types and restrictions

Supported types:

String - Unicode text, additional regular expressions restrictions can be applied.

Enum - restricted list of values

Number - numeric data

Integer - The integer type is used for integral numbers

Object - Objects are the mapping type in JSON. They map “keys” to “values”. In JSON, the “keys” must always be strings. Each of these pairs is conventionally referred to as a “property”.

Array - Arrays are used for ordered elements. In JSON, each element in an array may be of a different type.

Boolean - The boolean type matches only two special values: true and false. Note that values that evaluate to true or false, such as 1 and 0, are not accepted by the schema.

More details are available here [Type-specific keywords](https://json-schema.org/understanding-json-schema/reference/type.html).

#### List of attributes

Collection of data values are also supported as multiple data value might represent the entity property for example subjects taught : \[“english”,”science”, “mathematics”]

### Visibility scope:

3 types of visibility on attributes.

1. Public
2. Private (privateFields)
3. Internal

Public data attributes are available in discovery by default any sort of permission / authorization is not needed by default. By default all fields are public.

Private attributes can be accessed by the owner by default, with consent 3rd party can access the data field.

Internal fields are system fields that only serve internal functionalities, these can never be accessed by any actors in the system.

Configuring in the schema -&#x20;

```
{
    ...
    "_osConfig": {
        ...
        "privateFields": ["$.email", "$.mobile"],
        "internalFields": ["$.mobile"]
}
```

### System fields:

The following property is used to add additional audit fields to entity, to know who/when created/updated the entity.

1. osCreatedAt
2. osUpdatedAt
3. osCreatedBy
4. osUpdatedBy
5. \_osClaimId
6. \_osSignedData
7. \_osAttestedData

Configure in the schema -

```
{
    ...
    "_osConfig": {
        ...
        "systemFields": ["osCreatedAt", "osUpdatedAt"]
}
```

### Index field set

Indexes can help in faster access to information, based on usage context index fields can be configured. Example:

`"indexFields": ["phoneNumber"],`

### Primary Keys for Entities

Primary keys from domain space will help enforce uniqueness of information and make it easily accessible. “uniqueIndexFields” can be used to configure the same.

Example:

`"uniqueIndexFields": ["identityProperty"]`

### Validation Extensions

JSON LD schema allows defining basic type constraints like numeric type, text or list of items etc. Also it allows a list of possible values for given attributes (enum) and regular expressions based constraints for the value.

### Roles

#### Manage registry based on roles

Using `roles` config, one can set the authorization for crud operations on the schema

Example: let's say there are two registries Teacher and EducationCertificate, assume only Teacher can manage (add/update/delete) the EducationCertificate, then assign role "teacher" to the relevant user in a keycloak and add the "roles" : \["teacher"] in the EducationCertificate config, now only token which has the role "teacher" can manage the EducationCertificate

#### Invite based on roles

Using `inviteRoles` config, one can set the authorization for invite operation

#### Example:

**1. Only teacher can invite student**

Let's say there are two registries Teacher and Student, assume only Teacher can invite the Student, then assign role "teacher" to the relevant user in a keycloack and add the "inviteRoles" : \["teacher"] in the Student schema config, now only token which has the role "teacher" can invite the Student.

**2. Anyone can invite student**

Set "inviteRoles" : \["anonymous"] in Student schema config, now anyone can invite the Student

***Anonymous role: Any of the above role configs can be set to anonymous to allow anonymous access to the respective operations***

### Create login for registry

By default login is disabled for the registry, we need to set `enableLogin:true` inorder to create the user in keycloak. Login credentials for an entity can be configured through `ownershipAttributes` attributes. This attributes contains a list of objects for which a user enitity in keycloak will be created.

```
"ownershipAttributes": [
      {
        "email": "/email",
        "mobile": "/contact",
        "userId": "/contact"
        "password": "/password"
      }
    ]
```

We can have more than one owner for an entity. The respective json paths for the fields needs to be configured. All the properties are mandatory for creating an owner except password. The password is only set used for entity creation, it is not persisted in database.

### Attestation policy

List of policies can be configured for the attestation.

```json
{
              
    // The unique name for the attestation policy
    "name": "studentInstituteAttest",
    // The schema for the additional input to be captured that is not part of the schema/entity
    "additionalInput": {
      "enrollmentNumber": {"type": "string"}
    },
    // The fields/properties to be used for attestation. The value of the below mentioned properties
    // will be extracted and sent for attestation.
    // The path to the field (dot-separate fields if the field is nested, $
    // is the root of the entity)
    "attestationProperties": {
      "name": "$.name",
      "educationDetails": "$.school"
    },
    // Set the attestation type to `MANUAL` if another entity needs to login
    // and verify the claim
    "type": "MANUAL",
    // What type of entity should be able to attest the claim OR the role an
    // entity should have (in Keycloak) for them to be able to attest the claim
    "attestorPlugin": "did:internal:ClaimPluginActor?entity=Teacher",
    // The condition for a certain entity to be able to attest the claim. In
    // this case, the attestor Teacher entity must be in the same school as
    // the Student entity to attest the claim
    "conditions": "(ATTESTOR#$.school#.contains(REQUESTER#$.school#))"
}
```

#### Attestation Policy Attributes:

#### name

(required) A unique name for identifying an attestation policy. This name will be used to refer an attestation policy while raising a claim.

#### attestationProperties

(required) This field refers the schema properties which will be considered for attestation.

#### additionalInput

(optional) This denotes the additional inputs that needs to be captured outside the existing entity/schema fields for generating/processing the attestation.

#### type

(required) This denotes if the attestation should be raised manually or automatically.

* MANUAL: In this two types of user will come into the picture, i.e Attestor and Requestor, Requestor will rise a claim, and the Attestor will approve/reject. The authorization of the attestor will be defined in the config using `conditions` attribute.

Example: Only teacher from the particular institute can attest the student,

```
Student Education
{
    "program": "HSC",
    "graduationYear": "2021",
    "marks": "100",
    "instituteOSID": "b62b3d52-cffe-428d-9dd1-61ba7b0a5882",
    "documents": [
        {
            "fileName": "e3266115-0bd0-4456-a347-96f4dc335761-blog_draft",
            "format": "file"
        },
        {
            "fileName": "e56dab1b-bd92-41bb-b9e5-e991438f27b8-NDEAR.txt",
            "format": "file"
        }
    ]
}

Teacher Experience
{
  "experience": {
      "instituteOSID": "b62b3d52-cffe-428d-9dd1-61ba7b0a5882",
      "employmentType": "Permanent",
      "start": "1999-06-16",
      "end": "2022-06-16",
      "teacherType": "Head teacher",
      "subjects": [
        "Science",
        "Mathematics"
      ],
      "grades": [
        "Class I", "Class II"
      ]
  }
}
```

For this scenario the condition would be, `conditions: "(ATTESTOR#$.experience.[*].instituteOSID#.contains(REQUESTER#$.instituteOSID#))"` The above snippet says that attestor's education institute and requestor's experience must belong to the same institute.

* AUTOMATED: If the attestation policy is `AUTOMATED` then a claim will be initiated automatically without any user intervention/API calls. When there is any addition/modification to the `attestationProperties` then the matching attestation policy will be triggered and executed.

#### attestorPlugin

(required) This denotes who processes the claims that is been raised by the user. By default SunbirdRC will be shipped with a `ClaimPluginActor` who will process and store the respective claims in DB. If we need additional or different functionalities then we can

#### credentialTemplate

(optional) This template is required if we want to generate a certificate of attestation or generate a credential for attestation. The value is set similarly to [#credential-template](#credential-template "mention")

### Credential Template

This property holds the template to be used for generating the VC. It needs to be a template that follows W3C standards. It can be an url or the template object can be defined inline. The signed data (VC) generated by this template will be used to generate a QR Code.

* Ex: inline:

```json
{
  ...
  "credentialTemplate": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://gist.githubusercontent.com/dileepbapat/eb932596a70f75016411cc871113a789/raw/498e5af1d94784f114b32c1ab827f951a8a24def/skill"
    ],
    "type": [
      "VerifiableCredential"
    ],
    "issuanceDate": "2021-08-27T10:57:57.237Z",
    "credentialSubject": {
      "type": "Person",
      "name": "{{name}}",
      "trainedOn": "{{trainingTitle}}"
    },
    "issuer": "did:web:sunbirdrc.dev/vc/skill"
  },
  ...
}
```

* Ex: external url

```json
{
  ...
  "credentialTemplate": "https://gist.githubusercontent.com/tejash-jl/550aa1365c37e09065f1f134c936530d/raw/54f10668f8cad3953d9b09c09212d4ec4434ae7f/SkillExternalCredentialTemplate.json"
  ...
}
```

### Certificate Template

This property holds the template to be used for generating visual certificate. The key can be used while downloading the certificate.

```json
{
  ...
  "certificateTemplates": {
    "svg": "https://raw.githubusercontent.com/dileepbapat/ref-sunbirdrc-certificate/main/schemas/templates/TrainingCertificate.svg"
  },
  ...
}
```

### PrivateFieldConfig

The value for this property tells registry that how should privateFields configured in schema be emitted. This can have 5 different types of values.

There are 5 types of masking supported\
1\. NONE - field value will not be emitted\
2\. FULL - emit the field value as-is\
3\. HASH - emit the field as a one-way hash (salted)\
4\. MASK - emit the field using a masking strategy\
5\. HASH-MASK - emit two values for this field, one hashed and one masked

By default, both the configs hold NONE so the private and internal fields will not be emitted

```json
{
    ...
    "privateFieldConfig": "FULL",
    ...
}
```

### InternalFieldConfig

The value for this property tells registry that how should internalFields configured in schema be emitted. This can have 5 different types of values.

There are 5 types of masking supported\
1\. NONE - field value will not be emitted\
2\. FULL - emit the field value as-is\
3\. HASH - emit the field as a one-way hash (salted)\
4\. MASK - emit the field using a masking strategy\
5\. HASH-MASK - emit two values for this field, one hashed and one masked

By default, both the configs hold NONE so the private and internal fields will not be emitted

```json
{
    ...
    "internalFieldConfig": "FULL",
    ...
}
```

### Notification Templates

If you want to send out notifications, you can send it using this template configured in that particular schema. For each operation, you can have different templates. Also, for each operation, you can have multiple templates that you can send out.\
Following is an example of the notification templates

```
{
    ...
    "notificationTemplates": {
        "create": [{
            "subject": "Credential Created from schema",
            "body": "{\"sender\": \"AppName\",\"route\": \"4\",\"country\": \"91\",\"unicode\": 1,\"sms\": [{    \"message\": \"{{name}}, Your {{entityType}} credential has been created\",    \"to\": [      \"{{contact}}]\"    ]  
        }],
        "invite": [],
        "update": [],
        "delete": [],
        "revoke": []
    }
}
```

### UniqueIdentifierFields

If you want to auto generate some fields with specific format, you can generate those using this configuration in schema. each configuration of generatable field has 3 properties `field`, `idName`, `format` . Where field value should be path to the schema property you want to auto generate, idName is name with which you want to store the format, format is blueprint in which you want ids to be generated.

It can generate using different format, we can use below formatter in a square bracket to format our field (case insensitive) -

1. Using `seq` to generate a sequence
2. Using `fy` to generate financial year date
3. Using `cy` to generate a date in the current year
4. Using java regex to generate a random value of desired format

Following is an example of uniqueIdentifierFields configuration -&#x20;

The first configuration would generate a 6 digit number with prefix `ABN-` and the second would generate a sequence with prefix `STD` ie. `ABN-321123` , `STD1`

```
"_osConfig": {
  ...
  "uniqueIdentifierFields": [
    {
      "field": "/studentId",
      "idName": "student.id",
      "format": "ABN-[d{6}]"
    },
    {
      "field": "/classDetails/rollNumber",
      "idName": "class.details.roll.number",
      "format": "STD[SEQ_ROLLNUMBER]"
    }
  ],
  ...
}
```


# Create Schemas With Custom Password

This page demonstrates how to configure the schemas to allow entities to set their own password and walks you through the create and invite Registry APIs using the example of a Student to set the password.

## Configuring A Schema

We can create a schema in the registry using the [Schema API Endpoint](/v1.0.0/api-reference/schema/create-schema) and using JSON schema files as well

Here we are creating a `Student` schema, we would configure as following

```json
{
	"$schema": "http://json-schema.org/draft-07/schema",
	"type": "object",
	"properties": { "Student": { "$ref": "#/definitions/Student" } },
	"required": ["Student"],
	"title": "Student",
	"definitions": {
		"Student": {
			"$id": "#/properties/Student",
			"type": "object",
			"title": "Studentschema",
			"required": ["name", "phoneNumber", "email", "school"],
			"uniqueIndexFields": ["phoneNumber"],
			"properties": {
				"name": { "type": "string" },
				"phoneNumber": { "type": "string" },
				"email": { "type": "string" },
				"school": { "type": "string" },
				// this field will be considered as password
				"password": { "type": "string", "minLength": 8 }
			}
		}
	},
	"_osConfig": {
		"ownershipAttributes": [
			{
				"email": "/email",
				"mobile": "/phoneNumber",
				"userId": "/phoneNumber",
				// password ownership attribute required
				//  to map field to password
				"password": "/password"
			}
		],
		"inviteRoles": ["anonymous"]
	}
}

```

This will configure the entity to create a password while creating the entity object. Here ownership attribute password is required, Its value can be any path in the Student object we decide. If we don't set the password ownership attribute, It will take the default password [configured in the registry environment](/v1.0.0/use/developers-guide/configuration).

**Note: \_Password will only be used while creation of the Student object and Updating password using update entity API Endpoint is not supported.**\_

**Note: \_If the user is already created by another entity, the password will not be updated to the existing user account.**\_

## Inviting An Entity

We can create entities in the registry using the [Invite Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

To create a `Student` entity named Pranav Agate, we would make the following API call:

**cURL**

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--data-raw '{
		"name": "Pranav Agate",
		"phoneNumber": "1234567890",
		"email": "pranav@upps.in",
		"school": "UP Public School",
		"password": "pranav@1234"
	}' \
	'http://localhost:8081/api/v1/Student/invite'
```

**HTTPie**

```
echo '{
	"name": "Pranav Agate",
	"phoneNumber": "1234567890",
	"email": "pranav@upps.in",
	"school": "UP Public School",
	"password": "pranav@1234"
}' | http post \
	'http://localhost:8081/api/v1/Student/invite' \
	'content-type: application/json'
```

This will store the entity in the registry, create the user account in IAM (keycloak) with given password for the `Student` and return the following object:

```json
{
	"id": "open-saber.registry.invite",
	"ver": "1.0",
	"ets": 1634198998956,
	"params": {
		"resmsgid": "",
		"msgid": "3ee6a76f-d6c8-4262-a7ee-ddbe66fcb127",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK",
	"result": { "Student": { "osid": "1-9d6099fc-2c01-4714-bceb-55ff28c482f9" } }
}
```

## **Getting the Access Token**

So to authenticate as the `Student` entity we just created, we would make the following API call:

**cURL**

```
curl --location \
	--request POST \
	--header 'content-type: application/x-www-form-urlencoded' \
	--data 'client_id=registry-frontend' \
	--data 'username=1234567890' \
	--data 'password=pranav@1234' \
	--data 'grant_type=password' \
	'http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/token'
```

**HTTPie**

```
http --form post \
	'http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/token' \
	'content-type: application/x-www-form-urlencoded' \
	'client_id=registry-frontend' \
	'username=1234567890' \
	'password=pranav@1234' \
	'grant_type=password'
```

> Here, `registry-frontend` is the pre-configured client we use to make requests to keycloak and `pranav@1234` is the password for the `Student` entity, we created.

This API call should return a JSON object as follows:

```json
{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...2cSSaBKuB58I2OYDGw",
	"expires_in": 300,
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...9HulwVv12bBDUdU_nidZXo",
	"scope": "email profile",
	"session_state": "300f8a46-e430-4fd6-92aa-a2d337d7343e",
	"token_type": "Bearer"
}
```

## Retrieving An Entity

We can retrieve entities in the registry using the [Retrieve Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

So to retrieve the entity we created earlier, we would make the following request:

**cURL**

```
curl --location \
	--request GET \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	'http://localhost:8081/api/v1/Student'
```

**HTTPie**

```
http get \
	'http://localhost:8081/api/v1/Student' \
	'authorization: bearer {access-token}'
```

> Replace the `{id}` above with the entity's `osid` you saved from the create entity request. Replace the `{access-token}` with the `Student` entity's access token from the consent/authentication step.

This will return the entity's JSON representation as follows:

```json
{
	"name": "Pranav Agate",
	"phoneNumber": "1234567890",
	"email": "pranav@upps.in",
	"school": "UP Public School",
	"osid": "xxxxxx",
	"osOwner": ["xxxxxx"],
	"_osState/school": "DRAFT"
}
```

Here password won't be returned. Password is used only in the creation of the Student entity in Keycloak and not stored directly in the database.


# Setup the Backend

**Backend Repo**

[**https://github.com/Sunbird-RC**](https://github.com/Sunbird-RC)

\*\*Kubernetes deployment files are added to the repository : \*\*[**https://github.com/Sunbird-RC/sunbird-rc-core/tree/main/infra**](https://github.com/Sunbird-RC/sunbird-rc-core/tree/main/infra)

**Readme :**

[**https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/infra/README.md**](https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/infra/README.md)

\*\* The schemas for open-saber will be mentioned in this directory, \*\*[**https://github.com/Sunbird-RC/sunbird-rc-core/tree/main/java/registry/src/main/resources/public/\_schemas**](https://github.com/Sunbird-RC/sunbird-rc-core/tree/main/java/registry/src/main/resources/public/_schemas)


# Setup the Frontend

### Installation

You can get the latest code from the Sunbird RC UI Repository <https://github.com/Sunbird-RC/sunbird-rc-ui>

This is an Angular 8 project, and you need to install the dependencies, and run the project.

### Steps to follow

1. Make sure your back-end services are up and running
2. **Keycloak Configuration changes**:&#x20;
   * Once keycloak (<http://localhost:8080/auth/>) is up and running. Login to keycloak using the default username (admin) and password (admin). Navigate to Realm settings and update the ***FrontendURL*** attribute to - <http://localhost:4200/auth>
   * Then navigate to `Clients -> registry-frontend` and make sure to update these fields/ attibutes as mentioned below&#x20;
     1. &#x20;`Valid Redirect URIs` to <http://localhost:4200/*>&#x20;
     2. `Web Origins` to [http://localhost:4200](http://localhost:4200/*)
3. Clone the Sunbird RC UI Repository <https://github.com/Sunbird-RC/sunbird-rc-ui>
4. First step is to create a `ui-config` file in the directory `sunbird-rc-ui/src/assets/config`. We have provided a **sample-ui-config** in the same directory as a reference.
5. Sunbird-RC UI is a template that can be used to customise your UI application based on your use case. To do that you have to make changes in the UI-config and the angular application accordingly. You can refer Configuration section below to make the necessary changes based on your use case.
6. Commands to run :

```
yarn

npm start
```

7. If yarn is not available on you PC you can also use `npm install`.
8. Once the project is up and running - you can access it at [http://localhost:4200](http://localhost:4200/).

### Configuration

The application needs to be configured with the appropriate fields to be able to use it. Example configuration is provided in the `src/examples` folder.

#### Environment Config

| Key         | Value                                                                                                                                                       |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `baseUrl`   | Base URL for the Sunbird backend. Eg: <https://registry.com/api>                                                                                            |
| `schemaUrl` | URL to the OpenAPI schema definition. This could be a HTTP path or a path to a local file Eg: <https://registry.com/api/schema.json> OR /assets/schema.json |
| `logo`      | URL to logo. This logo is displayed in the header of the UI                                                                                                 |

#### Forms

The `forms.json` needs to be placed in `src/assets/config`. This file defines the schema for various forms used, along with the fields for each. The form rendering is based on the formly.dev library, and the forms.json is a small wrapper on top of the formly schema.

In this file `forms` is an array with key/value pairs. They key is the code / slug of the form which is used to access the form. Eg: if the key for a form is `employee-signup` that form can be accessed via `/forms/employee-signup`. Each form definition will have the below fields -

| Key               | Value                                                                                                                                                                                                                                                                              |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `form.api`        | This is the path to the API endpoints for the entity this form handles. Eg: `/Employer`                                                                                                                                                                                            |
| `form.type`       | Forms can be of 2 types. It can either be a form to create a new entity Eg: Employer, or it could be a form to submit a "sub-field" eg: work experience of an employee. For the former use `entity`. For the latter use `property:<property name>` (eg: property:work\_experience) |
| `form.formclass`  | HTML Class applied to the form container                                                                                                                                                                                                                                           |
| `form.title`      | Title of form                                                                                                                                                                                                                                                                      |
| `form.redirectTo` | Redirect URL on after form submit                                                                                                                                                                                                                                                  |
| `form.fieldsets`  | List of fieldsets(multiple) for this form. At least one fieldset is needed                                                                                                                                                                                                         |

**fieldsets**

| Key                    | Value                                                                                                                                                                      |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fieldsets.definition` | Name of the OpenAPI "Definition" to use                                                                                                                                    |
| `fieldsets.fields`     | List of fields(multiple) to populate for this fieldset. If you wish to display all fields from the schema, you can skip defining each field, and use use `"fields": ["*"]` |

**Form grouping**:

You can change the layout of form like add multiple columns in single row add panel using below configuration in **form.json** file.

| Key                   | Value                                   |
| --------------------- | --------------------------------------- |
| `fields.formclass`    | Apply the css classes on forms fieldset |
| wrappers": \["panel"] | Wrap the group of field                 |

Here is example for,

````json
```
{
  "teacher-setup": {
    "api": "/Teacher",
    "type": "entity",
    "fieldsets": [
      {
        "definition": "Teacher",
        "fields": [
          {
            "name": "contactDetails",
            "formclass": " row form-div",
            "class": "col-6"
          },
          {
            "name": "identityDetails",
            "wrappers": [
              "panel"
            ],
            "children": {
              "definition": "IdentityDetails",
              "title": true,
              "formclass": " row form-div line",
              "fields": [
                {
                  "name": "fullName",
                  "required": true,
                  "class": "col-6",
                }
              ]
            }
          }
```
````

**fields**

| Key                 | Value                                                                     |
| ------------------- | ------------------------------------------------------------------------- |
| `fields.name`       | Name of field (same as defined in definition of that schema)              |
| `fields.custom`     | `boolean` Name of custom field (not defined in defination of that schema) |
| `fields.required`   | `boolean`                                                                 |
| `fields.class`      | Class of field                                                            |
| `fields.disabled`   | `boolean` Disable the field (readonly)                                    |
| `fields.children`   | `object` Reference field of definition (same properties as `fieldsets`)   |
| `fields.validation` |                                                                           |

#### Layouts

The `layouts.json` is used to define how the public and private profile pages look like. For each entity in Sunbird backend, a layout file should be defined with the fields and the order in which they should display.

In this file `layouts` is an array with key/value pairs. They key is the code / slug of the layout page which is used to access the form. Eg: if the key for a layout is `employee-profile` that page can be accessed via `/profile/employee-profile`. Each layout definition will have the below fields -

| Key             | Value                                            |
| --------------- | ------------------------------------------------ |
| `layout.api`    | URL Path of API                                  |
| `layout.title`  | Title of form                                    |
| `layout.blocks` | Cards/Blocks (multiple) to populate in `layout`. |

**blocks**

| Key                 | Value                                                       |
| ------------------- | ----------------------------------------------------------- |
| `blocks.definition` | Definition of fields from JSON Schemas in `schemaUrl`       |
| `blocks.title`      | Title of Card/Block                                         |
| `blocks.add`        | `boolean` Enable Add Button                                 |
| `blocks.addform`    | `<name of form from forms>` Form opens on Add Button click  |
| `blocks.edit`       | `boolean` Enable Edit Button                                |
| `blocks.editform`   | `<name of form from forms>` Form opens on Edit Button click |
| `blocks.multiple`   | `boolean` Enable Multiple values                            |
| `blocks.fields`     | Array/List of fields(multiple) to populate in `fieldsets`   |

**fields**

| Key               | Value                                                               |
| ----------------- | ------------------------------------------------------------------- |
| `fields.includes` | Array/list of Included Fields from response or `[*]` for all fields |
| `fields.excludes` | Array/list of Excluded Fields from response                         |

## FAQs

### Proxy configuration

To avoid CORS issues you can use proxy configuration. Run `npm start` or `ng serve --proxy-config proxy.conf.json`. For additional configuration please check `proxy.conf.json` file.

### Hosting the Frontend

The frontend may be hosted any of the below ways

* As a container. You may create an image with the angular build files.
* On a VM
* In blob storage (eg: S3, with a CDN in front)


# Backup and Restore

Sunbird-RC has the capability to connect with various data sources, as indicated in the provided [link](https://docs.sunbirdrc.dev/learn/readme-1/high-level-architecture#db). Within this segment, we will present a few approaches for backing up and recovering data from [PostgreSQL](/v1.0.0/use/developers-guide/backup-and-restore/postgresql) and [Cassandra](/v1.0.0/use/developers-guide/backup-and-restore/cassandra). Apart from databases, it is essential to consider creating backups for Kafka, ElasticSearch, and Filestore (if they are utilized).


# PostgreSQL

Regular backups of PostgreSQL databases are crucial for preserving valuable data. Although the process is relatively straightforward, it is essential to grasp the underlying methods and assumptions involved.

There are three distinct methods for backing up PostgreSQL data, each with its own advantages and disadvantages:

1. [SQL dump](/v1.0.0/use/developers-guide/backup-and-restore/postgresql/sql-dump)
2. [File-system level backup](/v1.0.0/use/developers-guide/backup-and-restore/postgresql/file-system-level-backup)
3. [Continuous archiving](/v1.0.0/use/developers-guide/backup-and-restore/postgresql/continuous-archiving-and-point-in-time-recovery-pitr)

In the subsequent sections, we will discuss each approach individually, examining their respective strengths and weaknesses.


# SQL Dump

## **Create a SQL Dump**

**Command:**

```sh
pg_dump dbname > dumpfile
```

`pg_dump` is a PostgreSQL utility used for backing up databases. It generates an SQL file that can be used to recreate the database in its original state. The output can be redirected to a file or used in other formats for more control. `pg_dump` can be executed from a remote host with database access, but it requires read permissions for the tables being backed up. It offers advantages such as compatibility with different PostgreSQL versions and support for transferring databases across different machine architectures. Dumps created by `pg_dump` are internally consistent, representing a snapshot of the database at the time of the dump.

## Restore from a dump file

**Command:**

```sh
psql dbname < dumpfile
```

When using `pg_dump` to generate a database dump, the output is saved in a file called "dumpfile." It's important to create the database specified by "dbname" separately before using the `psql` utility for restoration. Ensure that all relevant users exist before restoring the SQL dump to maintain ownership and permissions. By default, `psql` continues executing even after encountering SQL errors, but you can change this behavior by setting the `ON_ERROR_STOP` variable. Alternatively, you can restore the entire dump as a single transaction using the `--single-transaction` option. The use of pipes enables direct database transfer between servers using pg\_dump and `psql` commands.

You might wish to run `psql` with the `ON_ERROR_STOP` variable set to alter that behavior and have `psql` exit with an exit status of 3 if an SQL error occurs:

```
psql --set ON_ERROR_STOP=on dbname < dumpfile
```

The ability of pg\_dump and psql to write to or read from pipes makes it possible to dump a database directly from one server to another, for example:

```
pg_dump -h host1 dbname | psql -h host2 dbname
```

## Important Note

When dealing with large `pg_dump` output files, certain operating systems may impose file size limits. Thankfully, `pg_dump` provides options to overcome this issue. Here are several methods to consider:

1. Compressed Dumps: Utilize compression tools like gzip to compress the `pg_dump` output file. For example:
   * Create a compressed dump: `pg_dump dbname | gzip > filename.gz`
   * Restore the dump: `gunzip -c filename.gz | psql dbname` or `cat filename.gz | gunzip | psql dbname`
2. Splitting Output: Use the split command to divide the output into smaller files that fit within the file system limits. For example:
   * Split into 2 GB chunks: `pg_dump dbname | split -b 2G - filename`
   * Restore the dump: `cat filename* | psql dbname`
3. Custom Dump Format: If PostgreSQL was built with the zlib compression library, you can utilize the custom dump format, which compresses data as it writes to the output file. This format allows selective table restoration. For example:
   * Create a custom-format dump: `pg_dump -Fc dbname > filename`
   * Restore the dump: `pg_restore -d dbname filename`

Note: Custom-format dumps must be restored using `pg_restore`, not `psql`.

For very large databases, combining the split method with other approaches may be necessary.

4. Parallel Dump: To expedite the dump process for large databases, you can use `pg_dump`'s parallel mode, which dumps multiple tables simultaneously. Control the degree of parallelism using the -j parameter. Parallel dumps are supported for the "directory" archive format. For example:
   * Dump in parallel: `pg_dump -j num -F d -f out.dir dbname`
   * Restore in parallel: Use `pg_restore -j` to restore a parallel dump, regardless of the archive mode used.

Refer to the pg\_dump and pg\_restore reference pages for further details on these methods.


# File System Level Backup

Instead of using the pg\_dump method, another backup strategy is to directly copy the files used by PostgreSQL to store database data. These files can be backed up using file system backup methods. For example:

```
tar -cf backup.tar /usr/local/pgsql/data
```

However, there are limitations to this approach that make it less practical compared to pg\_dump:

1. The database server must be shut down to obtain a usable backup. Simply disallowing connections is not sufficient. Stopping the server is necessary for both backup and restoration.
2. It is not possible to selectively back up or restore individual tables or databases from their respective files or directories. The commit log files (pg\_xact/\*) are required along with the table files to make the backup usable. Therefore, file system backups only work for complete backup and restoration of the entire database cluster.

An alternative file system backup approach is to create a "consistent snapshot" of the data directory, if supported by the file system. The typical procedure involves taking a frozen snapshot of the volume, copying the entire data directory from the snapshot to a backup device, and then releasing the frozen snapshot. This method allows backup while the database server is running. However, starting the database server using this backup will trigger WAL log replay, as if the previous server instance crashed. Including the WAL files in the backup is important, and performing a CHECKPOINT before taking the snapshot can reduce recovery time.

If the database is spread across multiple file systems, simultaneous frozen snapshots of all volumes may not be possible. In such cases, shutting down the database server to establish the frozen snapshots or using continuous archiving base backup can be options.

Another approach is to use rsync for file system backup. This involves running rsync while the database server is running and then temporarily shutting down the server to perform an rsync --checksum. This method allows a file system backup to be performed with minimal downtime.

Note that file system backups will generally be larger in size compared to SQL dumps. While pg\_dump excludes index contents and only includes commands for recreation, file system backups may include more data. However, file system backups may offer faster backup speeds.


# Continuous Archiving and Point-in-Time Recovery (PITR)

PostgreSQL maintains a write-ahead log (WAL) in the `pg_wal/` subdirectory of the data directory to record all changes made to the database's data files. This log ensures crash safety and allows restoring consistency by replaying the log entries since the last checkpoint. Combining a file-system-level backup with a backup of the WAL files provides an alternative backup strategy. To recover, the file system backup is restored, and then the backed-up WAL files are replayed to bring the system to the current state. This approach offers some benefits:

1. A perfectly consistent file system backup is not required as internal inconsistencies can be corrected through log replay.
2. Continuous backup can be achieved by archiving the WAL files, which is useful for large databases where frequent full backups may not be convenient.
3. Point-in-time recovery is supported, allowing the database to be restored to any desired state since the base backup.
4. By continuously feeding the series of WAL files to another machine with the same base backup, a warm standby system can be created for nearly-current database copies.

Note that `pg_dump` and `pg_dumpall` cannot be used as part of continuous archiving since they do not produce file-system-level backups with enough information for WAL replay.

It's important to consider that this method only supports the restoration of an entire database cluster and requires significant archival storage for the base backup and WAL traffic. However, it is a preferred backup technique in situations where high reliability is crucial.

To successfully recover using continuous archiving, a continuous sequence of archived WAL files extending back to the start time of the backup is necessary. Therefore, it's essential to set up and test the procedure for archiving WAL files before taking the initial base backup.

## Limitations

\
Currently, the continuous archiving technique in PostgreSQL has some limitations that may be addressed in future releases. These limitations include:

1. Risk of template database modifications during base backup: If a CREATE DATABASE command is executed while a base backup is in progress and the template database is modified during this time, the modifications may be applied to the created database during recovery. To avoid this issue, it is recommended not to modify any template databases while taking a base backup.
2. Tablespaces replaying with absolute paths: CREATE TABLESPACE commands are logged with absolute paths and will be replayed as tablespace creations with the same absolute path. This can be problematic if the log is replayed on a different machine or even on the same machine into a new data directory, as it will overwrite the contents of the original tablespace. To avoid potential issues, it is best practice to take a new base backup after creating or dropping tablespaces.
3. Bulky default WAL format: The default Write-Ahead Log (WAL) format is relatively large because it includes disk page snapshots to support crash recovery. These page snapshots ensure the recovery process can fix partially-written disk pages. However, depending on the hardware and software setup, the risk of partial writes may be negligible. In such cases, the total volume of archived logs can be significantly reduced by disabling page snapshots using the full\_page\_writes parameter. It's essential to carefully read the notes and warnings in Chapter 30 before making this change. Disabling page snapshots does not prevent the use of logs for point-in-time recovery (PITR). Future development may focus on compressing archived WAL data by removing unnecessary page copies even with full\_page\_writes enabled. Administrators can also reduce the number of page snapshots included in WAL by increasing the checkpoint interval parameters as much as possible.


# Cassandra

\
Apache Cassandra is an open-source distributed database management system that offers exceptional scalability, fault tolerance, and cost-effectiveness, making it highly desirable for enterprises. One of its standout features is the ability to ensure uninterrupted service even in the face of node failures.

Cassandra achieves this by replicating data across multiple nodes and data centers. The data is stored in SSTable files, which reside in the `keyspace` directory within the data directory path specified in the `Cassandra.yaml` file.

By default, the SSTable files are stored in the following directory path: `/var/lib/cassandra/data/`

With its robust data replication and fault-tolerant architecture, Cassandra guarantees continuous availability, making it a reliable choice for enterprise-level applications.

Cassandra offers two distinct approaches for backups:

1. [Snapshot-based backup:](/v1.0.0/use/developers-guide/backup-and-restore/cassandra/snapshot-based-backup-method) This method involves capturing point-in-time snapshots of the entire database. Snapshots provide a consistent view of the data at a specific moment, facilitating recovery from various issues or accidental data loss.
2. [Incremental backup:](/v1.0.0/use/developers-guide/backup-and-restore/cassandra/incremental-backup-method) With incremental backup, only the changes made since the last backup are stored. This approach reduces storage requirements and backup duration by capturing and preserving only the modified data. It complements snapshot-based backups by providing more frequent and efficient backup options.

By leveraging these backup methods, Cassandra users can ensure data resiliency and efficiently restore their databases in case of unexpected events or data inconsistencies.


# Snapshot-based backup method

Cassandra offers the `nodetool` utility, a command-line interface for managing clusters, including the ability to create data snapshots. By using the `nodetool` snapshot command, you can create snapshots by flushing `memtables` to disk and creating immutable hard links to SSTables.

Snapshots can be taken per node or across the entire cluster. For cluster-wide snapshots, parallel ssh utilities like `pssh` can be used, or you can take snapshots of each node individually. It's possible to capture snapshots of all keyspaces, specific keyspaces, or even individual tables within a keyspace. Keep in mind that sufficient free disk space is required on the node to accommodate the snapshot.

It's important to note that this snapshot method does not back up the schema, which must be backed up manually and separately. Here are a few examples of snapshot commands:

**Snapshot of all keyspaces:**

To capture a snapshot of all keyspaces, run the command:

```bash
nodetool snapshot
```

**Snapshot of a single keyspace:**

Assuming you have a keyspace named "organization" and you want to name the snapshot, use this command:

```bash
nodetool snapshot -t 2023.06.27 organization
```

**Snapshot of a single table:**

If you wish to snapshot only the "employee" table within the "organization" keyspace, execute the following command:

```
nodetool snapshot --table employee organization
```

After completing the snapshot, you can transfer the snapshot files to other storage locations like AWS S3, Google Cloud, or MS Azure. Remember to back up the schema separately because Cassandra can restore data from a snapshot only when the corresponding table schema exists.

## Advantages:

* Easy to manage and straightforward
* The nodetool utility in Cassandra offers the nodetool clearsnapshot command for removing snapshot files.

## Disadvantages:

* Taking daily backups of an entire keyspace can be challenging, especially for large datasets.
* Transferring large snapshot data to secure locations like AWS S3 can be costly.


# Incremental backup method

Enabling incremental backup in Cassandra involves modifying the `incremental_backups`value to `true` in the `cassandra.yaml` file. Once enabled, Cassandra establishes hard links to flushed memtables in SSTables within a backup directory located in the keyspace data directory. Incremental backups in Cassandra exclusively consist of new SSTable files, dependent on the last created snapshot. This approach minimizes disk space usage as it solely includes links to recently generated SSTable files from the previous full snapshot.

## Advantages

* Decreases disk space requirements
* Reduces transfer costs

## Disadvantages

* Cassandra does not automatically clear incremental backup files, necessitating the creation of a custom script for their removal
* Generates numerous small-sized files during backup, complicating file management and recovery procedures
* It is not possible to selectively choose specific column families for incremental backup.


# Data Restore

Restoring data from backups is crucial for ensuring data availability, especially in scenarios such as keyspace deletion, launching a new cluster from backup data, or replacing a node. The restoration process typically involves utilizing snapshots and incremental backup files.

There are two primary methods for restoring data from backups:

### Using `nodetool` refresh

The `nodetool` refresh command enables the loading of newly placed SSTables onto the system without requiring a restart. This method is useful when a new node replaces an unrecoverable node. To restore data from a snapshot using this method, follow these steps:

* Create the necessary schema if it doesn't already exist.
* Truncate the table if needed.
* Locate the snapshot folder (e.g., /var/lib/keyspace\_name/table\_name-UUID/snapshots/snapshot\_name) and copy the snapshot SSTable directory to the /var/lib/keyspace/table\_name-UUID directory.
* Execute the `nodetool refresh` command.

### Using `sstableloader`:

The `sstableloader` is a tool for loading a set of SSTable files into a Cassandra cluster. It offers options for loading external data, existing SSTables, and restoring snapshots. To restore data using `sstableloader`, follow these steps:

* Create the required schema if it's not already present.
* Truncate the table if necessary.
* Bring the backup data to a node from a storage service like AWS S3, Google Cloud, or MS Azure (e.g., download the backup data to /home/data).
* Run the following command:

  ```javascript
  sstableloader -d <ip> /home/data
  ```

Note: Replace `<ip>` with the appropriate IP address.

By following these methods, data can be effectively restored from backups, ensuring data availability and recovery in various scenarios.


# Generic Identity And Access Management

SunbirdRC was tightly coupled with keycloak for authentication & authorization of users. Currently, SunbirdRC is updated to support any identity layer (oauth2 compliant) for IAM

> Generic IAM is part of release-1.0.0 and above

SunbirdRC requires an IAM platform for mainly two purposes.

1. authN & authZ of users to enable trust between the user and the entity.
2. to manage user accounts for the entities created

### Below steps will enable authenticating and authorizing tokens generated from any oauth2 complaint IAM service

* Configure the below environment variables for the registry core service

```
- oauth2_resource_uri=https://domain/auth/
- oauth2_resource_email_path=email
- oauth2_resource_consent_path=consent
- oauth2_resource_roles_path=realm_access.roles
- oauth2_resource_entity_path=entity
```

`oauth2_resource_uri` should be configured with the domain url of the IAM service

**Example value**

**Keycloak: \`**[**https://keycloak-domain/auth/realms/sunbird-rc**](https://demo-education-registry.xiv.in/auth/realms/sunbird-rc)**\`**

**Auth0: \`**[**https://xxxx.us.auth0.com**](https://dev-i60gby3fxixns11k.us.auth0.com)**/\` (API Domain)**

**Fusionauth: \`<http://domain/\\`> (The value of the issuer configured in the tenant page)**

`oauth2_resource_email_path` should be configured with the path to be used for fetching email id from the token

`oauth2_resource_consent_path` (OPTIONAL) should be configured with the *path* to be used for fetching consent fields from the token

`oauth2_resource_roles_path` should be configured with the *path* to be used for fetching roles from the token

`oauth2_resource_entity_path` (OPTIONAL) should be configured with the *path* to be used for fetching entities from the token

### Steps to enable creating user accounts in any IAM platform

Currently, one needs to write a custom implementation to support creating users in the respective IAM platforms. SunbirdRC provided two ways to configure it:

<figure><img src="/files/ePa5EIpifZrkHdMD5DxB" alt=""><figcaption></figcaption></figure>

### **1. Sub module in Sunbird RC**

Currently, SunbirdRC is shipped with two submodules (Keycloak & auth0) to integrate with IAM platform. <https://github.com/Sunbird-RC/sunbird-rc-core/tree/main/java/middleware/registry-middleware>.\
If you need support for any other platform then you would need to create a module in a similar fashion.\
You need to configure the below env with respective values

```
identity_provider: dev.sunbirdrc.auth.keycloak.KeycloakProviderImpl (Replace the value with your package name)
sunbird_sso_url: http://localhost:8080/auth/ (IAM url)
sunbird_sso_realm: (Optional)
sunbird_sso_admin_client_id: (Optional)
sunbird_sso_admin_client_secret: (Optional)
sunbird_keycloak_user_set_password: (Optional)
sunbird_keycloak_user_password: (Optional)
identity_user_actions: (Optional)
```

The module needs to be added to the core registry and you need to build a custom docker image and use it in your application.

**Steps to create a submodule in SunbirdRC:**

* Create a [submodule](https://spring.io/guides/gs/multi-module/) in java/middleware/registry-middleware
* Implement this provider <https://github.com/Sunbird-RC/sunbird-rc-core/blob/generic-auth/java/middleware/registry-middleware/identity-provider/src/main/java/dev/sunbirdrc/registry/identity_providers/providers/IdentityProvider.java>, which returns the IdentityManager which handles user creation functionality. (Example <https://github.com/Sunbird-RC/sunbird-rc-core/blob/generic-auth/java/middleware/registry-middleware/keycloak/src/main/java/dev/sunbirdrc/auth/keycloak/KeycloakProviderImpl.java>)
* The IdentityManager should implement the <https://github.com/Sunbird-RC/sunbird-rc-core/blob/generic-auth/java/middleware/registry-middleware/identity-provider/src/main/java/dev/sunbirdrc/registry/identity_providers/pojos/IdentityManager.java>, which handles user creation and returns the user id. (Example: <https://github.com/Sunbird-RC/sunbird-rc-core/blob/generic-auth/java/middleware/registry-middleware/keycloak/src/main/java/dev/sunbirdrc/auth/keycloak/KeycloakAdminUtil.java>)
* A Service Provider is configured and identified through a provider configuration file which we put in the resource directory META-INF/services. The file name is the fully-qualified name of the SPI and its content is the fully-qualified name of the SPI implementation. (Example: <https://github.com/Sunbird-RC/sunbird-rc-core/blob/generic-auth/java/middleware/registry-middleware/keycloak/src/main/resources/META-INF/services/dev.sunbirdrc.registry.identity_providers.providers.IdentityProvider>)
* Update `identity_provider` env with the provider package name\\

### **2. Wrapper service**

Instead of creating a module in the core service, you can create an external/custom service which exposes an API to create users in your IAM platform.

The API should follow this API spec: <https://github.com/Sunbird-RC/sunbird-rc-core/blob/6a99ab9d564ef0518ff5fa8f6730a58e51808f6d/services/sample-fusionauth-service/api-spec.yml>

A sample service to create a user in FusionAuth is provided. <https://github.com/Sunbird-RC/sunbird-rc-core/tree/6a99ab9d564ef0518ff5fa8f6730a58e51808f6d/services/sample-fusionauth-service>

You need to configure the below env with respective values

```
identity_provider: dev.sunbirdrc.auth.genericiam.AuthProviderImpl
sunbird_sso_url: http://localhost:8080/auth/ (Replace the value with your service endpoint)
```


# Metrics

The following document describes how the metrics can be emitted through registry

Sunbird RC enables emitting events from the registry. Any operation like ADD, DELETE, UPDATE and READ can emit events

For Sunbird RC to start emitting events, there are few configurations you need to enable.

1. **event\_enabled:-** Boolean value which indicates whether the events will be emitted or not
2. **event\_topic:-** Kafka Topic to which events will be emitted if **event\_providerName** is set to **dev.sunbirdrc.registry.service.impl.KafkaEventService**
3. **event\_providerName:- dev.sunbirdrc.registry.service.impl.KafkaEventService** for Kafka based and **dev.sunbirdrc.registry.service.impl.FileEventService.java** for File based event logging

The events emitted are in the format of Sunbird telemetry specs. Following is the sample of the event that is emitted from the registry

```json
{
    "eid": "ADD", //operationType
    "ets": 1678958110872, 
    "ver": "3.1", 
    "mid": "abc-123", //message id
    "actor": {
      "id": "123", // userId of creator or anonymous
      "type":  "User"
    },
    "context": {
      "channel": "sunbird-rc-core",
      "env": "dev"
    },
    "object": {
      "id": "xyz-123",
      "type": "Student"
    },
    
    "edata": {
       "identityDetails": {
           "fullName": "kevin",
           "dob": "XX-XX-XX94",
           "identityHolder": {
               "type": "XXXXport",
               "value": "XXX741"
           }
       },
       "contactDetails": {
           "email": "XXXXom@gmail.com",
           "mobile": "XXXXXX6789",
           "address": {
               "plot": "XX",
               "street": "XXXnue"
           }
       },
       "guardianDetails": {
           "fullName": "John",
           "relation": "Father"
       }
    }
}
```

Sunbird RC supports two types in which events can be emitted.

1. [Kafka based](#kafka-based)
2. [File based](#file-based)

You can enable this two types by passing a configuration variable. **event\_providerName.**

The value for this will be class name. For eg: `dev.sunbirdrc.registry.service.impl.KafkaEventService` for Kafka based\
`dev.sunbirdrc.registry.service.impl.FileEventService.java` For File based

### **- Kafka based**

Registry sends the event in the above format i.e. Sunbird Telemetry format to the Kafka topic configured(default events). Kafka will hold the data and then the consumer can run on this to store this in the Clickhouse database

OperationType here can be ADD, UPDATE, DELETE, READ

Data of the entity will be masked using the configuration defined in the schema.

You can check the configuration for masking in [schema configuration](/v1.0.0/use/developers-guide/schema-setup/schema-configuration).

1. InternalFields [here](/v1.0.0/use/developers-guide/schema-setup/schema-configuration#internalfieldconfig)
2. PrivateFields [here](/v1.0.0/use/developers-guide/schema-setup/schema-configuration#privatefieldconfig)

**Metrics Service**

The service is a consumer for the events the registry emits into the Kafka topic.

Metric service by default uses Clickhouse as the database to store the events. The table Schema for events is as follows

```sql
create table <table_name> (
    operationType String,
    createdAt Date,
    entityId String,
    entity JSON
)
```

For every distinct type of schema, the service creates a new table and stores the data related to that object.

Metric Service also exposes two APIs

* The service also exposes an API which returns the count of all the events emitted. It retrieves the data from all the tables created. ([API Spec](/v1.0.0/api-reference/metrics-apis/get-count))
* The service also exposes another API which returns aggregates on all the tables created. The cron job will run and save the result in a Redis. This can be fetched through the API. ([API Spec](/v1.0.0/api-reference/metrics-apis/get-aggregates))\
  To configure Metrics Service for aggregates, the following configurations need to be setup for Metrics micro-service\
  \
  **CRON\_ENABLE** :- Boolean value which will tell metrics service to run cron job if the value is set to true\
  \
  **SCHEDULE\_INTERVAL**:- Interval period in days to run the cron job after\
  \
  **SCHEDULE\_TIME**:- Time in GMT at which the cron job should be running

Based on this, the cron job will run at the scheduled time and the results will be stored in redis. The aggregates API will then return back this results.

The Configuration for Metric Service can be found [here](/v1.0.0/use/developers-guide/configuration#metrics-service)

### - File Based

The events emitted by the registry are logged into a log file which is present at `metrics_log/metrics.log` . The log also has a rolling policy based on the size (30MB).

Following is a pictorial representation of the current approach

<figure><img src="/files/hP1armKP7n3RuUXAD5GT" alt=""><figcaption><p>Interaction Diagram for Events Thrown and Metric Consuming Events</p></figcaption></figure>

The discussion for all of these features can be found here, <https://github.com/orgs/Sunbird-RC/discussions/356>


# Custom Keycloak Build

SunbirdRC uses a custom keycloak image which is configured to enable/disable NONCE validation. The required changes are made in this repository, <https://github.com/Sunbird-RC/keycloak/tree/configurable-nonce-validation>.

NONCE validation is default enabled in keycloak, to turn off the validation `VALIDATE_NONCE` should be set to `"false".`

This configuration is not provided by keycloak by default even in the latest version. We have configured this change, particularly for enabling Digilocker Meripehchaan SSO (Task: <https://github.com/Sunbird-RC/community/issues/593>).

### Build custom keycloak image

#### Pre-requisites

* JAVA 11 (tested with 11.0.8)
* Maven

#### Build keycloak distribution jar

* Clone <https://github.com/Sunbird-RC/keycloak/tree/configurable-nonce-validation> the repository (Contains the source code)
* Run the below command to generate the distribution jar. Reference <https://github.com/Sunbird-RC/keycloak/blob/configurable-nonce-validation/docs/building.md> `mvn clean install -Pdistribution`
* The above command should create `keycloak-14.0.0.tar.gz` in `distribution/server-dist/target` directory

#### Build keycloak docker image

* Clone <https://github.com/keycloak/keycloak-containers/tree/main/> the repository (Contains the build files)
* `git checkout 14.0.0`
* `cd server`
* Run a Python HTTP server in the [keycloak repo](#build-keycloak-distribution-jar) to access the distributed jar file.\
  `python -m http.server 8001`
* Build the keycloak docker image,\
  `docker build -t sunbirdrc/keycloak --build-arg KEYCLOAK_DIST=http://<YOUR_IP_ADDRESS>:8001/keycloak-14.0.0.tar.gz .`
* Tag the new docker image and publish it to dockerhub / docker registry


# Custom QR Code design

Sunbird RC support configuring a custom design for the QR code instead of a plain black coloured QR Code

#### Below are the steps to configure custom designed QR code

* The below ENV needs to be configured for `certificate-api` service

`ENABLE_CUSTOM_QR_CODE_CANVAS: true`

* Create a `qr_code_config.json` file. And add the QR code styling which can be designed here, <https://qr-code-styling.com/>
* A sample styling is available here, <https://github.com/Sunbird-RC/sunbird-rc-core/blob/main/services/certificate-api/configs/qr_code_config.json>
* Once the styling file is added, the file needs to be mounted to `certificate-api` service as below

```
certificate-api:
    image: ghcr.io/sunbird-rc/sunbird-rc-certificate-api:latest
    volumes:
      - ./imports/qr_code_config.json:/app/configs/qr_code_config.json
```


# VC Verification Module

This is a common library created to be used in any Sunbird RC platform for VC verification.

This NPM module is developed for scanning the QR(Quick Response) codes inside your Angular applications. This library is designed to be used in sunbird RC platforms.

### **To use this module you need to follow the below steps**

1. Install the vc-verification npm package in your angular project. Using the below command

```
npm i vc-verification
```

**2.** The <mark style="color:red;">deprecated</mark> `ngx-scanner` has been removed starting from version 0.0.13

You need to install the @zxing/ngx-scanner npm module. Before installing this npm module you need to check your angular compatible version with this package version. You can check the details below too.

Run cmd -

```
npm i @zxing/ngx-scanner@vx.x.x
```

| Angular Version                           | Ngx-scanner version            |
| ----------------------------------------- | ------------------------------ |
| Angular 9.0.0 <10                         | v3.0.0, v3.0.1                 |
| Angular 10.1.5                            | v3.1.0, v3.1.1, v3.1.2, v3.1.3 |
| Angular 11.2.11 \|\| ^12.0.4              | V3.2.0, v3.3.0                 |
| Angular 11.2.11 \|\| ^12.0.4 \|\| ^13.0.0 | V3.4.2, v3.5.0                 |

\
For more detail about compatible version you can check this doc - <https://www.npmpeer.dev/packages/@zxing/ngx-scanner/compatibility>

3\. Add below CND link in index.html file

```
  <script src="https://cdn.jsdelivr.net/npm/@undecaf/zbar-wasm@0.9.12/dist/index.js"></script>
```

4\. Import **vc-verification** and **@zxing/ngx-scanner** library in your **app.module.ts** file

```
import { VerifyModule } from 'vc-verification';
import { ZXingScannerModule } from '@zxing/ngx-scanner'; <- not required >=0.0.13

import * as configData from '../assets/config.json';  // Read config from .json file

Or
// Add configuration in app.module.ts file
const configData = {
  baseUrl: "assets/api/event-detail.json",
 }

@NgModule({
  declarations: [
   AppComponent
  ],
  imports: [
  .....
  ......
    VerifyModule.forChild(configData),  < —
    ZXingScannerModule, < — not required >=0.0.13
    .....
  ......
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule { }

```

4.1 Anyone can use the Default Scan template using the sb-vc-verify selector or he/she can use only verify service too.

Add below code in your app.component.html file

```
 <sb-vc-verification> </sb-vc-verification>
```

4.2 If anyone wants to change labels and messages from template. You can pass it through item property.

app.component.html

```
<sb-vc-verification [item]="itemData"></sb-vc-verification>
```

App.component.ts : Change the value of key

```
this.itemData =
 {
      "scanner_type": "ZBAR_QRCODE",
      "showResult": [
        { "title": "Name", "path": "credentialSubject.name" },
        { "title": "Father Name", "path": "credentialSubject.fatherName" },
        { "title": "Date of Issuance", "path": "issuanceDate",  'type' : 'date' },
        { "title": "ABHA Number", "path": "credentialSubject.id",  "removeStr" : "did:abha:" },
        { "title": "NOTTO ID", "path": "credentialSubject.nottoId" },
        { "title": "Organs", "path": "credentialSubject.pledge.organs" },
        { "title": "Tissues", "path": "credentialSubject.pledge.tissues" },
        {  "title": "Emergency Contact Details", "path": "credentialSubject.emergency.mobileNumber" }
      ],
      "scanNote": "To verify pledge certificate, simply scan the QR code that's on the document.",
      "certificateTitle": 'Pledge Certificate',
      "verify_another_Certificate": 'Verify another Certificate',
      "cetificate_not_valid": 'This Certificate is not valid',
      "scan_qrcode_again": "Please scan QR code again"
    });
```

This library supports the two QR code scanners (ZXING\_QRCODE and ZBAR\_QRCODE). By default enable the ZXING\_QRCODE scanner to scan QR code. If you want to change the scanner, the user needs to set the **scanner\_type** property value to the **ZBAR\_QRCODE**.

Difference between ZXING\_QRCODE and ZBAR\_QRCODE.

* ZXING\_QRCODE doesn't scan QR code which contains a large amount of data, it's working fine with simple QR codes (<mark style="color:red;">Deprecated</mark>).
* ZBAR\_QRCODE supports fast scanning and easily scans QR code which contains large amounts of data.

*Starting from version 0.0.13 and onwards, the default scanner type has been changed to **ZBAR\_QRCODE** as ZXING\_QRCODE scanner has been removed by default.*

From v10 introduced one more **showResult** object under itemData to configure what certificate data the user wants to display on the result card after verifying QR code. In this object user need to add property path and title which is display on verified card.

* to show date on card, you wants to add **type** property with **date** value
* if you want remove any string from value, you can achieve this by using **removeStr** property

4.3 If anyone wants to use their own he/she can implement their own UI and he/she can use service methods of vc-verification library.

**App.component.ts**: Import service file in your component where you want to call vc-verification library service method call.

```
import { VerifyService } from 'verify-module'; 

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
 
  constructor(public verifyService: VerifyService) {

    this.verifyService.scanSuccessHandler(event).then((res) => {
      console.log(res);
    })
  }

}
```

**List of service methods**

| Method Name                     | Parameter | Description                          |
| ------------------------------- | --------- | ------------------------------------ |
| enableScanner()                 | -         | To Hide/show scanner screen          |
| scanSuccessHandler($event: any) | $event    | This method used to verify scan data |

## Change Button Color

To change the button color, user need to override **vc-btnPrimary** css class in stye.css

## Source Code

The source code to install this example can be found at <https://github.com/Sunbird-RC/vc-verification>


# Integrations


# SSO with existing systems

## Using OAuth based authentication from registry

* Onboard new api client
* Setup redirect url and Valid origin
* Configure the mapping for scope fields if any required.

{% content-ref url="/pages/sbUXhqQpCY43rjcwdjWw" %}
[Digilocker Meripehchaan SSO](/v1.0.0/use/integrations/digilocker-meripehchaan-sso)
{% endcontent-ref %}


# Digilocker Meripehchaan SSO

This document will illustrate on how digilocker meripehchaan can be configured.

### Assumptions

To get the Digilocker Meripehchaan SSO login button in the login page, you would need to use the keycloak theme instead of the custom theme provided by default.

### Pre-requisites

* Keycloak
* Digilocker partner account (<https://partners.digitallocker.gov.in/>)
* Generate client secrets in (<https://apisetu.gov.in/org/consumer/auth_partners>)
* Set the redirect url to `<domain>/auth/realms/master/broker/oidc/endpoint`

### Steps to integrate Digilocker Meripehchaan SSO in keycloak

* Goto keycloak admin page `<domain>/auth/`
* Login with admin credentials
* Goto `Identity Providers`
* Click on `Add provider`
* Select `OpenID Connect v1.0`
* Enter the display name to be showed on the login page, Ex: `Login with Digilocker Meripehchaan`
* Set the Authorization URL to \`<https://digilocker.meripehchaan.gov.in/public/oauth2/1/authorize>\`
* Set the Token URL to \`<https://digilocker.meripehchaan.gov.in/public/oauth2/2/token>\`
* Turn on `Disable User Info` button
* Select `Client secret sent as post` from `` Client Authentication` `` options
* Set `Client Id` that was generated in Digilocker partner portal
* Set `Client Secret` that was generated in Digilocker partner portal
* Select `consent` from `Prompt` options
* Enable `Use PKCE` option
* Select `S256` from `PKCE Method` options

### Enable default keycloak theme

* Goto keycloak admin page `<domain>/auth/`
* Login with admin credentials
* Goto `clients -> registry-frontend`
* Select `keycloak` from `Login Theme` options
* Save the changes


# Digilocker Integration

This document covers the process of integrating digilocker with SunbirdRC, to pull the credentials from SunbirdRC to digilocker wallet

## Pre-requisites

* Partner account in digilocker. <https://partners.digitallocker.gov.in/>
* Understand how digilocker issuer API works <https://partners.digitallocker.gov.in/assets/img/digital_locker_issuer_api_specification%20v1.10.pdf>

***Note: Currently digilocker doesn't have a sandbox environment to test the integration. Testing needs to be performed on the production account. So be careful and conscious before making any changes in the partner portal.***

## Onboarding Sunbird RC in Digilocker

* Log in to partner account
* Goto digilocker `Pull URI Request` section

<figure><img src="/files/l2iOfoSgk84c7Z8D6KYc" alt=""><figcaption></figcaption></figure>

* Click on `+ Add`
* Add the details as shown below.
* `Search API Id`: You need to give a unique name to your API Id. This id will be passed to your backend for retrieving the VC
* `Search API Description:` You can update this as per your business functionality.
* `API Key:` You need to create a new unique and secure API key. This key will be used to generate the HMAC of the request body sent by digilocker. This key needs to be kept secure and confidential.
* `Rest API Service URL:` You need to specify the SunbirdRC URL to access the VC. Ex: \`[https://\<host>/digilocker/v1/digilocker/pullUriRequest](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md)\`
* And click on `Next`

<figure><img src="/files/4t1Pu1vap3VDmM03CKRN" alt=""><figcaption></figcaption></figure>

* In the next section, you can define what user parameters you would need to be sent to backend for accessing the VC. Here you can select a few existing user profile parameters like Aadhaar / demographic details. Or else you can also define custom parameters as shown below. `Ex: Certificate ID.` These parameters will be used as search parameters to fetch the VC for the user. In the below section, the steps to configure the search parameters are defined.
* Click on \`Next

<figure><img src="/files/KDscw87jjqOeaYWmEhIQ" alt=""><figcaption></figcaption></figure>

* Add the type of document which you are fetching. This will be displayed in digilocker
* Click on `Update`

<figure><img src="/files/sfmkXTjZ1q4U272SKvx6" alt=""><figcaption></figcaption></figure>

* Now you can test your configuration. Enter the details of the parameters that are displayed and click on `Test Service.` If all the details were configured correctly, you will be displayed with the VC certificate in the below section.
* Once all the configuration is tested, this can be published. Only if it is published it will be displayed on the Digilocker portal for users to pull their credentials.

<figure><img src="/files/69JUtrZnkX4cfuZA3YEl" alt=""><figcaption></figcaption></figure>

## Configure SunbirdRC to access VC from Digilocker

You can fetch the credentials generated by Sunbird RC in Digilocker once you have configured the partner account.

Configurations required for the service to pull credentials are mentioned [here](/v1.0.0/use/developers-guide/configuration#digilocker-certificate-api)

Apart from this, you will also require a JSON File which has the following information. The below JSON file is used to map configuration for the document type configured in digilocker

Following is the sample JSON file.

```json
{
    "docType": {
        "schema": "Schema",
        "template": "html",
        "searchFilter": {
            "filters": {
                "osid": {
                    "eq": "{{.certificate_id}}"
                }
            }
        }
    }
}
```

**Definitions:**

* ***docType:*** This value refers to the document type that is configured in Digilocker
* ***schema:*** This refers to the schema which the VC needs to be fetched from.
* ***template:*** This refers to the template key that needs to be used for rendering the presentation layer for the VC.
* ***searchFilter:*** This defines the search filters that need to be executed on RC to identify the VC. We can mention the parameters that are configured on `Add New API` page of Digilocker. Sunbird RC uses this search filter to search for the credential in the registry and if present, it fetches the certificate in pdf format and creates a response in XML format to be sent to digilocker to store the certificate

Example JSON file:

`The below sample JSON is configured to fetch the` [`Pre Matric Scholarship`](https://github.com/Sunbird-RC/demo-education-registry/blob/federated_edu_registry/sample_schemas/PreMatricScholarship.json) `Credential`

```json
{
    "SACER": {
        "schema": "PreMatricScholarship",
        "template": "html",
        "searchFilter": {
            "filters": {
                "osid": {
                    "eq": "{{.certificate_id}}"
                }
            }
        }
    }
}
```


# Release Notes

### Version 1.0.0

Date of Release - 15 November 2023

[Release Notes](/v1.0.0/use/latest-release-v1.0.0/release-notes)

### Version 0.0.14

Date of Release - 30 June, 2023

[Release Notes](https://rc.sunbird.org/v/v0.0.14/use/releases)


# Latest Release - v1.0.0

<table data-full-width="true"><thead><tr><th>Release Version</th><th>Date</th></tr></thead><tbody><tr><td>1.0.0</td><td>15-Nov-2023</td></tr></tbody></table>

* **Full OAuth and OIDC support -** Sunbird-RC was dependent on Keycloak for its Identity and Access Management needs. Sunbird-RC has been enhanced to support any OAuth 2.0 and OIDC-compliant provider.
* **Enhanced Data Privacy with Encryption & Decryption on the Private Fields -** Sunbird-RC has been enhanced to encrypt, mask or hash data at a field level even during storage. Earlier, data was encrypted and masked only when shared with other integrators.
* **Unique ID Generation for Fields -**  Sunbird-RC has incorporated the capability to generate and add functional identifiers in registries, moving away from generic UUIDs. This enhancement facilitates seamless integration with DIGIT's Id-Gen service.
* **Cleanup of Registry Startup Errors -** Users reported various startup issues, especially when authentication is disabled or related to keycloak, elastic search, and auxiliary services. The update addresses these concerns for a smoother startup.
* **Enhanced Registry-CLI -** Registry-CLI has been upgraded and new options have been added for enabling or disabling various features. These updates empower users to tailor the CLI to their specific needs and streamline its operation based on individual use cases.
* Migrated all Registry Core Docker images from Dockerhub to the GitHub Container Registry (GHCR)
* Various bug fixes to enhance the overall user experience.

For a comprehensive list of changes in all our releases, you can find the detailed change log available at this link. <https://github.com/Sunbird-RC/sunbird-rc-core/releases>

### Artifacts

The various artifacts that form the crux of the Sunbird-RC platform are as follows. All of Sunbird-RC's artifacts are hosted on the Github Container Registry.

| Artifact               | Image                                                    |
| ---------------------- | -------------------------------------------------------- |
| Sunbird-RC Core        | ghcr.io/sunbird-rc/sunbird-rc-core                       |
| Claims services        | ghcr.io/sunbird-rc/sunbird-rc-claims-ms                  |
| Signer services        | ghcr.io/sunbird-rc/sunbird-rc-certificate-signer         |
| Certificate services   | ghcr.io/sunbird-rc/sunbird-rc-certificate-api            |
| Notification services  | ghcr.io/sunbird-rc/sunbird-rc-notification-service       |
| Digilocker services    | ghcr.io/sunbird-rc/sunbird-rc-digilocker-certificate-api |
| Metrics services       | ghcr.io/sunbird-rc/sunbird-rc-metrics                    |
| Bulk issuance services | ghcr.io/sunbird-rc/sunbird-rc-bulk-issuance              |
| Public Key services    | ghcr.io/sunbird-rc/sunbird-rc-public-key-service         |
| Context Proxy services | ghcr.io/sunbird-rc/sunbird-rc-context-proxy-service      |
| Keycloak               | ghcr.io/sunbird-rc/sunbird-rc-keycloak                   |
| ID Generation services | ghcr.io/sunbird-rc/id-gen-service                        |
| Encryption services    | ghcr.io/sunbird-rc/encryption-service                    |

The **`latest`**  tag always points to the latest version of the platform. The current version is also tagged to the image. The current version is **`v1.0.0`**

The details about the various docker images are available at: <https://github.com/orgs/Sunbird-RC/packages?repo_name=sunbird-rc-core>


# Admin Portal

Registry setup & configuration workflow can be streamlined with Admin Portal.

1. Prerequisites:
   * *Details coming soon*
2. Create Registry Instance
   * *Details coming soon*
3. Access administrator portal:
   * [Login](https://demo-admin-portal.xiv.in/) to admin portal
   * [Create schema](https://docs.sunbirdrc.dev/~/changes/ZV4lFZMKighmbjr9sJml/developer-documentation/admin-portal/get-started/create-schema) to manage your registry and credential platform
   * Customise theme of your platform *(coming soon)*

## Source Code

The source code to install this example can be found at:

{% embed url="<https://github.com/Sunbird-RC/Admin-Portal>" %}

## Development Status

{% embed url="<https://github.com/orgs/Sunbird-RC/projects/10>" %}


# Login

Access Administrator/Tenant Portal

Governing Body (Tenant) can complete the registry setup and manage the entity details and configurations

After initial setup, tenant can access tenant portal

#### Login

1. Tenant can login with username and password provided
2. First time users can change the username and password

<figure><img src="/files/3rORIAN1NTNmA6EpI83W" alt=""><figcaption></figcaption></figure>


# Get Started

Access Administrator Portal

Get Started in two ways:

1. Build Registry with following additional modules:
   * Attestation and Claim
   * Verifiable Credentials: To create VC template
   * Ownership
2. Using sample use cases:\
   If your scenario is close to one of the sample use case, you can get started immediately by cloning the sample use case. Please note you can edit the settings of these use cases later as per your requirement.

<figure><img src="/files/mwvKNAgELsxv9UpHZatH" alt=""><figcaption></figcaption></figure>

### Building Registry

1. Click **Start** to build your registry
2. You can optionally select any or all of the sunbird RC modules.

<figure><img src="/files/M8VUeVLkE24YyefjWUgt" alt=""><figcaption></figcaption></figure>

Depending on the sunbird RC modules selected, you will get following steps:

* If you have **not** selected any additional modules:\
  You can 'create schema' and 'Publish' it, to build registry.

  <figure><img src="/files/22GbGB44kJ2PZOMvunZa" alt=""><figcaption></figcaption></figure>
* If you have selected 'Verifiable Credentials':\
  You can 'create schema' and 'add VC template' for the schemas.\\

  <figure><img src="/files/sFf1WjaEIMIdFxRg5ZGQ" alt=""><figcaption></figcaption></figure>
* If you have selected "Attestation & Claim":\
  You can 'Create Schema', 'Add Attestation Workflow', 'Add VC template' for the attestation workflow and Publish the schema.\\

  <figure><img src="/files/1srgMnq1Oic9UU5r77v1" alt=""><figcaption></figcaption></figure>
* If you have selected "Ownership":\
  You can "Add Ownership" details on who would be authorised to manage the schema/entities.\\

  <figure><img src="/files/ORmgx69fRKEKm9yBZxNt" alt=""><figcaption></figcaption></figure>
* If you have selected all the modules:\
  You can configure all the modules and Publish it.\\

  <figure><img src="/files/nO4jYNg11KDwOt9H3XZC" alt=""><figcaption></figcaption></figure>

### Using Sample Use cases

<figure><img src="/files/hpo8GDIioB0ykiGJ2KTY" alt=""><figcaption></figcaption></figure>


# Create Schema

### Creating Schema for first time

<figure><img src="/files/6uUgrEvxJIsLH2kVJBc1" alt=""><figcaption></figcaption></figure>

### Add Schema

* Click on '+ Add Schema' to add schema name and description

![](/files/XwNbJGiXvce32iPXIdvv)

### Add Fields in schema

* Once Schema name is added, click on ''+ Add fields" to add fields in schema
* Drag and drop the fields that you want to include in the schema. You can add validations to the fields
* You can also add fields that are available in 'common schema'
* Click on 'delete' to delete schema
* Click on edit to edit schema name and description
* Click on 'JSON Schema' to edit schema using JSON editor

<figure><img src="/files/qf6LQ00u20EWUitidhUl" alt=""><figcaption></figcaption></figure>

### Pre-filled Schema

When sample use cases are selected, the schema and fields are pre-filled. User can review and edit or delete the fields or schema

<figure><img src="/files/xdnVVtsEJkrk2G0nIMRB" alt=""><figcaption></figcaption></figure>


# Attestation Workflows (WIP)

<figure><img src="/files/UwghmtH9art72m5qeomt" alt=""><figcaption></figcaption></figure>


# VC Template

Create a VC template for the schema saved in previous step "Create Schema"

<figure><img src="/files/BXKZiCCVqbpQWm6ZcaF6" alt=""><figcaption></figcaption></figure>

### Template

Once you have saved schema:

1. You can now add a verifiable credential template under each schema.
2. You can select existing template or [create custom template](https://docs.sunbirdrc.dev/developer-documentation/admin-portal/get-started/vc-template/custom-verifiable-credential-template)

<figure><img src="/files/9roePR3PjDvMzAuHljG6" alt=""><figcaption></figcaption></figure>

### Template for Attestation Workflow

If you have created Attestation Workflow:

1. You can create a VC template for the attestation workflow.
2. For each attestation workflow, you can add a VC template.
3. You can select existing template or [create custom template](https://docs.sunbirdrc.dev/developer-documentation/admin-portal/get-started/vc-template/custom-verifiable-credential-template)

<figure><img src="/files/aCSuNHsLMkk420Y9sFzi" alt=""><figcaption></figcaption></figure>

### Edit Template and Delete Template

**Editing a Template:**

If you need to modify an existing template, simply click on the template icon, you wish to edit. Within the template editor, you can add new fields, customise the appearance, and make any necessary changes.

<figure><img src="/files/YKKJlWMKoRTxW5WknlMd" alt=""><figcaption><p>Click on the icon, you will be able to edit the template</p></figcaption></figure>

<figure><img src="/files/KZB6uEHwfpituvFTy0y6" alt=""><figcaption><p>You can edit or delete the certificate template</p></figcaption></figure>

**Deleting a Template:**

Please note that the action of deleting a template is irreversible. Exercise caution when choosing to delete a template, as all associated data will be permanently removed.

<figure><img src="/files/mubvQZb8uMW7bzMGIwGa" alt=""><figcaption></figcaption></figure>


# Custom VC Template (WIP)

<figure><img src="/files/OSsiazXuuBC6SMcwtLOj" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QH5yo54iIRGLuIJWX5O7" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/GMlCqvXEgxssrLU2fx2Y" alt=""><figcaption></figcaption></figure>

##


# Ownership (WIP)

<figure><img src="/files/vLXhPE5xeJA7QDV17NMD" alt=""><figcaption></figcaption></figure>


# Publish (WIP)

Publish Schema one at a time

<figure><img src="/files/rV1ABo1Ve4DpxVy57MBE" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/0dU53dlNyPlVsWqF7H1e" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/ZnUsRX13ECSu4EZDzjYM" alt=""><figcaption></figcaption></figure>


# Dashboard

The dashboard provides users with a comprehensive view of schema-related information, allowing seamless navigation and management of schema creation, exploration of APIs, and handling of VC.

* The dashboard lets users view the structure they've created in the registry, along with certificates, schema count, and status information. It also offers the ability to explore APIs.&#x20;
* Using a sidebar, users can easily move between different steps in creating or modifying a schema. For example, clicking on a schema in the sidebar takes the user to a step where they can edit an existing schema in draft status or create a new one.
* When users click on "Explore API" here, they can examine the Swagger JSON representation of the published schema.&#x20;
* Additionally, there's a distinct card displaying schema details such as its name, count, and status. Within this card, users have the option to view the schema.&#x20;
* If the schema is in a "PUBLISHED" status, users can only view it in a read-only mode. However, if the schema is in "DRAFT" status, users have the ability not only to view but also to edit the schema.

<figure><img src="/files/8KKyMWP9YfXqooti4uA5" alt=""><figcaption><p>Dashboard of Admin Portal</p></figcaption></figure>

* In the bottom section of the dashboard, users can find Verifiable Credentials (VC), which are certificate templates corresponding to each schema, as depicted in the above template.
* By clicking the "Add" button, users are directed to the "Add VC" step, where they can seamlessly add new certificates to the relevant schema.
* Moreover, users can interact with the certificate icons by clicking on them. This action allows users to both view and edit the certificate templates associated with the specific schema they are working on.


# Registry


# Using The APIs

The following guide walks you through the different Registry APIs using the example of a student-teacher registry.

## Inviting An Entity

We can create entities in the registry using the [Invite Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

To create a `Teacher` entity named Pranav Agate who teaches Math at UP Public School, we would make the following API call:

**cURL**

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--data-raw '{
		"name": "Pranav Agate",
		"phoneNumber": "1234567890",
		"email": "pranav@upps.in",
		"subject": "Math",
		"school": "UP Public School"
	}' \
	'http://localhost:8081/api/v1/Teacher/invite'
```

**HTTPie**

```
echo '{
	"name": "Pranav Agate",
	"phoneNumber": "1234567890",
	"email": "pranav@upps.in",
	"subject": "Math",
	"school": "UP Public School"
}' | http post \
	'http://localhost:8081/api/v1/Teacher/invite' \
	'content-type: application/json'
```

This will store the entity in the registry and return the following object:

```json
{
	"id": "open-saber.registry.invite",
	"ver": "1.0",
	"ets": 1634198998956,
	"params": {
		"resmsgid": "",
		"msgid": "3ee6a76f-d6c8-4262-a7ee-ddbe66fcb127",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK",
	"result": { "Teacher": { "osid": "1-9d6099fc-2c01-4714-bceb-55ff28c482f9" } }
}
```

Important variables in the response body:

| Field                       | In   | Type     | Description                                                                                    |
| --------------------------- | ---- | -------- | ---------------------------------------------------------------------------------------------- |
| `result.{entity-type}.osid` | body | `string` | The ID of the create entity in the registry, used for retrieval and modification of the entity |

## Requesting Access To An Entity's Data

A client application can request access to an entity's data through an OAuth 2.0 flow by creating a scope in the registry that maps (via the `User Property` mapper) the scope to give the client permission to access the data.

To go through the consent flow, we must first decide which scope to request. In this case, we will be requesting the `openid` scope to get access to all the public fields of the entity. Then, we must construct a URL to request the entity to grant us access to their data as follows:

> The following example has been indented and split into multiple lines for readability only.

```
# Keycloak's consent endpoint
http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/auth?
 scope=openid& # The space separated list of scopes we want the entity to grant us access to
 response_type=code& # Return an authorization code once the entity grants access
 redirect_uri=*& # Send the code to this URL
 client_id=registry-frontend # The client requesting access to the entity's data
```

Here is what the URL looks like when it's url-encoded:

`http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=*&client_id=registry-frontend`

To go through the consent flow, click on the URL and login as an entity. In this case, we can login as the `Teacher` entity we created in the [Inviting An Entity section](#inviting-an-entity) - enter `1234567890` as the username and `test` as the password.

> Here, `registry-frontend` is the preconfigured client we use to make requests to keycloak and `test` is the default password for all entities.

Once you have authenticated yourself as the `Teacher`, you will see a consent screen, asking you to grant access to `Registry Frontend`. Click `YES` to grant access to the client and continue with the consent flow.

Once you click `YES`, it will redirect you to `http://localhost:8080/auth/*`. You will see an error page, as we have not setup a frontend application to parse the response and request an access token automatically. For this example (and to gain a better understanding of how the consent flow works), we will parse keycloak's response manually.

Notice that the URL query parameters contain two variables: `session_state` and `code`. The `code` parameter is of most importance here - it is a one-time code that will allow us to retrieve an access token with access to the entity's data. Copy the value of the `code` parameter (everything after `code=` in the URL). To retrieve an access token, we make the following request:

**cURL**

```
curl --location \
	--request POST \
	--header 'content-type: application/x-www-form-urlencoded' \
	--data 'client_id=registry-frontend' \
	--data 'code={code}' \
	--data 'redirect_uri=*' \
	--data 'grant_type=authorization_code' \
	'http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/token'
```

**HTTPie**

```
http --form post \
	'http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/token' \
	'content-type: application/x-www-form-urlencoded' \
	'client_id=registry-frontend' \
	'code={code}' \
	'redirect_uri=*' \
	'grant_type=authorization_code'
```

> If you get a `invalid_grant: Code not valid` error, just go through the consent flow again. The `code` expires quickly, so try to make the request for the access token as soon as you get redirected to the redirect URL!

This API call should return a JSON object as follows:

```json
{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...2cSSaBKuB58I2OYDGw",
	"expires_in": 300,
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...9HulwVv12bBDUdU_nidZXo",
	"scope": "openid email profile",
	"session_state": "300f8a46-e430-4fd6-92aa-a2d337d7343e",
	"token_type": "Bearer"
}
```

Important variables in the response body:

| Field          | In   | Type     | Description                                                                    |
| -------------- | ---- | -------- | ------------------------------------------------------------------------------ |
| `access_token` | body | `string` | Access token used to retrieve/update entity                                    |
| `expires_in`   | body | `number` | Number of seconds before the access token will be declared invalid             |
| `token_type`   | body | `string` | Should be `Bearer`, else we have gotten the wrong token                        |
| `scope`        | body | `string` | This should contain `openid`, and this means we successfully got user consent! |

Once we have the access token, we can start retrieving and modifying entity data.

## Authenticating As An Entity

We can authenticate as entities using the [Authenticate As Entity API Endpoint](/v1.0.0/api-reference/registry/authenticating-as-an-entity). **This step is only required if consent is turned off for the frontend client.**

So to authenticate as the `Teacher` entity we just created, we would make the following API call:

**cURL**

```
curl --location \
	--request POST \
	--header 'content-type: application/x-www-form-urlencoded' \
	--data 'client_id=registry-frontend' \
	--data 'username=1234567890' \
	--data 'password=test' \
	--data 'grant_type=password' \
	'http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/token'
```

**HTTPie**

```
http --form post \
	'http://localhost:8080/auth/realms/sunbird-rc/protocol/openid-connect/token' \
	'content-type: application/x-www-form-urlencoded' \
	'client_id=registry-frontend' \
	'username=1234567890' \
	'password=test' \
	'grant_type=password'
```

> Here, `registry-frontend` is the preconfigured client we use to make requests to keycloak and `test` is the default password for all entities.

This API call should return a JSON object as follows:

```json
{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...2cSSaBKuB58I2OYDGw",
	"expires_in": 300,
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...9HulwVv12bBDUdU_nidZXo",
	"scope": "email profile",
	"session_state": "300f8a46-e430-4fd6-92aa-a2d337d7343e",
	"token_type": "Bearer"
}
```

Important variables in the response body:

| Field          | In   | Type     | Description                                                        |
| -------------- | ---- | -------- | ------------------------------------------------------------------ |
| `access_token` | body | `string` | Access token used to retrieve/update entity                        |
| `expires_in`   | body | `number` | Number of seconds before the access token will be declared invalid |
| `token_type`   | body | `string` | Should be `Bearer`, else we have gotten the wrong token            |
| `scope`        | body | `string` | Using this token, what information we can access about the entity  |

## Retrieving An Entity

We can retrieve entities in the registry using the [Retrieve Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

So to retrieve the entity we created earlier, we would make the following request:

**cURL**

```
curl --location \
	--request GET \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	'http://localhost:8081/api/v1/Teacher/{id}'
```

**HTTPie**

```
http get \
	'http://localhost:8081/api/v1/Teacher/{id}' \
	'authorization: bearer {access-token}'
```

> Replace the `{id}` above with the entity's `osid` you saved from the create entity request. Replace the `{access-token}` with the `Teacher` entity's access token from the consent/authentication step.

This will return the entity's JSON representation as follows:

```json
{
	"phoneNumber": "1234567890",
	"school": "UP Public School",
	"subject": "Math",
	"name": "Pranav Agate",
	"osid": "{id}",
	"osOwner": ["{owner-id}"],
	"_osState/school": "DRAFT"
}
```

Important variables in the response body:

| Field              | In   | Type     | Description                                                                                                                                                                                                                            |
| ------------------ | ---- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `osOwner`          | body | `string` | User ID of the entity in Keycloak.                                                                                                                                                                                                     |
| `_osState/{field}` | body | `string` | State of an attestable field. Can be `DRAFT` (when it has not been sent for attestation), `ATTESTATION_REQUESTED` (when sent for attestation), `PUBLISHED` (when successfully attested) and `REJECTED` (when rejected by the attestor) |

## Updating An Entity

We can update entities in the registry using the [Update Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

So to update the subject our `Teacher` entity Pranav Agate teaches to `Biology`, we would make the following API call:

**cURL**

```
curl --location \
	--request 'PUT' \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	--data-raw '{
		"name": "Pranav Agate",
		"phoneNumber": "1234567890",
		"email": "pranav@upps.in",
		"subject": "Biology",
		"school": "UP Public School"
	}' \
	'http://localhost:8081/api/v1/Teacher/{id}'
```

**HTTPie**

```
echo '{
	"name": "Pranav Agate",
	"phoneNumber": "1234567890",
	"email": "pranav@upps.in",
	"subject": "Biology",
	"school": "UP Public School"
}' | http put \
	'http://localhost:8081/api/v1/Teacher/{id}' \
	'content-type: application/json' \
	'authorization: bearer {access-token}'
```

> Replace the `{id}` above with the entity's `osid` you saved from the create entity request. Replace the `{access-token}` with the `Teacher` entity's access token from the consent/authentication step.

> We need to send the whole entity and not just the updated fields because that is how RESTful APIs work. A PUT call should replace the existing record in the database with the new object as-is. To know more about this, take a look at the accepted answer on [this SO question](https://stackoverflow.com/questions/28459418/use-of-put-vs-patch-methods-in-rest-api-real-life-scenarios).

This will update the entity in the registry and return the following object:

```json
{
	"id": "open-saber.registry.update",
	"ver": "1.0",
	"ets": 1634371946769,
	"params": {
		"resmsgid": "",
		"msgid": "d51e6e6a-027d-4a42-84bb-2ce00e31d993",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK"
}
```

## Deleting An Entity

We can delete entities in the registry using the [Delete Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

So to delete the subject our `Teacher` entity, we would make the following API call:

**cURL**

```
curl --location \
	 --request 'DELETE' \
	 --header 'content-type: application/json' \
	 --header 'authorization: bearer {access-token}' \
	 'http://localhost:8081/api/v1/Teacher/{id}'
```

**HTTPie**

```
http DELETE \
	'http://localhost:8081/api/v1/Teacher/{id}' \
	'content-type: application/json' \
	'authorization: bearer {access-token}'
```

> Replace the `{id}` above with the entity's `osid` you saved from the create entity request. Replace the `{access-token}` with the `Teacher` entity's access token from the consent/authentication step.

This will delete the entity in the registry and return a blank HTTP 200 response.

## Making A Claim

To make a claim, we can use the [Claim API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/developer-documentation/broken-reference/README.md).

First, let us create a `Student` entity named Prashant Joshi who also goes to UP Public School:

**cURL**

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--data-raw '{
		"name": "Prashant Joshi",
		"phoneNumber": "9876543210",
		"email": "prashant@upps.in",
		"school": "UP Public School"
	}' \
	'http://localhost:8081/api/v1/Student/invite'
```

**HTTPie**

```
echo '{
	"name": "Prashant Joshi",
	"phoneNumber": "9876543210",
	"email": "prashant@upps.in",
	"school": "UP Public School"
}' | http post \
	'http://localhost:8081/api/v1/Student/invite' \
	'content-type: application/json'
```

Next, we can get an access token for Prashant by either making a POST request to the authentication server (see the [Authenticating As An Entity section](#authenticating-as-an-entity) to know how to do that) OR by requesting entity consent to access their data (see the [Requesting Access To An Entity's Data section](#requesting-access-to-an-entitys-data) to know how to do that). The default registry instance setup by the CLI has consent enabled, so we will follow the consent flow to retrieve an access token.

Then, we can send the claim (that Prashant is a student at UP Public School) for attestation by making the following request:

```
curl --location \
	--request 'PUT' \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	--data-raw '"UP Public School"' \
	'http://localhost:8081/api/v1/Student/{id}/school?send=true'
```

**HTTPie**

```
echo '"UP Public School"' | http put \
	'http://localhost:8081/api/v1/Student/{id}/school' \
	'content-type: application/json' \
	'authorization: bearer {access-token}' \
	'send==true'
```

> Replace the `{id}` above with the entity's `osid` you saved from the create entity request. Replace the `{access-token}` with the `Student` entity's access token from the consent/authentication step.

This will send the claim for attestation and return the following object:

```json
{
	"id": "open-saber.registry.update",
	"ver": "1.0",
	"ets": 1634371946769,
	"params": {
		"resmsgid": "",
		"msgid": "ksi38Dsl-8dIw-492j-6vlS-84KRe0Csop35",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK"
}
```

If you retrieve the `Student` entity by following the [Retrieving An Entity section](#retrieving-an-entity), you will get the following object in response:

```json
{
	"email": "prashant@upps.in",
	"name": "Prashant Joshi",
	"phoneNumber": "9876543210",
	"school": "UP Public School",
	"osid": "{id}",
	"osOwner": ["{owner-id}"],
	"_osClaimId/school": "{claim-id}",
	"_osState/school": "ATTESTATION_REQUESTED"
}
```

Important variables in the response body:

| Field                | In   | Type     | Description                                                                                                                                                                                                                            |
| -------------------- | ---- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `osOwner`            | body | `string` | User ID of the entity in Keycloak.                                                                                                                                                                                                     |
| `_osState/{field}`   | body | `string` | State of an attestable field. Can be `DRAFT` (when it has not been sent for attestation), `ATTESTATION_REQUESTED` (when sent for attestation), `PUBLISHED` (when successfully attested) and `REJECTED` (when rejected by the attestor) |
| `_osClaimId/{field}` | body | `string` | ID of the claim made on a field, required when attesting the claim.                                                                                                                                                                    |

## Attesting/Reject A Claim

We can attest/reject an entity's claim using the [Attest Claim API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/api/attesting-a-calim.md).

So to attest the claim we made in the previous section (that Prashant is a student at UP Public School), we make the following request:

**cURL**

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	--data-raw '{
		"action": "GRANT_CLAIM"
	}' \
	'http://localhost:8081/api/v1/Teacher/claims/{claim-id}/attest'
```

**HTTPie**

```
echo '{
	"action": "GRANT_CLAIM"
}' | http post \
	'http://localhost:8081/api/v1/Teacher/claims/{claim-id}/attest' \
	'content-type: application/json' \
	'authorization: bearer {access-token}'
```

> Replace the `{claim-id}` above with the `_osClaimId/school` you saved from the make a claim request. Replace the `{access-token}` with the `Teacher` entity's access token from the consent/authentication step. Replace `GRANT_CLAIM` with `REJECT_CLAIM` to reject the claim instead.

This will attest/reject the claim and return a blank HTTP 200 response.


# Create An Entity

To create an entity, we need to make the following HTTP request

## Request

## Create a record for entity-type

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-type}`

#### Path Parameters

| Name                                          | Type   | Description                  |
| --------------------------------------------- | ------ | ---------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | The type of entity to create |

#### Query Parameters

| Name        | Type   | Description                                                                                                                                                          |
| ----------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| mode        | String | Query parameter whose value can be `async` if creating an entity should be asynchronously handled                                                                    |
| callbackUrl | String | Query parameter whose value will be a `web-hook url`. The webook will be called once the entity is created in the registry. This is applicable only for `async mode` |

#### Headers

| Name                                           | Type   | Description                                                                                        |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                          |
| authorization                                  | String | Set to `Bearer {access-token}` if `roles` in schema config is not anonymous else this can be empty |

#### Request Body

| Name                                  | Type | Description       |
| ------------------------------------- | ---- | ----------------- |
| ...<mark style="color:red;">\*</mark> |      | The entity's data |

{% tabs %}
{% tab title="200: OK Success Response of entity Created" %}

```javascript
{
	"id": "sunbird-rc.registry.create",
	"ver": "1.0",
	"ets": 1634198998956,
	"params": {
		"resmsgid": "",
		"msgid": "3ee6a76f-d6c8-4262-a7ee-ddbe66fcb127",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK",
	"result": { "{entityName}": { "osid": "1-9d6099fc-2c01-4714-bceb-55ff28c482f9" } }
}
```

{% endtab %}
{% endtabs %}

Sample Request Body for Teacher as Entity-Type

```json
{
 "name": "Sunbird",
 "school": "UP Public School",
 "phoneNumber": "1234567890",
 "subject": "Math"
}
```

Important Fields in Response Body

<table><thead><tr><th width="261.3333333333333">Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>result.{entity-type}.osid</code></td><td><code>string</code></td><td>The ID of the create entity in the registry, used for retrieval and modification of the entity</td></tr></tbody></table>

### Usage

So to create a `Teacher` entity named Pranav Agate who teaches Math at UP Public School, we would make the following API call:

#### cURL

```shell
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--data-raw '{
		{
            "name": "Pranav Agate",
            "school": "UP Public School",
            "subject": "Math",
            "contact": "1234567890"
        }
	}' \
	'{registry-url}/api/v1/{entity-type}/'
```

#### HTTPie

```shell
printf '{
            "name": "Pranav Agate",
            "school": "UP Public School",
            "subject": "Math",
            "contact": "1234567890"
        }' | http post \
	'{registry-url}/api/v1/{entity-type}' \
	'content-type: application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Invite An Entity

To invite an entity, we need to make the following HTTP request

## Invite an Entity

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-type}/invite`

#### Path Parameters

| Name                                          | Type   | Description                  |
| --------------------------------------------- | ------ | ---------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | The type of entity to create |

#### Headers

| Name                                           | Type   | Description                                                                                              |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                                |
| authorization                                  | String | Set to `Bearer {access-token}` if `inviteRoles` in schema config is not anonymous else this can be empty |

#### Request Body

| Name                                  | Type   | Description       |
| ------------------------------------- | ------ | ----------------- |
| ...<mark style="color:red;">\*</mark> | Object | The entity's data |

{% tabs %}
{% tab title="200: OK Success response of entity invited" %}

```json
{
	"id": "sunbird-rc.registry.invite",
	"ver": "1.0",
	"ets": 1634198998956,
	"params": {
		"resmsgid": "",
		"msgid": "3ee6a76f-d6c8-4262-a7ee-ddbe66fcb127",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK",
	"result": { "Teacher": { "osid": "1-9d6099fc-2c01-4714-bceb-55ff28c482f9" } }
}
```

{% endtab %}
{% endtabs %}

Important Fields in Response Body

| Field                       | Type     | Description                                                                                    |
| --------------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `result.{entity-type}.osid` | `string` | The ID of the create entity in the registry, used for retrieval and modification of the entity |

## Usage

So to create a `Teacher` entity named Pranav Agate who teaches Math at UP Public School, we would make the following API call:

### cURL

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--data-raw '{
		"phoneNumber": "1234567890",
		"school": "UP Public School",
		"subject": "Math",
		"name": "Pranav Agate",
	}' \
	'{registry-url}/api/v1/Teacher/invite'
```

### HTTPie

```
printf '{
    "name": "Pranav Agate",
    "teaches": "Math",
    "school": "UP Public School"
}'| http POST '{registry-url}/api/v1/Teacher/invite' \
 Content-Type:'application/json'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.

#### Note: Invite API doesn't validate the required parameters. Invite API is designed to be used to invite another actor to the system with minimal information, hence required validations will not be applied. Instead, use [create an entity API](/v1.0.0/api-reference/registry/create-an-entity).


# Generate token

We can authenticate with the registry as a particular entity to perform operations like retrieving, searching, updating and attesting.

## Request

To authenticate as an entity, we need to make the following request:

<mark style="color:green;">`POST`</mark> `http:/keycloak-url/auth/realms/{realm}/protocol/openid-connect/token`

#### Headers

| Name                                           | Type   | Description                                |
| ---------------------------------------------- | ------ | ------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/x-www-form-urlencoded` |

#### Request Body

| Name                                          | Type   | Description                                                                                       |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------- |
| grant\_type<mark style="color:red;">\*</mark> | String | Set to `password`                                                                                 |
| client\_id<mark style="color:red;">\*</mark>  | String | Set to `registry-frontend`                                                                        |
| username<mark style="color:red;">\*</mark>    | String | The `_osConfig.ownershipAttributes.userId` of the entity according to the schema                  |
| password<mark style="color:red;">\*</mark>    | String | Set to `abcd@123` (default password, specified in registry's application.yml/docker compose file) |

{% tabs %}
{% tab title="200: OK " %}

```json
{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...2cSSaBKuB58I2OYDGw",
	"expires_in": 300,
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...9HulwVv12bBDUdU_nidZXo",
	"scope": "email profile",
	"session_state": "300f8a46-e430-4fd6-92aa-a2d337d7343e",
	"token_type": "Bearer"
}
```

{% endtab %}
{% endtabs %}

Important variables in the response body:

| Field          | In   | Type     | Description                                                        |
| -------------- | ---- | -------- | ------------------------------------------------------------------ |
| `access_token` | body | `string` | Access token used to retrieve/update entity                        |
| `expires_in`   | body | `number` | Number of seconds before the access token will be declared invalid |
| `token_type`   | body | `string` | Should be `Bearer`, else we have gotten the wrong token            |
| `scope`        | body | `string` | Using this token, what information we can access about the entity  |

## Usage

### cURL

```
curl --location \
	--request POST \
	--header 'content-type: application/x-www-form-urlencoded' \
	--data 'client_id=registry-frontend' \
	--data 'username={username}' \
	--data 'password=test' \
	--data 'grant_type=password' \
	'{keycloak-url}/auth/realms/{realm}/protocol/openid-connect/token'
```

### HTTPie

```
http --form post \
	'{keycloak-url}/auth/realms/{realm}/protocol/openid-connect/token' \
	'content-type: application/x-www-form-urlencoded' \
	'client_id=registry-frontend' \
	'username={username}' \
	'password=test' \
	'grant_type=password'
```

> `{keycloak-url}` is usually <http://localhost:8080>, and `{realm}` is usually `sunbird-rc`.
>
> The `{keycloak-url}` is usually `localhost:{port}`. The port can be found under the `keycloak` section in the `docker-compose.yml` file. The `{realm}` can be found at the top of the `realm-export.json` file used to configure keycloak.


# Generate admin token

## Pre-requisites

#### Steps to create an admin role

* Goto keycloak admin page, Ex: \<domain>/auth/
* The default admin credentials will be (admin / admin). Update the default admin password for security reasons.
* Goto roles section and add a `admin` role if not present

You can create a new user or update the existing user with the above role. A [client](#steps-to-create-a-client-with-an-admin-role) can also be used if you have a backend service that will call the registry APIs.

#### Steps to create a user and attach an admin role

* Goto keycloak admin page, Ex: \<domain>/auth/
* Goto `users` section and click on `Add user` button.
* Fill in the required information and click on `Save` button
* Goto `Credential` section and provide the password for the user
* Once the user is created goto `Role Mappings` section
* Select `admin` role from the `Available Roles` and click on `Add selected`

**Use the below API to generate the token for the above user**

## Request

To authenticate as an entity, we need to make the following request:

## Generate token API &#x20;

<mark style="color:green;">`POST`</mark> `http:/keycloak-url/auth/realms/{realm}/protocol/openid-connect/token`

#### Headers

| Name                                           | Type   | Description                                |
| ---------------------------------------------- | ------ | ------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/x-www-form-urlencoded` |

#### Request Body

| Name                                          | Type   | Description                                                                                       |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------- |
| grant\_type<mark style="color:red;">\*</mark> | String | Set to `password`                                                                                 |
| client\_id<mark style="color:red;">\*</mark>  | String | Set to `registry-frontend`                                                                        |
| username<mark style="color:red;">\*</mark>    | String | The `_osConfig.ownershipAttributes.userId` of the entity according to the schema                  |
| password<mark style="color:red;">\*</mark>    | String | Set to `abcd@123` (default password, specified in registry's application.yml/docker compose file) |

{% tabs %}
{% tab title="200: OK " %}

```json
{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...2cSSaBKuB58I2OYDGw",
	"expires_in": 300,
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...9HulwVv12bBDUdU_nidZXo",
	"scope": "email profile",
	"session_state": "300f8a46-e430-4fd6-92aa-a2d337d7343e",
	"token_type": "Bearer"
}
```

{% endtab %}
{% endtabs %}

Important variables in the response body:

| Field          | In   | Type     | Description                                                        |
| -------------- | ---- | -------- | ------------------------------------------------------------------ |
| `access_token` | body | `string` | Access token used to retrieve/update entity                        |
| `expires_in`   | body | `number` | Number of seconds before the access token will be declared invalid |
| `token_type`   | body | `string` | Should be `Bearer`, else we have gotten the wrong token            |
| `scope`        | body | `string` | Using this token, what information we can access about the entity  |

## Usage

### cURL

```
curl --location \
	--request POST \
	--header 'content-type: application/x-www-form-urlencoded' \
	--data 'client_id=registry-frontend' \
	--data 'username={username}' \
	--data 'password=test' \
	--data 'grant_type=password' \
	'{keycloak-url}/auth/realms/{realm}/protocol/openid-connect/token'
```

### HTTPie

```
http --form post \
	'{keycloak-url}/auth/realms/{realm}/protocol/openid-connect/token' \
	'content-type: application/x-www-form-urlencoded' \
	'client_id=registry-frontend' \
	'username={username}' \
	'password=test' \
	'grant_type=password'
```

> `{keycloak-url}` is usually <http://localhost:8080>, and `{realm}` is usually `sunbird-rc`.
>
> The `{keycloak-url}` is usually `localhost:{port}`. The port can be found under the `keycloak` section in the `docker-compose.yml` file. The `{realm}` can be found at the top of the `realm-export.json` file used to configure keycloak.

#### Steps to create a client with an admin role

* Goto keycloak admin page
* Goto `clients` section and click on `Add` button
* Give a new client id and click on the save button
* Update the `access type` to `confidential`.
* Turn on `Service Accounts Enabled` button.
* Add a `Valid Redirect Url` Ex: <http://localhost:8081/auth>
* And click on the save button
* Goto `Service Account Roles` tab
* Select `admin` role from the `Available Roles` and click on `Add selected`
* Goto `Credentials` section and click on `Regenerate secret` and copy the value

**Use the below API to get the token for the above client created**

## Generate token api

<mark style="color:green;">`POST`</mark> `http:/keycloak-url/auth/realms/{realm}/protocol/openid-connect/token`

#### Headers

| Name                                           | Type   | Description                       |
| ---------------------------------------------- | ------ | --------------------------------- |
| Content-Type<mark style="color:red;">\*</mark> | String | application/x-www-form-urlencoded |

#### Request Body

| Name                                             | Type   | Description                                                 |
| ------------------------------------------------ | ------ | ----------------------------------------------------------- |
| grant\_type<mark style="color:red;">\*</mark>    |        | client\_credentials                                         |
| client\_id<mark style="color:red;">\*</mark>     | String | Use the client name that was used above                     |
| client\_secret<mark style="color:red;">\*</mark> | String | Use the client secret that was generated in the above steps |

{% tabs %}
{% tab title="200: OK " %}

```json
{
	"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...2cSSaBKuB58I2OYDGw",
	"expires_in": 300,
	"not-before-policy": 0,
	"refresh_expires_in": 1800,
	"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lk...9HulwVv12bBDUdU_nidZXo",
	"scope": "email profile",
	"session_state": "300f8a46-e430-4fd6-92aa-a2d337d7343e",
	"token_type": "Bearer"
}
```

{% endtab %}
{% endtabs %}


# Get An Entity

To get an entity created by the owner, we need to make the following HTTP request

<mark style="color:blue;">`GET`</mark> `/api/v1/{entity-type}`

#### Path Parameters

| Name                                          | Type   | Description                    |
| --------------------------------------------- | ------ | ------------------------------ |
| entity-type<mark style="color:red;">\*</mark> | String | The type of entity to retrieve |

#### Headers

| Name                                            | Type   | Description                                                           |
| ----------------------------------------------- | ------ | --------------------------------------------------------------------- |
| authorization<mark style="color:red;">\*</mark> | String | Set to `Bearer {access-token}` A valid token of the owner is required |
| viewTemplateId                                  | String | File name of view templates configured                                |

{% tabs %}
{% tab title="200: OK Response when content-type is application/json" %}

```javascript
{
	"phoneNumber": "1234567890",
	"school": "UP Public School",
	"subject": "Math",
	"name": "Pranav Agate",
	"osid": "{id}",
	"osOwner": ["{owner-id}"],
	"_osState/school": "DRAFT"
}
```

{% endtab %}
{% endtabs %}


# Get An Entity By Id

To get an entity, we need to make the following HTTP request

<mark style="color:blue;">`GET`</mark> `/api/v1/{entity-type}/id`

#### Path Parameters

| Name                                          | Type   | Description                      |
| --------------------------------------------- | ------ | -------------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | The type of entity to retrieve   |
| id<mark style="color:red;">\*</mark>          | String | The ID of the entity to retrieve |

#### Headers

| Name                                            | Type   | Description                                                                                                                                                                  |
| ----------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| authorization<mark style="color:red;">\*</mark> | String | Set to `Bearer {access-token}` if roles in schema is not anonymous. Else authorization can be empty                                                                          |
| content-type<mark style="color:red;">\*</mark>  | String | Set to `application/json` to retrieve in json. Other allowed values include `application/vc+ld+json`, `application/ld+json`, `application/pdf`, `image/svg+xml`, `text/html` |
| template-key                                    | String | `template-key` is an optional header, it can be used for `pdf/html/svg` content type. It should be one of the keys mentioned in certificateTemplates in the schema config.   |
| template                                        | String | `template` is an optional header where we can pass the URL of the external template directly in the API. To use this `enable_external_templates` ENV needs to be enabled     |
| viewTemplateId                                  | String | File name of view templates configured                                                                                                                                       |

{% tabs %}
{% tab title="200: OK Response when content-type is application/json" %}

```javascript
{
	"phoneNumber": "1234567890",
	"school": "UP Public School",
	"subject": "Math",
	"name": "Pranav Agate",
	"osid": "{id}",
	"osOwner": ["{owner-id}"],
	"_osState/school": "DRAFT"
}
```

{% endtab %}
{% endtabs %}

Important variables in the response body:

| Field              | Type   | Description                                                                                                                                                                                                                            |
| ------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_osState/{field}` | String | State of an attestable field. Can be `DRAFT` (when it has not been sent for attestation), `ATTESTATION_REQUESTED` (when sent for attestation), `PUBLISHED` (when successfully attested) and `REJECTED` (when rejected by the attestor) |
| \_osOwner          | String | User ID of the entity in Keycloak.                                                                                                                                                                                                     |


# Update An Entity

To update an entity, we need to make the following HTTP request

## Updating an Entity

<mark style="color:orange;">`PUT`</mark> `/api/v1/{entity-type}/{id}`

#### Path Parameters

| Name                                          | Type   | Description                  |
| --------------------------------------------- | ------ | ---------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | The type of entity to modify |
| id<mark style="color:red;">\*</mark>          | String | The ID of entity to modify   |

#### Headers

| Name                                           | Type   | Description                                                                               |
| ---------------------------------------------- | ------ | ----------------------------------------------------------------------------------------- |
| authorization                                  | String | Set to Bearer {access-token} if roles in schema is not anonymous. Else token can be empty |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                 |

#### Request Body

| Name                                  | Type   | Description       |
| ------------------------------------- | ------ | ----------------- |
| ...<mark style="color:red;">\*</mark> | String | The entity's data |

{% tabs %}
{% tab title="200: OK Updated Entity Success Response" %}

```javascript
{
	"id": "sunbird-rc.registry.update",
	"ver": "1.0",
	"ets": 1634371946769,
	"params": {
		"resmsgid": "",
		"msgid": "d51e6e6a-027d-4a42-84bb-2ce00e31d993",
		"err": "",
		"status": "SUCCESSFUL",
		"errmsg": ""
	},
	"responseCode": "OK"
}
```

{% endtab %}
{% endtabs %}

## Usage

### cURL

```
curl --location \
	--request 'PUT' \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	--data-raw '{
		"phoneNumber": "1234567891",
		"school": "UP Public School",
		"subject": "Math",
		"name": "Pranav Agate",
	}' \
	'{registry-url}/api/v1/{entity-type}/{id}'
```

### HTTPie

```
printf '{
	"phoneNumber": "1234567891",
	"school": "UP Public School",
	"subject": "Math",
	"name": "Pranav Agate",
}' | http put \
	'{registry-url}/api/v1/{entity-type}/{id}' \
	'content-type: application/json' \
	'authorization: bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Create A Property Of An Entity

To add property to an existing entity, we need to make the following HTTP request

## Create a property in already existing entity

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-type}/{id}/{entity-property}`

#### Path Parameters

| Name                                              | Type   | Description                                                  |
| ------------------------------------------------- | ------ | ------------------------------------------------------------ |
| entity-type<mark style="color:red;">\*</mark>     | String | Type of entity to update                                     |
| id<mark style="color:red;">\*</mark>              | String | id of the entity to update                                   |
| entity-property<mark style="color:red;">\*</mark> | String | entity Property which to be added in already existing entity |

#### Headers

| Name                                           | Type   | Description                                                                                 |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------------------------------- |
| authorization                                  | String | Set to `Bearer {access-token}` if roles in Schema is not anonymous. Else token can be empty |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                   |

#### Request Body

| Name                                  | Type   | Description            |
| ------------------------------------- | ------ | ---------------------- |
| ...<mark style="color:red;">\*</mark> | Object | Property to be updated |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    "id": "sunbird-rc.registry.update",
    "ver": "1.0",
    "ets": 1669113170690,
    "params": {
        "resmsgid": "",
        "msgid": "85057df5-d4d6-4e7b-8bb1-a774f689e9c8",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK"
}
```

{% endtab %}
{% endtabs %}

## Usage

### cURL

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	--data-raw '{
		"city": "Ahmedabad"
	}' \
	'{registry-url}/api/v1/{entity-type}/{id}/{entity-property}'
```

### HTTPie

```
printf '{
		"city": "Ahmedabad"
	}' | http POST \
	'{registry-url}/api/v1/{entity-type}/{id}/{entity-property}' \
	'content-type: application/json' \
	'authorization: Bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Update A Property Of An Entity

To update the property of an existing entity, we need to make the following HTTP request

## Update a property which is already added to entity

<mark style="color:orange;">`PUT`</mark> `/api/v1/{entity-type}/{id}/{entity-property}/{property-id}`

#### Path Parameters

| Name                                              | Type   | Description                                                                        |
| ------------------------------------------------- | ------ | ---------------------------------------------------------------------------------- |
| entity-type<mark style="color:red;">\*</mark>     | String | Type of entity to update                                                           |
| id<mark style="color:red;">\*</mark>              | String | id of the entity to update                                                         |
| entity-property<mark style="color:red;">\*</mark> | String | entity Property which to be updated in already existing entity                     |
| property-id<mark style="color:red;">\*</mark>     | String | entity property osid which is to be updated in already existing property in entity |

#### Headers

| Name                                           | Type   | Description                                                                                 |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                   |
| authorization                                  | String | Set to `Bearer {access-token}` if roles in Schema is not anonymous. Else token can be empty |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    "id": "sunbird-rc.registry.update",
    "ver": "1.0",
    "ets": 1669113253859,
    "params": {
        "resmsgid": "",
        "msgid": "129c291e-f089-4052-811f-025330c9b239",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK"
}
```

{% endtab %}
{% endtabs %}

## Usage

### cURL

```
curl --location \
	--request 'POST' \
	--header 'content-type: application/json' \
	--header 'authorization: bearer {access-token}' \
	--data-raw '{
		"city": "Surat"
	}' \
	'{registry-url}/api/v1/{entity-type}/{id}/{entity-property}/{property-id}'
```

### HTTPie

```
printf '{
		"city": "Surat"
	}' | http POST \
	'/api/v1/{entity-type}/{id}/{entity-property}/{property-id}' \
	'content-type: application/json' \
	'authorization: Bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Revoke a Credential

To revoke an existing VC (Verifiable Credential) or an entity, we need to make the following HTTP request

## This revokes an existing  verifiable credential

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-type}/{id}/revoke`

The API revokes a verifiable credential by updating the signature data attached to it. This is done by updating the *\_osSignedData* field in the corresponding entity table to an *Empty String*. and storing the signedData in the **RevokedCredential** Registry.

#### Path Parameters

| Name                                          | Type   | Description                |
| --------------------------------------------- | ------ | -------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | Type of entity to update   |
| id<mark style="color:red;">\*</mark>          | String | id of the entity to revoke |

#### Headers

| Name                                           | Type   | Description                                                                                 |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------------------------------- |
| authorization                                  | String | Set to `Bearer {access-token}` if roles in Schema is not anonymous. Else token can be empty |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                   |

#### Request Body

| Name | Type   | Description |
| ---- | ------ | ----------- |
|      | String |             |

{% tabs %}
{% tab title="200: OK Entity is Succesfully revoked" %}

```json
{
    "id": "sunbird-rc.utils.revoke",
    "ver": "1.0",
    "ets": 1687421017075,
    "params": {
        "resmsgid": "",
        "msgid": "bbd1e0b7-aab4-4e91-988b-c832e9031bef",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK"
}
```

{% endtab %}

{% tab title="401: Unauthorized Issue in the token authentication - unauthorised" %}

{% endtab %}

{% tab title="500: Internal Server Error Credential is already revoked " %}

```json
revoked response: {
    "id": "sunbird-rc.utils.revoke",
    "ver": "1.0",
    "ets": 1687421091703,
    "params": {
        "resmsgid": "",
        "msgid": "70047a46-a0f1-453a-b6cf-c1cfe8e1a544",
        "err": "",
        "status": "UNSUCCESSFUL",
        "errmsg": "Credential is already revoked"
    },
    "responseCode": "OK"
}
```

{% endtab %}
{% endtabs %}

## Usage

### cURL

```
curl --location \
	--request POST \
	--header 'Content-Type: application/json' \
	--header 'Accept: application/json' \
	'{registry-url}/api/v1/{entity-type}/{id}/revoke' \


```

### HTTPie

```
http POST \
	'{registry_url}/api/v1/{entity-type}/{id}/revoke' \
	'content-type: application/json' \
	'authorization: Bearer {access-token}'
	
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Delete An Entity

To soft delete an entity, we need to make the following HTTP request

## Deleting an Entity

<mark style="color:red;">`DELETE`</mark> `/api/v1/{entity-type}/{id}`

#### Path Parameters

| Name                                          | Type   | Description                  |
| --------------------------------------------- | ------ | ---------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | The type of entity to modify |
| entity-id<mark style="color:red;">\*</mark>   | String | The ID of entity to modify   |

#### Headers

| Name                                           | Type   | Description                                                                               |
| ---------------------------------------------- | ------ | ----------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                 |
| authorization                                  | String | Set to Bearer {access-token} if roles in Schema is not anonymous. Else token can be empty |

{% tabs %}
{% tab title="200: OK Entity Deleted Success Response" %}

```javascript
```

{% endtab %}
{% endtabs %}

## Usage

**cURL**

```
curl --location \
	 --request 'DELETE' \
	 --header 'content-type: application/json' \
	 --header 'authorization: Bearer {access-token}' \
	 '{registry-url}/api/v1/Teacher/{id}'
```

**HTTPie**

```
http DELETE \
	'{registry_url}/api/v1/Teacher/{id}' \
	'content-type: application/json' \
	'authorization: Bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/registry/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Schema

This Section describes about CRUD operations on schema and how to publish the schema.\
Following are the APIs which enables the operations on Schema


# Create Schema

## Request

## Create a Schema

<mark style="color:green;">`POST`</mark> `/api/v1/Schema`

#### Headers

| Name                                           | Type   | Description                                                        |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                          |
| authorization                                  | String | Set to `Bearer {access-token}` . The token should be a admin token |

#### Request Body

| Name                                     | Type   | Description        |
| ---------------------------------------- | ------ | ------------------ |
| name<mark style="color:red;">\*</mark>   | string | schema name        |
| schema<mark style="color:red;">\*</mark> | string | json schema        |
| status                                   | String | DRAFT \| PUBLISHED |

{% tabs %}
{% tab title="200: OK Success Response of entity Created" %}

```javascript
{
    "id": "sunbird-rc.registry.create",
    "ver": "1.0",
    "ets": 1669113026569,
    "params": {
        "resmsgid": "",
        "msgid": "7b15f6ee-eb5b-4a13-ba79-f70b3ab54fc3",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK",
    "result": {
        "Schema": {
            "osid": "1-1a2f15e7-6c54-40e9-a689-68628a3d69df"
        }
    }
}
```

{% endtab %}
{% endtabs %}

Sample Schema Request Payload

```json
{
  "name": "{schema-name}",
  "schema": "{   \"$schema\": \"http://json-schema.org/draft-07/schema\",   \"type\": \"object\",   \"properties\": {      \"Place\": {         \"$ref\": \"#/definitions/Place\"      }   },   \"required\": [      \"Place\"   ],   \"title\": \"Place\",   \"definitions\": {      \"Place\": {         \"$id\": \"#/properties/Place\",         \"type\": \"object\",         \"title\": \"The Place Schema\",         \"required\": [            \"name\",            \"city\"],         \"properties\": {            \"name\": {               \"type\": \"string\"            },            \"city\": {               \"type\": \"string\"            }},   \"_osConfig\": {      \"privateFields\": [         \"name\"      ],      \"signedFields\": [],      \"roles\": [         \"anonymous\"      ],      \"ownershipAttributes\": [],      \"attestationPolicies\": [         {            \"name\": \"schemaAttestation\",            \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\",            \"type\": \"MANUAL\",            \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\",            \"attestationProperties\": {}         }      ],      \"credentialTemplate\": {         \"@context\": [            \"https://www.w3.org/2018/credentials/v1\",            \"{someUrlForTemplate}\"         ],         \"type\": [            \"VerifiableCredential\",            \"{TypeOfCertificate}\"         ],         \"issuer\": \"{issuerName}\",         \"issuanceDate\": \"{issuanceDate}\",         \"credentialSubject\": {            \"type\": \"Place\",            \"name\": \"{name}\"},         \"evidence\": {            \"type\": \"{SomeType}\"}},      \"certificateTemplates\": {        \"html\": \"{templateUrl}\"      }   }}}}"
}
```

Important Fields in Response Body

| Field                  | Type     | Description                                                                                     |
| ---------------------- | -------- | ----------------------------------------------------------------------------------------------- |
| `result.{Schema}.osid` | `string` | The ID of the created schema in the registry, used for retrieval and modification of the entity |

### Usage

#### cURL

```shell
curl --location --request POST '{registry-url}/api/v1/Schema' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "{schema-name}",
  "schema": "{   \"$schema\": \"http://json-schema.org/draft-07/schema\",   \"type\": \"object\",   \"properties\": {      \"Place\": {         \"$ref\": \"#/definitions/Place\"      }   },   \"required\": [      \"Place\"   ],   \"title\": \"Place\",   \"definitions\": {      \"Place\": {         \"$id\": \"#/properties/Place\",         \"type\": \"object\",         \"title\": \"The Place Schema\",         \"required\": [            \"name\",            \"city\"],         \"properties\": {            \"name\": {               \"type\": \"string\"            },            \"city\": {               \"type\": \"string\"            }},   \"_osConfig\": {      \"privateFields\": [         \"name\"      ],      \"signedFields\": [],      \"roles\": [         \"anonymous\"      ],      \"ownershipAttributes\": [],      \"attestationPolicies\": [         {            \"name\": \"schemaAttestation\",            \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\",            \"type\": \"MANUAL\",            \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\",            \"attestationProperties\": {}         }      ],      \"credentialTemplate\": {         \"@context\": [            \"https://www.w3.org/2018/credentials/v1\",            \"{someUrlForTemplate}\"         ],         \"type\": [            \"VerifiableCredential\",            \"{TypeOfCertificate}\"         ],         \"issuer\": \"{issuerName}\",         \"issuanceDate\": \"{issuanceDate}\",         \"credentialSubject\": {            \"type\": \"Place\",            \"name\": \"{name}\"},         \"evidence\": {            \"type\": \"{SomeType}\"}},      \"certificateTemplates\": {        \"html\": \"{templateUrl}\"      }   }}}}"
}'
```

#### HTTPie

```
printf '{
  "name": "{schema-name}",
  "schema": "{   \"$schema\": \"http://json-schema.org/draft-07/schema\",   \"type\": \"object\",   \"properties\": {      \"Place\": {         \"$ref\": \"#/definitions/Place\"      }   },   \"required\": [      \"Place\"   ],   \"title\": \"Place\",   \"definitions\": {      \"Place\": {         \"$id\": \"#/properties/Place\",         \"type\": \"object\",         \"title\": \"The Place Schema\",         \"required\": [            \"name\",            \"city\"],         \"properties\": {            \"name\": {               \"type\": \"string\"            },            \"city\": {               \"type\": \"string\"            }},   \"_osConfig\": {      \"privateFields\": [         \"name\"      ],      \"signedFields\": [],      \"roles\": [         \"anonymous\"      ],      \"ownershipAttributes\": [],      \"attestationPolicies\": [         {            \"name\": \"schemaAttestation\",            \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\",            \"type\": \"MANUAL\",            \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\",            \"attestationProperties\": {}         }      ],      \"credentialTemplate\": {         \"@context\": [            \"https://www.w3.org/2018/credentials/v1\",            \"{someUrlForTemplate}\"         ],         \"type\": [            \"VerifiableCredential\",            \"{TypeOfCertificate}\"         ],         \"issuer\": \"{issuerName}\",         \"issuanceDate\": \"{issuanceDate}\",         \"credentialSubject\": {            \"type\": \"Place\",            \"name\": \"{name}\"},         \"evidence\": {            \"type\": \"{SomeType}\"}},      \"certificateTemplates\": {        \"html\": \"{templateUrl}\"      }   }}}}"
}'| http  POST '{registry-url}/api/v1/Schema' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/schema/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Get Schema

## Request

## Fetch a Schema

<mark style="color:blue;">`GET`</mark> `/api/v1/Schema/{id}`

#### Path Parameters

| Name                                 | Type   | Description                |
| ------------------------------------ | ------ | -------------------------- |
| id<mark style="color:red;">\*</mark> | String | ID of Schema to be fetched |

#### Headers

| Name                                           | Type   | Description                                                        |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                          |
| authorization                                  | String | Set to `Bearer {access-token}` . The token should be a admin token |

{% tabs %}
{% tab title="200: OK Success Response" %}

```javascript
{
    "schema": "...",
    "osUpdatedAt": "2022-11-22T10:30:27.602Z",
    "osCreatedAt": "2022-11-22T10:30:27.602Z",
    "osUpdatedBy": "0eaf6099-9591-42bb-ac5a-21bbc2b47493",
    "name": "schema",
    "osCreatedBy": "0eaf6099-9591-42bb-ac5a-21bbc2b47493",
    "osid": "1-1a2f15e7-6c54-40e9-a689-68628a3d69df",
    "osOwner": [
        "0eaf6099-9591-42bb-ac5a-21bbc2b47493"
    ],
    "status": "{schemaStatus}"
}
```

{% endtab %}
{% endtabs %}

### Usage

#### cURL

```shell
curl --location --request GET '{registry-url}/api/v1/Schema/{id}' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json'
```

#### HTTPie

```
http  GET '{registry-url}/api/v1/Schema/{id}' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/schema/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Update Schema

## Request

## Create a Schema

<mark style="color:orange;">`PUT`</mark> `/api/v1/Schema/{id}`

#### Path Parameters

| Name                                 | Type   | Description                            |
| ------------------------------------ | ------ | -------------------------------------- |
| id<mark style="color:red;">\*</mark> | String | id of the schema that is to be updated |

#### Headers

| Name                                           | Type   | Description                                                        |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                          |
| authorization                                  | String | Set to `Bearer {access-token}` . The token should be a admin token |

#### Request Body

| Name                                  | Type | Description       |
| ------------------------------------- | ---- | ----------------- |
| ...<mark style="color:red;">\*</mark> |      | The entity's data |

{% tabs %}
{% tab title="200: OK Success Response of Updated Schema" %}

```javascript
{
    "id": "sunbird-rc.registry.update",
    "ver": "1.0",
    "ets": 1669117705369,
    "params": {
        "resmsgid": "",
        "msgid": "2ff44354-bb9a-4dce-93ba-053f97587df6",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK"
}
```

{% endtab %}
{% endtabs %}

Sample Schema Request Payload

```json
{
  "schema": "{   \"$schema\": \"http://json-schema.org/draft-07/schema\",   \"type\": \"object\",   \"properties\": {      \"Place\": {         \"$ref\": \"#/definitions/Place\"      }   },   \"required\": [      \"Place\"   ],   \"title\": \"Place\",   \"definitions\": {      \"Place\": {         \"$id\": \"#/properties/Place\",         \"type\": \"object\",         \"title\": \"The Place Schema\",         \"required\": [            \"name\",            \"city\"],         \"properties\": {            \"name\": {               \"type\": \"string\"            },            \"city\": {               \"type\": \"string\"            }},   \"_osConfig\": {      \"privateFields\": [         \"name\"      ],      \"signedFields\": [],      \"roles\": [         \"anonymous\"      ],      \"ownershipAttributes\": [],      \"attestationPolicies\": [         {            \"name\": \"schemaAttestation\",            \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\",            \"type\": \"MANUAL\",            \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\",            \"attestationProperties\": {}         }      ],      \"credentialTemplate\": {         \"@context\": [            \"https://www.w3.org/2018/credentials/v1\",            \"{someUrlForTemplate}\"         ],         \"type\": [            \"VerifiableCredential\",            \"{TypeOfCertificate}\"         ],         \"issuer\": \"{issuerName}\",         \"issuanceDate\": \"{issuanceDate}\",         \"credentialSubject\": {            \"type\": \"Place\",            \"name\": \"{name}\"},         \"evidence\": {            \"type\": \"{SomeType}\"}},      \"certificateTemplates\": {        \"html\": \"{templateUrl}\"      }   }}}}"
}
```

### Usage

#### cURL

```shell
curl --location --request PUT '{registry-url}/api/v1/Schema/{id}' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json' \
--data-raw '{
  "schema": "{   \"$schema\": \"http://json-schema.org/draft-07/schema\",   \"type\": \"object\",   \"properties\": {      \"Place\": {         \"$ref\": \"#/definitions/Place\"      }   },   \"required\": [      \"Place\"   ],   \"title\": \"Place\",   \"definitions\": {      \"Place\": {         \"$id\": \"#/properties/Place\",         \"type\": \"object\",         \"title\": \"The Place Schema\",         \"required\": [            \"name\",            \"city\"],         \"properties\": {            \"name\": {               \"type\": \"string\"            },            \"city\": {               \"type\": \"string\"            }},   \"_osConfig\": {      \"privateFields\": [         \"name\"      ],      \"signedFields\": [],      \"roles\": [         \"anonymous\"      ],      \"ownershipAttributes\": [],      \"attestationPolicies\": [         {            \"name\": \"schemaAttestation\",            \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\",            \"type\": \"MANUAL\",            \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\",            \"attestationProperties\": {}         }      ],      \"credentialTemplate\": {         \"@context\": [            \"https://www.w3.org/2018/credentials/v1\",            \"{someUrlForTemplate}\"         ],         \"type\": [            \"VerifiableCredential\",            \"{TypeOfCertificate}\"         ],         \"issuer\": \"{issuerName}\",         \"issuanceDate\": \"{issuanceDate}\",         \"credentialSubject\": {            \"type\": \"Place\",            \"name\": \"{name}\"},         \"evidence\": {            \"type\": \"{SomeType}\"}},      \"certificateTemplates\": {        \"html\": \"{templateUrl}\"      }   }}}}"
}'
```

#### HTTPie

```
printf '{
  "schema": "{   \"$schema\": \"http://json-schema.org/draft-07/schema\",   \"type\": \"object\",   \"properties\": {      \"Place\": {         \"$ref\": \"#/definitions/Place\"      }   },   \"required\": [      \"Place\"   ],   \"title\": \"Place\",   \"definitions\": {      \"Place\": {         \"$id\": \"#/properties/Place\",         \"type\": \"object\",         \"title\": \"The Place Schema\",         \"required\": [            \"name\",            \"city\"],         \"properties\": {            \"name\": {               \"type\": \"string\"            },            \"city\": {               \"type\": \"string\"            }},   \"_osConfig\": {      \"privateFields\": [         \"name\"      ],      \"signedFields\": [],      \"roles\": [         \"anonymous\"      ],      \"ownershipAttributes\": [],      \"attestationPolicies\": [         {            \"name\": \"schemaAttestation\",            \"conditions\": \"(ATTESTOR#$.[*]#.contains('board-cbse'))\",            \"type\": \"MANUAL\",            \"attestorPlugin\": \"did:internal:ClaimPluginActor?entity=board-cbse\",            \"attestationProperties\": {}         }      ],      \"credentialTemplate\": {         \"@context\": [            \"https://www.w3.org/2018/credentials/v1\",            \"{someUrlForTemplate}\"         ],         \"type\": [            \"VerifiableCredential\",            \"{TypeOfCertificate}\"         ],         \"issuer\": \"{issuerName}\",         \"issuanceDate\": \"{issuanceDate}\",         \"credentialSubject\": {            \"type\": \"Place\",            \"name\": \"{name}\"},         \"evidence\": {            \"type\": \"{SomeType}\"}},      \"certificateTemplates\": {        \"html\": \"{templateUrl}\"      }   }}}}"
}'| http  PUT '{registry-url}/api/v1/Schema' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/schema/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Delete Schema

## Request

## Delete a Schema

<mark style="color:red;">`DELETE`</mark> `/api/v1/Schema/{id}`

#### Path Parameters

| Name                                 | Type   | Description                |
| ------------------------------------ | ------ | -------------------------- |
| id<mark style="color:red;">\*</mark> | String | ID of Schema to be fetched |

#### Headers

| Name                                           | Type   | Description                                                        |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                          |
| authorization                                  | String | Set to `Bearer {access-token}` . The token should be a admin token |

{% tabs %}
{% tab title="200: OK Success Response" %}

```javascript
{
    "schema": "...",
    "osUpdatedAt": "2022-11-22T10:30:27.602Z",
    "osCreatedAt": "2022-11-22T10:30:27.602Z",
    "osUpdatedBy": "0eaf6099-9591-42bb-ac5a-21bbc2b47493",
    "name": "schema",
    "osCreatedBy": "0eaf6099-9591-42bb-ac5a-21bbc2b47493",
    "osid": "1-1a2f15e7-6c54-40e9-a689-68628a3d69df",
    "osOwner": [
        "0eaf6099-9591-42bb-ac5a-21bbc2b47493"
    ],
    "status": "{schemaStatus}"
}
```

{% endtab %}
{% endtabs %}

### Usage

#### cURL

```shell
curl --location --request DELETE '{registry-url}/api/v1/Schema/{id}' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json'
```

#### HTTPie

```
http  DELETE '{registry-url}/api/v1/Schema/{id}' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/schema/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Publish A Schema

## Request

## Publish a Schema

<mark style="color:orange;">`PUT`</mark> `/api/v1/Schema/{id}`

#### Path Parameters

| Name                                 | Type   | Description                              |
| ------------------------------------ | ------ | ---------------------------------------- |
| id<mark style="color:red;">\*</mark> | String | id of the schema that is to be published |

#### Headers

| Name                                           | Type   | Description                                                        |
| ---------------------------------------------- | ------ | ------------------------------------------------------------------ |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                          |
| authorization                                  | String | Set to `Bearer {access-token}` . The token should be a admin token |

#### Request Body

| Name                                     | Type | Description |
| ---------------------------------------- | ---- | ----------- |
| status<mark style="color:red;">\*</mark> |      | PUBLISHED   |

{% tabs %}
{% tab title="200: OK Success Response of Published Schema" %}

```javascript
{
    "id": "sunbird-rc.registry.update",
    "ver": "1.0",
    "ets": 1669117705369,
    "params": {
        "resmsgid": "",
        "msgid": "2ff44354-bb9a-4dce-93ba-053f97587df6",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK"
}
```

{% endtab %}
{% endtabs %}

Sample Schema Request Payload

```json
{
  "status": "PUBLISHED"
}
```

### Usage

#### cURL

```shell
curl --location --request PUT '{registry-url}/api/v1/Schema/{id}' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json' \
--data-raw '{
  "status": "PUBLISHED"
}'
```

#### HTTPie

```
printf '{
  "status": "PUBLISHED"
}'| http  PUT '{registry-url}/api/v1/Schema' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/schema/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Attestation API

Attestation APIs allow us to raise an attestation for certain fields. These attestation will be sent to certain entity who then can approve/reject. This attested entity can then retrieve a document in **`VC/PDF/HTML/SVG`** format\
In the following subpages, we will see APIs that will help us in achieving the same.


# Raise An Attestation

## Making a Claim

<mark style="color:green;">`POST`</mark> `/api/v1/send`

#### Headers

| Name                                           | Type   | Description                                                                                                                              |
| ---------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                                                                |
| authorization                                  | String | Set to `Bearer {access-token}` if roles in schema of which attestation is to raised does not contain `anonymous` else token can be empty |

#### Request Body

| Name                                  | Type   | Description            |
| ------------------------------------- | ------ | ---------------------- |
| ...<mark style="color:red;">\*</mark> | Object | The value of the claim |

{% tabs %}
{% tab title="200: OK Success Response of attestation sent" %}

```json
{
    "id": "sunbird-rc.registry.send",
    "ver": "1.0",
    "ets": 1668756344546,
    "params": {
        "resmsgid": "",
        "msgid": "d1ff3fa8-fac8-4b4b-a2a9-6910d395bfde",
        "err": "",
        "status": "SUCCESSFUL",
        "errmsg": ""
    },
    "responseCode": "OK",
    "result": {
        "attestationOSID": "1-c809dccf-4d93-453f-a110-d04443f5d679"
    }
}
```

{% endtab %}
{% endtabs %}

Sample Request Body

```json
{
  "entityName": "Teacher",
  "entityId": "{id}",
  "name": "schoolAffiliation" // attestation name
   "propertiesOSID": { // OSIDs of properties to be attested
   }
}
```

\
\
If you retrieve the entity by the [Retrieve Entity API Endpoint](https://github.com/Sunbird-RC/community/blob/v1.0.0/api-reference/attestation-api/broken-reference/README.md), you can see the `id` field in `osid`

### Usage

#### cURL

```shell
curl --location --request POST '{registry-url}/api/v1/send' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json' \
--data-raw '{
  "entityName": "Teacher",
  "entityId": "{id}",
  "name": "schoolAffiliation"
}'
```

#### HTTPie

```shell
printf '{
  "entityName": "Teacher",
  "entityId": "{id}",
  "name": "schoolAffiliation"
}'| http POST '{registry-url}/api/v1/send' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json' \
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/attestation-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Get Attestation Certificate

## Retrieve Attestation Certificate

<mark style="color:blue;">`GET`</mark> `/api/v1/{entity-type}/{entity-id}/attestation/{attestation-name}/{attestation-id}`

#### Path Parameters

| Name                                               | Type   | Description                                     |
| -------------------------------------------------- | ------ | ----------------------------------------------- |
| entity-name<mark style="color:red;">\*</mark>      | String | Name of Entity for which attestation was raised |
| entity-id<mark style="color:red;">\*</mark>        | String | ID of entity for which attestation was raised   |
| attestation-name<mark style="color:red;">\*</mark> | String | Name of attestation for that entity-type        |
| attestation-id<mark style="color:red;">\*</mark>   | String | ID of the attestation for that record of entity |

#### Headers

| Name                                     | Type   | Description                                                                                         |
| ---------------------------------------- | ------ | --------------------------------------------------------------------------------------------------- |
| accept<mark style="color:red;">\*</mark> | String | Set to `application/pdf, application/json, text/html, image/svg+xml`                                |
| template                                 | String | if `enable_external_templates` is set to true, send in a url which has html template                |
| template-key                             | String | A key pointing to html template which is present in `Schema`                                        |
| access-token                             | String | Set to `Bearer {access-token}` if roles in schema is not anonymous. Else authorization can be empty |

{% tabs %}
{% tab title="200: OK Successful retrieval of certification" %}

```markup
PDF File
```

{% endtab %}
{% endtabs %}

### Usage

### cURL

```shell
curl --location --request GET '{registry-url}/api/v1/{entity-type}/{entity-id}/attestation/{attestation-name}/{attestation-id}' \
--header 'Accept: application/pdf' \
--header 'template: {url}' \
--header 'Authorization: Bearer {access-token}'
```

### HTTPie

```shell
http GET '{registry-url}/api/v1/{entity-type}/{entity-id}/attestation/{attestation-name}/{attestation-id}' \
 Accept:'application/pdf' \
 template:'{url}' \
 Authorization:'Bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/attestation-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Claims API

Claims API allow retrieve all the claims and attest a particular claim. In the following subpages, we will have a look at these APIs


# Get All Claims

<mark style="color:blue;">`GET`</mark> `/api/v1/{entity-name}/claims`

#### Path Parameters

| Name                                          | Type   | Description                                              |
| --------------------------------------------- | ------ | -------------------------------------------------------- |
| entity-name<mark style="color:red;">\*</mark> | String | Name of the entity to which attestation request was sent |

#### Query Parameters

| Name | Type   | Description                                      |
| ---- | ------ | ------------------------------------------------ |
| page | String | Page no if you want response in pagenated format |
| size | String | Maximum claims claims to be returned in one page |

#### Headers

| Name                                           | Type   | Description                                                                                        |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                          |
| authorization                                  | String | Set to `Bearer {access-token}` if `roles` in schema config is not anonymous else this can be empty |

{% tabs %}
{% tab title="200: OK " %}

```javascript
{
    "totalPages": "",
    "content": [
        {
            "id": "{claimId}",
            "entity": "{entityName",
            "entityId": "{entityId}",
            "status": "OPEN",
            "attestationId": "{attestationID}",
            "attestationName": "{attestationName}",
            "closed": false
            ...
        }
    ]
    "totalElements": ""
}
```

{% endtab %}
{% endtabs %}

### Usage

#### cURL

```shell
curl --location --request GET '{registry-url}/api/v1/{entity-name}/claims?page=1&size=10' \
--header 'Authorization: Bearer {access-token}'
```

#### HTTPie

```shell
http GET '{registry-url}/api/v1/{entity-name}/claims?page=1&size=10' \
 Authorization:'Bearer {access-token}' \
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/claims-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Get Claim by ID

<mark style="color:blue;">`GET`</mark> `/api/v1/{entity-name}/claims/{claimId}`

#### Path Parameters

| Name                                          | Type   | Description                                              |
| --------------------------------------------- | ------ | -------------------------------------------------------- |
| entity-name<mark style="color:red;">\*</mark> | String | Name of the entity to which attestation request was sent |
| claimId<mark style="color:red;">\*</mark>     | String | ID of the claim to be returned                           |

#### Headers

| Name                                           | Type   | Description                                                                                        |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json`                                                                          |
| authorization                                  | String | Set to `Bearer {access-token}` if `roles` in schema config is not anonymous else this can be empty |

{% tabs %}
{% tab title="200: OK " %}

```json
{
    "id": "{claimId}",
    "entity": "{entityName",
    "entityId": "{entityId}",
    "status": "OPEN",
    "attestationId": "{attestationID}",
    "attestationName": "{attestationName}",
    "closed": false        
}
```

{% endtab %}
{% endtabs %}

### Usage

#### cURL

```shell
curl --location --request GET '{registry-url}/api/v1/{entity-name}/claims/{claimId}' \
--header 'Authorization: Bearer {access-token}'
```

#### HTTPie

```shell
http GET '{registry-url}/api/v1/{entity-name}/claims/{claimId}' \
 Authorization:'Bearer {access-token}'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/claims-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Attest A Claim

## Attest a particular claim

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-type}/claims/{claimId}/attest`

#### Path Parameters

| Name                                          | Type   | Description                            |
| --------------------------------------------- | ------ | -------------------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | Type of entity to which claim was sent |
| claimId<mark style="color:red;">\*</mark>     | String | ID of claim that is to be attested     |

#### Headers

| Name                                            | Type   | Description                                                                                |
| ----------------------------------------------- | ------ | ------------------------------------------------------------------------------------------ |
| authorization<mark style="color:red;">\*</mark> | String | Set to `Bearer {access-token}`. `access-token` should have a role with name as entity-type |
| content-type<mark style="color:red;">\*</mark>  | String | Set to `application/json`                                                                  |

#### Request Body

| Name | Type   | Description                                               |
| ---- | ------ | --------------------------------------------------------- |
| {    | String | action type can be either `GRANT_CLAIM` or `REJECT_CLAIM` |

### Usage

#### cURL

```shell
curl --location --request POST '{registry-url}/api/v1/{entity-type}/claims/a52708f8-c06f-4df7-a078-d567ec769637/attest' \
--header 'Authorization: Bearer {access-token}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "action":"GRANT_CLAIM"
}'
```

#### HTTPie

```shell
printf '{
    "action":"GRANT_CLAIM"
}'| http POST '{registry-url}/api/v1/{entity-type}/claims/a52708f8-c06f-4df7-a078-d567ec769637/attest' \
 Authorization:'Bearer {access-token}' \
 Content-Type:'application/json'
```

`{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/claims-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`


# Discovery API

Discovery API allow us to search for particular entity. In the following subpages, We will see the API that allow us to discover entities.


# Search An Entity

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-name}/search`

#### Path Parameters

| Name                                          | Type   | Description                       |
| --------------------------------------------- | ------ | --------------------------------- |
| entity-name<mark style="color:red;">\*</mark> | String | Name of the entity to be searched |

#### Headers

| Name                                           | Type   | Description               |
| ---------------------------------------------- | ------ | ------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `application/json` |

#### Request Body

| Name                                  | Type   | Description                                       |
| ------------------------------------- | ------ | ------------------------------------------------- |
| ...<mark style="color:red;">\*</mark> | Object | Filters to be sent in order to identify an entity |

{% tabs %}
{% tab title="200: OK Success Response of Search" %}

```javascript
[
    {
        "school": "UP Public School",
        "name": "Pranav Agate",
        "contact": "1234567890",
        "subject": "Math",
        "osid": "{id}",
        "osOwner": ["{osOwner}"]
    }
]
```

{% endtab %}
{% endtabs %}

Sample Request Body

> {\
> "filters": {\
> "school": {\
> "eq": "UP Public School"\
> }\
> },\
> "limit": 1,\
> "offset": 0\
> }

> Important Fields in Request Body

| Field            | Type   | Description                                                                                                                                                             |
| ---------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| limit            | Number | Number of responses to be retrieved out of total number of search results                                                                                               |
| offset           | Number | Starting point for responses to be returned                                                                                                                             |
| viewTemplateId   | String | Any operation to be carried on the response before it is returned via API, that can be provided here. For eg: Combining First Name and Last Name into Single Field Name |
| Filter Operators | String | eq, neq, gte, gt, lte, lt, contains, notContains, between, or, startsWith, notStartsWith, endsWith, notEndsWith, queryString are some of the operators provided         |

### Usage

### cURL

```
curl --location \
    --request POST \
    --header 'Content-Type: application/json' \
    '{registry-url}/api/v1/Place/search' \
    --data-raw '{
        "filters": {
            "name": {
                "eq": "UP Public School"
            }
        },
        "limit": 1,
        "offset": 0
    }'
```

### HTTPie

```
printf '{
    "filters": {
        "school": {
            "eq": "UP Public School"
        }
    },
    "limit": 1,
    "offset": 0
}'| http POST '{registry-url}/api/v1/Place/search' \
 Content-Type:'application/json' \
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/discovery-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# File Storage API

File Storage APIs allow to upload a file to server and use it as and when needed. For this, we use [minio](https://min.io/) to store the files\
\
In the following subpages, we will see APIs to upload and retrieve files using registry. minio should be enabled to use these APIs


# Upload A File

<mark style="color:green;">`POST`</mark> `/api/v1/{entity-type}/{entity-id}/{property}/documents`

#### Path Parameters

| Name                                          | Type   | Description                                         |
| --------------------------------------------- | ------ | --------------------------------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | Entity type for which the template will be uploaded |
| entity-id<mark style="color:red;">\*</mark>   | String | Entity ID for mentioned Entity Type                 |

#### Headers

| Name                                           | Type   | Description                                                                                        |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark> | String | Set to `multipart/form-data`                                                                       |
| authorization                                  | String | Set to `Bearer {access-token}` if `roles` in schema config is not anonymous else this can be empty |

#### Request Body

| Name                                    | Type   | Description                                                                                                              |
| --------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ |
| files<mark style="color:red;">\*</mark> | Object | `files` is template-key which can be replaced with your choice. Requires a `html file` to be sent which will be uploaded |

{% tabs %}
{% tab title="200: OK Success Response of File uploaded" %}

```javascript
{
    "documentLocations": [
        "{url}"
    ],
    "errors": []
}
```

{% endtab %}
{% endtabs %}

## Usage

### cURL

```
curl --location \
    --header 'Authorization: {access-token}' \
    --form 'files=@"{file-path}"'
    --request POST 
    '{registry-url}/api/v1/{entity-type}/{entity-id}/{property}/documents' \
```

### HTTPie

```
http --ignore-stdin \
    --form POST \
    '{registry-url}/api/v1/{entity-type}/{entity-id}/{property}/documents' \
 'files'@{file-path} \
 Authorization:'Bearer {access-token}' \
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/file-storage-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Get Uploaded File

<mark style="color:blue;">`GET`</mark> `/api/v1/{entity-type}/{entity-id}/{property}/documents/{document-id}`

#### Path Parameters

| Name                                          | Type   | Description                                             |
| --------------------------------------------- | ------ | ------------------------------------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | Entity for which file was uploaded                      |
| entity-id<mark style="color:red;">\*</mark>   | String | Entity ID of corresponding entity                       |
| property<mark style="color:red;">\*</mark>    | String | any String for eg templates for uploading html template |
| document-id<mark style="color:red;">\*</mark> | String | ID of document that was uploaded                        |

#### Headers

| Name                                            | Type   | Description                                                                                        |
| ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------- |
| content-type<mark style="color:red;">\*</mark>  | String | Set to `application/octet-stream`                                                                  |
| authorization<mark style="color:red;">\*</mark> | String | Set to `Bearer {access-token}` if `roles` in schema config is not anonymous else this can be empty |

{% tabs %}
{% tab title="200: OK Success response of uploaded file" %}

```javascript
{file contents that was uploaded}
```

{% endtab %}
{% endtabs %}

## Usage

### cURL

```shell
curl --location \
    --request GET '{registry-url}/api/v1/{entity-type/{entity-id}/{property}/documents/{document-id}' \
    --header 'Authorization: Bearer {access-token}'
```

### HTTPie

```shell
http '{registry-url}/api/v1/{entity-type/{entity-id}/{property}/documents/{document-id}' \
 Authorization:'Bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/file-storage-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Delete A File/ Multiple Files

<mark style="color:red;">`DELETE`</mark> `/api/v1/{entity-type}/{entity-id}/{property}/documents/{document-id}`

#### Path Parameters

| Name                                          | Type   | Description                                                                                                            |
| --------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- |
| entity-type<mark style="color:red;">\*</mark> | String | Entity type for which the template will be uploaded                                                                    |
| entity-id<mark style="color:red;">\*</mark>   | String | Entity ID for mentioned Entity Type                                                                                    |
| property<mark style="color:red;">\*</mark>    | String | any String for eg templates for uploading html template                                                                |
| document-id                                   | String | ID of document that was uploaded. If this is not provided, entire directory that holds any no of files will be deleted |

#### Headers

| Name          | Type   | Description                                                                                         |
| ------------- | ------ | --------------------------------------------------------------------------------------------------- |
| authorization | String | Set to `Bearer {access-token}` if roles in schema is not anonymous. Else authorization can be empty |

{% tabs %}
{% tab title="200: OK Success in deleting a/multiple files" %}

```javascript
```

{% endtab %}
{% endtabs %}

### Usage

### cURL

```shell
curl --location \
    --request DELETE '{registry-url}/api/v1/{entity-type/{entity-id}/{property}/documents/{document-id}' \
    --header 'Authorization: Bearer {access-token}'
```

### HTTPie

```shell
http DELETE '{registry-url}/api/v1/{entity-type/{entity-id}/{property}/documents/{document-id}' \
 Authorization:'Bearer {access-token}'
```

> `{registry-url}` is usually [http://localhost:{port}](https://rc.sunbird.org/v1.0.0/api-reference/file-storage-api/http:/localhost:{port}). The port can be found under the `registry` section in the `docker-compose.yml` file and is usually `8081`.


# Bulk Issuance API

Bulk issuance API allows you to upload a CSV file to create multiple Entities in a single go


# Get Sample Template

<mark style="color:blue;">`GET`</mark> `/bulk/v1/{schemaName}/sample-csv`

this will download a csv with the all fields that are needed to create entity for this schema

#### Path Parameters

| Name                                         | Type   | Description    |
| -------------------------------------------- | ------ | -------------- |
| schemaName<mark style="color:red;">\*</mark> | String | name of schema |

#### Headers

| Name          | Type   | Description                                                                                                                                                                                                                                                                           |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Authorization | String | <p>Set to <code>Bearer {access-token}</code> if roles in schema is not anonymous. Else authorization can be empty<br>\* make sure ROLES env property has this role <a data-mention href="/pages/3ZoyCMNqTJWXDJrIp6eJ#bulk-issuance">/pages/3ZoyCMNqTJWXDJrIp6eJ#bulk-issuance</a></p> |

{% tabs %}
{% tab title="200: OK A CSV File with fields for header" %}

{% endtab %}

{% tab title="403: Forbidden if the token is expired or you do not have appropriate permission to create entity" %}

{% endtab %}

{% tab title="404: Not Found If schema is not found in the system" %}

{% endtab %}
{% endtabs %}




---

[Next Page](/llms-full.txt/1)

