Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces database storage functionality using SQLite and implements an AI API key management system. The changes add persistent storage for AI provider credentials (Gemini, OpenAI, Claude) with a settings UI for configuration management.
- SQLite database integration with schema for storing AI provider configurations
- Backend API layer with database repository and Wails service bindings
- Settings dialog UI with tabs for managing AI model credentials and base URLs
Reviewed changes
Copilot reviewed 16 out of 19 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| storage/dir.go | Provides application config directory and database path resolution across platforms |
| database/db.go | Initializes SQLite database connection and creates ai_configs table schema |
| database/models.go | Defines AIConfig model and AIProvider constants for supported providers |
| database/repository.go | Implements CRUD operations for AI configuration persistence |
| binding/database/service.go | Exposes database operations to frontend via Wails bindings |
| main.go | Integrates database initialization and replaces App binding with database service |
| go.mod/go.sum | Adds sqlx and go-sqlite3 dependencies |
| frontend/wailsjs/go/models.ts | Auto-generated TypeScript models for AIConfig |
| frontend/wailsjs/go/database/Service.* | Auto-generated TypeScript bindings for database service methods |
| frontend/wailsjs/go/main/App.* | Removes old App service bindings (replaced by database service) |
| frontend/src/components/ui/tabs.tsx | New tabs component for settings navigation |
| frontend/src/components/ui/dialog.tsx | New dialog component for settings modal |
| frontend/src/components/settings/settings-dialog.tsx | Settings dialog container with sidebar navigation |
| frontend/src/components/settings/ai-model-settings.tsx | AI model configuration form with API key and base URL inputs |
| frontend/src/components/app-sidebar.tsx | Updates sidebar to include settings button and removes user profile section |
| frontend/src/App.tsx | Integrates settings dialog with state management |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -0,0 +1,88 @@ | |||
| import * as React from "react" | |||
| import { cva, type VariantProps } from "class-variance-authority" | |||
| import { Tabs as TabsPrimitive } from "radix-ui" | |||
There was a problem hiding this comment.
The imports from "radix-ui" package appear to be incorrect. The package should typically be imported from "@radix-ui/react-tabs" instead of just "radix-ui". Verify that this import path is correct, as it may cause build failures.
| import { Tabs as TabsPrimitive } from "radix-ui" | |
| import * as TabsPrimitive from "@radix-ui/react-tabs" |
| "use client" | ||
|
|
||
| import * as React from "react" | ||
| import { Dialog as DialogPrimitive } from "radix-ui" |
There was a problem hiding this comment.
The import from "radix-ui" package appears to be incorrect. The package should typically be imported from "@radix-ui/react-dialog" instead of just "radix-ui". Verify that this import path is correct, as it may cause build failures.
| import { Dialog as DialogPrimitive } from "radix-ui" | |
| import * as DialogPrimitive from "@radix-ui/react-dialog" |
| } | ||
|
|
||
| func SaveConfig(config *AIConfig) error { | ||
| log.Println("Saving config:", config) |
There was a problem hiding this comment.
API keys are being logged to the console in plain text. This is a security risk as logs may be persisted or exposed. Remove or redact sensitive information like API keys from log statements.
| log.Println("Saving config:", config) | |
| log.Printf("Saving config for provider: %s", config.Provider) |
| CREATE TABLE IF NOT EXISTS ai_configs ( | ||
| provider TEXT PRIMARY KEY, | ||
| api_key TEXT NOT NULL, | ||
| base_url TEXT DEFAULT '', | ||
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at DATETIME DEFAULT CURRENT_TIMESTAMP |
There was a problem hiding this comment.
API keys are stored in plain text in the SQLite database. Consider encrypting sensitive data like API keys at rest to prevent exposure if the database file is accessed. You could use encryption libraries or operating system keychain services for secure storage.
| func (s *Service) GetAIConfig(provider string) (*db.AIConfig, error) { | ||
| return db.GetConfig(db.AIProvider(provider)) |
There was a problem hiding this comment.
Missing input validation for the provider parameter. The function accepts a string and converts it to AIProvider without checking if it's a valid provider. This could lead to database operations with invalid provider values. Consider validating the provider against the defined constants.
| } | ||
|
|
||
| // DeleteAIConfig deletes the configuration for a specific provider | ||
| func (s *Service) DeleteAIConfig(provider string) error { |
There was a problem hiding this comment.
Missing input validation for the provider parameter. Consider validating the provider against the defined constants before attempting deletion to provide clearer error messages for invalid providers.
| func (s *Service) DeleteAIConfig(provider string) error { | |
| func (s *Service) DeleteAIConfig(provider string) error { | |
| // Validate that the provider corresponds to an existing configuration | |
| if _, err := db.GetConfig(db.AIProvider(provider)); err != nil { | |
| return err | |
| } |
| } | ||
|
|
||
| appDir := filepath.Join(configDir, "firebringer") | ||
| if err := os.MkdirAll(appDir, 0755); err != nil { |
There was a problem hiding this comment.
The directory is created with 0755 permissions, which makes it readable and executable by all users on the system. For a directory containing sensitive data like API keys, consider using more restrictive permissions like 0700 to ensure only the owner can access it.
| if err := os.MkdirAll(appDir, 0755); err != nil { | |
| if err := os.MkdirAll(appDir, 0700); err != nil { |
| ) | ||
|
|
||
| // GetAppConfigDir returns the application configuration directory. | ||
| // On macOS: ~/Library/Application Support/firebringer |
There was a problem hiding this comment.
Comment contains missing Chinese text. The comment states "On macOS: ~/Library/Application Support/firebringer" and "On Windows: %APPDATA%\firebringer" but doesn't document the Linux behavior. Add documentation for the Linux directory path for completeness.
| // On macOS: ~/Library/Application Support/firebringer | |
| // On macOS: ~/Library/Application Support/firebringer | |
| // On Linux: ~/.config/firebringer |
| if err := database.InitDB(); err != nil { | ||
| println("Error initializing database:", err.Error()) | ||
| return | ||
| } |
There was a problem hiding this comment.
The error message is printed using println but the application continues to return, which may not properly signal the error to the operating system. Consider using log.Fatal or os.Exit(1) to ensure the application exits with a non-zero status code when database initialization fails.
| Dialog, | ||
| DialogContent, | ||
| DialogTitle, | ||
| DialogDescription, |
There was a problem hiding this comment.
Unused import DialogDescription.
| DialogDescription, |
No description provided.