From 75d61b9a478b4061d5900be8e1316c1b79be6dde Mon Sep 17 00:00:00 2001 From: shrimbly Date: Fri, 9 Jan 2026 14:05:49 +1300 Subject: [PATCH] docs(01): create phase 1 provider infrastructure plans Phase 01: Provider Infrastructure - 2 plans created - 5 total tasks defined - Ready for execution Co-Authored-By: Claude Opus 4.5 --- .../01-provider-infrastructure/01-01-PLAN.md | 188 ++++++++++++++++ .../01-provider-infrastructure/01-02-PLAN.md | 200 ++++++++++++++++++ 2 files changed, 388 insertions(+) create mode 100644 .planning/phases/01-provider-infrastructure/01-01-PLAN.md create mode 100644 .planning/phases/01-provider-infrastructure/01-02-PLAN.md diff --git a/.planning/phases/01-provider-infrastructure/01-01-PLAN.md b/.planning/phases/01-provider-infrastructure/01-01-PLAN.md new file mode 100644 index 00000000..58d3bcd6 --- /dev/null +++ b/.planning/phases/01-provider-infrastructure/01-01-PLAN.md @@ -0,0 +1,188 @@ +--- +phase: 01-provider-infrastructure +plan: 01 +type: execute +--- + + +Add provider settings UI enabling users to configure Replicate and fal.ai API keys in ProjectSetupModal. + +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. + + + +~/.claude/get-shit-done/workflows/execute-phase.md +~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +**Key files:** +@src/types/index.ts +@src/store/workflowStore.ts +@src/components/ProjectSetupModal.tsx + +**Established patterns:** +- Types defined in `src/types/index.ts` with PascalCase interfaces +- Settings persisted via localStorage with `node-banana-*` key prefix +- Zustand store pattern in `workflowStore.ts` with 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` + + + + + + Task 1: Add provider types to types/index.ts + src/types/index.ts + +Add provider-related types at the end of the file: + +1. `ProviderType` union: `"gemini" | "replicate" | "fal"` +2. `ProviderConfig` interface with fields: + - `id: ProviderType` + - `name: string` (display name) + - `enabled: boolean` + - `apiKey: string | null` + - `apiKeyEnvVar?: string` (for Gemini which uses env var) +3. `ProviderSettings` interface with field: + - `providers: Record` + +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 + + + + Task 2: Add provider settings state to workflowStore + src/store/workflowStore.ts + +Add provider settings management to the Zustand store: + +1. Add storage key constant: `PROVIDER_SETTINGS_KEY = "node-banana-provider-settings"` + +2. Add helper functions (after existing localStorage helpers around line 310): + - `getProviderSettings(): ProviderSettings` - loads from localStorage, returns defaults if not found + - `saveProviderSettings(settings: ProviderSettings): void` - saves to localStorage + +3. Default provider settings (Gemini enabled by default with env var, others disabled): + ```typescript + 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 }, + } + }; + ``` + +4. Add to store state interface: + - `providerSettings: ProviderSettings` + +5. Add store actions: + - `updateProviderSettings: (settings: ProviderSettings) => void` - updates state and saves to localStorage + - `updateProviderApiKey: (providerId: ProviderType, apiKey: string | null) => void` - updates single provider key + - `toggleProvider: (providerId: ProviderType, enabled: boolean) => void` - enables/disables provider + +6. Initialize `providerSettings` in create() using `getProviderSettings()` + +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: + +1. Add tab state: `const [activeTab, setActiveTab] = useState<"project" | "providers">("project")` + +2. Import provider state from store: + ```typescript + const { providerSettings, updateProviderApiKey, toggleProvider } = useWorkflowStore(); + ``` + +3. Add local state for provider form (to avoid saving on every keystroke): + ```typescript + const [localProviders, setLocalProviders] = useState(providerSettings); + ``` + Sync localProviders when modal opens (in useEffect). + +4. Add tab bar below the title: + ```tsx +
+ + +
+ ``` + +5. Wrap existing form content in `{activeTab === "project" && (...)}` block. + +6. 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 + +7. Update handleSave to also save provider settings when on providers tab: + - Call `updateProviderApiKey` for each changed provider + - Call `toggleProvider` for each changed enabled state + +8. 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 + + + + +- 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 + + + +After completion, create `.planning/phases/01-provider-infrastructure/01-01-SUMMARY.md` + diff --git a/.planning/phases/01-provider-infrastructure/01-02-PLAN.md b/.planning/phases/01-provider-infrastructure/01-02-PLAN.md new file mode 100644 index 00000000..4b07fc78 --- /dev/null +++ b/.planning/phases/01-provider-infrastructure/01-02-PLAN.md @@ -0,0 +1,200 @@ +--- +phase: 01-provider-infrastructure +plan: 02 +type: execute +--- + + +Create provider abstraction layer defining how providers expose model discovery and generation capabilities. + +Purpose: Establish the interface contract that all providers (Gemini, Replicate, fal.ai) will implement, enabling uniform access to different AI services. +Output: Provider abstraction interfaces and types in src/lib/providers/ ready for implementation in Phase 2. + + + +~/.claude/get-shit-done/workflows/execute-phase.md +~/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md + +**Prior plan context:** +Plan 01-01 added ProviderType, ProviderConfig, and ProviderSettings types. + +**Key files:** +@src/types/index.ts +@src/app/api/generate/route.ts + +**Established patterns:** +- Feature libraries in `src/lib/{feature}/` (see quickstart/) +- Types defined with PascalCase interfaces +- Prefer fetch over SDKs per PROJECT.md constraints + +**Constraints:** +- No hardcoded schemas - model parameters fetched at runtime +- Fetch over SDKs for bundle size +- Dynamic model discovery for future-proofing + + + + + + Task 1: Create provider abstraction interfaces + src/lib/providers/types.ts + +Create `src/lib/providers/` directory and `types.ts` with provider abstractions: + +1. `ProviderModel` interface - represents a model from any provider: + ```typescript + interface ProviderModel { + id: string; // Provider-specific model ID (e.g., "stability-ai/sdxl") + name: string; // Display name + description: string | null; // Model description + provider: ProviderType; // Which provider this is from + capabilities: ModelCapability[]; // What it can do + coverImage?: string; // Thumbnail URL + pricing?: { // Optional pricing info + type: "per-run" | "per-second"; + amount: number; + currency: string; + }; + } + ``` + +2. `ModelCapability` union: + ```typescript + type ModelCapability = "text-to-image" | "image-to-image" | "text-to-video" | "image-to-video"; + ``` + +3. `GenerationInput` interface - unified input for all providers: + ```typescript + interface GenerationInput { + model: ProviderModel; + prompt: string; + images?: string[]; // Base64 data URLs or HTTP URLs + parameters?: Record; // Model-specific params + } + ``` + +4. `GenerationOutput` interface: + ```typescript + interface GenerationOutput { + success: boolean; + outputs?: Array<{ + type: "image" | "video"; + data: string; // Base64 data URL + url?: string; // Original URL if applicable + }>; + error?: string; + } + ``` + +5. `ProviderInterface` - contract all providers implement: + ```typescript + interface ProviderInterface { + id: ProviderType; + name: string; + + // Model discovery + listModels(): Promise; + getModel(modelId: string): Promise; + searchModels(query: string): Promise; + + // Generation + generate(input: GenerationInput): Promise; + + // Utilities + isConfigured(): boolean; // Check if API key is set + getApiKey(): string | null; + } + ``` + +Import ProviderType from "@/types". +Export all interfaces and types. + + npm run build passes, types can be imported from "@/lib/providers/types" + Provider abstraction interfaces defined in src/lib/providers/types.ts + + + + Task 2: Create provider registry and factory + src/lib/providers/index.ts + +Create provider registry that will be populated by specific provider implementations in Phase 2: + +1. Create `src/lib/providers/index.ts` with: + +2. Export all types from types.ts: + ```typescript + export * from "./types"; + ``` + +3. Provider registry (empty for now, filled in Phase 2): + ```typescript + import { ProviderType } from "@/types"; + import { ProviderInterface } from "./types"; + + // Registry populated by provider implementations + const providerRegistry: Partial> = {}; + + export function registerProvider(provider: ProviderInterface): void { + providerRegistry[provider.id] = provider; + } + + export function getProvider(id: ProviderType): ProviderInterface | undefined { + return providerRegistry[id]; + } + + export function getConfiguredProviders(): ProviderInterface[] { + return Object.values(providerRegistry).filter( + (p): p is ProviderInterface => p !== undefined && p.isConfigured() + ); + } + + export function getAllProviders(): ProviderInterface[] { + return Object.values(providerRegistry).filter( + (p): p is ProviderInterface => p !== undefined + ); + } + ``` + +4. Add JSDoc comments explaining: + - Registry will be populated when provider modules are imported + - Phase 2 will add Replicate and fal.ai implementations + - Gemini implementation is special-cased in existing generate route for now + +This creates the foundation without implementing actual providers yet. + + npm run build passes, registry functions can be imported from "@/lib/providers" + Provider registry and factory functions exist in src/lib/providers/index.ts + + + + + +Before declaring plan complete: +- [ ] `npm run build` succeeds without errors +- [ ] `npm run lint` passes +- [ ] src/lib/providers/types.ts exists with all interfaces +- [ ] src/lib/providers/index.ts exports types and registry functions +- [ ] Types can be imported: `import { ProviderModel, ProviderInterface } from "@/lib/providers"` + + + + +- All tasks completed +- All verification checks pass +- No TypeScript errors +- Provider abstraction layer ready for Phase 2 implementations +- Phase 1 complete + + + +After completion, create `.planning/phases/01-provider-infrastructure/01-02-SUMMARY.md` + +Include in summary: +- Phase 1 complete, ready for Phase 2: Model Discovery +