Skip to content

ENG-1519: Add legacy-to-blockprops migration, remove backedBy from schemea#876

Merged
sid597 merged 6 commits intomigration-block-init-staging-branchfrom
eng-1519-legacy-to-blockprops-migration
Mar 13, 2026
Merged

ENG-1519: Add legacy-to-blockprops migration, remove backedBy from schemea#876
sid597 merged 6 commits intomigration-block-init-staging-branchfrom
eng-1519-legacy-to-blockprops-migration

Conversation

@sid597
Copy link
Collaborator

@sid597 sid597 commented Mar 10, 2026

https://www.loom.com/share/f7367e084c2e424eb20e31fdfd937d14


Open with Devin

Summary by CodeRabbit

  • Chores
    • Implemented legacy settings migration system to transfer existing settings to block properties format.
    • Added support for migrating feature flags, global settings, and personal settings with progress tracking.
    • Updated node configuration to align with new settings storage structure.

@linear
Copy link

linear bot commented Mar 10, 2026

@supabase
Copy link

supabase bot commented Mar 10, 2026

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@sid597
Copy link
Collaborator Author

sid597 commented Mar 10, 2026

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

✅ Actions performed

Full review triggered.

devin-ai-integration[bot]

This comment was marked as resolved.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

The PR removes the backedBy field from discourse node schema and introduces migration utilities to convert legacy settings into block properties. New functions enable reading legacy feature flags, global, personal, and discourse node settings. Migration functions handle transformation and persistence of these settings during initialization.

Changes

Cohort / File(s) Summary
Schema Changes
apps/roam/src/components/settings/utils/zodSchema.ts, apps/roam/src/components/settings/utils/zodSchema.example.ts
Removed backedBy optional field from DiscourseNodeSchema, eliminating the property from the public schema and derived DiscourseNodeSettings type.
Legacy Settings Readers
apps/roam/src/components/settings/utils/accessors.ts
Added four new utility functions: readAllLegacyFeatureFlags(), readAllLegacyGlobalSettings(), readAllLegacyPersonalSettings(), and readAllLegacyDiscourseNodeSettings() to aggregate legacy settings by iterating over keys and invoking corresponding legacy getters.
Migration Orchestration
apps/roam/src/components/settings/utils/migrateLegacyToBlockProps.ts
New module implementing migrateGraphLevel() and migratePersonalSettings() that validate legacy data against schemas, compare against defaults, write to block properties when needed, and track migration status via marker blocks.
Initialization
apps/roam/src/components/settings/utils/init.ts
Added calls to migrateGraphLevel(blockUids) before and migratePersonalSettings(blockUids) after discourse node page initialization in initSchema.
Node Creation
apps/roam/src/components/settings/DiscourseNodeConfigPanel.tsx
Removed backedBy: "user" property from object passed to DiscourseNodeSchema.parse() during node creation.

Sequence Diagram

sequenceDiagram
    participant Init as Initialization
    participant LegacyReader as Legacy Settings Reader
    participant Validator as Schema Validator
    participant BlockProps as Block Properties Writer
    participant Storage as Marker Storage

    Init->>Init: Start initSchema
    Init->>LegacyReader: Call migrateGraphLevel()
    LegacyReader->>LegacyReader: Read legacy feature flags, global, & discourse node settings
    LegacyReader->>Validator: Validate against FeatureFlagsSchema, GlobalSettingsSchema, etc.
    Validator->>Validator: Compare against defaults & existing props
    Validator->>BlockProps: Write block properties if needed
    BlockProps->>Storage: Write migration marker block on success
    Storage-->>Init: Migration complete
    Init->>LegacyReader: Call migratePersonalSettings()
    LegacyReader->>LegacyReader: Read personal settings
    Validator->>BlockProps: Write personal settings to block props
    BlockProps->>Storage: Set personal settings marker
    Storage-->>Init: Personal migration complete
    Init->>Init: Initialize discourse node pages
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the two main changes: adding legacy-to-blockprops migration and removing backedBy from schema, matching the primary objectives of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as resolved.

.optional()
.transform((val) => val ?? defaultNodeIndex()),
suggestiveRules: SuggestiveRulesSchema.default({}),
backedBy: z
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need to have the backedBy in the schema, in the legacy settings we set the backedBy at the runtime, we do not save it anywhere in the blocks

export const migratePersonalSettings = async (
blockUids: Record<string, string>,
): Promise<void> => {
if (getSetting<boolean>(PERSONAL_MIGRATION_MARKER, false)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal settings is per user so we check if this user's personal settings have migrated or not, it could be the case that all the global and discourse node settings have migrated but not the user's personal settings


export const initSchema = async (): Promise<InitSchemaResult> => {
const blockUids = await initSettingsPageBlocks();
await migrateGraphLevel(blockUids);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs before initDiscourseNodePages() on purpose. The init check for “do we already have user discourse nodes?” only looks at block props, so legacy node pages without migrated props would be invisible there and the graph could be mistaken for an empty graph. Running migration first makes those existing legacy node pages visible to the new-store check before default node seeding happens.

@sid597 sid597 requested a review from mdroidian March 11, 2026 09:33
};

// Reconstructs global settings from getFormattedConfigTree() shape to match block-props schema shape
// Reconstructs global settings from legacy Roam tree to match block-props schema shape
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving away from getFormattedConfigTree()

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. One small change from backend to async for the query.

I also added a few additional devin comments, let's take a second to review/resolve them before merging 👍

@sid597 sid597 merged commit a1f1dc0 into migration-block-init-staging-branch Mar 13, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants