User Settings
The ChaasKit Template includes a flexible user settings system that allows users to customize their experience and provide context to the AI.
Configuration
Define available settings in config/app.config.ts:
userSettings: {
fields: [
{
key: 'name',
label: 'Your Name',
type: 'text',
placeholder: 'Enter your name',
},
{
key: 'role',
label: 'Your Role',
type: 'select',
options: ['Developer', 'Designer', 'Manager', 'Other'],
},
{
key: 'context',
label: 'Additional Context',
type: 'textarea',
placeholder: 'Any context the AI should know about you...',
},
],
}
Field Types
Text Field
Simple single-line text input.
{
key: 'company',
label: 'Company',
type: 'text',
placeholder: 'Your company name',
}
Select Field
Dropdown selection from predefined options.
{
key: 'experience',
label: 'Experience Level',
type: 'select',
options: ['Beginner', 'Intermediate', 'Expert'],
}
Textarea Field
Multi-line text input for longer content.
{
key: 'bio',
label: 'About You',
type: 'textarea',
placeholder: 'Tell us about yourself...',
}
How Settings Work
Storage
User settings are stored in the settings JSON field on the User model:
model User {
// ...
settings Json @default("{}")
}
API
Get Settings:
GET /api/user/settings
Authorization: Bearer <token>
Update Settings:
PUT /api/user/settings
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "John",
"role": "Developer",
"context": "I work with React and Node.js"
}
AI Context
Settings are automatically included in the AI's system prompt:
// agent.ts
if (options?.userContext) {
const contextStr = Object.entries(options.userContext)
.filter(([, v]) => v != null && v !== '')
.map(([k, v]) => `${k}: ${v}`)
.join('\n');
if (contextStr) {
systemPrompt += `\n\nUser context:\n${contextStr}`;
}
}
This allows the AI to personalize responses based on user preferences.
Frontend Integration
Settings Page
The settings are displayed in a form on the settings page:
import { useAuth } from '../contexts/AuthContext';
import { useConfig } from '../contexts/ConfigContext';
function SettingsPage() {
const { user } = useAuth();
const config = useConfig();
return (
<form>
{config.userSettings.fields.map((field) => (
<FormField key={field.key} field={field} />
))}
</form>
);
}
FormField Component
Renders appropriate input based on field type:
function FormField({ field }) {
switch (field.type) {
case 'text':
return <input type="text" {...props} />;
case 'select':
return (
<select {...props}>
{field.options.map((opt) => (
<option key={opt} value={opt}>{opt}</option>
))}
</select>
);
case 'textarea':
return <textarea {...props} />;
}
}
MCP Credentials
Users can manage credentials for MCP servers that require authentication directly in the Settings modal.
Credential Types
API Key: For servers with authMode: 'user-apikey'
- Text input to enter/update the API key
- Key is encrypted and stored securely
OAuth: For servers with authMode: 'user-oauth'
- "Connect" button initiates OAuth flow
- Tokens are encrypted and stored
- "Disconnect" button to revoke access
Settings Modal Section
The MCP Credentials section appears automatically when servers with user authentication are configured:
// In SettingsModal
{mcpServers.length > 0 && (
<MCPCredentialsSection servers={mcpServers} />
)}
API Endpoints
Get Credential Status:
GET /api/mcp/credentials
Authorization: Bearer <token>
Set API Key:
POST /api/mcp/credentials/:serverId/apikey
Authorization: Bearer <token>
Content-Type: application/json
{
"apiKey": "sk-..."
}
Start OAuth:
GET /api/mcp/oauth/:serverId/authorize
Authorization: Bearer <token>
Remove Credentials:
DELETE /api/mcp/credentials/:serverId
Authorization: Bearer <token>
Usage Metrics
The Settings modal displays usage metrics showing the user's message consumption:
Display
- Progress bar showing messages used vs. limit
- Numerical display: "X / Y messages used"
- For unlimited plans: "X messages used (unlimited)"
API Endpoint
GET /api/user/usage
Authorization: Bearer <token>
Response:
{
"messagesUsed": 15,
"messagesLimit": 100,
"unlimited": false
}
Theme Preference
The user's theme preference is stored separately:
model User {
themePreference String? // 'light' | 'dark' | null (system)
}
API
Get Theme:
GET /api/user/theme
Update Theme:
PUT /api/user/theme
Content-Type: application/json
{
"theme": "dark"
}
Frontend
Use the ThemeContext:
import { useTheme } from '../contexts/ThemeContext';
function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
);
}
Use Cases
Developer Context
userSettings: {
fields: [
{
key: 'primaryLanguage',
label: 'Primary Language',
type: 'select',
options: ['JavaScript', 'Python', 'Go', 'Rust', 'Other'],
},
{
key: 'framework',
label: 'Preferred Framework',
type: 'text',
placeholder: 'React, Vue, Django, etc.',
},
{
key: 'codeStyle',
label: 'Code Style Preferences',
type: 'textarea',
placeholder: 'Describe your coding style preferences...',
},
],
}
Customer Support
userSettings: {
fields: [
{
key: 'accountId',
label: 'Account ID',
type: 'text',
},
{
key: 'department',
label: 'Department',
type: 'select',
options: ['Sales', 'Engineering', 'Support', 'Finance'],
},
],
}
Creative Writing
userSettings: {
fields: [
{
key: 'writingStyle',
label: 'Preferred Writing Style',
type: 'select',
options: ['Formal', 'Casual', 'Technical', 'Creative'],
},
{
key: 'targetAudience',
label: 'Target Audience',
type: 'text',
placeholder: 'Who are you writing for?',
},
],
}
Extending Settings
Custom Field Types
Add new field types by extending the configuration:
// types/config.ts
export interface UserSettingsField {
key: string;
label: string;
type: 'text' | 'select' | 'textarea' | 'number' | 'boolean';
// ...
}
Validation
Add validation using Zod:
// validation/user.ts
export const settingsSchema = z.object({
name: z.string().optional(),
role: z.enum(['Developer', 'Designer', 'Manager', 'Other']).optional(),
context: z.string().max(1000).optional(),
});
Computed Settings
Process settings before sending to AI:
function processUserContext(settings) {
return {
...settings,
// Add computed fields
fullContext: `${settings.name} is a ${settings.role}. ${settings.context}`,
};
}