## Architecture Diagram (Proposed)
```plantuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
title Everpro Users & Safety (Subscribe Before Register) - Proposed Architecture Diagram
Person(user_everpro, "User Everpro / Imers")
System_Boundary(everpro_brand_system, "Everpro Customer Web Application") {
Container(web, "Browser", "Software System", "All supported browser")
Container(everpro_web, "Everpro Customer Web Application", "Nuxt.js", "Provides everpro management functionalities to customer via their web browser")
System(subscription, "Subscription Page (Without Login)")
System(checkout_form, "Checkout Form (Without Login)")
System(purchase2, "Purchase Subscription (Without Token) \n And \n Register Account Automatic")
System(login, "Login")
System(layananku, "Layananku")
System(purchase, "Purchase Subscription")
}
System_Boundary(api_endpoint, "API Endpoint") {
Container(everpro_subscription, "everpro-subscription API", "Golang", "Provides everpro subscription functionalities via HTTPS / REST / JSON API")
Container(everpro_subscription_public, "everpro-subscription-public API", "Golang", "Provides everpro subscription public functionalities via HTTPS / REST / JSON API")
Container(everpro_auth, "everpro-auth API", "Golang", "Provides authentication functionalities via HTTPS / REST / JSON API")
Container(everpro_voucher, "everpro-voucher API", "Golang", "Provides voucher functionalities via HTTPS / REST / JSON API")
Container(everpro_wallet, "everpro-wallet API", "Golang", "Provides wallet functionalities via HTTPS / REST / JSON API")
Container(everpro_payment, "everpro-payment API", "Golang", "Provides payment functionalities via HTTPS / REST / JSON API")
}
ContainerDb(db_everpro_subscription, "Database", "PostgreSQL", "popaket_user schema")
ContainerDb(db_everpro_voucher, "Database", "PostgreSQL", "everpro_voucher schema")
ContainerDb(db_popaket_wallet, "Database", "PostgreSQL", "popaket_wallet schema")
ContainerDb(db_popaket_auth, "Database", "PostgreSQL", "popaket_auth schema")
ContainerDb(redis, "Redis", "In Memory Storage", "")
ContainerDb(db_popaket_payment, "Database", "PostgreSQL", "popaket_payment schema")
Rel(user_everpro, web, "View dashboard", "Client Device")
Rel(web, everpro_web, "Access", "HTTPS")
Rel_L(everpro_web, subscription, "Click To Feature", "")
Rel(subscription, checkout_form, "Click To Feature", "")
Rel(checkout_form, purchase2, "Click To Feature", "")
Rel(purchase2, everpro_subscription_public, "Makes API calls to", "HTTPS / REST / JSON")
Rel_R(everpro_web, login, "User pass the authentication process", "")
Rel(login, layananku, "Click To Feature", "")
Rel(layananku, purchase, "Click To Feature", "")
Rel(purchase, everpro_subscription, "Makes API calls to", "HTTPS / REST / JSON")
Rel_L(everpro_subscription_public, everpro_subscription, "Makes API calls to", "HTTPS / REST / JSON")
Rel(everpro_subscription, db_everpro_subscription, "Reads from & Writes to", "TCP/IP")
Rel(everpro_subscription_public, everpro_auth, "Makes API calls to", "HTTPS / REST / JSON")
Rel(everpro_auth, db_popaket_auth, "Reads from & Writes to", "TCP/IP")
Rel(everpro_subscription_public, everpro_payment, "Makes API calls to", "HTTPS / REST / JSON")
Rel(everpro_payment, db_popaket_payment, "Reads from & Writes to", "TCP/IP")
Rel(everpro_subscription_public, everpro_voucher, "Makes API calls to", "HTTPS / REST / JSON")
Rel(everpro_subscription, everpro_voucher, "Makes API calls to", "HTTPS / REST / JSON")
Rel(everpro_voucher, db_everpro_voucher, "Reads from & Writes to", "TCP/IP")
Rel(everpro_voucher, redis, "Reads from & Writes to", "TCP/IP")
Rel_R(everpro_wallet, db_popaket_wallet, "Reads from & Writes to", "TCP/IP")
Rel_R(everpro_subscription, everpro_wallet, "Makes API calls to", "HTTPS / REST / JSON")
```
## Database Design - Proposed System
```plantuml
hide circle
'skinparam linetype ortho
skinparam class {
ArrowColor #FF7878
BackgroundColor #FFF89A
BorderColor #694E4E
}
title Proposed Database Schema
entity "[everpro_voucher] voucher" as v {
*entity_id: UUID()
--
name: text()
description: text()
code: text() unique()
purpose_type: enum('discount','cashback')
service_type: enum('subscription','shipping')
discount_type: enum('nominal','percentage')
value: float64()
is_active: bool()
start_date: timestamptz()
end_date: timestamptz()
event_id: UUID()
source_of_fund: enum('internal','external','mix')
specification: enum('acquisition','affiliate','onboarding')
user_id: UUID()
created_by: text()
updated_by: text()
deleted_by: text()
meta_created_at: timestamptz()
meta_updated_at: timestamptz()
meta_deleted_at: timestamptz()
}
entity "[everpro_voucher] voucher_log" as vl {
*entity_id: UUID()
--
voucher_id: UUID()
before: text()
after: text()
reason: text()
created_by: text()
meta_created_at: timestamptz()
meta_updated_at: timestamptz()
meta_deleted_at: timestamptz()
}
entity "[everpro_voucher] event" as ev {
*entity_id: UUID()
--
name: text()
description: text()
created_by: text()
updated_by: text()
deleted_by: text()
meta_created_at: timestamptz()
meta_updated_at: timestamptz()
meta_deleted_at: timestamptz()
}
entity "[popaket_user] users" as u {
*id: UUID(20)
--
balance: bigint(20)
name: text()
msisdn: text()
email: text()
client_key: text()
client_secret: text()
primary_phone: text()
primary_device_name: text()
primary_device_key: text()
vip: bool()
...
is_active: bool()
is_phone_verified: bool()
is_email_verified: bool()
created_at: timestamptz()
created_by: text()
updated_at: timestamptz()
updated_by: text()
deleted_at: timestamptz()
deleted_by: text()
}
entity "[popaket_user] invoices" as i {
*id: UUID(20)
--
user_id: UUID()
expired_at: timestamptz()
paid_at: timestamptz()
status: text()
payment_method: text()
payment_id: text()
amount: numeric()
discount: numeric()
<b><color red>voucher_id: UUID()
<b><color red>voucher_code: text()
<b><color red>voucher_discount: numeric()
<b><color red>voucher_applied_at: timestamptz()
number: text()
additional_info: text()
...
meta_created_at: timestamptz()
meta_updated_at: timestamptz()
meta_deleted_at: timestamptz()
}
ev ||-L|| v
v ||--|{ vl
u ||-|| v
u ||-L|{ i
```
## Process Flow (Proposed)
```plantuml
skinparam responseMessageBelowArrow true
title Public Check Account By Email - Existing Interaction Diagram
participant "client" as c
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> ea : process check account by email
activate ea
ea -> ea : encrypt user email
ea -> db_pa : resolve user by email
activate db_pa
return user data
alt if user data not found
ea -> c : error account not found
end
return return account found
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Check Account By Telephone - Existing Interaction Diagram
participant "client" as c
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> ea : process check account by telephone
activate ea
ea -> ea : encrypt user telephone
ea -> db_pa : resolve user by msisdn
activate db_pa
return user data
alt if user data not found
ea -> c : error account not found
end
return return account found
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Register V3 - Existing Interaction Diagram
participant "client" as c
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> ea : process register v3
activate ea
ea -> db_pa : check email exist
activate db_pa
return user data
alt if email already registered
ea -> c : error email is already registered
end
ea -> ea : encrypt user email
ea -> db_pa : check telephone exist
activate db_pa
return user data
alt if telephone already registered
ea -> c : error telephone is already registered
end
ea -> ea : encrypt user telephone
alt if user data not found
ea -> c : error account not found
end
ea -> db_pa : Create user data
activate db_pa
return success
return success (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Verify Email - Existing Interaction Diagram
participant "client" as c
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> ea : process verify email
activate ea
alt if client unauthorized
ea -> ea : check bearer token
ea -> c : error unauthorized
end
ea -> db_pa : get user data by id
activate db_pa
return user data
ea -> db_pa : update verification email by user id
activate db_pa
return success
ea -> ea : generate & store token
return success (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Login Email - Existing Interaction Diagram
participant "client" as c
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> ea : process login email
activate ea
ea -> db_pa : check email and password
activate db_pa
alt if email or password mismatch
ea -> c : error email or password mismatch
end
return generate token
return return token data
```
```plantuml
skinparam responseMessageBelowArrow true
title Consumer NSQ Send Email Activate Account - Proposed Interaction Diagram
participant "NSQ" as c
participant "everpro-email" as ea
database "email" as db_pa
activate c
c -> ea : consume nsq message send email activate account
activate ea
ea -> ea : check payload request
ea -> ea : generate html content email activate account
ea -> db_pa : send the email that was previously set
activate db_pa
return success (ok)
return success (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Private Package Bundles Filter - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription" as es
database "popaket_user" as db_pu
c -> es : resolve packages bundles filter
activate es
alt if client unauthorized
es -> es : check api key
es -> c : error unauthorized (invalid api key)
end
es -> db_pu : resolve package bundles filter
activate db_pu
return package bundles data
return package bundles data
```
```plantuml
skinparam responseMessageBelowArrow true
title Private Resolve Payment Detail - Proposed Interaction Diagram
participant "client" as c
participant "everpro-payment" as es
database "popaket_payment" as db_pu
c -> es : resolve payment detail
activate es
alt if client unauthorized
es -> es : check api key
es -> c : error unauthorized (invalid api key)
end
es -> db_pu : resolve payment detail
activate db_pu
return payment detail data
return payment detail data
```
```plantuml
skinparam responseMessageBelowArrow true
title Private Get User By Msisdn - Proposed Interaction Diagram
participant "client" as c
participant "everpro-user" as eu
database "popaket_user" as db_pu
c -> eu : get user by msisdn
activate eu
alt if client unauthorized
eu -> eu : check api key
eu -> c : error unauthorized (invalid api key)
end
eu -> eu : util encrypt msisdn
eu -> db_pu : get user data by encrypt msisdn
activate db_pu
return user detail data
return user detail data
```
```plantuml
skinparam responseMessageBelowArrow true
title Private Resolve Voucher Eligable With Calculate Amount - Proposed Interaction Diagram
participant "client" as c
participant "everpro-voucher" as ev
database "everpro_voucher" as db_ev
participant "everpro-subscription" as es
database "popaket_user" as db_pu
c -> ev : resolve voucher eligable with calculate amount by code
activate ev
alt if client unauthorized
ev -> ev : check api key
ev -> c : error unauthorized (invalid api key)
end
ev -> db_ev : get voucher code by active & eligable
activate db_ev
return voucher data
ev -> es : get packages bundles by id
activate es
es -> db_pu : resolve package bundles filter
activate db_pu
return package bundles data
return package bundles data
ev -> ev: calculate amount and voucher discount
return voucher data & amount
```
```plantuml
skinparam responseMessageBelowArrow true
title Private Create Subscription V2 VA Payment - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription" as es
database "popaket_user" as db_pu
participant "everpro-voucher" as ev
database "everpro_voucher" as db_ev
participant "NSQ" as nsq
c -> es : create subscription v2 va payment
activate es
alt if client unauthorized
es -> es : check api key
es -> c : error unauthorized (invalid api key)
end
es -> db_pu : get detail package bundles
activate db_pu
return detail package bundles
es -> es : validation package bundles (active,period & tier)
alt if package validation failed
es -> c : error validation package bundles
end
alt if payload exist voucher
es -> ev : get voucher eligable with calculate amount by code
activate ev
ev -> db_ev: get voucher dta
activate db_ev
return voucher data
ev -> ev: calculcate amount & voucher discount
return voucher & amount data
es -> es: re-assign invoice data
end
es -> db_pu : insert invoices data (with tx)
activate db_pu
return success (ok)
es -> db_pu : insert subscription mapping (with tx)
activate db_pu
return success (ok)
es -> db_pu : insert subscription (with tx)
activate db_pu
return success (ok)
es -> nsq : publish message virtual account payment request
activate nsq
return success (ok)
return success (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Check Email - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription-public" as esp
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
participant "everpro-user" as eu
participant "everpro-subscription" as es
database "popaket_user" as db_pu
c -> esp : process check email
activate esp
esp -> ea: check account email (/v1/check-account/email)
activate ea
ea -> db_pa: check account by email
activate db_pa
return data account
return data account
alt if account not found
esp -> c : return success (ok)
end
esp -> eu: get user detail by email (/private/v1/check-email)
activate eu
eu -> db_pu: get user detail by email
activate db_pu
return user detail data
return user detail data
esp -> es: resolve invoice v2 by filter (pending & userId) (/v2/invoice/invoices/filter)
activate es
es -> db_pu: get invoice data by filter
activate db_pu
return list invoice data
return list invoice data
esp -> esp: setup struct response
return response success (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Check Telephone - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription-public" as esp
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> esp : process check telephone
activate esp
esp -> ea: check account telephone (/v1/check-account)
activate ea
ea -> db_pa: check account by telephone
activate db_pa
return data account
return data account
return account found / notfound (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Subscription Calculate - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription-public" as esp
participant "everpro-voucher" as ev
database "everpro_voucher" as db_ev
c -> esp : process subscription calculate
activate esp
esp -> ev: get voucher eligable with calculate amount \n (/private/v1/vouchers/eligable-with-calculate)
activate ev
ev -> db_ev: get voucher detail by code
activate db_ev
return voucher data
ev -> ev: calculate amount & voucher discount
return voucher & calculate amount
return voucher & calculate amount
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Check Telephone - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription-public" as esp
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
c -> esp : process check telephone
activate esp
esp -> ea: check account telephone (/v1/check-account)
activate ea
ea -> db_pa: check account by telephone
activate db_pa
return data account
return data account
return account found / notfound (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Package Bundles Filter - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription-public" as esp
participant "everpro-subscription" as ea
database "popaket_user" as db_pa
c -> esp : process get package bundles filter
activate esp
esp -> ea: resolve package bundles filter (/private/v1/package-bundles/filter)
activate ea
ea -> db_pa: get package bundles data
activate db_pa
return data package bundles
return data package bundles
return data package bundles
```
```plantuml
skinparam responseMessageBelowArrow true
title Public Create Subscription - Proposed Interaction Diagram
participant "client" as c
participant "everpro-subscription-public" as esp
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
participant "everpro-user" as eu
participant "everpro-subscription" as es
c -> esp : process create subscription
activate esp
esp -> ea: check account email (/v1/check-account/email)
activate ea
ea -> db_pa: check account by email
activate db_pa
return data account
return data account
alt if account not found by email
esp -> ea: check account telephone (/v1/check-account)
activate ea
ea -> db_pa: check account by telephone
activate db_pa
return data account
return data account
esp -> eu: get user by msisdn (/private/v1/check-msisdn)
activate eu
return user detail data
esp -> esp: setup sruct user detail
end
alt else
esp -> eu: get user by email (/private/v1/check-email)
activate eu
return user detail data
esp -> esp: setup sruct user detail
end
alt if user detail == nil
esp -> ea: register the user (/v3/register)
activate ea
return user detail
esp -> ea: private activate user after susbcribe (/private/v1/send/email-activate-after-subs)
activate ea
return success (ok)
esp -> esp: setup sruct user detail
end
esp -> es: private create subscription v2 with va payment (/private/v2/subscription/va-payment)
activate es
return success (ok)
return success (ok)
```
```plantuml
skinparam responseMessageBelowArrow true
title Private Send Email Activate Account - Proposed Interaction Diagram
participant "client" as c
participant "everpro-auth" as ea
database "popaket_auth" as db_pa
participant "nsq" as nsq
participant "everpro-email" as ee
participant "email" as email
c -> ea : process send email activate account
activate ea
alt if client unauthorized
ea -> ea : check api key
ea -> c : error unauthorized (invalid api key)
end
ea -> ea: generate verify email token
ea -> db_pa: update verification email (with tx)
activate db_pa
return success (ok)
ea -> ea: prepare payload request nsq send email activate account
ea -> nsq: publish message nsq send email activate account (asyncronus)
activate nsq
return success publish
return success (ok)
nsq -> ee: consume message nsq send email activate account
activate ee
ee -> ee: process request payload message
ee -> email: send the email that was previously set
activate email
return success (ok)
```