Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/arverma/Bihar-Police-Notebook/llms.txt

Use this file to discover all available pages before exploring further.

Bihar Police Notebook persists all documents locally in the browser using IndexedDB. There is no server — every letter and diary is stored on the device that opened the editor. The editor/js/store.js module is the single source of truth for reads, writes, soft-deletes, and Drive sync metadata. A separate prefs.js module handles lightweight UI and auth preferences via localStorage.

Database Schema

PropertyValue
Database namebp-writing-tool
Version2
Object storesletter, diary
Key pathid (auto-increment integer)
Indexesfilename (non-unique), uuid (unique)
Version 2 added the uuid index and ran a migration (migrateAssignUuids) that backfills stable UUIDs onto any existing rows created before the Drive sync feature was introduced.

Document Fields

id
number
Auto-increment integer primary key assigned by IndexedDB.
filename
string
Display name shown in the History sidebar. Defaults to the formatted creation date (e.g. "12 Jun 2024").
content
string
For letters: raw text or Quill delta HTML. For diaries: JSON-serialised { header, pages } object.
type
"letter" | "diary"
Identifies which object store the document lives in.
uuid
string
Stable identifier used to match local documents with their Drive counterparts. Generated with crypto.randomUUID() where available, or a bp-{timestamp}-{random} fallback.
created_at
string
ISO 8601 timestamp set when the document is first created. Never updated on subsequent saves.
updated_at
string
ISO 8601 timestamp updated on every saveDocumentById call.
driveFileId
string | null
Google Drive file ID of the corresponding {uuid}.json file, or null if never synced.
syncedAt
string | null
ISO 8601 timestamp of the last successful Drive push, or null.
syncError
string | null
Error message from the most recent failed sync attempt, cleared to null on a successful push.
deletedAt
string | null
ISO 8601 timestamp set by soft-delete. null for live documents. Used as a Drive tombstone until the deletion is confirmed uploaded.

Read Functions

type
"letter" | "diary"
required
The object store to query.

getDocuments(type)

export async function getDocuments(type)
// Returns: Promise<object[]>
Lists all live (non-deleted) documents for the given type. The History sidebar calls this to populate its document list. Soft-deleted tombstones (deletedAt set) are filtered out.

getDocumentsIncludingDeleted(type?)

export async function getDocumentsIncludingDeleted(type)
// Returns: Promise<object[]>
Returns every row including tombstones. When type is omitted, queries both letter and diary stores and merges the results. Used by the Drive sync module to enumerate all pending operations.

getDocumentById(type, id)

export async function getDocumentById(type, id)
// Returns: Promise<object | null>
Fetches a single document by its integer id. Returns null if the row does not exist. Called on startup to restore the last-active document.

getDocumentByUuid(uuid, type?)

export async function getDocumentByUuid(uuid, type)
// Returns: Promise<object | null>
Looks up a document by its stable uuid. Searches across both stores when type is omitted. Used during Drive pull-and-merge to match remote JSON files to local rows.

previewText(doc)

export function previewText(doc)
// Returns: string
Returns a short plain-text preview string for the History sidebar. For diaries, returns "FIR {fir_number} · Case {case_diary_no}". For letters, strips HTML tags and returns up to 40 characters of plain text.

Write Functions

saveDocumentById(type, doc)

export async function saveDocumentById(type, doc)
// doc: { id?: number|null, filename: string, content: string, created_at?: string, uuid?: string }
// Returns: Promise<number>  — the document id
The primary upsert used by autosave. When doc.id is provided and a matching row exists, it updates filename, content, updated_at, and clears syncError. When no matching row is found (or doc.id is null), it inserts a new row. Returns the document’s integer id.
On update, syncError is cleared but syncedAt is not updated — the document is now dirty and needsBackup will return true until the next Drive push.

saveDocument(type, filename, content)

export async function saveDocument(type, filename, content)
// Returns: Promise<number>
Convenience wrapper around saveDocumentById that always inserts a new row (passes id: null). Intended for programmatic document creation where no existing ID is known.

upsertFromRemote(remote)

export async function upsertFromRemote(remote)
// remote: { uuid, type, filename, content, created_at?, updated_at?, deleted?, driveFileId? }
// Returns: Promise<object>
Merges a Drive payload into the local store using last-write-wins by updated_at. If a local document with the same uuid exists and the remote updated_at is newer, the local row is overwritten. If no local match exists, a new row is inserted. Sets syncedAt to the remote’s updated_at so the document is not immediately re-uploaded.

Delete Functions

softDeleteDocumentById(type, id)

export async function softDeleteDocumentById(type, id)
// Returns: Promise<object | null>  — the deleted row or null if not found
Sets deletedAt and updated_at on the row without physically removing it. The tombstone allows Drive sync to propagate the deletion before the row is purged. Returns null if the document was already deleted or does not exist.

softDeleteDocument(type, filename)

export async function softDeleteDocument(type, filename)
// Returns: Promise<object | null>
Soft-deletes by filename index lookup. Targets the first live document that matches. Used in legacy code paths and when no numeric ID is available.

hardDeleteById(type, id)

export async function hardDeleteById(type, id)
// Returns: Promise<boolean>
Physically removes a row from IndexedDB. Called after a tombstone has been confirmed uploaded to Drive, or immediately for documents that were never synced.

Sync Metadata Functions

needsBackup(doc)

export function needsBackup(doc)
// Returns: boolean
Returns true when a document needs a Drive upload. A document needs backup if it has no driveFileId, has never been synced (syncedAt is null), or its updated_at (or deletedAt) timestamp is newer than syncedAt.

backupStatus(doc)

export function backupStatus(doc)
// Returns: 'synced' | 'pending' | 'error'
Derives the three-state Drive badge shown in the History sidebar. Returns 'error' when syncError is set and needsBackup is true, 'pending' when needsBackup is true without an error, and 'synced' otherwise.

markSynced(type, id, fields)

export async function markSynced(type, id, fields)
// fields: { driveFileId?: string|null, syncedAt?: string|null, syncError?: string|null, deletedAt?: string|null }
// Returns: Promise<boolean>
Patches Drive sync metadata fields onto an existing row without touching content or updated_at. Called by drive-sync.js after a successful or failed upload.

listPendingSync(type?)

export async function listPendingSync(type)
// Returns: Promise<object[]>
Returns all documents (including tombstones) for which needsBackup is true. Queries both stores when type is omitted. Used by pushPending() in drive-sync.js.

clearAllDriveFileIds()

export async function clearAllDriveFileIds()
// Returns: Promise<number>  — number of rows updated
Nullifies driveFileId on every row in both object stores. Called when the Drive backup folder is found to have been deleted — clearing the IDs forces the next pushPending to re-create all remote files from scratch.

Preferences (localStorage)

UI flags, auth state, and user preferences are stored separately in localStorage via editor/js/prefs.js, not in IndexedDB. Keys follow the bpnt.* namespace convention:
KeyMeaning
bpnt.drive.connectedtrue when a Drive session has been authorised
bpnt.drive.emailConnected Google account email address
bpnt.drive.folderIdCached ID of the backup folder in My Drive
bpnt.dictationLangLast-used dictation language (hi-IN or en-IN)
bpnt.cloudConsent.{lang}true when the user has consented to cloud speech for a language
prefs.js exposes getPref(key, default), setPref(key, value), and removePref(key) helpers. Prefer these over calling localStorage directly so that the bpnt. prefix and serialisation are applied consistently.

Build docs developers (and LLMs) love