diff --git a/README-APP.md b/README-APP.md
new file mode 100644
index 00000000..a31fed54
--- /dev/null
+++ b/README-APP.md
@@ -0,0 +1 @@
+# APP DESIGN CONVENTION
\ No newline at end of file
diff --git a/README-DB.md b/README-DB.md
new file mode 100644
index 00000000..c361ca31
--- /dev/null
+++ b/README-DB.md
@@ -0,0 +1,37 @@
+# DATABASE MODELING CONVETION
+
+## Naming
+1. Table names are written in combination, with the following rules:
+ 1. Basically uses `PascalCase`
+ 2. An underscore is used in `derived-table`, separating the original name and the derived name.
+ 3. A derived table is a table derived from another table but not used in the main flow of the business process.
+ 4. Examples of derived table implementations include:
+ 1. Archiving, for example: `Transaction_2019`, is an archive of the `Transaction` table for the year `2019`.
+ 2. Trashing for deleted data, for example: `Transaction_deleted`, stores data from the deleted `transaction` table.
+ 3. History for storing historical information, for example: `ProductStock_History`, stores historical data from the `ProductStock` table.
+2. Columns are written in combination, with the following rules:
+ 1. Basically, uses `PascalCase`
+ 2. Use underscores to represent relationships `object`-`attribute` or `table`-`column`
+
Example:
+ 1. `User_Id` represents the `User` object and the `Id` attribute
+ 2. `BestProduct_Code` represents the `BestProduct` object and the `Code` attribute
+ 3. When more than one column has a similar definition, a `prefix` can be added to indicate the column's purpose.
+
Example:
+ 1. `Admin_User_Id` represents the `Admin` of the `User` object and the `Id` attribute
+ 2. `Operator_User_Id` refers to the `Operator` of the `User` object and the `Id` column.
+3. Attributes/properties in JSON (for output purpose) are written in combination, with the following rules:
+ 1. Basically uses `camelCase`
+ 2. Using underscores to represent relationships `object`-`attribute` or `table`-`column`
+
Example:
+ 1. `user_id` represents the `User` object and the `Id` attribute.
+ 2. `bestProduct_code` represents the `bestProduct` object and the `code` attribute.
+ 3. When more than one column has a similar definition, a `prefix` can be added to indicate the column's purpose.
+
Example:
+ 1. `admin_user_id` refers to the `admin` of the `user` object and `id` attribute
+ 2. `operator_user_id` refers to the `operator` of the `user` object, column `id`
+ 3. `newArrival_bestProduct_code` refers to the `newArrival` of the `bestProduct` object, column `code`
+ 4. `favorite_bestProduct_code` refers to the `favorite` of the `bestProduct` object, column `code`
+
+## Avoiding Circular Dependency
+1. Prioritize the child due to it's nature to define the foreign key. This means the child is allowed to import main entities that define the table, not the base.
+2. Parent imports the child's non main entities, can be the base or others depending on the needs.
diff --git a/README.md b/README.md
index 3bd78fd3..a186c2f0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
-# simrs-be
\ No newline at end of file
+# SIMRS-VX
+
diff --git a/assets/.keep b/assets/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/assets/language/en/data.json b/assets/language/en/data.json
new file mode 100644
index 00000000..be5c94c1
--- /dev/null
+++ b/assets/language/en/data.json
@@ -0,0 +1,78 @@
+{
+ "request-ok": "request is done succesfully",
+ "request-methodNotAllowed": "request has been rejected, method is not allowed",
+ "request-tooMany": "too many request",
+ "payload-bad": "invalid data structure",
+
+ "auth-required": "authentication required",
+ "auth-missingHeader": "authentication header is missing",
+ "auth-forbidden": "forbidden",
+ "auth-login-success": "login success",
+ "auth-login-incorrect": "login failed, icorrect username or password",
+ "auth-login-tooMany": "login failed, too many login attempts",
+ "auth-login-blocked": "login failed, account is blocked",
+ "auth-login-unverified": "login failed, account is not verified",
+ "auth-logout-success": "logout success",
+ "auth-reject-suspend": "restricted for suspended account",
+
+ "balance-exceeded": "must not exceeds balance",
+
+ "email-confirmation-success": "email confirmation success",
+ "email-confirmation-fail": "failed to confirm email",
+ "email-confirmation-resend-fail": "failed to resend email confirmation",
+
+ "data-create-success": "data has been created",
+ "data-create-fail": "failed to create data",
+ "data-notFound": "data or resource can not be found",
+ "data-notFound-condition": "\"%v\" with %v \"%v\" can not be found",
+ "data-get-fail": "get data failed, %v",
+ "data-update-fail": "failed to update data",
+ "data-delete-success": "data has been deleted",
+ "data-delete-fail": "failed to delete data",
+ "data-send-fail": "send data failed, %v",
+ "data-fetch-fail": "failed to fetch data",
+ "data-copy-fail": "failed to copy data",
+ "data-process-fail": "failed to process data",
+ "data-confirm-fail": "failed to confirm data",
+ "data-generate-fail": "failed to generate data",
+ "data-registered": "is already registered",
+ "data-state-mismatch": "\"%v\" is not in \"%v\" state",
+ "data-duplicate": "duplicate data",
+ "data-payment-fail": "failed to create payment",
+
+ "expired": "is expired",
+ "registered": "is already registered",
+ "mustUuid": "must be a valid uuid",
+ "invalid": "invalid value",
+ "equalToField": "must equal to",
+ "constraint-vioalate": "must not violate constraint",
+
+ "config-fetch-done": "app config is fetched successfully",
+ "userToken-incorrect": "incorrect email, token, or token type",
+
+ "token-missing": "missing required token",
+ "token-invalid": "invalid token",
+ "token-invalidType": "invalid token type",
+ "token-sign-unexcpeted": "unexpected signing method: %v",
+ "token-sign-err": "token signing failed, %v",
+ "token-parse-fail": "token parsing failed, %v",
+ "token-expired": "token is expired",
+ "token-unidentified": "token is could not be identified",
+
+ "file-detect-fail": "file type detection failed",
+ "file-type-mismatch": "file type mismatch",
+ "file-create-fail": "failed to create file, %v",
+ "file-open-fail": "failed to open file, %v",
+ "file-copy-fail": "failed to copy file, %v",
+
+ "uuid-gen-fail" : "failed to generate uuid, %v",
+ "nanoid-gen-fail" : "failed to generate nanoid, %v",
+
+ "redis-store-fail": "redis storing value failed, %v",
+
+ "eq": "must be equal to %v",
+ "gt": "must be greater than %v",
+ "gte": "must be greater than or equal to %v",
+ "lt": "must be less than %v",
+ "lte": "must be less than or equal to %v"
+}
diff --git a/assets/language/id/data.json b/assets/language/id/data.json
new file mode 100644
index 00000000..9e064e9a
--- /dev/null
+++ b/assets/language/id/data.json
@@ -0,0 +1,83 @@
+{
+ "request-ok": "'request' berhasil diproses",
+ "request-methodNotAllowed": "'request' ditolak, method tidak diijinkan",
+ "request-tooMany": "terlalu banyak 'request'",
+ "payload-bad": "struktur data tidak sesuai standar",
+
+ "auth-required": "butuh autentikasi",
+ "auth-missingHeader": "Header autentikasi tidak ditemukan",
+ "auth-forbidden": "tidak diijinkan",
+ "auth-login-success": "login berhasil",
+ "auth-login-incorrect": "Username atau Password Tidak Sesuai",
+ "auth-login-tooMany": "login gagal, terlalu banyak percobaan",
+ "auth-login-blocked": "login gagal, akun diblokir",
+ "auth-login-unverified": "login gagal, akun belum terverifikasi",
+ "auth-logout-success": "logout berhasil",
+ "auth-reject-suspend": "dibatasi untuk akun dibekukan",
+
+ "balance-exceeded": "tidak boleh melebihi saldo",
+
+ "email-confirmation-success": "konfimrasi email berhasil",
+ "email-confirmation-fail": "gagal mengkonfirmasi email",
+ "email-confirmation-resend-fail": "gagal mengirim konfirmasi email",
+
+ "data-create-success": "data telah dibuat",
+ "data-create-fail": "gagal membuat data",
+ "data-notFound": "data atau sumber tidak daoat ditemukan",
+ "data-notFound-condition": "\"%v\" dengan %v \"%v\" tidak dapat ditemukan",
+ "data-get-fail": "gagal mengambil data, %v",
+ "data-update-success": "berhasil memperbarui data",
+ "data-update-fail": "gagal memperbarui data",
+ "data-delete-success": "data telah dihapus",
+ "data-delete-fail": "gagal menghapus data",
+ "data-fetch-fail": "gagal mengambil data",
+ "data-copy-fail": "gagal menyalin data",
+ "data-process-fail": "gagal memproses data",
+ "data-confirm-fail": "gagal mengirim data",
+ "data-generate-fail": "gagal membuat data",
+ "data-registered": "sudah pernah dibuat",
+ "data-state-mismatch": "\"%v\" tidak dalam kondisi \"%v\"",
+ "data-duplicate": "duplicate data",
+ "data-payment-fail": "failed to create payment",
+
+ "expired": "expired",
+ "registered": "sudah terdaftar",
+ "mustUuid": "harus UUID yang valid",
+ "invalid": "nilai tidak sesuai",
+ "equalToField": "harus sama dengan",
+ "constraint-vioalate": "tidak boleh melanggar batasan",
+
+ "config-fetch-done": "konfigurasi app berhasil diterapkan",
+ "userToken-incorrect": "salah email, token, atau jenis token",
+
+ "token-missing": "token tidak dapat ditemukan",
+ "token-invalid": "token tidak berlaku",
+ "token-invalidType": "jenis token tidak berlaku",
+ "token-sign-unexcpeted": "metode penanda tidak beralku: %v",
+ "token-sign-err": "penanda token tidak sesuai, %v",
+ "token-parse-fail": "%v",
+ "token-expired": "Token Expired",
+ "token-unidentified": "token tidak dapat diidentifikasi",
+
+ "file-detect-fail": "gagal mendeteksi tipe file",
+ "file-type-mismatch": "tipe file tidak sesuai",
+ "file-create-fail": "gagal membuat file, %v",
+ "file-open-fail": "gagal membuka file, %v",
+ "file-copy-fail": "gagal menyalin file, %v",
+
+ "uuid-gen-fail" : "gagal membuat UUID, %v",
+ "nanoid-gen-fail" : "gagal membuat NANOID, %v",
+
+ "redis-store-fail": "gagal mengimpan data pada redis, %v",
+
+ "eq": "must be equal to %v",
+ "gt": "must be greater than %v",
+ "gte": "lebih besar atau sama dengan %v",
+ "lt": "must be less than %v",
+ "lte": "lebih kecil atau sama dengan %v",
+
+ "jknData-required": "%v Belum Diisi",
+ "jknData-length": "Format %v Tidak Sesuai",
+ "jknData-numeric": "Format %v Tidak Sesuai",
+ "jknData-notFound": "%v Tidak Ditemukan"
+}
diff --git a/assets/language/readme.md b/assets/language/readme.md
new file mode 100644
index 00000000..720e25c8
--- /dev/null
+++ b/assets/language/readme.md
@@ -0,0 +1,2 @@
+# convention
+Key - value data indexed. Key prefered to be be consisting of 3 part: [feature]-[action]-[status]. Special case for validation that is intended to point error on an input (field), the key can be stated directly to the validation index, for example: min is for minimum value needed.
\ No newline at end of file
diff --git a/cmd/.keep b/cmd/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/cmd/main-api/config.yml-example b/cmd/main-api/config.yml-example
new file mode 100644
index 00000000..19893fd7
--- /dev/null
+++ b/cmd/main-api/config.yml-example
@@ -0,0 +1,47 @@
+appCfg:
+ fullName: BPJS Bridge
+ codeName: simrs-vx
+ version: 0.1.0
+ env: development
+ lang: en
+
+httpCfg:
+ host:
+ port:
+
+dbCfg:
+ dsn:
+ maxOpenConns: 5
+ maxIdleConns: 5
+ maxIdleTime: 100
+
+loggerCfg:
+ hideTime:
+ hideLevel:
+
+msCfg:
+ dsn:
+
+langCfg:
+ active:
+ path:
+ fileName:
+
+minioCfg:
+ endpoint:
+ region:
+ accessKey:
+ secretKey:
+ useSsl:
+ bucketName:
+ - patient
+
+corsCfg:
+ allowedOrigin:
+ allowedMethod:
+
+satuSehatCfg:
+ host: localhsot:8200
+
+bpjsCfg:
+ host: localhsot:8200
diff --git a/cmd/main-api/main.go b/cmd/main-api/main.go
new file mode 100644
index 00000000..74be3afd
--- /dev/null
+++ b/cmd/main-api/main.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ a "github.com/karincake/apem"
+ d "github.com/karincake/apem/db-gorm-pg"
+ l "github.com/karincake/apem/logger-zerolog"
+ m "github.com/karincake/apem/ms-redis"
+
+ h "simrs-vx/internal/interface/main-handler"
+)
+
+func main() {
+ a.Run(h.SetRoutes(), &l.O, &m.O, &d.O)
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 00000000..535bb824
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,32 @@
+module simrs-vx
+
+go 1.23.0
+
+toolchain go1.23.11
+
+require (
+ github.com/karincake/apem v0.0.16-e
+ github.com/karincake/dodol v0.0.1
+ gorm.io/gorm v1.25.10
+)
+
+require (
+ github.com/go-redis/redis v6.15.9+incompatible // indirect
+ github.com/google/go-cmp v0.7.0 // indirect
+ github.com/jackc/pgpassfile v1.0.0 // indirect
+ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
+ github.com/jackc/pgx/v5 v5.4.3 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
+ github.com/kr/text v0.2.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/nxadm/tail v1.4.11 // indirect
+ github.com/rs/zerolog v1.33.0 // indirect
+ golang.org/x/crypto v0.40.0 // indirect
+ golang.org/x/net v0.42.0 // indirect
+ golang.org/x/sys v0.34.0 // indirect
+ golang.org/x/text v0.27.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ gorm.io/driver/postgres v1.5.7 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 00000000..79fad110
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,78 @@
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
+github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY=
+github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/karincake/apem v0.0.16-e h1:KGeQYmgNw8luidSWkZyGcMbW1PP3KMRCHMTEHQ7twU8=
+github.com/karincake/apem v0.0.16-e/go.mod h1:cQP2sJfDrLRIiwWoaLWw/z8uAya+DWu/FpmYeinMQXM=
+github.com/karincake/dodol v0.0.1 h1:jUXmJh1r0Ei4fmHPZ6IUkoplW/V9d27L63JEl6zudL0=
+github.com/karincake/dodol v0.0.1/go.mod h1:2f1NcvkvY0J3GMUkwILNDYVvRUpz0W3lpPp/Ha/Ld24=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
+github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
+golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
+golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
+golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
+golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
+golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM=
+gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA=
+gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
+gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
diff --git a/internal/domain/_template/child/base/entity.go b/internal/domain/_template/child/base/entity.go
new file mode 100644
index 00000000..62d55346
--- /dev/null
+++ b/internal/domain/_template/child/base/entity.go
@@ -0,0 +1,26 @@
+/*
+DESCRIPTION:
+Sample of base-entity, results of the extraction of the attributes from the
+original entity.
+
+NOTE:
+Make sure to use 'case-sensitive' option when searching
+
+TODO:
+create several types according to the needs
+*/
+package base // adjust this
+
+type Basic struct {
+ Code string `json:"code" gorm:"uniqueIndex;not null;size:10"`
+ Name string `json:"name" gorm:"not null;size:100"`
+}
+
+type Default struct {
+ Type_Code TypeCode `json:"type" gorm:"not null;size:10"`
+ Status_Code StatusCode `json:"status" gorm:"not null;size:10"`
+}
+
+type Extra struct {
+ Description string `json:"description"`
+}
diff --git a/internal/domain/_template/child/base/tycovar.go b/internal/domain/_template/child/base/tycovar.go
new file mode 100644
index 00000000..7665aa9a
--- /dev/null
+++ b/internal/domain/_template/child/base/tycovar.go
@@ -0,0 +1,17 @@
+/*
+DESCRIPTION:
+A sample, part of the package that contains type, constants, and/or variables.
+*/
+package base // adjust this
+
+type StatusCode string
+type TypeCode string
+
+const (
+ SCActive StatusCode = "active" // prefixed with SC that stands for StatusCode
+ SCInactive StatusCode = "inactive"
+
+ TCPrimary TypeCode = "prim" // prefixed with TC that stands for TypeCode
+ TCScondary TypeCode = "seco"
+ TCTertiary TypeCode = "tert"
+)
diff --git a/internal/domain/_template/child/entity.go b/internal/domain/_template/child/entity.go
new file mode 100644
index 00000000..7d3e0109
--- /dev/null
+++ b/internal/domain/_template/child/entity.go
@@ -0,0 +1,28 @@
+/*
+DESCRIPTION:
+Sample of struct to define an entity both in the application and database.
+Uses the base struct from the core package for the standard attributes.
+
+The sampel is part of the the workaround sample on how to avoid the
+circle-depency. The child is used to define the relationship for the database.
+
+TODO:
+- replace 'child' with the name of the package, ie: myentity
+- replace 'Child' with the name of the entity, ie: MyEntity
+*/
+package child
+
+import (
+ ecore "simrs-vx/internal/domain/base-entities/core"
+ eb "simrs-vx/internal/domain/main-entities/child/base"
+ ep "simrs-vx/internal/domain/main-entities/parent"
+)
+
+type Child struct {
+ ecore.Main
+ eb.Basic
+ Parent_Id int `json:"parent_id"`
+ Pareng ep.Parent `json:"parent" gorm:"foreignKey:Parent_Id;references:Id"`
+ eb.Default
+ eb.Extra
+}
diff --git a/internal/domain/_template/child/simple/entity.go b/internal/domain/_template/child/simple/entity.go
new file mode 100644
index 00000000..dbdd1169
--- /dev/null
+++ b/internal/domain/_template/child/simple/entity.go
@@ -0,0 +1,21 @@
+/*
+DESCRIPTION:
+Sample of a case-entity that utilized the base according to the needs.
+
+NOTE:
+Make sure to use 'case-sensitive' option when searching
+
+TODO:
+replace 'child' with the name of the package, ie: myentity
+replace 'Child' with the name of the entity, ie: MyEntity
+*/
+package child
+
+import (
+ eb "simrs-vx/internal/domain/main-entities/child/base"
+)
+
+type Child struct {
+ Id int `json:"id"` // in many cases the usage of
+ eb.Basic
+}
diff --git a/internal/domain/_template/parent/base/entity.go b/internal/domain/_template/parent/base/entity.go
new file mode 100644
index 00000000..62d55346
--- /dev/null
+++ b/internal/domain/_template/parent/base/entity.go
@@ -0,0 +1,26 @@
+/*
+DESCRIPTION:
+Sample of base-entity, results of the extraction of the attributes from the
+original entity.
+
+NOTE:
+Make sure to use 'case-sensitive' option when searching
+
+TODO:
+create several types according to the needs
+*/
+package base // adjust this
+
+type Basic struct {
+ Code string `json:"code" gorm:"uniqueIndex;not null;size:10"`
+ Name string `json:"name" gorm:"not null;size:100"`
+}
+
+type Default struct {
+ Type_Code TypeCode `json:"type" gorm:"not null;size:10"`
+ Status_Code StatusCode `json:"status" gorm:"not null;size:10"`
+}
+
+type Extra struct {
+ Description string `json:"description"`
+}
diff --git a/internal/domain/_template/parent/base/tycovar.go b/internal/domain/_template/parent/base/tycovar.go
new file mode 100644
index 00000000..7665aa9a
--- /dev/null
+++ b/internal/domain/_template/parent/base/tycovar.go
@@ -0,0 +1,17 @@
+/*
+DESCRIPTION:
+A sample, part of the package that contains type, constants, and/or variables.
+*/
+package base // adjust this
+
+type StatusCode string
+type TypeCode string
+
+const (
+ SCActive StatusCode = "active" // prefixed with SC that stands for StatusCode
+ SCInactive StatusCode = "inactive"
+
+ TCPrimary TypeCode = "prim" // prefixed with TC that stands for TypeCode
+ TCScondary TypeCode = "seco"
+ TCTertiary TypeCode = "tert"
+)
diff --git a/internal/domain/_template/parent/entity.go b/internal/domain/_template/parent/entity.go
new file mode 100644
index 00000000..2983af6f
--- /dev/null
+++ b/internal/domain/_template/parent/entity.go
@@ -0,0 +1,31 @@
+/*
+DESCRIPTION:
+Sample of struct to define an entity both in the application and database.
+Uses the base struct from the core package for the standard attributes.
+
+The sampel shows a workaround on how to avoid the circle-depency which is a
+common problem when it involves the parent-child relationship. By default,
+the relationship is defined in the child entity, and when the parent entity
+needs to use the child as an attribute (array for example), the circle-depency
+happens.
+
+To avoid this problem, the parent will have a case-entity like 'full' entity,
+which embeds the 'base' and the 'child' structs.
+
+TODO:
+- replace 'parent' with the name of the package, ie: myentity
+- replace 'Parent' with the name of the entity, ie: MyEntity
+*/
+package parent
+
+import (
+ ecore "simrs-vx/internal/domain/base-entities/core"
+ eb "simrs-vx/internal/domain/main-entities/parent/base"
+)
+
+type Parent struct {
+ ecore.Main
+ eb.Basic
+ eb.Default
+ eb.Extra
+}
diff --git a/internal/domain/_template/parent/full/entity.go b/internal/domain/_template/parent/full/entity.go
new file mode 100644
index 00000000..ccbae089
--- /dev/null
+++ b/internal/domain/_template/parent/full/entity.go
@@ -0,0 +1,24 @@
+/*
+DESCRIPTION:
+Sample of a case-entity that utilized the base according to the needs. In this
+sample, it imports the child entity, and uses it as an attribute. And by
+separating this entity from the original entity, it avoids the circle dependency.
+
+TODO:
+replace 'parent' with the name of the package, ie: patient
+replace 'Parent' with the name of the entity, ie: Patient
+*/
+package parent
+
+import (
+ ec "simrs-vx/internal/domain/main-entities/child"
+ eb "simrs-vx/internal/domain/main-entities/parent/base"
+ // ec "simrs-vx/internal/domain/main-entities/child/minimal" // can use other case
+)
+
+type Parent struct {
+ Id int `json:"id"`
+ eb.Basic
+ eb.Default
+ Childs []ec.Child `json:"childs" gorm:"foreignKey:Parent_Id;references:Id"`
+}
diff --git a/internal/domain/_template/parent/minimal/entity.go b/internal/domain/_template/parent/minimal/entity.go
new file mode 100644
index 00000000..9ea7630e
--- /dev/null
+++ b/internal/domain/_template/parent/minimal/entity.go
@@ -0,0 +1,19 @@
+/*
+DESCRIPTION:
+Sample of a case-entity that utilized the base according to the needs.
+
+TODO:
+replace 'parent' with the name of the package, ie: patient
+replace 'Parent' with the name of the entity, ie: Patient
+*/
+package parent
+
+import (
+ eb "simrs-vx/internal/domain/main-entities/parent/base"
+)
+
+type Parent struct {
+ Id int `json:"id"`
+ eb.Basic
+ eb.Default
+}
diff --git a/internal/domain/_template/separated/base/entity.go b/internal/domain/_template/separated/base/entity.go
new file mode 100644
index 00000000..62d55346
--- /dev/null
+++ b/internal/domain/_template/separated/base/entity.go
@@ -0,0 +1,26 @@
+/*
+DESCRIPTION:
+Sample of base-entity, results of the extraction of the attributes from the
+original entity.
+
+NOTE:
+Make sure to use 'case-sensitive' option when searching
+
+TODO:
+create several types according to the needs
+*/
+package base // adjust this
+
+type Basic struct {
+ Code string `json:"code" gorm:"uniqueIndex;not null;size:10"`
+ Name string `json:"name" gorm:"not null;size:100"`
+}
+
+type Default struct {
+ Type_Code TypeCode `json:"type" gorm:"not null;size:10"`
+ Status_Code StatusCode `json:"status" gorm:"not null;size:10"`
+}
+
+type Extra struct {
+ Description string `json:"description"`
+}
diff --git a/internal/domain/_template/separated/base/helper.go b/internal/domain/_template/separated/base/helper.go
new file mode 100644
index 00000000..9a910db3
--- /dev/null
+++ b/internal/domain/_template/separated/base/helper.go
@@ -0,0 +1,13 @@
+/*
+DESCRIPTION:
+A sample, part of the package that contains functions.
+*/
+package base
+
+import (
+ "strings"
+)
+
+func (b *Basic) ExtractName() []string {
+ return strings.Split(b.Name, " ")
+}
diff --git a/internal/domain/_template/separated/base/tycovar.go b/internal/domain/_template/separated/base/tycovar.go
new file mode 100644
index 00000000..7665aa9a
--- /dev/null
+++ b/internal/domain/_template/separated/base/tycovar.go
@@ -0,0 +1,17 @@
+/*
+DESCRIPTION:
+A sample, part of the package that contains type, constants, and/or variables.
+*/
+package base // adjust this
+
+type StatusCode string
+type TypeCode string
+
+const (
+ SCActive StatusCode = "active" // prefixed with SC that stands for StatusCode
+ SCInactive StatusCode = "inactive"
+
+ TCPrimary TypeCode = "prim" // prefixed with TC that stands for TypeCode
+ TCScondary TypeCode = "seco"
+ TCTertiary TypeCode = "tert"
+)
diff --git a/internal/domain/_template/separated/entity.go b/internal/domain/_template/separated/entity.go
new file mode 100644
index 00000000..dfcc3726
--- /dev/null
+++ b/internal/domain/_template/separated/entity.go
@@ -0,0 +1,34 @@
+/*
+DESCRIPTION:
+Sample of struct to define an entity both in the application and database.
+Uses the base struct from the core package for the standard attributes.
+
+The original attributes are extracted and grouped into several parts (structs),
+which later embeded. The extracted attributes are stored into the subdirectory
+'base'.
+
+The extraction is done to cover several cases regarding the eficiency the of
+the data retreiving by using only needed attributes. Each case has its own
+directory with the same struct name with the main entity that embeds the
+needed attributes from the 'base'.
+
+NOTES:
+Make sure to use 'case-sensitive' option when doing search-replace
+
+TODO:
+- replace 'separated' with the name of the package, ie: myentity
+- replace 'Separated' with the name of the entity, ie: MyEntity
+*/
+package separated
+
+import (
+ ecore "simrs-vx/internal/domain/base-entities/core"
+ eb "simrs-vx/internal/domain/main-entities/separated/base"
+)
+
+type Separated struct {
+ ecore.Main // adjust this according to the needs
+ eb.Basic
+ eb.Default
+ eb.Extra
+}
diff --git a/internal/domain/_template/separated/minimal/entity.go b/internal/domain/_template/separated/minimal/entity.go
new file mode 100644
index 00000000..b4a7c45a
--- /dev/null
+++ b/internal/domain/_template/separated/minimal/entity.go
@@ -0,0 +1,21 @@
+/*
+DESCRIPTION:
+Sample of a case-entity that utilized the base according to the needs.
+
+NOTE:
+Make sure to use 'case-sensitive' option when searching
+
+TODO:
+replace 'separated' with the name of the package, ie: myentity
+replace 'Separated' with the name of the entity, ie: MyEntity
+*/
+package separated
+
+import (
+ eb "simrs-vx/internal/domain/main-entities/separated/base"
+)
+
+type Separated struct {
+ Id int `json:"id"`
+ eb.Basic
+}
diff --git a/internal/domain/_template/separated/simple/entity.go b/internal/domain/_template/separated/simple/entity.go
new file mode 100644
index 00000000..d9b74b23
--- /dev/null
+++ b/internal/domain/_template/separated/simple/entity.go
@@ -0,0 +1,22 @@
+/*
+DESCRIPTION:
+Sample of a case-entity that utilized the base according to the needs.
+
+NOTE:
+Make sure to use 'case-sensitive' option when searching
+
+TODO:
+replace 'separated' with the name of the package, ie: myentity
+replace 'Separated' with the name of the entity, ie: MyEntity
+*/
+package separated
+
+import (
+ eb "simrs-vx/internal/domain/main-entities/separated/base"
+)
+
+type Separated struct {
+ Id int `json:"id"` // in many cases the usage of
+ eb.Basic
+ eb.Default
+}
diff --git a/internal/domain/_template/single/dto.go b/internal/domain/_template/single/dto.go
new file mode 100644
index 00000000..ba3e602b
--- /dev/null
+++ b/internal/domain/_template/single/dto.go
@@ -0,0 +1,26 @@
+package single
+
+type Createdto struct {
+ Code string `json:"code"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+}
+
+type ReadListDto struct {
+ Code string `json:"code"`
+ Name string `json:"name"`
+}
+
+type ReadDetailDto struct {
+ Code string `json:"code"`
+ Name string `json:"name"`
+}
+
+type Updatedto struct {
+ Id uint `json:"id"`
+ Createdto
+}
+
+type Deletedto struct {
+ Id uint `json:"id"`
+}
diff --git a/internal/domain/_template/single/entity.go b/internal/domain/_template/single/entity.go
new file mode 100644
index 00000000..0b9d4d79
--- /dev/null
+++ b/internal/domain/_template/single/entity.go
@@ -0,0 +1,25 @@
+/*
+DESCRIPTION:
+Sample of struct to define an entity both in the application and database.
+Uses the base struct from the core package for the standard
+attributes.
+
+NOTES:
+Make sure to use 'case-sensitive' option when doing search-replace
+
+TODO:
+- replace 'single' with the name of the package, ie: 'patient'
+- replace 'Single' with the name of the entity, ie: 'Patient'
+*/
+package single
+
+import (
+ ecore "simrs-vx/internal/domain/base-entities/core"
+)
+
+type Single struct {
+ ecore.Main // adjust this according to the needs
+ Code string `json:"code" gorm:"uniqueIndex;not null;size:10"`
+ Name string `json:"name" gorm:"not null;size:100"`
+ Description string `json:"description"`
+}
diff --git a/internal/domain/base-entities/.keep b/internal/domain/base-entities/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/domain/base-entities/actor/entity.go b/internal/domain/base-entities/actor/entity.go
new file mode 100644
index 00000000..ce538bb1
--- /dev/null
+++ b/internal/domain/base-entities/actor/entity.go
@@ -0,0 +1,11 @@
+package actor
+
+type Actor struct {
+ CreatedBy_User_Id uint `json:"createdBy_user_id"`
+ UpdatedBy_User_Id uint `json:"updatedBy_user_id"`
+ DeletedBy_User_Id uint `json:"deletedBy_user_id"`
+}
+
+type Owner struct {
+ OwnedBy_User_Id uint `json:"ownedBy_user_id"`
+}
diff --git a/internal/domain/base-entities/core/entity.go b/internal/domain/base-entities/core/entity.go
new file mode 100644
index 00000000..6a88e7af
--- /dev/null
+++ b/internal/domain/base-entities/core/entity.go
@@ -0,0 +1,31 @@
+package core
+
+import "gorm.io/gorm"
+
+type Base struct {
+ CreatedAt string `json:"createdAt"`
+ UpdatedAt string `json:"updatedAt"`
+ DeteledAt gorm.DeletedAt `json:"deletedAt,omitempty"`
+}
+
+//
+type Main struct {
+ Id uint `json:"id" gorm:"primaryKey"` // depends on the system architecture
+ Base
+}
+
+type TinyMain struct {
+ Id uint8 `json:"id" gorm:"primaryKey"`
+ Base
+}
+
+type SmallMain struct {
+ Id uint16 `json:"id" gorm:"primaryKey"`
+ Base
+}
+
+// Mainly for transaction
+type BigMain struct {
+ Id uint64 `json:"id" gorm:"primaryKey"`
+ Base
+}
diff --git a/internal/infra/.keep b/internal/infra/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/interface/.keep b/internal/interface/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/interface/_template/crud/handler.go b/internal/interface/_template/crud/handler.go
new file mode 100644
index 00000000..5ee7c413
--- /dev/null
+++ b/internal/interface/_template/crud/handler.go
@@ -0,0 +1,40 @@
+/*
+DESCRIPTION:
+Sample of the use-case that has fully CRUD functionality. Uses object with CRUD
+functions to satisfy CRUD interface so it will be able to be generated into
+CRUD routing.
+
+Functions other than CRUD can be writen outside the object.
+*/
+package crud
+
+import (
+ "net/http"
+)
+
+type myBase struct{}
+
+var O myBase
+
+func (obj myBase) Create(w http.ResponseWriter, r *http.Request) {
+ // MULAI MEETING E
+ // JIKA SUATU SAAT MAU OUTPUT XML, HANDLER YG MELAKUKAN
+ // BUKAN CASE
+ // YES MIRIP HANDLER
+ // MEETING E MULAI
+}
+
+func (obj myBase) Read(w http.ResponseWriter, r *http.Request) {
+}
+
+func (obj myBase) Update(w http.ResponseWriter, r *http.Request) {
+}
+
+func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) {
+}
+
+func OtherFunc(w http.ResponseWriter, r *http.Request) {
+}
+
+func AnotherFunc(w http.ResponseWriter, r *http.Request) {
+}
diff --git a/internal/interface/_template/invoke-auth/handler.go b/internal/interface/_template/invoke-auth/handler.go
new file mode 100644
index 00000000..87462bd4
--- /dev/null
+++ b/internal/interface/_template/invoke-auth/handler.go
@@ -0,0 +1,16 @@
+/*
+DESCRIPTION:
+Sample of a use-case that has fully CRUD functionality. User Id and the other
+things related to credentials are passed within the dto.
+*/
+package invokeauth
+
+import (
+ "net/http"
+)
+
+func SomeFunc(w http.ResponseWriter, r *http.Request) {
+ // if dto.User_Id > 0 {
+ // query = query.Where("User_Id = ?", dto.User_Id)
+ // }
+}
diff --git a/internal/interface/_template/non-crud/handler.go b/internal/interface/_template/non-crud/handler.go
new file mode 100644
index 00000000..a98a807c
--- /dev/null
+++ b/internal/interface/_template/non-crud/handler.go
@@ -0,0 +1,15 @@
+package crud
+
+import (
+ "net/http"
+)
+
+type myBase struct{}
+
+var O myBase
+
+func SomeFunc(w http.ResponseWriter, r *http.Request) {
+}
+
+func Read(w http.ResponseWriter, r *http.Request) {
+}
diff --git a/internal/interface/main-handler/home/handler.go b/internal/interface/main-handler/home/handler.go
new file mode 100644
index 00000000..ad0461da
--- /dev/null
+++ b/internal/interface/main-handler/home/handler.go
@@ -0,0 +1,23 @@
+package home
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+func Home(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/" {
+ jsonText, _ := json.Marshal(map[string]string{"message": "Resource can not be found!!"})
+ w.WriteHeader(http.StatusNotFound)
+ w.Write(jsonText)
+ return
+ }
+
+ jsonText, _ := json.Marshal(map[string]string{"message": "Welcome to the API"})
+ w.Write(jsonText)
+}
+
+func TempResponse(w http.ResponseWriter, r *http.Request) {
+ jsonText, _ := json.Marshal(map[string]string{"message": "Nice move by the programmer, now tell him that he forgot this part"})
+ w.Write(jsonText)
+}
diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go
new file mode 100644
index 00000000..b959178b
--- /dev/null
+++ b/internal/interface/main-handler/main-handler.go
@@ -0,0 +1,25 @@
+package handler
+
+import (
+ "net/http"
+
+ ///// PKG
+ handlerlogger "simrs-vx/pkg/middleware/handler-logger"
+
+ ///// Internal
+ "simrs-vx/internal/interface/main-handler/home"
+)
+
+// One place route to relatively easier to manage, ESPECIALLY in tracking
+func SetRoutes() http.Handler {
+ /////
+ // a.RegisterExtCall(gs.Adjust)
+
+ r := http.NewServeMux()
+
+ /******************** Main ********************/
+ r.HandleFunc("/", home.Home)
+
+ /////
+ return handlerlogger.SetLog(r)
+}
diff --git a/internal/use-case/.keep b/internal/use-case/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/use-case/_plugin-template/.keep b/internal/use-case/_plugin-template/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/use-case/_plugin-template/modifier/modifire.go b/internal/use-case/_plugin-template/modifier/modifire.go
new file mode 100644
index 00000000..1c546e32
--- /dev/null
+++ b/internal/use-case/_plugin-template/modifier/modifire.go
@@ -0,0 +1,20 @@
+package modifier
+
+import (
+ "gorm.io/gorm"
+
+ e "simrs-vx/internal/domain/main-entities/single"
+)
+
+// a sampel of modifying some input
+func ModifInput(input *e.Createdto, data *e.Single, tx *gorm.DB) error {
+ input.Name = "Prefix_" + input.Name
+ return nil
+}
+
+// a sampel of utilizing transaction
+func CheckData(input *e.Createdto, data *e.Single, tx *gorm.DB) error {
+ tx.Where("Name = ?", input.Name)
+ input.Name = "Prefix_" + input.Name
+ return nil
+}
diff --git a/internal/use-case/_use-case-template/.keep b/internal/use-case/_use-case-template/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/use-case/_use-case-template/crud/README.md b/internal/use-case/_use-case-template/crud/README.md
new file mode 100644
index 00000000..27825b2e
--- /dev/null
+++ b/internal/use-case/_use-case-template/crud/README.md
@@ -0,0 +1,59 @@
+# Use-Case
+Standard pattern to be used to maintain the code scalability by providing
+middleware-based flow. Each function can have its own middlewares for
+pre- and post-processing.
+
+According to the pattern above all of the case-functions runs only basic
+rdbms operations, like getting data or writing data. And it's all based
+on the data structure. The middlewares are used to for additional actions.
+
+## How It's Done
+The use-case is divided into at least 2 parts:
+1. Case (`case.go`), where the `case` functions (the main functions) are stored
+2. Tycovar (`tycovar.go`), where package scoped types, const, and variables
+ are stored
+
+Optionally, there can be other parts, such as:
+1. Helper (`helper.go`), where internal functions are stored
+2. Middleware (`middleware.go`), where the pre- and post-processing functions
+ are stored
+
+Then proceed the following steps (example):
+1. Inside the `tycovar.go`, define the middleware types for each case
+ functions. Make sure to:
+ 1. Include dto, table definition, and transaction for the parameters
+ since the middlewares are to utilize or modifies one ot the parameters.
+ 2. Make all of the parameter pointer for easier handling.
+ 3. Return `error` for blocking purpose when error occurs.
+ ```go
+ type createMw func(input *e.Createdto, tx *gorm.DB) error
+ .
+ .
+ ```
+2. Inside the `tycovar.go`, create variables in form of array to make it
+ possible to have more than one middleware. There are 2 modes (pre- and
+ post-processing) for each case functions:
+
+ ```go
+ var createPreMw []createMw
+ var createPostMw []createMw
+ .
+ .
+ ```
+3. Inside the `middleware.go`, create the necessary middlewares
+ ```go
+ func createPreMwAddNamePrefix(input *e.Createdto, tx *gorm.DB) error {
+ input.Name = "Prefix_" + input.Name
+ return nil
+ }
+ ```
+4. Inside the `middleware.go`, append the middlewares during initialization.
+ The order of the does not really is important, except there are steps that
+ are dependent on each other.
+ ```go
+ func init() {
+ createPreMw = append(createPreMw, createPreMwAddNamePrefix)
+ }
+ ```
+5. Loop through the middleware variables and call each middleware. Since there
+ are 2 modes (pre- and post-processing), the order of the calls is important.
diff --git a/internal/use-case/_use-case-template/crud/case.go b/internal/use-case/_use-case-template/crud/case.go
new file mode 100644
index 00000000..cf617ff7
--- /dev/null
+++ b/internal/use-case/_use-case-template/crud/case.go
@@ -0,0 +1,71 @@
+/*
+DESCRIPTION:
+Any functions that are available to be used externally.
+*/
+package crud
+
+import (
+ dg "github.com/karincake/apem/db-gorm-pg"
+ d "github.com/karincake/dodol"
+ "gorm.io/gorm"
+
+ e "simrs-vx/internal/domain/main-entities/single"
+)
+
+const source = "crud"
+
+func Create(input e.Createdto) (*d.Data, error) {
+ err := dg.I.Transaction(func(tx *gorm.DB) error {
+ for i := range createPreMw {
+ if err := createPreMw[i](&input, &data, dg.I); err != nil {
+ return nil
+ }
+ }
+
+ if err := dg.I.Create(&data).Error; err != nil {
+ return nil
+ }
+
+ for i := range createPostMw {
+ if err := createPostMw[i](&input, &data, dg.I); err != nil {
+ return nil
+ }
+ }
+
+ return nil
+ })
+
+ return &d.Data{
+ Meta: d.II{
+ "source": source,
+ "type": "list",
+ "status": "created",
+ },
+ Data: result,
+ }, nil
+}
+
+func ReadList(input e.ReadListDto) (*d.Data, error) {
+ data := d.Data{}
+ query := dg.I
+ query.Find(&data)
+ if err := query.Error; err != nil {
+ return nil, err
+ }
+ return &d.Data{
+ Meta: d.II{},
+ Data: data,
+ }, nil
+}
+
+func ReadDetail() {
+
+}
+
+func Update() {
+
+}
+
+func Delete() {
+
+}
diff --git a/internal/use-case/_use-case-template/crud/helper.go b/internal/use-case/_use-case-template/crud/helper.go
new file mode 100644
index 00000000..0d09eb8f
--- /dev/null
+++ b/internal/use-case/_use-case-template/crud/helper.go
@@ -0,0 +1,13 @@
+/*
+DESCRIPTION:
+Any functions that are used internally by the use-case
+*/
+package crud
+
+import (
+ e "simrs-vx/internal/domain/main-entities/single"
+)
+
+func setData(src e.Createdto, dst *e.Single) {
+
+}
diff --git a/internal/use-case/_use-case-template/crud/lib.go b/internal/use-case/_use-case-template/crud/lib.go
new file mode 100644
index 00000000..0283c7d8
--- /dev/null
+++ b/internal/use-case/_use-case-template/crud/lib.go
@@ -0,0 +1,25 @@
+package crud
+
+import (
+ e "simrs-vx/internal/domain/main-entities/single"
+
+ dg "github.com/karincake/apem/db-gorm-pg"
+ "gorm.io/gorm"
+)
+
+func CreateData(input e.Createdto, tx ...*gorm.DB) (*e.Single, error) {
+ data := e.Single{}
+
+ var db *gorm.DB
+ if tx != nil {
+ db = tx
+ } else {
+ db = dg.I
+ }
+
+ if err := dg.I.Create(&data).Error; err != nil {
+ return nil, err
+ }
+
+ return &data, err
+}
diff --git a/internal/use-case/_use-case-template/crud/middleware.go b/internal/use-case/_use-case-template/crud/middleware.go
new file mode 100644
index 00000000..6ca644fd
--- /dev/null
+++ b/internal/use-case/_use-case-template/crud/middleware.go
@@ -0,0 +1,10 @@
+package crud
+
+import (
+ pm "simrs-vx/internal/use-case/plugin/modifier"
+)
+
+func init() {
+ createPreMw = append(createPreMw, pm.ModifInput)
+ createPreMw = append(createPreMw, pm.CheckData)
+}
diff --git a/internal/use-case/_use-case-template/crud/tycovar.go b/internal/use-case/_use-case-template/crud/tycovar.go
new file mode 100644
index 00000000..17945a31
--- /dev/null
+++ b/internal/use-case/_use-case-template/crud/tycovar.go
@@ -0,0 +1,32 @@
+/*
+DESCRIPTION:
+A sample, part of the package that contains type, constants, and/or variables.
+
+In this sample it also provides type and variable regarding the needs of the
+middleware to separate from main use-case which has the basic CRUD
+functionality. The purpose of this is to make the code more maintainable.
+*/
+package crud
+
+import (
+ "gorm.io/gorm"
+
+ e "simrs-vx/internal/domain/main-entities/single"
+)
+
+type createMw func(input *e.Createdto, data *e.Single, tx *gorm.DB) error
+type readListMw func(input *e.ReadListDto, data *e.Single, tx *gorm.DB) error
+type readDetailMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error
+type updateMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error
+type deleteMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error
+
+var createPreMw []createMw // preprocess middleware
+var createPostMw []createMw // postprocess middleware
+var readListPreMw []readListMw // ..
+var readListPostMw []readListMw // ..
+var readDetailPreMw []readDetailMw
+var readDetailPostMw []readDetailMw
+var udpatePreMw []readDetailMw
+var udpatePostMw []readDetailMw
+var deletePreMw []readDetailMw
+var deletePostMw []readDetailMw
diff --git a/internal/use-case/main-use-case/.keep b/internal/use-case/main-use-case/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/internal/use-case/plugin/.keep b/internal/use-case/plugin/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/middleware/.keep b/pkg/middleware/.keep
new file mode 100644
index 00000000..e69de29b
diff --git a/pkg/middleware/handler-logger/handler-logger.go b/pkg/middleware/handler-logger/handler-logger.go
new file mode 100644
index 00000000..ed6b77c6
--- /dev/null
+++ b/pkg/middleware/handler-logger/handler-logger.go
@@ -0,0 +1,52 @@
+package handlerloggermw
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "time"
+
+ l "github.com/karincake/apem/loggera"
+ lo "github.com/karincake/apem/loggero"
+)
+
+var Logger l.LoggerItf
+
+type wrappedWriter struct {
+ http.ResponseWriter
+ statusCode int
+}
+
+func (w *wrappedWriter) WriteHeader(statusCode int) {
+ w.statusCode = statusCode
+ w.ResponseWriter.WriteHeader(statusCode)
+}
+
+func SetLog(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ start := time.Now()
+ wrapped := &wrappedWriter{
+ ResponseWriter: w,
+ statusCode: http.StatusOK,
+ }
+
+ next.ServeHTTP(wrapped, r)
+ Logger.Info().
+ String("scope", "request").
+ Int("status", wrapped.statusCode).
+ String("method", r.Method).
+ String("path", r.URL.Path).
+ String("query", r.URL.RawQuery).
+ String("duration", time.Since(start).String()).Send()
+ })
+}
+
+func WriteJson(data any) {
+ lo.I.Println("Showing additional info for the payload")
+ js, err := json.Marshal(data)
+ if err == nil {
+ fmt.Println(string(js))
+ } else {
+ fmt.Println("error converting data or result to json:", err)
+ }
+}