mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-23 04:52:58 +00:00
Document onboarding and settings lifecycles
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# Architectural Decision Record: Make Onboarding Profile-Aware
|
||||
|
||||
## Status
|
||||
|
||||
Accepted — implemented and verified against the locked Commonlib package.
|
||||
|
||||
## Context
|
||||
|
||||
Self-hosted LiveSync stores multiple remote connections in `remoteConfigurations` and selects the ordinary replication target with `activeConfigurationId`. P2P features have a separate `P2P_ActiveRemoteConfigurationId`. Existing replication implementations still consume the older flat CouchDB, Object Storage, and P2P fields, so selecting a profile projects its connection settings onto those compatibility fields.
|
||||
|
||||
The settings pane already creates and edits profiles directly. The Setup Wizard was inconsistent:
|
||||
|
||||
- modern Setup URI and QR payloads retained a supplied profile map;
|
||||
- legacy imports relied on `SettingService` to migrate flat connection fields into `legacy-*` profiles;
|
||||
- manual CouchDB and Object Storage setup wrote only the flat fields and relied on that same migration; and
|
||||
- manual P2P setup partly updated the profile map itself.
|
||||
|
||||
Legacy migration deliberately runs only when the profile map is empty. If a Vault already had one or more profiles, manually configuring another CouchDB or Object Storage connection changed the flat fields but did not add a profile. The selected stored profile could subsequently project its older values back onto those fields. Fresh P2P onboarding could also finish without a profile when no P2P profile ID existed beforehand.
|
||||
|
||||
## Decision
|
||||
|
||||
The profile map is authoritative persisted state for every newly configured remote. The compatibility fields remain the runtime projection of a selected profile and the input accepted from an older settings payload.
|
||||
|
||||
### Manual onboarding
|
||||
|
||||
A successful manual CouchDB, Object Storage, or P2P setup creates or deliberately updates a profile through Commonlib's focused `@vrtmrz/livesync-commonlib/remote-configurations` entry.
|
||||
|
||||
- Existing profiles are preserved.
|
||||
- A newly created profile receives an opaque generated ID.
|
||||
- CouchDB and Object Storage setup select the new profile as the main remote.
|
||||
- P2P setup selects the profile through `P2P_ActiveRemoteConfigurationId`.
|
||||
- P2P setup also selects it as the main remote when P2P is being configured as the main remote.
|
||||
- Configuring P2P alongside another main remote changes only the P2P selection.
|
||||
- A known profile ID is supplied only when an existing profile is deliberately being updated; omitting the ID creates another profile.
|
||||
|
||||
The onboarding dialogue does not add a naming step. Commonlib proposes a concise type-specific display name and adds a numeric suffix when necessary. The settings pane can rename it later.
|
||||
|
||||
### Identity and naming
|
||||
|
||||
Profile names are presentation only. They are neither unique identity nor a marker for the selected profile. No entry receives a special `default` ID or name. Opaque IDs establish identity, `activeConfigurationId` establishes the main selection, and `P2P_ActiveRemoteConfigurationId` establishes the P2P selection.
|
||||
|
||||
Generated names describe the connection without exposing credentials, for example `CouchDB couch.example`, `S3 notes`, or `P2P team-room`.
|
||||
|
||||
### Setup URI and QR import
|
||||
|
||||
A modern payload preserves its profile IDs, display names, profile URIs, main selection, and P2P selection. Setup does not rename or recreate those profiles.
|
||||
|
||||
A legacy payload containing only flat connection fields remains supported. `SettingService` migrates it into clearly labelled `legacy-couchdb`, `legacy-s3`, or `legacy-p2p` profiles only when no modern profile map exists. This is the only onboarding path which intentionally relies on the compatibility migration.
|
||||
|
||||
### Persistence and restart ordering
|
||||
|
||||
Profile construction happens before the settings are submitted to the onboarding completion boundary. Existing-device and new-device setup reserve Fetch or Rebuild respectively before enabling and saving the settings. Profile awareness does not change that initialisation ownership or restart ordering.
|
||||
|
||||
Commonlib produces an in-memory plaintext profile URI. The standard setting service applies its configured at-rest encryption during persistence.
|
||||
|
||||
## Alternatives rejected
|
||||
|
||||
### Keep relying on legacy migration
|
||||
|
||||
This works only while the profile map is empty. It silently fails to register a newly configured connection once multiple-remote settings are already in use and leaves P2P with a separate implementation.
|
||||
|
||||
### Create a special `default` profile
|
||||
|
||||
The special meaning would duplicate `activeConfigurationId`, make a user-visible name carry identity, and become ambiguous as soon as the user selects another profile. Selection IDs already express the required state.
|
||||
|
||||
### Add profile naming and full list editing to onboarding
|
||||
|
||||
That would make the first-run path longer and duplicate the established Remote Databases interface. Automatic descriptive names and later renaming keep this change limited to data integrity and consistent selection.
|
||||
|
||||
### Replace the compatibility fields immediately
|
||||
|
||||
Replication, diagnostics, and older settings paths still consume the projected fields. Removing them belongs to a broader runtime migration and is not required to make onboarding correctly profile-aware.
|
||||
|
||||
## Verification
|
||||
|
||||
Commonlib unit tests cover preserving existing profiles, opaque-ID insertion, generated display names, duplicate-name suffixes, main activation, independent P2P selection, and URI serialisation. Its packed-consumer test imports the focused entry point from the generated package.
|
||||
|
||||
Self-hosted LiveSync unit tests cover preserving modern Setup URI profiles and their active selection, retaining legacy Setup URI and QR migration, adding CouchDB and Object Storage profiles beside an existing profile, independent P2P selection, fresh P2P selection as both main and P2P remote, and cancellation without mutation.
|
||||
|
||||
The real-Obsidian onboarding E2E owns the invitation, dialogue presentation, safe-area and touch-target checks, cancellation, and command reopening. It does not contact a remote or submit credentials. Remote connection correctness remains owned by the CouchDB, Object Storage, P2P, and two-Vault suites. The end-to-end Setup URI and provisioning acceptance workflow remains a separate release gate.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Manual onboarding and the Remote Databases pane share one Commonlib profile contract.
|
||||
- Existing profiles survive reconfiguration, and a newly configured connection becomes explicitly selectable.
|
||||
- Modern imports retain user-assigned profile identity and names.
|
||||
- Legacy Setup URIs continue to work through an isolated compatibility boundary.
|
||||
- Runtime consumers may keep using projected flat fields while the persisted model and new APIs use the 1.0 multiple-remote contract.
|
||||
@@ -6,7 +6,7 @@ Accepted for the 1.0 release line.
|
||||
|
||||
## Context
|
||||
|
||||
Self-hosted LiveSync historically used two unrelated kinds of version state during start-up.
|
||||
Self-hosted LiveSync historically used several unrelated kinds of version and settings state during start-up.
|
||||
|
||||
The plug-in SemVer was converted into a numeric major/minor value and stored in `lastReadUpdates`. The settings dialogue used that value to open the change log automatically, and offered a button which marked the release line as read. Patch versions were intentionally ignored. Pre-release identifiers containing an additional dot did not fit this numeric representation and could be interpreted as a much larger release line.
|
||||
|
||||
@@ -14,6 +14,8 @@ Separately, the internal database compatibility constant `VER` is recorded in de
|
||||
|
||||
The remote `obsydian_livesync_version` document also carries the internal database version. It is a protocol and data-compatibility mechanism, not a copy of the plug-in SemVer.
|
||||
|
||||
Commonlib's `settingVersion` describes the stored settings shape, while `DEFAULT_SETTINGS` was historically used both to complete missing values in an existing document and to initialise a new Vault. Those operations require different defaults: an existing Vault needs conservative completion, while a genuinely new Vault can use current recommendations without changing an established configuration.
|
||||
|
||||
## Decision
|
||||
|
||||
### Release notes
|
||||
@@ -23,6 +25,18 @@ The remote `obsydian_livesync_version` document also carries the internal databa
|
||||
- Do not derive data-compatibility behaviour from the plug-in's major, minor, patch, or pre-release identifiers.
|
||||
- Retain the saved `lastReadUpdates` field in the settings schema for backwards compatibility, but do not use it in the plug-in. It can be removed through a separately reviewed settings-schema migration if retaining it later becomes burdensome.
|
||||
|
||||
### Settings schema and initial settings
|
||||
|
||||
- Keep the Commonlib settings schema version independent of the plug-in SemVer and the internal database version `VER`. Increment it only for an ordered change to the stored settings shape.
|
||||
- Use Commonlib's conservative schema defaults to complete an existing settings document. Explicit stored values take precedence, and an ordinary migration does not disable or replace the person's synchronisation choices.
|
||||
- Use `createNewVaultSettings()` only for a store which has never held Self-hosted LiveSync settings, explicit new-user onboarding, a factory reset, or CLI settings creation. Setup URI, QR, Markdown, and other existing-setting imports retain conservative completion semantics.
|
||||
- Apply remote-specific preferred values only when that remote is explicitly selected during setup. Do not infer and merge new recommendations into an existing configuration.
|
||||
- Keep settings saved by a future Commonlib schema fail-closed and do not persist an apparent downgrade migration.
|
||||
|
||||
The current new-Vault base selects a 50 MB maximum synchronised file size, Rabin–Karp chunk splitting, Plug-in Sync V2, case-insensitive file-name handling, and E2EE V2. It does not enable synchronisation, encryption, or a remote connection without user action. Chunk revisions are always content-derived; `doNotUseFixedRevisionForChunks` remains only as deprecated compatibility input and is not a recommendation or review setting.
|
||||
|
||||
An existing settings document without an explicit `handleFilenameCaseSensitive` choice keeps that value unresolved and enters compatibility review. The running host can explicitly retain legacy case-sensitive handling. Adopting cross-platform case-insensitive handling remains paused until the person has checked case-only path conflicts and rebuilt the local database.
|
||||
|
||||
### Database compatibility
|
||||
|
||||
- Continue to use the internal database version `VER` for changes which require explicit compatibility review. Changing the plug-in SemVer alone does not increment `VER`.
|
||||
@@ -31,6 +45,7 @@ The remote `obsydian_livesync_version` document also carries the internal databa
|
||||
- Treat a missing marker on a configured Vault as an ambiguous device transition. Copying or restoring a Vault, or opening it with a new Obsidian profile, can preserve settings and database files without preserving device-local storage. Do not infer acknowledgement from an empty local database: a recovery operation, partial copy, or remote-first setup can also produce that state. Explain these cases and require an explicit decision in the compatibility dialogue.
|
||||
- Derive one structured pause from the acknowledged database version, Commonlib's settings-migration state, and any persisted legacy review message. Persist the generic `versionUpFlash` message without changing any automatic synchronisation setting, because Commonlib already treats that field as a replication gate.
|
||||
- Treat non-empty `versionUpFlash` as a runtime replication gate. Standard and one-shot replication must stop before remote work begins.
|
||||
- Apply the same ordinary replication policy to P2P pull, push, and peer-requested synchronisation. An explicitly confirmed Fetch or Rebuild may bypass the ordinary policy because it is the operation selected to construct or recover the local state.
|
||||
- Present the reason in a dedicated dialogue after the Obsidian layout is ready. The details view is explanatory only and returns to the summary before any decision can be made. The safe default and closing either dialogue keep synchronisation paused. A persistent Notice and a command allow the dialogue to be reopened without using the settings pane.
|
||||
- Let the person read focused compatibility details without presenting the whole release history as a safety instruction. The Change Log remains a manually opened release-history pane and contains no compatibility acknowledgement control.
|
||||
- Offer an explicit resume action only when every reason is recoverable in the running implementation. An upgrade, a missing or invalid marker on an existing Vault, and a reviewed migration from an older settings schema are resumable after all devices have been updated. A downgrade from a newer acknowledged `VER`, or settings saved by a future schema, cannot be acknowledged by the older installation.
|
||||
@@ -38,6 +53,17 @@ The remote `obsydian_livesync_version` document also carries the internal databa
|
||||
- Preserve the original legacy review message as a structured reason when no more specific database or settings-schema reason is available. Escape it before including it in Markdown UI.
|
||||
- Continue to reject a remote version document which is newer than the running implementation. That receiver-side check is independent of the local upgrade review.
|
||||
|
||||
### Onboarding activation and initialisation
|
||||
|
||||
- Keep an unconfigured Vault outside database initialisation, offline scanning, and configured-only checks. Offer setup through the long-lived onboarding Notice and the permanent command instead of opening a competing dialogue automatically.
|
||||
- For new-device onboarding, reserve Rebuild before enabling and saving the accepted settings.
|
||||
- For an unconfigured existing device, reserve Fetch before enabling and saving imported or manually confirmed settings.
|
||||
- Suspend the current runtime after the flag has been written, apply the accepted settings through the scheduler's preparation callback, and request restart only after that callback succeeds.
|
||||
- If the flag cannot be written, do not enable the settings. If preparation fails, remove the flag, resume the current runtime, and leave the transition incomplete.
|
||||
- Applying compatible settings to an already configured device remains an ordinary edit and does not schedule Fetch automatically.
|
||||
|
||||
`isConfigured`, the Fetch and Rebuild flags, and in-memory suspension therefore retain separate meanings. `isConfigured` controls participation in ordinary processing, a flag selects a one-shot operation for the next start, and suspension prevents the old process from observing newly enabled settings before that selected restart.
|
||||
|
||||
### Flag-file recovery order
|
||||
|
||||
- Evaluate and persist the compatibility gate after settings load, before Obsidian layout-ready recovery begins. This blocks ordinary and one-shot replication even while the review dialogue has not yet opened.
|
||||
@@ -52,6 +78,8 @@ The remote `obsydian_livesync_version` document also carries the internal databa
|
||||
- An internal compatibility change remains fail-closed for replication, but it no longer destroys the person's synchronisation preferences.
|
||||
- A new installation has no previous internal-version marker and therefore does not show an upgrade review. Its initial settings and onboarding remain responsible for keeping replication disabled until configuration is complete.
|
||||
- A copied or restored configured Vault can show a one-time compatibility review on its new device or profile. This is intentional even when its local database appears empty, because emptiness does not prove how the Vault was produced.
|
||||
- A genuinely new Vault receives current recommendations without applying them as fallbacks to an existing configuration. It remains inert until onboarding is accepted.
|
||||
- Accepted new-device and existing-device setup cannot enable ordinary processing before the selected Rebuild or Fetch has been reserved.
|
||||
- An older installation cannot dismiss evidence that a newer implementation or settings schema has already been used on the device.
|
||||
- The Obsidian-specific dialogue depends only on a host-neutral compatibility result and the injected confirmation capability. Commonlib remains responsible for settings migration, device-local storage, and the replication gate.
|
||||
- A future incompatible database change must increment `VER`, provide an actionable review message, verify the remote version negotiation, and test both the pending and acknowledged states. A major SemVer increase without those changes has no database-compatibility effect.
|
||||
@@ -59,7 +87,10 @@ The remote `obsydian_livesync_version` document also carries the internal databa
|
||||
## Verification
|
||||
|
||||
- Unit tests verify new-Vault initialisation, upgrades, missing and invalid markers, downgrades, future settings schemas, legacy marker migration, acknowledgement ordering, and save-failure recovery while retaining automatic synchronisation choices.
|
||||
- Commonlib package tests verify conservative stored-setting completion, independently mutable new-Vault settings, unresolved file-name case policy, future-schema protection, and the focused settings entry from a clean consumer.
|
||||
- Host unit tests verify new-Vault factory use, conservative import paths, the unconfigured start-up gate, flag-before-settings ordering, rollback when the flag cannot be reserved, ordinary configured edits, and the explicit file-name case decision.
|
||||
- Unit tests verify that a pending review is honoured by the packaged Commonlib replication service before remote activity begins.
|
||||
- Unit and Compose tests verify that ordinary P2P replication observes the policy, explicit P2P rebuild uses the setup bypass, and replacement leaves host actions on the current replicator.
|
||||
- A real-Obsidian settings test verifies the dedicated summary and details dialogues, captures representative screenshots, confirms that the acknowledged internal version advances only after explicit resume, and confirms that the Change Log contains no acknowledgement control.
|
||||
- The real-Obsidian CouchDB workflow starts from configured plug-in data without a device-local marker, verifies the copied-or-restored Vault explanation, resumes through the actual dialogue, and then completes remote metadata, chunk, and activity checks. The two-Vault workflow performs the same review once per isolated Vault before reusing the acknowledged device state for later process launches.
|
||||
- Unit tests fix the layout-ready priority after the three flag-file recovery priorities, so a recovery which stops start-up cannot race the compatibility dialogue.
|
||||
|
||||
Reference in New Issue
Block a user