diff --git a/.env b/.env
index 1f5f0f141e9c1391bcd5b0325fbb516f0fa4bbfb..d4be5051a8f94bc7ee3b00530bd3191d5194a842 100644
--- a/.env
+++ b/.env
@@ -7,4 +7,5 @@ LOG_FLUSH_INTERVAL_MS=1000
 DB_STRING="host=localhost user=ocw password=ocw dbname=ocw-db port=5433 sslmode=disable TimeZone=Asia/Shanghai"
 SMTP_USERNAME="noreply@ocw.id"
 SMTP_SERVER=localhost
-SMTP_PORT=1025
\ No newline at end of file
+SMTP_PORT=1025
+REDIS_STRING="localhost"
\ No newline at end of file
diff --git a/.env.docker b/.env.docker
index 11f1edfc100a7fcebca3466da30fcdd21feff42d..2f87fea919b87db0f51f52306a1a8c21e13e3aaf 100644
--- a/.env.docker
+++ b/.env.docker
@@ -1,3 +1,14 @@
 POSTGRES_USER=ocw
 POSTGRES_PASSWORD=ocw
 POSTGRES_DB=ocw-db
+ENV=DEVELOPMENT
+LISTEN_ADDR=0.0.0.0
+PORT=8080
+LOGTAIL_TOKEN=
+HTTP_TIMEOUT_SEC=2
+LOG_FLUSH_INTERVAL_MS=1000
+DB_STRING="host=database user=ocw password=ocw dbname=ocw-db port=5432 sslmode=disable TimeZone=Asia/Shanghai"
+SMTP_USERNAME="noreply@ocw.id"
+SMTP_SERVER=mailhog
+SMTP_PORT=1025
+REDIS_STRING="redis"
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 7ccabe6b9f336b3be6a3a55f4c8d11c8c2127306..3eccf485e7a93a9172dcdfca800f8bcf2b732655 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -21,7 +21,7 @@ services:
       - .:/app
     ports:
       - 8888:8080
-    env_file: .env
+    env_file: .env.docker
     depends_on:
       - database
       - minio
diff --git a/go.mod b/go.mod
index b69d320688f3db0c6bbdcc1ad19eea994fde74ea..b6cf3e2e6812ad2a15b62a2272bf6fc00fc72b76 100644
--- a/go.mod
+++ b/go.mod
@@ -19,6 +19,11 @@ require (
 	gorm.io/gorm v1.24.5
 )
 
+require (
+	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+)
+
 require (
 	github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect
 	github.com/KyleBanks/depth v1.2.1 // indirect
@@ -35,6 +40,8 @@ require (
 	github.com/go-openapi/swag v0.22.3 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/go-redis/redis/v8 v8.11.5
+	github.com/gomodule/redigo v1.8.9
 	github.com/jackc/pgpassfile v1.0.0 // indirect
 	github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
 	github.com/jackc/pgx/v5 v5.2.0 // indirect
diff --git a/go.sum b/go.sum
index d771a874f694fecc968e13f8658ba7de1cd1ca6f..104db32d430bfc3149b43928c0b68f3784d9056d 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II=
 github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cosmtrek/air v1.41.0 h1:6ck2LbcVvby6cyuwE8ruia41U2nppMZGWOpq+E/EhoU=
 github.com/cosmtrek/air v1.41.0/go.mod h1:+RBGjJt7T2f3I7td8Tvk0XsH/hZ3E1QBLfiWObICO4c=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -16,6 +18,8 @@ github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr
 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
 github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -49,8 +53,12 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
 github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
+github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
+github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
 github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
 github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
+github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
diff --git a/handler/reset/test.go b/handler/reset/test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6ca85124c85ef35e20c9dcead322ac18214844e3
--- /dev/null
+++ b/handler/reset/test.go
@@ -0,0 +1,21 @@
+package reset
+
+import (
+	"fmt"
+	"net/http"
+
+	"gitlab.informatika.org/ocw/ocw-backend/model/web/reset/request"
+)
+
+func (rs ResetHandlerImpl) Test(w http.ResponseWriter, r *http.Request) {
+	payload := request.RequestRequestPayload{Email: "test@test.com",}
+
+	err := rs.ResetService.Request(payload)
+
+	if err != nil {
+		fmt.Print("Oh no :)")
+	}
+
+	responsePayload := rs.WrapperUtil.SuccessResponseWrap(nil)
+	rs.HttpUtil.WriteSuccessJson(w, responsePayload)
+}
\ No newline at end of file
diff --git a/handler/reset/types.go b/handler/reset/types.go
index 7f0a8dbcfb276d41ad8067d6848d857535d739c4..91fb28636fa74b2e46ebc98b51e54a53b0747ea4 100644
--- a/handler/reset/types.go
+++ b/handler/reset/types.go
@@ -6,4 +6,5 @@ type ResetHandler interface {
 	Request(w http.ResponseWriter, r *http.Request)
 	Confirm(w http.ResponseWriter, r *http.Request)
 	Validate(w http.ResponseWriter, r *http.Request)
+	Test(w http.ResponseWriter, r *http.Request)
 }
diff --git a/model/domain/cache/cache.go b/model/domain/cache/cache.go
new file mode 100644
index 0000000000000000000000000000000000000000..1cab93ca021e9cd8db82f517f00d9a2692c862c0
--- /dev/null
+++ b/model/domain/cache/cache.go
@@ -0,0 +1,50 @@
+package cache
+
+import "fmt"
+
+type Cache struct {
+	Key             Key
+	Values          []Value
+	ExpiryInMinutes int
+}
+
+type Key struct {
+	Hash string
+	Id   string
+}
+
+type Value struct {
+	Field string
+	Store string
+}
+
+func (c *Cache) AppendValue(value Value) *Cache {
+	c.Values = append(c.Values, value)
+	return c
+}
+
+func NewKey(hash string, id string) *Key {
+	return &Key{hash, id}
+}
+
+func (k Key) String() string {
+	return fmt.Sprintf("%s:%s", k.Hash, k.Id)
+}
+
+func NewValue(field string, store string) *Value {
+	return &Value{field, store}
+}
+
+func NewCache(key Key, initValue Value, expiryInMinutes int) *Cache {
+	return &Cache{key, []Value{initValue}, expiryInMinutes}
+}
+
+func (c *Cache) Slice() ([]interface{}) {
+	slice := make([]interface{}, len(c.Values) * 2 + 1)
+	slice[0] = c.Key.String()
+	for i := range make([]int, len(c.Values)) {
+		slice[i * 2 + 1] = c.Values[i].Field
+		slice[i * 2 + 2] = c.Values[i].Store
+	}
+	return slice
+}
diff --git a/provider/di.go b/provider/di.go
index 51e100b166816bee6b5d9c23147f9470831a1b9f..7b0746b2416fac00b85f4373327d116981b8a350 100644
--- a/provider/di.go
+++ b/provider/di.go
@@ -3,6 +3,7 @@ package provider
 import (
 	"github.com/google/wire"
 	"gitlab.informatika.org/ocw/ocw-backend/provider/db"
+	"gitlab.informatika.org/ocw/ocw-backend/provider/redis"
 	"gitlab.informatika.org/ocw/ocw-backend/provider/mail"
 	"gitlab.informatika.org/ocw/ocw-backend/provider/mail/smtp"
 )
@@ -22,4 +23,8 @@ var ProviderSet = wire.NewSet(
 	// Database utility
 	wire.Bind(new(db.Database), new(*db.DatabaseImpl)),
 	db.NewPostgresEnv,
+	
+	// Redis utility
+	wire.Bind(new(redis.Redis), new(*redis.RedisImpl)),
+	redis.NewRedisEnv,
 )
diff --git a/provider/redis/cache.go b/provider/redis/cache.go
new file mode 100644
index 0000000000000000000000000000000000000000..2ffd5060c6c699f1534712a7466ec0595bcb8591
--- /dev/null
+++ b/provider/redis/cache.go
@@ -0,0 +1,66 @@
+package redis
+
+import (
+	"fmt"
+	"os"
+	"runtime/debug"
+	"strings"
+	"time"
+
+	"github.com/gomodule/redigo/redis"
+	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
+	"gitlab.informatika.org/ocw/ocw-backend/utils/env"
+)
+
+type RedisImpl struct {
+	pool *redis.Pool
+}
+
+func resolver(log logger.Logger) {
+	if rec := recover(); rec != nil {
+		log.Error("Some panic occured when processing request:")
+		log.Error(fmt.Sprint(rec))
+		log.Error("")
+
+		log.Error("Stack Trace:")
+		stacks := strings.Split(string(debug.Stack()), "\n")
+
+		for _, val := range stacks {
+			log.Error(val)
+		}
+
+		os.Exit(-1)
+	}
+}
+
+func NewRedisEnv(
+	env *env.Environment,
+	log logger.Logger,
+) (*RedisImpl, error) {
+	return &RedisImpl{
+				&redis.Pool{
+					MaxIdle: 3,
+					IdleTimeout: 240 * time.Second,
+					Dial: func() (redis.Conn, error) {
+						defer resolver(log)
+						conn, err := redis.Dial("tcp", env.RedisConnection + ":" + env.RedisPort)
+						
+						if err != nil {
+							return nil, err
+						}
+
+						return conn, err
+					},
+					TestOnBorrow: func(c redis.Conn, t time.Time) error {
+						if time.Since(t) < time.Minute {
+						return nil
+						}
+						_, err := c.Do("PING")
+						return err
+					},
+				}}, nil
+}
+
+func (r RedisImpl) Pool() (*redis.Pool) {
+	return r.pool
+}
\ No newline at end of file
diff --git a/provider/redis/type.go b/provider/redis/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..c2b4e2c661a7ce9851e8963e107c7fd063f04c26
--- /dev/null
+++ b/provider/redis/type.go
@@ -0,0 +1,7 @@
+package redis
+
+import "github.com/gomodule/redigo/redis"
+
+type Redis interface {
+	Pool() *redis.Pool
+}
\ No newline at end of file
diff --git a/repository/cache/cache.go b/repository/cache/cache.go
new file mode 100644
index 0000000000000000000000000000000000000000..80b61d2318848612dfbf0d2b63ebb2e260decdcd
--- /dev/null
+++ b/repository/cache/cache.go
@@ -0,0 +1,57 @@
+package cache
+
+import (
+	"github.com/gomodule/redigo/redis"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/cache"
+	rd "gitlab.informatika.org/ocw/ocw-backend/provider/redis"
+)
+
+type CacheRepositoryImpl struct {
+	pool *redis.Pool
+}
+
+func New(
+	cache rd.Redis,
+) *CacheRepositoryImpl {
+	return &CacheRepositoryImpl{cache.Pool()}
+}
+
+func (c CacheRepositoryImpl) Get(cache cache.Cache, field string) (string, error) {
+	conn := c.pool.Get()
+	defer conn.Close()
+
+	value, err := redis.String(conn.Do("HGET", cache.Key.String(), field))
+
+	if err != nil {
+		return "", err
+	}
+
+	return value, nil
+}
+
+func (c CacheRepositoryImpl) GetAll(cache cache.Cache) (map[string]string, error) {
+	conn := c.pool.Get()
+	defer conn.Close()
+
+	value, err := redis.StringMap(conn.Do("HGETALL", cache.Key.String()))
+	
+	if err != nil {
+		return nil, err
+	}
+
+	return value, nil
+}
+
+func (c CacheRepositoryImpl) Set(cache cache.Cache) error {
+	conn := c.pool.Get()
+	defer conn.Close()
+
+	slice := cache.Slice()
+	_, err := conn.Do("HSET", slice...)
+
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
\ No newline at end of file
diff --git a/repository/cache/type.go b/repository/cache/type.go
new file mode 100644
index 0000000000000000000000000000000000000000..97b3691959e3bea124eb0b04a11e5f13e3fa08c6
--- /dev/null
+++ b/repository/cache/type.go
@@ -0,0 +1,11 @@
+package cache
+
+import (
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/cache"
+)
+
+type CacheRepository interface {
+	Get(cache cache.Cache, field string) (string, error)
+	GetAll(cache cache.Cache) (map[string]string, error)
+	Set(cache cache.Cache) error
+}
diff --git a/repository/di.go b/repository/di.go
index ccec9594f14c22bb4d6444b2edbb26f54b8a90f3..3a1d5b9646290496eabde8604276da5c39f15332 100644
--- a/repository/di.go
+++ b/repository/di.go
@@ -3,12 +3,17 @@ package repository
 import (
 	"github.com/google/wire"
 	"gitlab.informatika.org/ocw/ocw-backend/repository/user"
+	"gitlab.informatika.org/ocw/ocw-backend/repository/cache"
 )
 
 var RepositoryBasicSet = wire.NewSet(
 	// User Repository
 	user.New,
 	wire.Bind(new(user.UserRepository), new(*user.UserRepositoryImpl)),
+
+	// Cache Repository
+	cache.New,
+	wire.Bind(new(cache.CacheRepository), new(*cache.CacheRepositoryImpl)),
 )
 
 var RepositorySet = wire.NewSet(
diff --git a/routes/reset/route.go b/routes/reset/route.go
index 46b32e0f9f389bfe8f3ff730d2c683225dfcee91..e225524ff2141a97aa00e56f27e1e67bfd3018e2 100644
--- a/routes/reset/route.go
+++ b/routes/reset/route.go
@@ -14,5 +14,6 @@ func (rr ResetRoutes) Register(r chi.Router) {
 		r.Post("/request", rr.ResetHandler.Request)
 		r.Post("/confirm", rr.ResetHandler.Confirm)
 		r.Post("/validate", rr.ResetHandler.Validate)
+		r.Get("/test", rr.ResetHandler.Test)
 	})
 }
diff --git a/service/reset/impl.go b/service/reset/impl.go
index b9986e2509f4af7f8c0deb9053bf8d30640e4168..ac2d214853e70fb7d61b5cab92a76f82b6584bf4 100644
--- a/service/reset/impl.go
+++ b/service/reset/impl.go
@@ -2,7 +2,9 @@ package reset
 
 import (
 	"gitlab.informatika.org/ocw/ocw-backend/repository/user"
+	"gitlab.informatika.org/ocw/ocw-backend/repository/cache"
 	"gitlab.informatika.org/ocw/ocw-backend/service/verification"
+	"gitlab.informatika.org/ocw/ocw-backend/service/logger"
 	"gitlab.informatika.org/ocw/ocw-backend/utils/env"
 	"gitlab.informatika.org/ocw/ocw-backend/utils/password"
 	"gitlab.informatika.org/ocw/ocw-backend/utils/token"
@@ -10,8 +12,10 @@ import (
 
 type ResetServiceImpl struct {
 	user.UserRepository
+	cache.CacheRepository
 	password.PasswordUtil
 	*env.Environment
 	token.TokenUtil
 	verification.VerificationService
+	logger.Logger
 }
diff --git a/service/reset/request.go b/service/reset/request.go
index 05584e6a9bb3dcf0a7a78c4ec5e12e1c4502732d..1b90703361c00b16d4e0e2364a118dd51046c362 100644
--- a/service/reset/request.go
+++ b/service/reset/request.go
@@ -1,11 +1,23 @@
 package reset
 
 import (
-	// "gitlab.informatika.org/ocw/ocw-backend/model/domain/user"
+	"gitlab.informatika.org/ocw/ocw-backend/model/domain/cache"
 	"gitlab.informatika.org/ocw/ocw-backend/model/web/reset/request"
 )
 
 func (rs ResetServiceImpl) Request(payload request.RequestRequestPayload) error {
-	// TODO replace dummy
+	c := cache.NewCache(*cache.NewKey("Test", "123"), *cache.NewValue("Test", "123"), 30)
+	c.AppendValue(*cache.NewValue("Hello", "World"))
+
+	err := rs.CacheRepository.Set(*c)
+	if err != nil {
+		panic(err)
+	}
+
+	_, err = rs.CacheRepository.Get(*c, "Test")
+	if err != nil {
+		panic(err)
+	}
+	
 	return nil
 }
\ No newline at end of file
diff --git a/utils/env/env.go b/utils/env/env.go
index e1b914f0d6842317f23ab5288ed18f9d8a4a38b1..e688d945d6a52d2dc5a9e124111d965ed66f6b7e 100644
--- a/utils/env/env.go
+++ b/utils/env/env.go
@@ -40,6 +40,9 @@ type Environment struct {
 	FrontendBaseURL       string `env:"FE_BASE_URL"`
 	ResetPasswordPath     string `env:"RESET_PASSWORD_PATH" envDefault:""`
 	EmailVerificationPath string `env:"EMAIL_VERIFICATION_PATH" envDefault:""`
+
+	RedisConnection string `env:"REDIS_STRING"`
+	RedisPort string `env:"REDIS_PORT" envDefault:"6379"`
 }
 
 func New() (*Environment, error) {