Are you sure it’s actually necessary to have a distinct status for local encryption? I believe encryption_blob_encrypted is used because E2EE decryption is all done in the background. In the case of option gated Resource load, the decryption is done explicitly and should be awaited, so it will be in a ready state at that point.
Also, did you see the update I made yesterday on #87 (added with UPDATE: at the bottom)?
you're right, a separate readyStatus value is probably not needed.
encryption_blob_encrypted/readyStatus('encrypted') is mainly for E2EE background decrypt flow. for local encryption, the gated resource path can await decrypt when vault is unlocked, and when locked we should intentionally render the locked placeholder flow instead of treating it as a download state.
so i'll keep status handling simple and use is_locally_encrypted + placeholder interaction logic for the UX split, rather than adding a new readyStatus enum.
and yes, i saw your #87 UPDATE and will align with that placeholder-to-decrypt path.
FYI I’m not sure how far through you got with implementing the latest changes to the proposal, but in the save section of 3.2, make sure the following sections are removed
Setting resources is not relevant anymore, and deleting revisions will be done on gated load instead (for an encrypted note only), but just deleting unencrypted revisions
updated, thanks for catching that. save path now just does encrypt + beforeChangeItemJson suppression, moved the plaintext revision cleanup into the gated load - on every load of an encrypted note, delete any revisions where the encrypted flag isn't set. cleaner since it handles both initial lock and cross-device sync in one place. first post is updated.
Hi @mrjo118 ,
Just wanted to let you know i've finalized my proposal and will be submitting it on the GSoC portal. Let me know if you have any feedback before the deadline!
ResourceService.indexNoteResources guard: the background indexer (ResourceService.ts,
L82-91) parses note.body to populate note_resources. For locally encrypted notes, the
ciphertext body would yield no resource IDs, wiping associations. Core change: skip locally
encrypted notes in the indexer.
You mentioned a resource indexer change in the section about why the solution shouldn’t be plugin only, but did not specify anything about this in section 3.11, which describes the changes for encrypted resources. Also I don’t think the indexer specifically needs to be amended, but the service which deletes orphaned resources needs to be amended to skip deleting resources where is_locally_encrypted is true. An optimal way to do this could be to alter the NoteResources.orphanResources function to join to the resources table and exclude encrypted resources there. It means encrypted resources have to always be manually deleted, but that is a minor caveat.
3.3 Option-Gated Note.save / Note.load
In this section, it should be made clear that useLocalEncryption: true will be applied in all places that local encryption / decryption may need to be applied, not just when the note is actually encrypted. Then note that each of the points about the functionality of the gated save / load only applies when is_locally_encrypted is true, with the exception of the migration logic on load, which applies always when useLocalEncryption: true, and this should happen before the check if is_locally_encrypted is true
3.6 Revision Strategy
It’s worth mentioning here that revisions with is_locally_encrypted = true should trigger the unlock UI
hey, thanks for the final notes. All three are in the updated PDF (attaching v2 here).
orphaned resources - went with your suggestion, NoteResources.orphanResources() gets a JOIN to exclude encrypted resources (3.9, point 7). means encrypted resources need manual deletion but that's a reasonable tradeoff to avoid accidental data loss.
option-gated scope - rewrote 3.3 to make it clear useLocalEncryption: true goes on all code paths where encryption might apply, not just when the note is already encrypted. migration (null -> 1 or 0) runs first before the is_locally_encrypted check.
revision viewer - added to 3.6, NoteRevisionViewer checks the flag on each revision and triggers the unlock prompt for encrypted ones.
submitted on the GSoC portal. updated PDF attached.
yeah you're right, that should say migration only runs on load. on save you're setting the flag explicitly so there's no migration needed there, still have time before the 31st so i'll update the PDF on the portal with this fix. edit: also updated first post in thread GSoC_2026_Keshav_Idea7_Local_Note_Encryption_v2.1.pdf (768.5 KB)