SHOWCASING WORLD-CLASS SOFTWARE ENGINEERING
Underwater Hockey π
Underwater Rugby π
Underwater Contact Team Sports
Certified scuba and freediverΒ
Market Enabler
Contract Generator for a Marketplace
Framework migration
Market Enabler
Loans and everything to support them
Who is involved?
𧩠Extensive workflow π
Why world-class?
What would I change?
Indigo's Architecture
AgFinance Architecture
πΌ
We received a small project
π π
Two weeks adaptation period
@Entity('AgFinancingMatricula')
export class AgFinancingMatriculaModel extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne((type) => Phase2Model, (phase2) => phase2.matriculas, { nullable: true })
phase2?: AgFinancingMatriculaModel;
@OneToOne((type) => AgFinancingFileModel, (file) => file.id, { nullable: true })
@JoinColumn()
matricula?: AgFinancingFileModel;
@OneToOne((type) => AgFinancingFileModel, (file) => file.id, { nullable: true })
@JoinColumn()
kml?: AgFinancingFileModel;
@OneToMany((type) => AgFinancingMatriculaDetailModel, (detail) => detail.parent)
@JoinColumn()
details: AgFinancingMatriculaDetailModel[];
@OneToMany((type) => AgFinancingFileModel, (file) => file.matricula)
@JoinColumn()
fieldMonitoringFiles: AgFinancingFileModel[];
@Column({ default: false })
includedInAnalysis: boolean;
@Column({ default: false })
includedInFormalization: boolean;
}
@Injectable()
export default class AgFinancingMatriculaService {
@Inject()
private readonly agFinancingMatriculaDal: AgFinancingMatriculaDal;
@Inject()
private readonly agFinancingDal: AgFinancingDal;
@Inject()
private readonly phase2Dal: Phase2Dal;
@Inject()
private readonly matriculaDetailDal: AgFinancingMatriculaDetailDal;
@Inject()
private readonly agStateService: AgStateService;
@Inject()
private readonly creditApprovalService: CreditApprovalService;
}
@Resolver()
export default class GrowerLeadResolver {
@Inject()
private readonly growerService: GrowerService;
@Query()
@Auth({ scope: Scope.BR, permissions: [PermissionNames.FA_INTERNAL, PermissionNames.FA_EXTERNAL] })
async financingBrazilGrowerLead(parent: object, args: { leadId: string }, context: Context) {
return this.growerService.findById(+args.leadId);
}
@ResolveField({ typeName: 'FinancingBrazilGrowerLead', fieldName: 'additionalInfo' })
async lead(grower: GrowerLeadDTO, args: object, context: Context) {
return this.growerService.getAdditionalInfo(grower, !!grower.salesforceId);
}
@ResolveField({ typeName: 'FinancingBrazilGrowerLead', fieldName: 'agFinancingProcesses' })
async agFinancingProcesses(grower: GrowerLeadDTO, args: object, context: Context) {
return this.growerService.getAgFinancingProcessesByGrower(+grower.id);
}
@Mutation()
@Auth({ scope: Scope.BR, permissions: [PermissionNames.FA_ADMIN] })
async createFinancingBrazilGrowerLead(
parent: object,
args: { data: FinancingBrazilGrowerLeadCreateInput },
context: Context
) {
return this.growerService.createLead(args.data);
}
}
βοΈ ποΈ Β π§ π§
Due to the project's high complexity, often, we required complex DB migrations
Planning, being thoughtful
Development
Staging Environment Testing
Execution
Monitoring and Verification
Cleanup and Optimization
export default const mainScript: fnToExecuteType = async (dm: typeof DIManager, dbConnection: Connection): Promise<void> => {
log.info('------- START -------');
const currentStateDal = dm.get(AgCurrentStateDal);
const agEventDal = dm.get(AgFinancingEventDal);
const agStateDal = dm.get(AgStateDal);
const agStateService = dm.get(AgStateService);
const stateList = await currentStateDal.find({
relations: ['agFinancing', 'agState'],
where: {
agState: { stateId: In([AgStateName.P3_PHYSICAL_DOCS_RECEIVED, AgStateName.P3_AWAITING_PHYSICAL_DOCS]) },
},
});
for (const state of stateList) {
await agStateService.insertAndClearStateChange(state.agFinancing.id, AgStateName.AWAITING_CONTRACT_VALIDATION);
}
const events = await agEventDal.find({
agState: {
stateId: In([
AgStateName.P3_COMPLETE,
AgStateName.P3_PHYSICAL_DOCS_RECEIVED,
AgStateName.P3_AWAITING_PHYSICAL_DOCS,
]),
},
});
for (const event of events) {
await agEventDal.save(agEventDal.create({ id: event.id, agState: null }));
}
await agStateDal.delete({
stateId: In([
AgStateName.P3_COMPLETE,
AgStateName.P3_PHYSICAL_DOCS_RECEIVED,
AgStateName.P3_AWAITING_PHYSICAL_DOCS,
]),
});
log.info('------- DONE --------');
};
π π π
We run over 20 complex migrations successfully
We required to have updates from Salesforce
Webhook is the best option, but:
Implemented solution:
Scheduler or Cron Jobs β°π
with DB lock
Why?
Today, What would I change?
Go to person to perform DevOps task π¨βπ»β
Migration from dedicated RDS to OneDB
Terraform
data "aws_caller_identity" "current" {}
locals {
name = "financing-api"
env = var.environment
description = "Infrastructure for financing-api"
bucket_name = "indigo-financing-api-${local.env}-us-east-1"
db_role = "financing_api"
tags = {
project = "financing-api"
team = "gefion"
environment = local.env
product = "AgFinancing"
repo-name = local.name
slack = "squad-gefion"
alerts = "@alerts-financing"
tier = "infra"
}
}
resource "aws_s3_bucket" "financing_api_bucket" {
bucket = local.bucket_name
acl = "private"
tags = merge(local.tags, {
"Name" = "Financing API Documents",
}
)
versioning {
enabled = true
}
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET", "PUT"]
allowed_origins = var.main_bucket_allowed_domains
expose_headers = ["ETag"]
max_age_seconds = 3000
}
}
resource "aws_s3_bucket" "financing_api_bucket_brazil" {
bucket = "${local.bucket_name}-brazil-orders"
acl = "private"
tags = merge(local.tags, {
"Name" = "Financing API Documents for Brazil Orders",
}
)
versioning {
enabled = true
}
cors_rule {
allowed_headers = ["*"]
allowed_methods = ["GET", "PUT"]
allowed_origins = var.main_bucket_allowed_domains
expose_headers = ["ETag"]
max_age_seconds = 3000
}
}
module "yggdrasil_remote_state" {
source = "app.terraform.io/indigoag/lookup_indigo_terraform_remote_state/aws"
version = "1.0.0"
environment = local.env
state_name = "yggdrasil"
}
data "aws_iam_policy_document" "assume_role" {
statement {
actions = ["sts:AssumeRole"]
effect = "Allow"
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
data "aws_iam_policy_document" "rds_yggdrasil_iam_auth" {
statement {
sid = "rdsYggdrasilIamAuth"
effect = "Allow"
resources = [
"arn:aws:rds-db:us-east-1:${data.aws_caller_identity.current.account_id}:dbuser:${module.yggdrasil_remote_state.outputs.rds_cluster_resource_identifier}/${local.db_role}"
]
actions = ["rds-db:connect"]
}
statement {
sid = "rdsYggdrasilDescribeDBClusterEndpoints"
effect = "Allow"
resources = ["*"]
actions = ["rds:DescribeDBClusterEndpoints"]
}
}
module "service_scoped_secrets" {
source = "app.terraform.io/indigoag/service_scoped_secrets_app_policy/aws"
version = "1.0.0"
environment = var.environment
service_name = local.name
}
data "aws_cloudformation_stack" "sns_main" {
# this stack still lives in the infrastrucutre repository
# https://github.com/indigo-ag/infrastructure/blob/develop/cloudformation/sns/platform-events-stack.yml
name = "sns-main"
}
resource "aws_iam_role" "ecs_task_role" {
name = "${local.db_role}_task_role"
description = "Role to be utilized by ${local.name} containers run by ECS"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
tags = local.tags
managed_policy_arns = [module.service_scoped_secrets.read_only_policy_arn]
inline_policy {
name = "rds_yggdrasil_iam_auth"
policy = data.aws_iam_policy_document.rds_yggdrasil_iam_auth.json
}
inline_policy {
name = "s3_policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = ""
Action = ["s3:*"]
Effect = "Allow"
Resource = ["arn:aws:s3:::indigo-financing*", "arn:aws:s3:::indigo-financing*/*"
]
},
{
Sid = "1"
Action = ["s3:GetObject", "s3:List*"]
Effect = "Allow"
Resource = ["arn:aws:s3:::ag-finance-attachments-${local.env}", "arn:aws:s3:::ag-finance-attachments-${local.env}/*"
]
}
]
})
}
inline_policy {
name = "notify_schema_change"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = ""
Action = ["cloudformation:DescribeStacks", "elasticloadbalancing:Describe*"]
Effect = "Allow"
Resource = ["*"]
}
]
})
}
inline_policy {
name = "sns_policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "SnsAccess"
Action = ["sns:Publish"]
Effect = "Allow"
Resource = [data.aws_cloudformation_stack.sns_main.outputs["SNSTopicARN"]]
}
]
})
}
}
# Load Balancer and associated resources for the api container
module "indigo_api" {
source = "app.terraform.io/indigoag/indigo_api/aws"
version = "1.0.0"
name = local.name
container_name = "api"
environment = local.env
product = local.tags.product
project = local.tags.project
repo_name = local.tags["repo-name"]
team = local.tags.team
health_check_interval = 16
health_check_timeout = 15
deregistration_delay = 60
publicly_accessible = var.publicly_accessible
}
Contract Generator for a Marketplace
Process Automation using BPMN
(Business Process Model and Notation)
Why world-class?
What would I change?
More time for POC or Camunda expert
Be clear with the intention of camunda
Requirement
Use the web app to allow the manager to create the contract template
Challenges
Use the web app to allow the manager to create the contract template
Use the web app to allow the manager to create the contract template
Define contract type
Build template
Develop Tag Resolvers
Create repository
Use the web app to allow the manager to create the contract template
print("Code time π»")
Easy to reuse, functional
Doesn't require any training
Use the web app to allow the manager to create the contract template
AngularJS to Angular migration
Legend:
Legacy
New
Why world-class?
What would I change?
Challange: Communicate both frameworks
Let's imagine the following scenario
// Traditional Ngrx
this.store.dispatch(AccountsActions.deleteProjectAccount({ accountId }));
// Facade
projectFacade.deleteAccount(accountId);
Another Problem π«
Change Detection on both frameworks
Solution
Create a wrapper to execute the required steps to comply with the change detection
Simply frameworks comunication
@decorators
var checksFacade =
bridge.store.getFacade('checks');
Get Facade
@FacadeLegacySupport({
registrationKey: 'checks'
})
@Injectable()
export class ChecksFacade {
}
Register Facade
@actionLegacySupport()
load() {
this.store.dispatch(ChecksActions.load());
}
Add Legacy Support
Trigger Action
var checksFacade = bridge.store.getFacade('checks');
entitiesFacade.load_legacySupport();
@selectorLegacySupport()
checkList$ = this.store.pipe(
select(ChecksSelectors.getAllChecks)
);
Add Legacy Support
Use Selector
var checksFacade = bridge.store.getFacade('checks');
checksFacade.checkList$_legacySupport
.subscribe(console.log)
@selectorLegacySupport({promisfy: true})
checkList$ = this.store.pipe(
select(ChecksSelectors.getAllChecks)
);
var checksFacade = bridge.store.getFacade('checks');
checksFacade.checkList$_legacySupport_promise
.then(console.log)
Regular meetings to manage scope, prioritization, and project status
Agile Methodology
Mentorship
π Top Performer Project
High Client Satisfaction
High efficient team
Driving substantial operational improvements
Market Enabler
Contract Generator for a Marketplace
Framework migration
dianjuar@gmail.com
linkedin.com/in/dianjuar