---
phase: 06-new-backends
plan: "03"
type: execute
wave: 2
depends_on:
- "06-01"
- "06-02"
files_modified:
- src/components/wizard/RemoteConfigStep.tsx
autonomous: false
requirements:
- BACK-01
- BACK-02
- BACK-03
- BACK-04
must_haves:
truths:
- "User can select OneDrive in BackendSelectionStep and see token, drive_id, drive_type fields in RemoteConfigStep"
- "User can select SFTP and see host, user, and the Password/Private Key toggle in RemoteConfigStep"
- "User can select GCS and see project_number and service_account_credentials fields"
- "User can select Backblaze B2 and see Application Key ID and Application Key fields"
- "All four new backends appear in BackendSelectionStep (automatic — driven by BACKEND_REGISTRY)"
- "Full Vitest suite passes with zero failures and zero TypeScript errors"
artifacts:
- path: "src/components/wizard/RemoteConfigStep.tsx"
provides: "Extended component handling all 7 backends; sftp branch with SftpAuthToggle"
contains: "SftpAuthToggle"
key_links:
- from: "src/components/wizard/RemoteConfigStep.tsx"
to: "src/components/wizard/SftpAuthToggle.tsx"
via: "sftp branch import and render"
pattern: "backendType === 'sftp'"
- from: "src/components/wizard/RemoteConfigStep.tsx"
to: "src/schemas/index.ts BACKEND_SCHEMAS"
via: "schema lookup — all 7 BackendType values must be keys in BACKEND_SCHEMAS"
pattern: "BACKEND_SCHEMAS\\[backendType\\]"
- from: "src/components/wizard/RemoteConfigStep.tsx"
to: "src/schemas/registry.ts BACKEND_REGISTRY"
via: "backendLabel record must be exhaustive over all 7 BackendType values"
pattern: "backendLabel.*onedrive|sftp|gcs|b2"
---
Wire all four new backends into RemoteConfigStep — extend backendLabel, add the sftp branch with SftpAuthToggle, and ensure gcs/b2/onedrive render via the existing registry loop.
Purpose: The only UI wiring step. After Plans 01 and 02, the data layer is complete. This plan makes it visible and interactive in the wizard.
Output: RemoteConfigStep.tsx updated; all RemoteConfigStep tests green; full suite green.
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-new-backends/06-RESEARCH.md
@.planning/phases/06-new-backends/06-01-SUMMARY.md
@.planning/phases/06-new-backends/06-02-SUMMARY.md
From src/components/wizard/RemoteConfigStep.tsx (current — pre-modification):
```typescript
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { useWizard } from '../../store/context';
import { BACKEND_REGISTRY } from '../../schemas/registry';
import { BACKEND_SCHEMAS } from '../../schemas';
import { FieldRenderer } from '../ui/FieldRenderer';
import { AzureAuthToggle } from './AzureAuthToggle';
import type { FieldError } from 'react-hook-form';
export function RemoteConfigStep() {
const { state, dispatch } = useWizard();
const backendType = state.remote.backendType;
useEffect(() => {
if (!backendType) dispatch({ type: 'SET_STEP', payload: 0 });
}, [backendType, dispatch]);
const schema = backendType ? BACKEND_SCHEMAS[backendType] : BACKEND_SCHEMAS['azureblob'];
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
mode: 'onSubmit',
reValidateMode: 'onChange',
defaultValues: state.remote.params,
});
if (!backendType) return null;
const onNext = (values: Record) => {
dispatch({ type: 'SET_REMOTE_PARAMS', payload: values });
dispatch({ type: 'SET_STEP', payload: 2 });
};
const backendLabel: Record, string> = {
azureblob: 'Azure Blob Storage',
s3: 'Amazon S3',
's3-compatible': 'S3-Compatible Storage',
};
return (
Step 2: Configure {backendLabel[backendType]}
);
}
```
From src/components/wizard/SftpAuthToggle.tsx (created by Plan 02):
```typescript
export function SftpAuthToggle({ register, errors }: SftpAuthToggleProps)
// Props: { register: UseFormRegister; errors: { pass?: FieldError; key_pem?: FieldError } }
```
Task 1: Extend RemoteConfigStep.tsx — backendLabel + sftp branch + all four new backendssrc/components/wizard/RemoteConfigStep.tsx
- Import SftpAuthToggle from './SftpAuthToggle'
- backendLabel record covers all 7 BackendType values: adds onedrive/'OneDrive', sftp/'SFTP', gcs/'Google Cloud Storage', b2/'Backblaze B2'
- The ternary in JSX becomes a three-branch chain:
1. backendType === 'azureblob' → existing AzureAuthToggle branch (unchanged)
2. backendType === 'sftp' → host field + user field via FieldRenderer, then SftpAuthToggle for pass/key_pem
3. all others (onedrive, gcs, b2, s3, s3-compatible) → registry loop (unchanged)
- SFTP branch renders host and user fields from BACKEND_REGISTRY.sftp.fields using FieldRenderer (same as azureblob renders account), then SftpAuthToggle
- onedrive, gcs, b2 render entirely via the registry loop — no custom branch needed
- `npx vitest run src/components/wizard/RemoteConfigStep.test.tsx` fully green for all 7 backends
- `npx vitest run` (full suite) fully green
- `npx tsc --noEmit` zero errors
Edit src/components/wizard/RemoteConfigStep.tsx:
1. Add import at top (after AzureAuthToggle import):
`import { SftpAuthToggle } from './SftpAuthToggle';`
2. Extend backendLabel record:
```typescript
const backendLabel: Record, string> = {
azureblob: 'Azure Blob Storage',
s3: 'Amazon S3',
's3-compatible': 'S3-Compatible Storage',
onedrive: 'OneDrive',
sftp: 'SFTP',
gcs: 'Google Cloud Storage',
b2: 'Backblaze B2',
};
```
3. Replace the ternary block in JSX (inside the form, before the button div):
```tsx
{backendType === 'azureblob' ? (
<>
{/* Account field via FieldRenderer */}
f.key === 'account')!}
register={register}
error={errors.account as FieldError | undefined}
/>
{/* Auth toggle handles key + sas_url — both always registered */}
>
) : backendType === 'sftp' ? (
<>
{/* host and user via FieldRenderer */}
f.key === 'host')!}
register={register}
error={errors.host as FieldError | undefined}
/>
f.key === 'user')!}
register={register}
error={errors.user as FieldError | undefined}
/>
{/* Auth toggle handles pass + key_pem — both always registered */}
>
) : (
/* All others (onedrive, gcs, b2, s3, s3-compatible): full registry loop */
BACKEND_REGISTRY[backendType].fields.map(field => (
))
)}
```
After editing, run the full suite immediately. Confirm all 7 backend describe blocks in RemoteConfigStep.test.tsx are green.
Note on OneDrive drive_type field: BACKEND_REGISTRY.onedrive has drive_type with inputType: 'select'. FieldRenderer already handles 'select' type — no changes to FieldRenderer needed. The test asserts getByLabelText(/drive type/i) — ensure FieldRenderer renders a label matching that text.
npx vitest run 2>&1 | tail -20RemoteConfigStep handles all 7 backends; SFTP branch uses SftpAuthToggle; onedrive/gcs/b2 render via registry loop; full Vitest suite green; zero TypeScript errors from `npx tsc --noEmit`Task 2: Human verify all four new backends in the wizard UIsrc/components/wizard/RemoteConfigStep.tsxRun `npm run dev` and manually test each new backend through the wizard UI flow.npx vitest run 2>&1 | tail -5All four backends visually verified in the running app by the user
All four new backends fully wired into the wizard:
- OneDrive: token (password field), Drive ID, Drive Type (select: Personal/Business/SharePoint)
- SFTP: Host, Username, Password/Private Key toggle (CSS-hidden, preserves values on switch)
- Google Cloud Storage: Project Number, Service Account JSON (password field)
- Backblaze B2: Application Key ID, Application Key (password field)
All four backends appear as cards in BackendSelectionStep. Automated tests are fully green.
1. `npm run dev` — open http://localhost:5173
2. Verify BackendSelectionStep shows 7 backend cards including OneDrive, SFTP, Google Cloud Storage, Backblaze B2
3. Select OneDrive → confirm OAuth Token (JSON), Drive ID, Drive Type fields appear
4. Go back, select SFTP → confirm Host, Username fields + Password/Private Key tab buttons
- Type a value in Password field, switch to Private Key, switch back — value must still be there
5. Go back, select GCS → confirm Project Number and Service Account JSON fields appear
6. Go back, select B2 → confirm Application Key ID and Application Key fields appear
7. For any backend: fill all required fields, click Next — wizard must advance without errors
Type "approved" to complete Phase 6, or describe any visual issues found
`npx vitest run` — all tests green including all 4 new backend describe blocks in RemoteConfigStep.test.tsx
`npx tsc --noEmit` — zero TypeScript errors
Manual: all 4 new backends visible and functional in the wizard UI
- RemoteConfigStep handles all 7 BackendType values without TypeScript errors
- SFTP branch uses SftpAuthToggle with CSS-hidden pattern
- onedrive, gcs, b2 render entirely via the registry loop
- All 4 new backends visible in BackendSelectionStep UI (automatic via registry)
- Full Vitest suite green
- Zero TypeScript errors
- Human verification: all backends visually correct and functional