7.1 KiB
| phase | plan | type |
|---|---|---|
| 01-provider-infrastructure | 1 | execute |
Purpose: Establish the foundation for multi-provider support by allowing users to enable/disable providers and securely store API keys. Output: Provider settings tab in ProjectSetupModal with API key inputs for Replicate and fal.ai, persisted to localStorage.
<execution_context> ~/.claude/get-shit-done/workflows/execute-phase.md ~/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.mdKey files: @src/types/index.ts @src/store/workflowStore.ts @src/components/ProjectSetupModal.tsx
Established patterns:
- Types defined in
src/types/index.tswith PascalCase interfaces - Settings persisted via localStorage with
node-banana-*key prefix - Zustand store pattern in
workflowStore.tswith inline actions - Modal UI pattern from existing ProjectSetupModal (neutral-* Tailwind colors, consistent spacing)
Constraints:
- Gemini remains default, Replicate/fal.ai are optional add-ons
- API keys stored in localStorage (client-side only, no server storage)
- Follow existing naming conventions:
node-banana-provider-settings
ProviderTypeunion:"gemini" | "replicate" | "fal"ProviderConfiginterface with fields:id: ProviderTypename: string(display name)enabled: booleanapiKey: string | nullapiKeyEnvVar?: string(for Gemini which uses env var)
ProviderSettingsinterface with field:providers: Record<ProviderType, ProviderConfig>
Keep existing types unchanged. Add new types after NodeGroup interface.
npm run build passes with no TypeScript errors
ProviderType, ProviderConfig, and ProviderSettings types exist and are exported
-
Add storage key constant:
PROVIDER_SETTINGS_KEY = "node-banana-provider-settings" -
Add helper functions (after existing localStorage helpers around line 310):
getProviderSettings(): ProviderSettings- loads from localStorage, returns defaults if not foundsaveProviderSettings(settings: ProviderSettings): void- saves to localStorage
-
Default provider settings (Gemini enabled by default with env var, others disabled):
const defaultProviderSettings: ProviderSettings = { providers: { gemini: { id: "gemini", name: "Google Gemini", enabled: true, apiKey: null, apiKeyEnvVar: "GEMINI_API_KEY" }, replicate: { id: "replicate", name: "Replicate", enabled: false, apiKey: null }, fal: { id: "fal", name: "fal.ai", enabled: false, apiKey: null }, } }; -
Add to store state interface:
providerSettings: ProviderSettings
-
Add store actions:
updateProviderSettings: (settings: ProviderSettings) => void- updates state and saves to localStorageupdateProviderApiKey: (providerId: ProviderType, apiKey: string | null) => void- updates single provider keytoggleProvider: (providerId: ProviderType, enabled: boolean) => void- enables/disables provider
-
Initialize
providerSettingsin create() usinggetProviderSettings()
Import ProviderType and ProviderSettings from "@/types". npm run build passes, store exports new actions Provider settings state and actions exist in workflowStore, persisted to localStorage
Task 3: Add Providers tab to ProjectSetupModal src/components/ProjectSetupModal.tsx Extend ProjectSetupModal with a tabbed interface and Providers settings:-
Add tab state:
const [activeTab, setActiveTab] = useState<"project" | "providers">("project") -
Import provider state from store:
const { providerSettings, updateProviderApiKey, toggleProvider } = useWorkflowStore(); -
Add local state for provider form (to avoid saving on every keystroke):
const [localProviders, setLocalProviders] = useState(providerSettings);Sync localProviders when modal opens (in useEffect).
-
Add tab bar below the title:
<div className="flex gap-4 border-b border-neutral-700 mb-4"> <button onClick={() => setActiveTab("project")} className={`pb-2 text-sm ${activeTab === "project" ? "text-neutral-100 border-b-2 border-white" : "text-neutral-400"}`} > Project </button> <button onClick={() => setActiveTab("providers")} className={`pb-2 text-sm ${activeTab === "providers" ? "text-neutral-100 border-b-2 border-white" : "text-neutral-400"}`} > Providers </button> </div> -
Wrap existing form content in
{activeTab === "project" && (...)}block. -
Add Providers tab content
{activeTab === "providers" && (...)}:- Show each provider (Gemini, Replicate, fal.ai) in a card-like section
- For Gemini: Show "Configured via GEMINI_API_KEY environment variable" (no input field, just info)
- For Replicate and fal.ai:
- Toggle switch to enable/disable
- API key input field (type="password", only shown when enabled)
- Show/hide password toggle button
- Use consistent neutral-* Tailwind classes matching existing UI
-
Update handleSave to also save provider settings when on providers tab:
- Call
updateProviderApiKeyfor each changed provider - Call
toggleProviderfor each changed enabled state
- Call
-
When in "providers" tab and user clicks Save, save provider settings and close modal (no directory validation needed).
Follow existing modal patterns: neutral-800 background, neutral-700 borders, consistent button styling. npm run dev, open Project Settings, switch to Providers tab, toggle Replicate on, enter API key, save, reload page, verify settings persisted ProjectSetupModal has Providers tab with API key inputs for Replicate and fal.ai, settings persist across page reloads
Before declaring plan complete: - [ ] `npm run build` succeeds without errors - [ ] `npm run lint` passes - [ ] Provider types exported from src/types/index.ts - [ ] Provider settings load/save via localStorage - [ ] ProjectSetupModal shows Project and Providers tabs - [ ] Replicate/fal.ai can be enabled with API keys - [ ] Settings persist after page reload<success_criteria>
- All tasks completed
- All verification checks pass
- No TypeScript errors
- Users can configure Replicate and fal.ai API keys in settings
- Settings persist to localStorage </success_criteria>