diff --git a/environment/environment.go b/environment/environment.go
new file mode 100644
index 0000000000000000000000000000000000000000..114924aa50eefea902fee010aa3e5722887acbea
--- /dev/null
+++ b/environment/environment.go
@@ -0,0 +1,62 @@
+package environment
+
+import (
+	"encoding/json"
+	"github.com/hibiken/asynq"
+	"github.com/jmoiron/sqlx"
+	"github.com/justjanne/imgconv"
+	"os"
+)
+
+type Environment struct {
+	Queue      *asynq.Client
+	Database   *sqlx.DB
+	RolePrefix string
+	Sizes      []imgconv.Size
+	Quality    imgconv.Quality
+}
+
+func NewEnvironment(
+	redisAddress string,
+	dbType string,
+	dbUrl string,
+	rolePrefix string,
+	sizes []imgconv.Size,
+	quality imgconv.Quality,
+) (env Environment, err error) {
+	env.Queue = asynq.NewClient(asynq.RedisClientOpt{
+		Addr: redisAddress,
+	})
+	env.Database, err = sqlx.Open(dbType, dbUrl)
+	env.RolePrefix = rolePrefix
+	env.Sizes = sizes
+	env.Quality = quality
+	return
+}
+
+func InitializeEnvironment() (env Environment, err error) {
+	var sizes []imgconv.Size
+	if err = json.Unmarshal([]byte(os.Getenv("CONFIG_SIZES")), &sizes); err != nil {
+		return
+	}
+	var quality imgconv.Quality
+	if err = json.Unmarshal([]byte(os.Getenv("CONFIG_QUALITY")), &quality); err != nil {
+		return
+	}
+	rolePrefix := os.Getenv("CONFIG_ROLE_PREFIX")
+
+	redisAddress := os.Getenv("REDIS_ADDRESS")
+	dbType := os.Getenv("DB_TYPE")
+	dbUrl := os.Getenv("DB_URL")
+	return NewEnvironment(redisAddress, dbType, dbUrl, rolePrefix, sizes, quality)
+}
+
+func (env Environment) Destroy() error {
+	if err := env.Queue.Close(); err != nil {
+		return err
+	}
+	if err := env.Database.Close(); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/go.mod b/go.mod
index e3712525ade50b986a838c2ac3e5977d33d94a5f..96db1b4367823f02aad20f4964a48c1f05b8eb34 100644
--- a/go.mod
+++ b/go.mod
@@ -3,12 +3,13 @@ module git.kuschku.de/justjanne/imghost-frontend
 go 1.13
 
 require (
-	github.com/hibiken/asynq v0.18.2 // indirect
-	github.com/jackc/pgx v3.6.2+incompatible // indirect
-	github.com/jmoiron/sqlx v1.3.4 // indirect
-	github.com/justjanne/imgconv v1.0.3
-	github.com/minio/minio-go/v7 v7.0.12 // indirect
-	github.com/pkg/errors v0.9.1 // indirect
-	golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
+	github.com/hibiken/asynq v0.18.2
+	github.com/jmoiron/sqlx v1.3.4
+	github.com/justjanne/imgconv v1.0.3 // indirect
+	github.com/lib/pq v1.10.2
+	github.com/stretchr/testify v1.4.0 // indirect
+	golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
+	golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
 	golang.org/x/text v0.3.6 // indirect
+	gopkg.in/yaml.v2 v2.2.8 // indirect
 )
diff --git a/go.sum b/go.sum
index 07641f48c5ed326a6a430db967e19868ccd56f48..190c08b6451b72e1f0b75aaf35d5a69b58cec899 100644
--- a/go.sum
+++ b/go.sum
@@ -3,14 +3,15 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 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/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
 github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -27,73 +28,47 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
 github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/hibiken/asynq v0.18.2 h1:hbLVygnmQMc2evTmNildtUWaUPHIBtggA59MoaHp/bY=
 github.com/hibiken/asynq v0.18.2/go.mod h1:Sn3Ql1clxIO5kXoFOAE3W73tX81Hkau+2Kam9LfgymM=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
-github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
 github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
 github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
-github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
-github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/justjanne/imgconv v1.0.3 h1:XXgqeLJ1ibV0XCdosMqVV65CdpmDADTnC3yBR2w52vE=
 github.com/justjanne/imgconv v1.0.3/go.mod h1:8VxkQjMdEOziT9LJ8Mrqtz7SbmqlpExl69K8/CZWeAc=
-github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
-github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
 github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
-github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
-github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
-github.com/minio/minio-go/v7 v7.0.12 h1:/4pxUdwn9w0QEryNkrrWaodIESPRX+NxpO0Q6hVdaAA=
-github.com/minio/minio-go/v7 v7.0.12/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs=
-github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
-github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
 github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
-github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
-github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
 go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -103,9 +78,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -115,16 +88,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -137,8 +105,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -158,17 +126,19 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
 google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gographics/imagick.v2 v2.6.0 h1:ewRsUQk3QkjGumERlndbFn/kTYRjyMaPY5gxwpuAhik=
 gopkg.in/gographics/imagick.v2 v2.6.0/go.mod h1:/QVPLV/iKdNttRKthmDkeeGg+vdHurVEPc8zkU0XgBk=
-gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
-gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+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.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/main.go b/main.go
index 50d110baf9b85a705092c309c3e866ee0591bd25..e5a5af7d474fcb5ec5cd8d632efc946cc369ce03 100644
--- a/main.go
+++ b/main.go
@@ -1,27 +1,58 @@
 package main
 
 import (
-	"net/http"
+	"fmt"
+	"git.kuschku.de/justjanne/imghost-frontend/environment"
+	"git.kuschku.de/justjanne/imghost-frontend/model"
+	"git.kuschku.de/justjanne/imghost-frontend/repo"
+	_ "github.com/lib/pq"
 )
 
-func MethodOverride(next http.Handler) http.Handler {
-	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		if r.Method == http.MethodPost {
-			method := r.PostFormValue("_method")
-			if method == "" {
-				method = r.Header.Get("X-HTTP-Method-Override")
-			}
-
-			if method == http.MethodPut ||
-				method == http.MethodPatch ||
-				method == http.MethodDelete {
-				r.Method = method
-			}
-		}
-		next.ServeHTTP(w, r)
-	})
-}
-
 func main() {
-	println("Hello World!")
+	user := model.User{
+		Id:    "ad45284c-be4d-4546-8171-41cf126ac091",
+		Name:  "justJanne",
+		Email: "janne@kuschku.de",
+		Roles: []string{"imghost:user", "imghost:admin"},
+	}
+
+	var env environment.Environment
+	env, err := environment.InitializeEnvironment()
+	if err != nil {
+		panic(err)
+	}
+	defer env.Destroy()
+
+	imageRepo, err := repo.NewImageRepo(env.Database)
+	if err != nil {
+		panic(err)
+	}
+
+	albumRepo, err := repo.NewAlbumRepo(env.Database)
+	if err != nil {
+		panic(err)
+	}
+
+	albumImageRepo, err := repo.NewAlbumImageRepo(env.Database)
+	if err != nil {
+		panic(err)
+	}
+
+	images, err := imageRepo.List(user)
+	if err != nil {
+		panic(err)
+	}
+	fmt.Printf("images: %v\n", len(images))
+
+	albums, err := albumRepo.List(user)
+	if err != nil {
+		panic(err)
+	}
+	fmt.Printf("albums: %v\n", len(albums))
+
+	albumImages, err := albumImageRepo.List(model.Album{})
+	if err != nil {
+		panic(err)
+	}
+	fmt.Printf("albumImages: %v\n", len(albumImages))
 }
diff --git a/model/album.go b/model/album.go
index 59f060dec70ba7bf12a42c9d16ec690e14f25c05..75da1e6da418997525fd60c6f01e249cc90fac8d 100644
--- a/model/album.go
+++ b/model/album.go
@@ -6,12 +6,12 @@ import (
 )
 
 type Album struct {
-	Id          string    `json:"id"`
-	Owner       string    `json:"owner"`
-	Title       string    `json:"title"`
-	Description string    `json:"description"`
-	CreatedAt   time.Time `json:"created_at"`
-	UpdatedAt   time.Time `json:"updated_at"`
+	Id          string    `json:"id" db:"id"`
+	Owner       string    `json:"owner" db:"owner"`
+	Title       string    `json:"title" db:"title"`
+	Description string    `json:"description" db:"description"`
+	CreatedAt   time.Time `json:"created_at" db:"created_at"`
+	UpdatedAt   time.Time `json:"updated_at" db:"updated_at"`
 }
 
 func (album Album) VerifyOwner(user User) error {
diff --git a/model/album_image.go b/model/album_image.go
index 3bb099c54d02400ca53eeb8c41283d91cb478af6..b757f7fb6102e69fb73118247318900c3c0ae5f3 100644
--- a/model/album_image.go
+++ b/model/album_image.go
@@ -1,7 +1,8 @@
 package model
 
 type AlbumImage struct {
-	Id          string `json:"id"`
-	Title       string `json:"title"`
-	Description string `json:"description"`
+	Album       string `json:"album" db:"album"`
+	Image       string `json:"image" db:"image"`
+	Title       string `json:"title" db:"title"`
+	Description string `json:"description" db:"description"`
 }
diff --git a/model/image.go b/model/image.go
index 695ad83f134e93e92492f63b20163ffe0db507bd..f3ba2ed39665f0ace26daf2c07c11e898861a842 100644
--- a/model/image.go
+++ b/model/image.go
@@ -6,14 +6,14 @@ import (
 )
 
 type Image struct {
-	Id           string    `json:"id"`
-	Owner        string    `json:"owner"`
-	Title        string    `json:"title"`
-	Description  string    `json:"description"`
-	CreatedAt    time.Time `json:"created_at"`
-	UpdatedAt    time.Time `json:"updated_at"`
-	OriginalName string    `json:"original_name"`
-	MimeType     string    `json:"mime_type"`
+	Id           string    `json:"id" db:"id"`
+	Owner        string    `json:"owner" db:"owner"`
+	Title        string    `json:"title" db:"title"`
+	Description  string    `json:"description" db:"description"`
+	CreatedAt    time.Time `json:"created_at" db:"created_at"`
+	UpdatedAt    time.Time `json:"updated_at" db:"updated_at"`
+	OriginalName string    `json:"original_name" db:"original_name"`
+	MimeType     string    `json:"mime_type" db:"mime_type"`
 }
 
 func (image Image) VerifyOwner(user User) error {
diff --git a/repo/album_images.go b/repo/album_images.go
new file mode 100644
index 0000000000000000000000000000000000000000..9cfdbc590d692dfc189615c018495a2cb7375e56
--- /dev/null
+++ b/repo/album_images.go
@@ -0,0 +1,142 @@
+package repo
+
+import (
+	"git.kuschku.de/justjanne/imghost-frontend/model"
+	"github.com/jmoiron/sqlx"
+)
+
+type AlbumImages struct {
+	db            *sqlx.DB
+	queryList     *sqlx.NamedStmt
+	queryGet      *sqlx.NamedStmt
+	stmtCreate    *sqlx.NamedStmt
+	stmtUpdate    *sqlx.NamedStmt
+	stmtDelete    *sqlx.NamedStmt
+	stmtDeleteAll *sqlx.NamedStmt
+	stmtReorder   *sqlx.NamedStmt
+}
+
+func NewAlbumImageRepo(db *sqlx.DB) (repo AlbumImages, err error) {
+	repo.db = db
+	repo.queryList, err = db.PrepareNamed(`
+			SELECT album_images.album,
+			       album_images.image,
+			       album_images.title,
+			       album_images.description
+			FROM album_images
+			WHERE album_images.album = :albumId
+			ORDER BY album_images.position
+		`)
+	repo.queryGet, err = db.PrepareNamed(`
+			SELECT album_images.album,
+			       album_images.image,
+			       album_images.title,
+			       album_images.description
+			FROM album_images
+			WHERE album_images.album = :albumId
+			AND album_images.image = :imageId
+			ORDER BY album_images.position
+		`)
+	repo.stmtCreate, err = db.PrepareNamed(`
+			INSERT INTO album_images (album, image, title, description, position)
+			VALUES (:albumId, :imageId, :title, :description, (
+			    SELECT COUNT(album_images.image)
+			    FROM album_images
+			    WHERE album_images.album = :albumId
+			))
+		`)
+	repo.stmtUpdate, err = db.PrepareNamed(`
+			UPDATE album_images 
+			SET album_images.title = :title, 
+			    album_images.description = :description
+			WHERE album_images.album = :albumId
+		    AND album_images.image = :imageId
+		`)
+	repo.stmtDelete, err = db.PrepareNamed(`
+			DELETE FROM album_images
+			WHERE album_images.album = :albumId
+			AND album_images.image = :imageID
+		`)
+	repo.stmtDeleteAll, err = db.PrepareNamed(`
+			DELETE FROM album_images
+			WHERE album_images.album = :albumId
+		`)
+	repo.stmtReorder, err = db.PrepareNamed(`
+			UPDATE album_images 
+			SET album_images.position = :position
+			WHERE album_images.album = :albumId
+		    AND album_images.image = :imageId
+		`)
+
+	return repo, nil
+}
+
+func (repo AlbumImages) List(album model.Album) (images []model.AlbumImage, err error) {
+	rows, err := repo.queryList.Queryx(map[string]interface{}{
+		"albumId": album.Id,
+	})
+	if err != nil {
+		return
+	}
+	for rows.Next() {
+		var image model.AlbumImage
+		err = rows.StructScan(&image)
+		if err != nil {
+			return
+		}
+		images = append(images, image)
+	}
+	return
+}
+
+func (repo AlbumImages) Get(album model.Album, imageId string) (image model.AlbumImage, err error) {
+	err = repo.queryGet.Get(&image, map[string]interface{}{
+		"albumId": album.Id,
+		"imageId": imageId,
+	})
+	return
+}
+
+func (repo AlbumImages) Create(new model.AlbumImage) (err error) {
+	_, err = repo.stmtCreate.Exec(map[string]interface{}{
+		"albumId":     new.Album,
+		"imageId":     new.Image,
+		"title":       new.Title,
+		"description": new.Description,
+	})
+	return
+}
+
+func (repo AlbumImages) Update(changed model.AlbumImage) (err error) {
+	_, err = repo.stmtUpdate.Exec(map[string]interface{}{
+		"albumId":     changed.Album,
+		"imageId":     changed.Image,
+		"title":       changed.Title,
+		"description": changed.Description,
+	})
+	return
+}
+
+func (repo AlbumImages) Delete(changed model.AlbumImage) (err error) {
+	_, err = repo.stmtDelete.Exec(map[string]interface{}{
+		"albumId": changed.Album,
+		"imageId": changed.Image,
+	})
+	return
+}
+
+func (repo AlbumImages) DeleteAll(changed model.AlbumImage) (err error) {
+	_, err = repo.stmtDeleteAll.Exec(map[string]interface{}{
+		"albumId": changed.Album,
+	})
+	return
+}
+
+func (repo AlbumImages) Reorder(changed model.AlbumImage, position int) (err error) {
+	_, err = repo.stmtDeleteAll.Exec(map[string]interface{}{
+		"albumId":  changed.Album,
+		"imageId":  changed.Image,
+		"position": position,
+	})
+	return
+}
diff --git a/repo/albums.go b/repo/albums.go
new file mode 100644
index 0000000000000000000000000000000000000000..6be98f1c4f65fbd0f64ac4d726e0f0f25ae33923
--- /dev/null
+++ b/repo/albums.go
@@ -0,0 +1,108 @@
+package repo
+
+import (
+	"git.kuschku.de/justjanne/imghost-frontend/model"
+	"github.com/jmoiron/sqlx"
+)
+
+type Albums struct {
+	db         *sqlx.DB
+	queryList  *sqlx.NamedStmt
+	queryGet   *sqlx.NamedStmt
+	stmtUpdate *sqlx.NamedStmt
+	stmtCreate *sqlx.NamedStmt
+	stmtDelete *sqlx.NamedStmt
+}
+
+func NewAlbumRepo(db *sqlx.DB) (repo Albums, err error) {
+	repo.db = db
+	repo.queryList, err = db.PrepareNamed(`
+			SELECT albums.id,
+			       albums.owner,
+			       albums.title,
+			       albums.description,
+			       albums.created_at,
+			       albums.updated_at
+			FROM albums
+			WHERE albums.owner = :userId
+			ORDER BY albums.created_at DESC
+		`)
+	repo.queryGet, err = db.PrepareNamed(`
+			SELECT albums.id,
+			       albums.owner,
+			       albums.title,
+			       albums.description,
+			       albums.created_at,
+			       albums.updated_at
+			FROM albums
+			WHERE albums.id = :albumId
+		`)
+	repo.stmtCreate, err = db.PrepareNamed(`
+			INSERT INTO albums (id, owner, title, description, created_at, updated_at)
+			VALUES (:albumId, :userId, :title, :description, NOW(), NOW())
+		`)
+	repo.stmtUpdate, err = db.PrepareNamed(`
+			UPDATE albums 
+			SET albums.title = :title, 
+			    albums.description = :description, 
+			    albums.updated_at = NOW()
+			WHERE albums.id = :albumId
+		`)
+	repo.stmtDelete, err = db.PrepareNamed(`
+			DELETE FROM albums
+			WHERE albums.id = :albums
+		`)
+
+	return repo, nil
+}
+
+func (repo Albums) List(user model.User) (albums []model.Album, err error) {
+	rows, err := repo.queryList.Queryx(map[string]interface{}{
+		"userId": user.Id,
+	})
+	if err != nil {
+		return
+	}
+	for rows.Next() {
+		var album model.Album
+		err = rows.StructScan(&album)
+		if err != nil {
+			return
+		}
+		albums = append(albums, album)
+	}
+	return
+}
+
+func (repo Albums) Get(albumId string) (album model.Album, err error) {
+	err = repo.queryGet.Get(&album, map[string]interface{}{
+		"albumId": albumId,
+	})
+	return
+}
+
+func (repo Albums) Create(changed model.Album) (err error) {
+	_, err = repo.stmtCreate.Exec(map[string]interface{}{
+		"albumId":     changed.Id,
+		"userId":      changed.Owner,
+		"title":       changed.Title,
+		"description": changed.Description,
+	})
+	return
+}
+
+func (repo Albums) Update(changed model.Album) (err error) {
+	_, err = repo.stmtUpdate.Exec(map[string]interface{}{
+		"albumId":     changed.Id,
+		"title":       changed.Title,
+		"description": changed.Description,
+	})
+	return
+}
+
+func (repo Albums) Delete(changed model.Album) (err error) {
+	_, err = repo.stmtDelete.Exec(map[string]interface{}{
+		"albumId": changed.Id,
+	})
+	return
+}
diff --git a/repo/images.go b/repo/images.go
new file mode 100644
index 0000000000000000000000000000000000000000..a29c01bf08b4b45d1b35aa709b4349097c1cca55
--- /dev/null
+++ b/repo/images.go
@@ -0,0 +1,112 @@
+package repo
+
+import (
+	"git.kuschku.de/justjanne/imghost-frontend/model"
+	"github.com/jmoiron/sqlx"
+)
+
+type Images struct {
+	db         *sqlx.DB
+	queryList  *sqlx.NamedStmt
+	queryGet   *sqlx.NamedStmt
+	stmtCreate *sqlx.NamedStmt
+	stmtUpdate *sqlx.NamedStmt
+	stmtDelete *sqlx.NamedStmt
+}
+
+func NewImageRepo(db *sqlx.DB) (repo Images, err error) {
+	repo.db = db
+	repo.queryList, err = db.PrepareNamed(`
+			SELECT images.id,
+			       images.owner,
+			       images.title,
+			       images.description,
+			       images.original_name,
+			       images.created_at,
+			       images.updated_at
+			FROM images
+			WHERE images.owner = :userId
+			ORDER BY images.created_at DESC
+		`)
+	repo.queryGet, err = db.PrepareNamed(`
+			SELECT images.id,
+			       images.owner,
+			       images.title,
+			       images.description,
+			       images.original_name,
+			       images.created_at,
+			       images.updated_at
+			FROM images
+			WHERE images.id = :imageId
+		`)
+	repo.stmtCreate, err = db.PrepareNamed(`
+			INSERT INTO images (id, owner, title, description, original_name, type, created_at, updated_at)
+			VALUES (:imageId, :userId, :title, :description, :originalName, :mimeType, NOW(), NOW())
+		`)
+	repo.stmtUpdate, err = db.PrepareNamed(`
+			UPDATE images 
+			SET images.title = :title, 
+			    images.description = :description, 
+			    images.updated_at = NOW()
+			WHERE images.id = :imageId
+		`)
+	repo.stmtDelete, err = db.PrepareNamed(`
+			DELETE FROM images
+			WHERE images.id = :imageId
+		`)
+
+	return repo, nil
+}
+
+func (repo Images) List(user model.User) (images []model.Image, err error) {
+	rows, err := repo.queryList.Queryx(map[string]interface{}{
+		"userId": user.Id,
+	})
+	if err != nil {
+		return
+	}
+	for rows.Next() {
+		var image model.Image
+		err = rows.StructScan(&image)
+		if err != nil {
+			return
+		}
+		images = append(images, image)
+	}
+	return
+}
+
+func (repo Images) Get(imageId string) (image model.Image, err error) {
+	err = repo.queryGet.Get(&image, map[string]interface{}{
+		"imageId": imageId,
+	})
+	return
+}
+
+func (repo Images) Create(new model.Image) (err error) {
+	_, err = repo.stmtUpdate.Exec(map[string]interface{}{
+		"imageId":      new.Id,
+		"userId":       new.Owner,
+		"title":        new.Title,
+		"description":  new.Description,
+		"originalName": new.OriginalName,
+		"mimeType":     new.MimeType,
+	})
+	return
+}
+
+func (repo Images) Update(changed model.Image) (err error) {
+	_, err = repo.stmtUpdate.Exec(map[string]interface{}{
+		"imageId":     changed.Id,
+		"title":       changed.Title,
+		"description": changed.Description,
+	})
+	return
+}
+
+func (repo Images) Delete(changed model.Image) (err error) {
+	_, err = repo.stmtDelete.Exec(map[string]interface{}{
+		"imageId": changed.Id,
+	})
+	return
+}
diff --git a/task/image_resize.go b/task/image_resize.go
new file mode 100644
index 0000000000000000000000000000000000000000..1e140b2e4adb49d78fb2a655774fb70651f3f2b2
--- /dev/null
+++ b/task/image_resize.go
@@ -0,0 +1,68 @@
+package task
+
+import (
+	"context"
+	"encoding/json"
+	"git.kuschku.de/justjanne/imghost-frontend/util"
+	"github.com/hibiken/asynq"
+	"github.com/justjanne/imgconv"
+	"gopkg.in/gographics/imagick.v2/imagick"
+)
+
+const TypeImageResize = "image:Resize"
+
+type ImageResizePayload struct {
+	ImageId string
+	Sizes   []imgconv.Size
+	Quality imgconv.Quality
+}
+
+func NewResizeTask(imageId string, sizes []imgconv.Size, quality imgconv.Quality) (task *asynq.Task, err error) {
+	payload, err := json.Marshal(ImageResizePayload{
+		ImageId: imageId,
+		Sizes:   sizes,
+		Quality: quality,
+	})
+	if err != nil {
+		return
+	}
+	task = asynq.NewTask(TypeImageResize, payload)
+	return
+}
+
+func HandleImageResizeTask(ctx context.Context, task *asynq.Task) (err error) {
+	var payload ImageResizePayload
+	if err = json.Unmarshal(task.Payload(), &payload); err != nil {
+		return
+	}
+
+	wand := imagick.NewMagickWand()
+	defer wand.Destroy()
+
+	tmpFile := ""
+	if err = wand.ReadImage(tmpFile); err != nil {
+		return
+	}
+	var originalImage imgconv.ImageHandle
+	if originalImage, err = imgconv.NewImage(wand); err != nil {
+		return err
+	}
+
+	err = util.LaunchGoroutines(len(payload.Sizes), func(index int) error {
+		size := payload.Sizes[index]
+		tmpTargetFile := ""
+		image := originalImage.CloneImage()
+		if err := image.Crop(size); err != nil {
+			return err
+		}
+		if err := image.Resize(size); err != nil {
+			return err
+		}
+		if err := image.Write(payload.Quality, tmpTargetFile); err != nil {
+			return err
+		}
+		return nil
+	})
+
+	return
+}
diff --git a/util/goroutine_launch.go b/util/goroutine_launch.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8ea8f5365dab110bd7a89bb0b00aa12fe690f1a
--- /dev/null
+++ b/util/goroutine_launch.go
@@ -0,0 +1,29 @@
+package util
+
+func readAllErrors(amount int, errorChannel chan error) []error {
+	errors := make([]error, 0)
+	for i := 0; i < amount; i++ {
+		err := <-errorChannel
+		if err != nil {
+			errors = append(errors, err)
+		}
+	}
+
+	return errors
+}
+
+func LaunchGoroutines(amount int, function func(index int) error) error {
+	errorChannel := make(chan error)
+	for i := 0; i < amount; i++ {
+		index := i
+		go func() { errorChannel <- function(index) }()
+	}
+	errs := readAllErrors(amount, errorChannel)
+	for _, err := range errs {
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/util/method_override.go b/util/method_override.go
new file mode 100644
index 0000000000000000000000000000000000000000..35a3d9274274f069bb76b95810008aae4bd3c4bb
--- /dev/null
+++ b/util/method_override.go
@@ -0,0 +1,21 @@
+package util
+
+import "net/http"
+
+func MethodOverride(next http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == http.MethodPost {
+			method := r.PostFormValue("_method")
+			if method == "" {
+				method = r.Header.Get("X-HTTP-Method-Override")
+			}
+
+			if method == http.MethodPut ||
+				method == http.MethodPatch ||
+				method == http.MethodDelete {
+				r.Method = method
+			}
+		}
+		next.ServeHTTP(w, r)
+	})
+}