# Boot Config Schema Guide

This guide explains how to add new boot config keys and covers the V1-to-V2 data migration pipeline.

## When to Use BootConfig

BootConfig is for a **very narrow** set of configuration items. Before adding a key here, ask:

| Question | If Yes | If No |
|----------|--------|-------|
| Must it load before the lifecycle system takes over? | BootConfig | Preference |
| Does it affect process-level behavior (Chromium flags, data directory)? | BootConfig | Preference |
| Can it wait for the `BeforeReady` lifecycle phase? | Preference | BootConfig |
| Can it be changed at runtime without restart? | Preference | BootConfig |

**Rule of thumb:** If the setting can wait until the lifecycle's `BeforeReady` phase, it belongs in Preference. BootConfig is only for settings that must be available before the lifecycle system even starts. Keep it minimal.

## Key Naming Conventions

Boot config keys follow the same naming convention as preferences.

### Format

`namespace.key_name` — at least 2 segments separated by dots.

**Rules:**

- Lowercase letters, numbers, and underscores only
- Pattern: `/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/`
- Use dots for hierarchy, underscores for multi-word names

### Examples

| Valid | Invalid | Reason |
|-------|---------|--------|
| `app.disable_hardware_acceleration` | `disableHardwareAcceleration` | Missing dot separator |
| `app.user_data_path` | `App.userDataPath` | Uppercase, camelCase |
| `chromium.gpu_compositing` | `gpu` | Single segment |

## Adding a New Boot Config Key

### Step 1: Add to Schema Interface

**File:** `src/shared/data/bootConfig/bootConfigSchemas.ts`

The schema interface and defaults live side by side. The current shape looks like this — follow the same pattern for any new key (matching naming convention, matching entry in `DefaultBootConfig`):

```typescript
export interface BootConfigSchema {
  'app.disable_hardware_acceleration': boolean
  'app.user_data_path': Record<string, string>
}

export const DefaultBootConfig: BootConfigSchema = {
  'app.disable_hardware_acceleration': false,
  'app.user_data_path': {}
}
```

> **Note:** If this file is currently auto-generated by the V1-to-V2 migration pipeline, add your key outside the `=== AUTO-GENERATED CONTENT ===` markers, or coordinate with the migration toolchain (see [V1 to V2 Data Migration](#v1-to-v2-data-migration) below).

### Step 2: Add Custom Types (if needed)

**File:** `src/shared/data/bootConfig/bootConfigTypes.ts`

For simple types (boolean, string, number), no changes needed — the type is inferred from the schema. For custom types, define them alongside `BootConfigKey`:

```typescript
export type BootConfigKey = keyof BootConfigSchema

// Custom types if needed
export type GpuMode = 'auto' | 'disabled' | 'software'
```

### Step 3: Use in Early Boot Code (if needed)

Only for settings that must take effect before lifecycle:

**File:** `src/main/index.ts`

```typescript
import { bootConfigService } from '@main/data/bootConfig'

// Apply before app.whenReady()
if (bootConfigService.get('app.disable_hardware_acceleration')) {
  app.disableHardwareAcceleration()
}
```

### Step 4: Access from Renderer / Lifecycle Services

No additional wiring needed. The `BootConfigPreferenceKeys` mapped type automatically adds the `BootConfig.` prefix, making the key available through the unified preference API:

```typescript
// Renderer — works immediately after adding to schema
const [disableHardwareAcceleration, setDisableHardwareAcceleration] = usePreference(
  'BootConfig.app.disable_hardware_acceleration'
)

// Main process lifecycle service
const disableHardwareAcceleration = preferenceService.get('BootConfig.app.disable_hardware_acceleration')
```

For detailed usage of `usePreference`, see [Preference Usage Guide](./preference-usage.md).

## V1 to V2 Data Migration

> This section covers the **migration toolchain** used to move legacy data from V1 (Redux/ElectronStore/Dexie) into the V2 boot config system. This is **not** the regular path for adding new keys.

### Overview

The `v2-refactor-temp/tools/data-classify/` directory contains the code generation pipeline for migrating legacy data into V2 systems. `classification.json` is the single source of truth that classifies every legacy key into its target system (Preference, BootConfig, Cache, or DataApi).

### How It Works

1. Each item in `classification.json` with `"category": "bootConfig"` maps a legacy key to a boot config key
2. The generator reads these classifications and produces:
   - `src/shared/data/bootConfig/bootConfigSchemas.ts` — schema interface and defaults
   - `src/main/data/migration/v2/migrators/mappings/BootConfigMappings.ts` — legacy-to-new key mappings
3. At migration time, `BootConfigMigrator` reads values from legacy sources (Redux, ElectronStore, Dexie settings, localStorage, and the legacy home config file) and writes them to `bootConfigService`

### Migration Sources

| Source | Accessor | Example |
|--------|----------|---------|
| Redux Store | `ReduxStateReader` with category + dot-path | `settings.disableHardwareAcceleration` |
| ElectronStore | `ConfigManager.get(key)` | Direct key lookup |
| Dexie settings | Key-value table | Direct key lookup |
| localStorage | `localStorage.getItem(key)` | Direct key lookup |
| Legacy home config file | `LegacyHomeConfigReader` | `~/.cherrystudio/config/config.json` (`appDataPath` field only) |

> **Config-file source mappings are manually maintained.** The `data-classify` toolchain's `classification.json` doesn't model config-file sources yet. In two places, a small hand-maintained list complements the classification-driven pipeline:
>
> - **Schema keys**: `MANUAL_BOOT_CONFIG_ITEMS` at the top of `v2-refactor-temp/tools/data-classify/scripts/generate-boot-config.js` — these items are merged with the classification-derived items and emitted into `bootConfigSchemas.ts` as part of the normal auto-generated output. The resulting schema file is fully auto-generated (no manual sections).
> - **Mappings**: inline `configFileMappings` inside `BootConfigMigrator.loadMigrationItems()` — a small `ReadonlyArray<{ originalKey: string; targetKey: BootConfigKey }>` whose `BootConfigKey` annotation is the regen safety net: if the schema loses `app.user_data_path`, this array fails to compile at its declaration site.
>
> To add a new config-file-sourced key in the future: add an entry to `MANUAL_BOOT_CONFIG_ITEMS` in the generator, add the matching entry to `BootConfigMigrator.loadMigrationItems()`'s `configFileMappings`, and run `npm run generate`.

### Adding a Migration Mapping

To migrate a legacy key to boot config:

1. Add or update the item in `classification.json`:

```json
{
  "originalKey": "disableHardwareAcceleration",
  "source": "redux",
  "category": "bootConfig",
  "status": "classified",
  "targetKey": "app.disable_hardware_acceleration",
  "targetType": "boolean",
  "defaultValue": false,
  "reduxCategory": "settings"
}
```

2. Regenerate mappings:

```bash
cd v2-refactor-temp/tools/data-classify && npm run generate
```

3. Verify the generated output in `BootConfigMappings.ts`

### Current Mappings

| Legacy Source | Legacy Key | Target Key |
|---------------|-----------|------------|
| Redux (`settings`) | `disableHardwareAcceleration` | `app.disable_hardware_acceleration` |
| Config file (`~/.cherrystudio/config/config.json`) | `appDataPath` | `app.user_data_path` |

#### Known Limitation: AppImage / Windows Portable Executable Path

The v1 `~/.cherrystudio/config/config.json` stores `appDataPath` as an array of `{ executablePath, dataPath }` entries keyed by executable path. On AppImage Linux builds and Windows portable builds, `src/main/utils/init.ts:51-60` writes a **special** `executablePath` that differs from `app.getPath('exe')`:

- AppImage: `path.dirname(process.env.APPIMAGE) + '/cherry-studio.appimage'`
- Windows portable: `process.env.PORTABLE_EXECUTABLE_DIR + '/cherry-studio-portable.exe'`

`LegacyHomeConfigReader` does NOT reproduce this normalization — array entries are migrated verbatim with their original `executablePath` key, and the legacy-string fallback uses the raw `app.getPath('exe')`. This is harmless in the current PR because nothing yet reads `app.user_data_path`. **But the follow-up PR that rewires `initAppDataDir()` to consume it MUST normalize the exe path using the same logic in `src/main/utils/init.ts:51-60`, otherwise migrated records under AppImage/portable will never match the lookup key.**

## File Structure

| File | Purpose |
|------|---------|
| `src/shared/data/bootConfig/bootConfigSchemas.ts` | Schema interface and default values |
| `src/shared/data/bootConfig/bootConfigTypes.ts` | `BootConfigKey` type, `BootConfigPreferenceKeys` mapped type |
| `src/main/data/bootConfig/BootConfigService.ts` | Service implementation |
| `src/main/data/bootConfig/types.ts` | `BootConfigLoadError` type |
| `v2-refactor-temp/tools/data-classify/data/classification.json` | Migration source of truth |
| `v2-refactor-temp/tools/data-classify/scripts/generate-boot-config.js` | Schema generator (migration) |
| `src/main/data/migration/v2/migrators/BootConfigMigrator.ts` | Migration executor |
| `src/main/data/migration/v2/migrators/mappings/BootConfigMappings.ts` | Auto-generated migration mappings |

## Best Practices

1. **Keep BootConfig minimal** — most settings belong in Preference. Only use BootConfig for settings that must load before the lifecycle system takes over.
2. **Provide sensible defaults** — BootConfigService uses defaults on first launch (missing file). A missing default means the key is unusable on first launch.
3. **Follow naming conventions** — use the same `namespace.key_name` pattern as preferences for consistency.
4. **Process-level settings require restart** — document this in the UI when exposing boot config settings to users.

## Related Documentation

- [Boot Config Overview](./boot-config-overview.md) - Architecture and timing
- [Preference Schema Guide](./preference-schema-guide.md) - Adding preference keys (non-boot)
- [Preference Usage Guide](./preference-usage.md) - `usePreference` hook and service API
- [V2 Migration Guide](./v2-migration-guide.md) - Full migration system documentation
