Midas Lab

Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

Name - Anand Pratap Singh

Roll No. - 20051930


Branch - CSE
Collage Name - KIIT University

Back-End Engineer Code Assessment Documentation

Overview:

This document details the Backend Engineer Code Assessment, designed to evaluate
your skills in integrating Stripe payment processing into a pre-existing Spring Boot
application leveraging Temporal Workflow Engine.

Project Setup:

 Base Application: Spring Boot application with Java 21.


 External Service: Temporal Workflow Engine for orchestrating business logic.
 Task Focus: Stripe integration for customer creation and data management.
 Repository: https://github.com/Midas-Labs/backend-engineer-assessment

Tasks:

1. Stripe Integration for Customer Creation using Temporal Workflow:


o Implement a workflow using Temporal to create a new Stripe customer upon user
signup using the provided Stripe Create Customer API.
o Bootstrap code and SDK are provided.
2. Add New Fields to User Model:
o Include a providerType field with an enum for "stripe".
o Add a providerId field to store the Stripe customer ID.
o Update the application controller to handle these fields during user signup and store the
providerId appropriately.
3. API Implementation:
o Utilize the existing GET /accounts endpoint for verification and testing.
Bonus:
 Write unit and integration tests for your implementation, covering Stripe integration, user
model changes, signup process, and GET /accounts functionality.
Project Submission Guidelines:
 Code Quality: Clean, well-documented, adhering to standard practices.
 Testing: Include tests for all new functionalities. Bonus points for comprehensive testing.
 Documentation: Provide a README file with:
o Setup instructions.
o Test execution instructions.
o Brief explanation of your implementation approach and assumptions.
Evaluation Criteria:
 Functionality: Meets all requirements and works as expected.
 Code Quality: Well-organized, clean, readable, and utilizes good practices.
 Testing: Covers critical paths and edge cases, ensuring application stability.
 Documentation: Clear setup instructions and development insights.
Additional Notes:
 Feel free to use any libraries or frameworks that enhance your solution.
 This assessment is designed to be completed within a specified timeframe.
 Be prepared to discuss your approach and answer questions during the evaluation.

AccountController Code:
package com.midas.app.controllers;

import com.midas.app.mappers.Mapper;
import com.midas.app.models.Account;
import com.midas.app.models.User.ProviderType;
import com.midas.app.services.AccountService;
import com.midas.generated.api.AccountsApi;
import com.midas.generated.model.AccountDto;
import com.midas.generated.model.CreateAccountDto;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/api/accounts")
@RequiredArgsConstructor
public class AccountController implements AccountsApi {

private final AccountService accountService;


private final WorkflowClient workflowClient;
private final Logger logger =
LoggerFactory.getLogger(AccountController.class);

@Override
@PostMapping("/signup")
public ResponseEntity<AccountDto> createUserAccount(
@RequestBody CreateAccountDto createAccountDto) {
logger.info("Creating account for user with email: {}",
createAccountDto.getEmail());

// Set providerType as STRIPE


createAccountDto.setProviderType(ProviderType.STRIPE);

WorkflowOptions options =
WorkflowOptions.newBuilder().setTaskQueue("user-signup-
tasks").build();
UserSignupWorkflow workflow =
workflowClient.newWorkflowStub(UserSignupWorkflow.class, options);

// Execute the workflow for user signup


Account account = workflow.signupUser(createAccountDto);

return new ResponseEntity<>(Mapper.toAccountDto(account),


HttpStatus.CREATED);
}

@Override
@GetMapping
public ResponseEntity<List<AccountDto>> getUserAccounts() {
logger.info("Retrieving all accounts");

List<Account> accounts = accountService.getAccounts();


List<AccountDto> accountsDto =
accounts.stream().map(Mapper::toAccountDto).toList();

return new ResponseEntity<>(accountsDto, HttpStatus.OK);


}
}

User/Accounts information:
package com.midas.app.models;

import jakarta.persistence.*;
import java.time.OffsetDateTime;
import java.util.UUID;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

@Setter
@Getter
@RequiredArgsConstructor
@AllArgsConstructor
@Builder
@Entity
@Table(name = "accounts")
public class Account {

@Id
@Column(name = "id")
@GeneratedValue
private UUID id;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Column(name = "email")
private String email;

@Enumerated(EnumType.STRING)
@Column(name = "provider_type")
private User.ProviderType providerType; // Added field

@Column(name = "provider_id")
private String providerId; // Added field

@Column(name = "created_at")
@CreationTimestamp
private OffsetDateTime createdAt;

@Column(name = "updated_at")
@UpdateTimestamp
private OffsetDateTime updatedAt;
}

1. AccountController:
Role: Handles HTTP requests related to user accounts.
 Key Methods:
o createUserAccount: Creates a new user account using a Temporal workflow.
o getUserAccounts: Retrieves a list of existing accounts.

2. Account Model:

 Purpose: Represents a user account in the application.


 Key Fields:
o id: Unique identifier for the account.
o firstName, lastName, email: Personal information.
o providerType: The type of payment provider (e.g., Stripe).
o providerId: The ID associated with the payment provider.
o createdAt, updatedAt: Timestamps for account creation and updates.
To delve deeper, please specify:
 Specific functionalities: Which parts of the code's behavior do you want to understand?
 Key areas of interest: Are you more interested in the controller logic, model structure, or
other aspects?

Creating Account dto :

package com.midas.generated.model;

import java.net.URI;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonTypeName;
import java.time.OffsetDateTime;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import io.swagger.v3.oas.annotations.media.Schema;

import java.util.*;
import jakarta.annotation.Generated;

/**
* CreateAccountDto
*/
@JsonTypeName("createAccount")
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date =
"2024-02-06T00:41:20.524414800+05:30[Asia/Calcutta]")
public class CreateAccountDto {

private String firstName;

private String lastName;

private String email;

public CreateAccountDto firstName(String firstName) {


this.firstName = firstName;
return this;
}

/**
* User's first name
* @return firstName
*/

@Schema(name = "firstName", example = "John", description = "User's first


name", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@JsonProperty("firstName")
public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {


this.firstName = firstName;
}

public CreateAccountDto lastName(String lastName) {


this.lastName = lastName;
return this;
}

/**
* User's last name
* @return lastName
*/

@Schema(name = "lastName", example = "Doe", description = "User's last


name", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@JsonProperty("lastName")
public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {


this.lastName = lastName;
}

public CreateAccountDto email(String email) {


this.email = email;
return this;
}
/**
* Email of user
* @return email
*/

@Schema(name = "email", example = "john@doe.com", description = "Email of


user", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@JsonProperty("email")
public String getEmail() {
return email;
}

public void setEmail(String email) {


this.email = email;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CreateAccountDto createAccount = (CreateAccountDto) o;
return Objects.equals(this.firstName, createAccount.firstName) &&
Objects.equals(this.lastName, createAccount.lastName) &&
Objects.equals(this.email, createAccount.email);
}

@Override
public int hashCode() {
return Objects.hash(firstName, lastName, email);
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class CreateAccountDto {\n");
sb.append(" firstName:
").append(toIndentedString(firstName)).append("\n");
sb.append(" lastName:
").append(toIndentedString(lastName)).append("\n");
sb.append(" email: ").append(toIndentedString(email)).append("\n");
sb.append("}");
return sb.toString();
}

/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
}

Purpose:

 This class serves as a data transfer object (DTO) to encapsulate information required
for creating a new user account. It acts as a carrier of data between different parts of
the application.
Key Fields:
 firstName: Stores the user's first name (String).
 lastName: Stores the user's last name (String).
 email: Stores the user's email address (String).
Annotations:
 @JsonTypeName("createAccount"): This annotation from Jackson library designates a
logical type name for this DTO, useful for serialization and deserialization.
 @Generated: Indicates that the code was generated automatically, likely using a tool
like Spring Codegen.
 @Schema: Annotations from OpenAPI 3 for defining API documentation elements, such
as examples and descriptions.
 @JsonProperty: Specifies the names of properties for JSON serialization and
deserialization.
Generated Methods:
 Getters and Setters: Standard methods for accessing and modifying the fields of the
DTO.
 equals() and hashCode(): Methods for comparing objects and generating hash codes,
used for operations like checking object equality and creating hash-based collections.
 toString(): Provides a string representation of the DTO, primarily for debugging and
logging purposes.
Key Points:
 This DTO is likely used by controllers or services to receive account creation requests
and transfer the data within the application.
 It doesn't contain any business logic or processing itself; it's solely a data structure for
information exchange.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy