Challenge Overview
CHALLENGE OBJECTIVES
-
Build the SMS, Email and OTP microservices.
TECHNOLOGY STACK
-
Java 11
-
Spring 5.2.8
-
Spring Boot 2.3.3
-
Spring Security 5.3.5
-
Spring GCP Cloud
-
Istio (Discovery Service)
-
APIGEE
-
Log4j/Slf4j
-
JSON (gzipped)
-
REST
-
Microservices
-
Docker
-
Kubernetes
-
Open Api Spec 3.0
-
SMTP
-
MySQL 8.0
REQUIREMENTS
The following common and generic requirements must all be followed:
-
Implement the SMS / Email / OTP microservices
-
Use com.cyn as the root package name
-
Follow the same structure and practices that we have implemented in the existing microservices, make sure you set up the same code style check and format commands like the existing ones
-
All Data being Ingress or Egress from Spring Boot Application needs to be GZIPPED (see https://www.javainuse.com/spring/boot-zip for an example)
-
Each of the microservice and API gateway need to be buildable and deployable on its own, i.e. there should be no direct build dependency between any of them so we can have them in separate repos, and it must be possible to deploy them to different servers.
-
Licenses to be followed in development:
-
Apache License 2.0
-
MIT License
-
Common Development and Distribution License
-
Eclipse Public License version 2.0
-
-
Service should follow Spring Slueth Tracking (check the Server Side Request Tracking document shared in the forum)
-
Implement logging properly for each service and api gateway
-
Please follow the requirements in the Server Side Logging document shared in the forum
-
You must use Aspect Oriented Programming (AOP) for Trace Logging
-
-
Exception handling should be implemented as described in the Service Exceptions Coding Convention document shared in the forum
-
Service Registration and Service Discovery must be implemented (this is already done via Istio in the existing code, so you can just follow the same approach)
-
Data traversal between the logical layers in microservice architecture should follow the scope bounding rules for application entities and domain entities, separation of concerns needs to be adhered to strictly:
-
Other guidelines mentioned in the Guiding Principles document shared in the forum must be followed
-
Service configurations must be done in key=value format so that it’s compatible with Kubernetes’s ConfigMap, and should support environment variable based configuration as well. Sensitive configurations will be put in Secrets instead.
-
Reusability as much as possible. Please build common components in order to delegate basic activities like Encryption, decryption, masking, hashing etc. These components can be packaged into its own common components archives, reusable by all the microservices being developed. Please add common code to the existing cyn-common package.
-
MySQL will NOT run inside Kubernetes, it’ll be MySQL SaaS in production but each microservice will have its own / separate schema.
-
Please note we consider requirements and client guidelines mentioned above to be major requirements.
Email Microservice
-
This service is responsible for sending emails to the customers, emails can be template based emails
-
This service will be using Spring Mail with FreeMarker to update the email templates, any image assets which need to be shown as part of the email template will use cloud CDN with a backend bucket
-
Please use com.cyn.ccds.email as root package name for this service
-
Here are the api details:
-
Service Name: CYN_EMAIL_SERVICE
-
Invoking Component Name: CCDS_CYN_EMAIL_SERVICE
-
Type of API: Private API (exposed to internal APIGEE only)
-
Service Type: Stateless
-
Protocols: HTTPS
-
HTTP Method: POST
-
API Versioning: URL Based Versioning to be followed, we can use v1 for this one
-
Payload Encryption Required from Client Side or Invoking Service:
-
Emails parameters received would be encrypted in nature
-
We only expect the invoking service to encrypt the payload it sends to this service, and this service will decrypt the payload, generate the email and send it directly via SMTP.
-
-
Encryption / Decryption is to be performed using a common library (cyn-common), though keys must be managed and read from Kubernetes Secrets
-
-
Output:
-
Success: org.springframework.http.ResponseEntity
-
Exception coding and messages to follow: Server Side Service Exceptions Coding Convention mentioned above
-
-
-
This service should not be exposed via the API gateway
-
Proper configuration & logging should be implemented
-
Provide a docker file for this microservice so we can build it into a docker image
SMS Microservice
-
This service is responsible for sending SMS to the customers, SMS can be template based messages
-
For the purpose of this challenge the actual SMS sending logic will be mocked, please implement it so it writes the SMS to the logs, but the logic to generate SMs based on templates should be implemented, only the SMS sending part should be mocked and abstracted so we can replace it easily later
-
Please use com.cyn.ccds.sms as root package name for this service
-
Here are the api details:
-
Service Name: CYN_SMS_SERVICE
-
Invoking Component Name: CCDS_CYN_SMS_SERVICE
-
Type of API: Private API (exposed to internal APIGEE only)
-
Service Type: Stateless
-
Protocols: HTTPS
-
HTTP Method: POST
-
API Versioning: URL Based Versioning to be followed, we can use v1 for this one
-
Payload Encryption Required from Client Side or Invoking Service:
-
SMS parameters received would be encrypted in nature
-
We only expect the invoking service to encrypt the payload it sends to this service, and this service will decrypt the payload, generate the SMS and send it directly via the 3rd party service.
-
-
Encryption / Decryption is to be performed using a common library (cyn-common), though keys must be managed and read from secrets storage
-
-
Output:
-
Success: org.springframework.http.ResponseEntity
-
Exception coding and messages to follow: Server Side Service Exceptions Coding Convention mentioned above
-
-
-
This service should not be exposed via the API gateway
-
Proper configuration & logging should be implemented
-
Provide a docker file for this microservice so we can build it into a docker image
OTP Microservice
-
The service is responsible for generating the 6 digit OTP, it will perform the following activities:
-
OTP Generation
-
OTP Authentication / Validation
-
OTP Counter checking (check # of OTP generated by unique user identifier), the user is allowed to generate a certain number of OTPs every day, and this number should be configurable
-
In event of resend OTP - new OTP would be generated and sent, since these are time based OTP
-
-
OTP generated would be sent to the customers using Email or SMS depending on the channel in the request.
-
The one time password may be either numeric or alphanumeric and any configured length (default is 6) and the randomization algorithm should be pluggable.
-
Number of failures allowed while performing OTP authentication / validation default would be 3 but should be configurable.
-
Audit trail needs to be maintained for the OTP generated and validated by the user along with timestamp and ip from which the OTP authentication was sent.
-
The OTP service will use a redis cache to store generated OTP for faster lookup.
-
Please use com.cyn.ccds.otp as root package name for this service
-
Here are the api details:
-
Service Name: CYN_OTP_SERVICE
-
Invoking Component Name: CCDS_CYN_OTP_SERVICE
-
Please check CYN-OTPService-API-150920-1712.pdf for api signature
-
Type of API: Private API (exposed to internal APIGEE only)
-
Service Type: Stateless
-
Protocols: HTTPS
-
HTTP Method: POST
-
API Versioning: URL Based Versioning to be followed, we can use v1 for this one
-
Payload Encryption Required from Client Side or Invoking Service:
-
Validation / creation OTP payload will be received into system as encrypted
-
Encryption / Decryption is to be performed using a common library (cyn-common), though keys must be managed and read from secrets storage
-
-
Service Dependencies:
-
For storing the information in cache to enable it to be validated from any of the cluster instances, service will store data for the limited time duration using TTL entry configuration in a cache service which uses Redis. Since that service is not available yet, let’s mark this step as a TODO in the code so we won’t forget to add it later.
-
It also depends on a Customer Profile Service which will return the user's email and / or mobile number based on the customer unique identifier. Since we don't have the service implemented yet, you should use a configuration based (map user id to email / phone numbers) approach for now, and add a TODO in the code so we won't forget to switch to the real implemenation here later.
-
-
Timeouts:
-
OTP - 30 seconds default, should be configurable though
-
-
Output:
-
Success: org.springframework.http.ResponseEntity
-
OTP CREATE: OTP Would be generated and sent to the customer on channel of communication of user.
-
OTP_VALIDATED: OTP Validation message.
-
Failure: org.springframework.http.ResponseEntity with appropriate messages picked up from message resource files.
-
Exception coding and messages to follow: Server Side Service Exceptions Coding Convention mentioned above
-
-
Important Notes:
-
Application communications paths should be configurable to i.e. through which channel the communication needs to take place.
-
All validations would be successful/failed and would be logged into the system for audit trail purposes. Logging would be performed in DB + Logs
-
-
-
Data Model
-
Schema name: CYN_OTP_SERVICE
-
Table name: CCDS_OTP_AUDIT_TRAIL
-
Fields:
-
ID: BIGINT
-
CUSTOMER_ID: VARCHAR 128
-
INVOKING_COMPONENT: VARCHAR 128
-
OTP: VARCHAR 32 (Encrypted / Masked)
-
IP: VARCHAR 64
-
GENERATION_DATE_TIME: DATETIME
-
VALIDATION_DATE_TIME: DATETIME
-
VALIDATION_STATUS: VARCHAR 16 (SUCCESS / FAILED)
-
CREATE_DATE: DATE
-
-
-
Auditing and Logging
-
Record the component invoking the OTP service, Time of sending, Count, Expiry Time on that particular day
-
Do not log the OTP into Logs. Consider it as Sensitive Information. Flag should be there to switch it off in UAT and PROD. But on DEV we should allow it to show in logs
-
Make sure you follow the server side logging guidelines mentioned above
-
-
Design Patterns to Follow
-
Factory Pattern - For choosing the channel of communication.
-
Sidecar Pattern - Envoy Proxy
-
Circuit Breaker - Using Istio
-
-
System will use OTP generated using the library below:
-
<dependency>
<groupId>com.eatthepath</groupId>
<artifactId>java-otp</artifactId>
<version>0.2.0</version>
</dependency>
-
-
Purging Scripts to be provided for DB
-
Data would be purged from database basis the number of days configured in the system, default to 90 days but should be configurable. Purging will be based on CREATE_DATE
-
Please create a script that can purge the data, the deletion would be based on OTP date. Please note eventually we want to run this script using Google scheduler or Kubernetes jobs, make sure the script is compatible with that.
-
-
This service should not be exposed via the API gateway
-
Proper configuration & logging should be implemented
-
Provide a docker file for this microservice so we can build it into a docker image
Final Submission Guidelines
FINAL DELIVERABLES
-
Full code that covers all the requirements.
-
A detailed README file including information on how to configure, run, and verify your application.
-
Maven script(s) that at least cover the following:
-
Run the services locally
-
Build the API gateway and each microservice into separate packages that can be deployed independently
-
Build the API gateway and each microservice into separate docker images
-
Generate a sitemap for the project using Maven Site Plugin (mvn site)
-
-
Postman collection file to properly test the API (covering positive and negative cases).