diff --git a/pkg/store/factory.go b/pkg/store/factory.go
new file mode 100644
index 0000000..7fbfcf3
--- /dev/null
+++ b/pkg/store/factory.go
@@ -0,0 +1,78 @@
+// Copyright (c) 2022 Proton Technologies AG
+//
+// This file is part of ProtonMail Bridge.
+//
+// ProtonMail Bridge is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ProtonMail Bridge is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with ProtonMail Bridge. If not, see .
+
+package store
+
+import (
+ "fmt"
+ "path/filepath"
+
+ "github.com/ljanyst/peroxide/pkg/config/settings"
+ "github.com/ljanyst/peroxide/pkg/listener"
+ "github.com/ljanyst/peroxide/pkg/message"
+ "github.com/ljanyst/peroxide/pkg/store/cache"
+)
+
+type StoreFactory struct {
+ settings *settings.Settings
+ listener listener.Listener
+ events *Events
+ cache cache.Cache
+ builder *message.Builder
+}
+
+func NewStoreFactory(
+ settingsObj *settings.Settings,
+ listener listener.Listener,
+ cache cache.Cache,
+ builder *message.Builder,
+) *StoreFactory {
+ eventsCachePath := filepath.Join(settingsObj.Get(settings.CacheDir), "store_events.json")
+ return &StoreFactory{
+ settings: settingsObj,
+ listener: listener,
+ events: NewEvents(eventsCachePath),
+ cache: cache,
+ builder: builder,
+ }
+}
+
+// New creates new store for given user.
+func (f *StoreFactory) New(user BridgeUser) (*Store, error) {
+ return New(
+ user,
+ f.listener,
+ f.cache,
+ f.builder,
+ getUserStorePath(f.settings.Get(settings.CacheDir), user.ID()),
+ f.events,
+ )
+}
+
+// Remove removes all store files for given user.
+func (f *StoreFactory) Remove(userID string) error {
+ return RemoveStore(
+ f.events,
+ getUserStorePath(f.settings.Get(settings.CacheDir), userID),
+ userID,
+ )
+}
+
+// getUserStorePath returns the file path of the store database for the given userID.
+func getUserStorePath(storeDir string, userID string) (path string) {
+ return filepath.Join(storeDir, fmt.Sprintf("mailbox-%v.db", userID))
+}
diff --git a/pkg/store/utils.go b/pkg/store/utils.go
new file mode 100644
index 0000000..51a5932
--- /dev/null
+++ b/pkg/store/utils.go
@@ -0,0 +1,71 @@
+// Copyright (c) 2022 Lukasz Janyst
+//
+// This file is part of Peroxide.
+//
+// Peroxide is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Peroxide is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Peroxide. If not, see .
+
+package store
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/ljanyst/peroxide/pkg/files"
+)
+
+const Version = "c11"
+
+type StoreInfo struct {
+ StoreVersion string
+}
+
+func recreateStore(storeDir, storeInfoPath string) error {
+ if err := files.Remove(storeDir).Do(); err != nil {
+ return err
+ }
+
+ if err := os.MkdirAll(storeDir, 0700); err != nil {
+ return err
+ }
+
+ f, err := os.Create(storeInfoPath)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ return json.NewEncoder(f).Encode(StoreInfo{Version})
+}
+
+func ClearIncompatibleStore(storeDir string) error {
+ storeInfoPath := filepath.Join(storeDir, "store_info.json")
+ data, err := ioutil.ReadFile(storeInfoPath)
+ if err != nil {
+ return recreateStore(storeDir, storeInfoPath)
+ }
+
+ var info StoreInfo
+ if err := json.Unmarshal(data, &info); err != nil {
+ // Nuke the store if we can't unmarshal the info
+ return recreateStore(storeDir, storeInfoPath)
+ }
+
+ if info.StoreVersion != Version {
+ return recreateStore(storeDir, storeInfoPath)
+ }
+
+ return nil
+}