
# What to do about storage for native apps?


## Problem

We can't trust iOS IndexedDB to persist. I want to start delivering an app to people now, in preparation for presentations mid-June: Rotary on June 12 and Porcfest on June 17.

* Apple WebKit puts a [7-day cap on IndexedDB](https://webkit.org/blog/10218/full-third-party-cookie-blocking-and-more/).

  * The web standards expose a `persist` method to mark memory as persistent, and [supposedly WebView supports it](https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persisted), but too many other things indicate it's not reliable. I've talked with [ChatGPT](https://chatgpt.com/share/68322f40-84c8-8007-b213-855f7962989a) & Venice & Claude (in Cursor); [this answer from Perplexity](https://www.perplexity.ai/search/which-platforms-prompt-the-use-HUQLqy4qQD2cRbkmO4CgHg) says that most platforms don't prompt and Safari doesn't support it; I don't know if that means WebKit as well.

* Capacitor says [not to trust it on iOS](https://capacitorjs.com/docs/v6/guides/storage).

Also, with sensitive data, the accounts info should be encrypted.


# Options

* There is a community [SQLite plugin for Capacitor](https://github.com/capacitor-community/sqlite) with encryption by [SQLCipher](https://github.com/sqlcipher/sqlcipher).

  * [This tutorial](https://jepiqueau.github.io/2023/09/05/Ionic7Vue-SQLite-CRUD-App.html#part-1---web---table-of-contents) shows how that plugin works for web as well as native.

* Capacitor abstracts [user preferences in an API](https://capacitorjs.com/docs/apis/preferences), which uses different underlying libraries on iOS & Android. Unfortunately, it won't do any filtering or searching, and is only meant for small amounts of data. (It could be used for settings and for identifiers, but contacts will grow and image blobs won't work.)

  * There are hints that Capacitor offers another custom storage API but all I could find was that Preferences API.

* [Ionic Storage](https://ionic.io/docs/secure-storage) is an enterprise solution, which also supports encryption.

* Not an option yet: Dexie may support SQLite in [a future version](https://dexie.org/roadmap/dexie5.0).



# Current Plan

* Implement SQLite for Capacitor & web, with encryption. That will allow us to test quickly and keep the same interface for native & web, but we don't deal with migrations for current web users.

* After that is delivered, write a migration for current web users from IndexedDB to SQLite.



# Current method calls

... which is not 100% complete because the AI that generated thus claimed no usage of 'temp' DB.

### Secret Database (secretDB) - Used for storing the encryption key

secretDB.open() - Opens the database
secretDB.secret.get(MASTER_SECRET_KEY) - Retrieves the secret key
secretDB.secret.add({ id: MASTER_SECRET_KEY, secret }) - Adds a new secret key

### Accounts Database (accountsDB) - Used for storing sensitive account information

accountsDB.open() - Opens the database
accountsDB.accounts.count() - Counts number of accounts
accountsDB.accounts.toArray() - Gets all accounts
accountsDB.accounts.where("did").equals(did).first() - Gets a specific account by DID
accountsDB.accounts.add(account) - Adds a new account

### Non-sensitive Database (db) - Used for settings, contacts, logs, and temp data

Settings operations:
export all settings (Dexie format)
db.settings.get(MASTER_SETTINGS_KEY) - Gets default settings
db.settings.where("accountDid").equals(did).first() - Gets account-specific settings
db.settings.where("accountDid").equals(did).modify(settingsChanges) - Updates account settings
db.settings.add(settingsChanges) - Adds new settings
db.settings.count() - Counts number of settings
db.settings.update(key, changes) - Updates settings

Contacts operations:
export all contacts (Dexie format)
db.contacts.toArray() - Gets all contacts
db.contacts.add(contact) - Adds a new contact
db.contacts.update(did, contactData) - Updates a contact
db.contacts.delete(did) - Deletes a contact
db.contacts.where("did").equals(did).first() - Gets a specific contact by DID

Logs operations:
db.logs.get(todayKey) - Gets logs for a specific day
db.logs.update(todayKey, { message: fullMessage }) - Updates logs
db.logs.clear() - Clears all logs


