## 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) ```