create-chaaskit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +25 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add-infra.d.ts +6 -0
- package/dist/commands/add-infra.d.ts.map +1 -0
- package/dist/commands/add-infra.js +160 -0
- package/dist/commands/add-infra.js.map +1 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +63 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/db-sync.d.ts +13 -0
- package/dist/commands/db-sync.d.ts.map +1 -0
- package/dist/commands/db-sync.js +108 -0
- package/dist/commands/db-sync.js.map +1 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +61 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +214 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/.env.example +24 -0
- package/dist/templates/README.md +81 -0
- package/dist/templates/app/components/AcceptInviteClient.tsx +10 -0
- package/dist/templates/app/components/AdminDashboardClient.tsx +10 -0
- package/dist/templates/app/components/AdminTeamClient.tsx +10 -0
- package/dist/templates/app/components/AdminTeamsClient.tsx +10 -0
- package/dist/templates/app/components/AdminUsersClient.tsx +10 -0
- package/dist/templates/app/components/ApiKeysClient.tsx +10 -0
- package/dist/templates/app/components/AutomationsClient.tsx +10 -0
- package/dist/templates/app/components/ChatClient.tsx +13 -0
- package/dist/templates/app/components/ClientOnly.tsx +6 -0
- package/dist/templates/app/components/DocumentsClient.tsx +10 -0
- package/dist/templates/app/components/OAuthConsentClient.tsx +10 -0
- package/dist/templates/app/components/PricingClient.tsx +10 -0
- package/dist/templates/app/components/TeamSettingsClient.tsx +10 -0
- package/dist/templates/app/components/VerifyEmailClient.tsx +10 -0
- package/dist/templates/app/entry.client.tsx +12 -0
- package/dist/templates/app/entry.server.tsx +67 -0
- package/dist/templates/app/root.tsx +91 -0
- package/dist/templates/app/routes/_index.tsx +82 -0
- package/dist/templates/app/routes/admin._index.tsx +57 -0
- package/dist/templates/app/routes/admin.teams.$teamId.tsx +57 -0
- package/dist/templates/app/routes/admin.teams._index.tsx +57 -0
- package/dist/templates/app/routes/admin.users.tsx +57 -0
- package/dist/templates/app/routes/api-keys.tsx +57 -0
- package/dist/templates/app/routes/automations.tsx +57 -0
- package/dist/templates/app/routes/chat._index.tsx +11 -0
- package/dist/templates/app/routes/chat.admin._index.tsx +10 -0
- package/dist/templates/app/routes/chat.admin.teams.$teamId.tsx +10 -0
- package/dist/templates/app/routes/chat.admin.teams._index.tsx +10 -0
- package/dist/templates/app/routes/chat.admin.users.tsx +10 -0
- package/dist/templates/app/routes/chat.api-keys.tsx +10 -0
- package/dist/templates/app/routes/chat.automations.tsx +10 -0
- package/dist/templates/app/routes/chat.documents.tsx +10 -0
- package/dist/templates/app/routes/chat.team.$teamId.settings.tsx +10 -0
- package/dist/templates/app/routes/chat.thread.$threadId.tsx +11 -0
- package/dist/templates/app/routes/chat.tsx +39 -0
- package/dist/templates/app/routes/documents.tsx +57 -0
- package/dist/templates/app/routes/invite.$token.tsx +10 -0
- package/dist/templates/app/routes/login.tsx +334 -0
- package/dist/templates/app/routes/oauth.consent.tsx +10 -0
- package/dist/templates/app/routes/pricing.tsx +10 -0
- package/dist/templates/app/routes/privacy.tsx +197 -0
- package/dist/templates/app/routes/register.tsx +398 -0
- package/dist/templates/app/routes/shared.$shareId.tsx +226 -0
- package/dist/templates/app/routes/team.$teamId.settings.tsx +57 -0
- package/dist/templates/app/routes/terms.tsx +173 -0
- package/dist/templates/app/routes/thread.$threadId.tsx +102 -0
- package/dist/templates/app/routes/verify-email.tsx +10 -0
- package/dist/templates/app/routes.ts +47 -0
- package/dist/templates/config/app.config.ts +216 -0
- package/dist/templates/docs/admin.md +257 -0
- package/dist/templates/docs/api-keys.md +403 -0
- package/dist/templates/docs/authentication.md +247 -0
- package/dist/templates/docs/configuration.md +1212 -0
- package/dist/templates/docs/custom-pages.md +466 -0
- package/dist/templates/docs/deployment.md +362 -0
- package/dist/templates/docs/development.md +411 -0
- package/dist/templates/docs/documents.md +293 -0
- package/dist/templates/docs/extensions.md +639 -0
- package/dist/templates/docs/index.md +139 -0
- package/dist/templates/docs/installation.md +286 -0
- package/dist/templates/docs/mcp.md +952 -0
- package/dist/templates/docs/native-tools.md +688 -0
- package/dist/templates/docs/queue.md +514 -0
- package/dist/templates/docs/scheduled-prompts.md +279 -0
- package/dist/templates/docs/settings.md +415 -0
- package/dist/templates/docs/slack.md +318 -0
- package/dist/templates/docs/styling.md +288 -0
- package/dist/templates/extensions/agents/.gitkeep +0 -0
- package/dist/templates/extensions/pages/.gitkeep +0 -0
- package/dist/templates/extensions/payment-plans/.gitkeep +0 -0
- package/dist/templates/index.html +16 -0
- package/dist/templates/infra-aws/.github/workflows/deploy.yml +95 -0
- package/dist/templates/infra-aws/README.md +207 -0
- package/dist/templates/infra-aws/bin/cdk.ts +18 -0
- package/dist/templates/infra-aws/cdk.json +43 -0
- package/dist/templates/infra-aws/config/deployment.ts +156 -0
- package/dist/templates/infra-aws/lib/chaaskit-stack.ts +419 -0
- package/dist/templates/infra-aws/package.json +27 -0
- package/dist/templates/infra-aws/scripts/build-app.sh +63 -0
- package/dist/templates/infra-aws/tsconfig.json +25 -0
- package/dist/templates/package.json +46 -0
- package/dist/templates/prisma/schema/base.prisma +584 -0
- package/dist/templates/prisma/schema/custom.prisma +24 -0
- package/dist/templates/prisma/schema.prisma +271 -0
- package/dist/templates/public/favicon.svg +4 -0
- package/dist/templates/public/logo.svg +4 -0
- package/dist/templates/react-router.config.ts +11 -0
- package/dist/templates/server.js +52 -0
- package/dist/templates/src/main.tsx +8 -0
- package/dist/templates/tsconfig.json +26 -0
- package/dist/templates/vite.config.ts +26 -0
- package/package.json +46 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Admin Dashboard
|
|
2
|
+
|
|
3
|
+
The Admin Dashboard provides site-wide administration capabilities for managing users, teams, and viewing usage analytics.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
Site administrators are configured via the `admin` section in `config/app.config.ts`:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
admin: {
|
|
11
|
+
emails: [
|
|
12
|
+
'admin@example.com',
|
|
13
|
+
'another-admin@example.com',
|
|
14
|
+
],
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Users whose email addresses are in this list will see the "Admin" link in the sidebar and have access to all admin features.
|
|
19
|
+
|
|
20
|
+
### Admin Access
|
|
21
|
+
|
|
22
|
+
Admin access is granted if the user meets either condition:
|
|
23
|
+
- Their email is listed in `config.admin.emails` (case-insensitive)
|
|
24
|
+
- They have `isAdmin: true` in the database (legacy support)
|
|
25
|
+
|
|
26
|
+
## Admin Pages
|
|
27
|
+
|
|
28
|
+
### Dashboard (`/admin`)
|
|
29
|
+
|
|
30
|
+
The main admin dashboard displays:
|
|
31
|
+
|
|
32
|
+
- **Stats Cards**: Total users, teams, threads, messages, and recent activity
|
|
33
|
+
- **Usage Chart**: Visual chart showing messages and token usage over time
|
|
34
|
+
- Period selector: 7, 30, or 90 days
|
|
35
|
+
- Metric selector: Messages, Input Tokens, Output Tokens, Total Tokens
|
|
36
|
+
- Summary row with total, daily average, and peak day
|
|
37
|
+
- **Plan Distribution**: Breakdown of users by subscription plan
|
|
38
|
+
- **Recent Feedback**: Latest user feedback on AI responses
|
|
39
|
+
|
|
40
|
+
Navigation links to Manage Users and Manage Teams (if teams enabled).
|
|
41
|
+
|
|
42
|
+
### User Management (`/admin/users`)
|
|
43
|
+
|
|
44
|
+
Lists all users in the system with:
|
|
45
|
+
|
|
46
|
+
| Column | Description |
|
|
47
|
+
|--------|-------------|
|
|
48
|
+
| User | Name, email, avatar, OAuth provider |
|
|
49
|
+
| Plan | Dropdown to change user's subscription plan |
|
|
50
|
+
| Messages | Message count this month |
|
|
51
|
+
| Teams | Clickable pills showing team memberships with roles |
|
|
52
|
+
| Admin | Toggle button to grant/revoke database admin flag |
|
|
53
|
+
| Joined | Account creation date |
|
|
54
|
+
|
|
55
|
+
Features:
|
|
56
|
+
- **Search**: Filter users by email or name
|
|
57
|
+
- **Pagination**: Navigate through large user lists
|
|
58
|
+
- **Team Links**: Click a team pill to view that team's details
|
|
59
|
+
|
|
60
|
+
### Team Management (`/admin/teams`)
|
|
61
|
+
|
|
62
|
+
Lists all teams in the system (only visible if teams are enabled):
|
|
63
|
+
|
|
64
|
+
| Column | Description |
|
|
65
|
+
|--------|-------------|
|
|
66
|
+
| Team | Team name and avatar |
|
|
67
|
+
| Members | Number of team members |
|
|
68
|
+
| Threads | Number of team threads |
|
|
69
|
+
| Created | Team creation date |
|
|
70
|
+
|
|
71
|
+
Features:
|
|
72
|
+
- **Search**: Filter teams by name
|
|
73
|
+
- **Pagination**: Navigate through large team lists
|
|
74
|
+
- **Click to View**: Click any team row to see team details
|
|
75
|
+
|
|
76
|
+
### Team Details (`/admin/teams/:teamId`)
|
|
77
|
+
|
|
78
|
+
Displays detailed information about a specific team:
|
|
79
|
+
|
|
80
|
+
- **Stats**: Member count, thread count, creation date
|
|
81
|
+
- **Team Context**: The AI context configured for team conversations
|
|
82
|
+
- **Members List**: All team members with:
|
|
83
|
+
- Name and email (clickable to search in user management)
|
|
84
|
+
- Role badge (owner, admin, member, viewer)
|
|
85
|
+
- Join date
|
|
86
|
+
|
|
87
|
+
## API Endpoints
|
|
88
|
+
|
|
89
|
+
All admin endpoints require authentication and admin access.
|
|
90
|
+
|
|
91
|
+
### Stats & Analytics
|
|
92
|
+
|
|
93
|
+
| Method | Endpoint | Description |
|
|
94
|
+
|--------|----------|-------------|
|
|
95
|
+
| `GET` | `/api/admin/stats` | Dashboard statistics |
|
|
96
|
+
| `GET` | `/api/admin/usage` | Usage data over time |
|
|
97
|
+
| `GET` | `/api/admin/feedback` | Feedback statistics and recent items |
|
|
98
|
+
|
|
99
|
+
**Usage Query Parameters:**
|
|
100
|
+
|
|
101
|
+
| Parameter | Type | Default | Description |
|
|
102
|
+
|-----------|------|---------|-------------|
|
|
103
|
+
| `days` | number | 30 | Number of days of data (1-365) |
|
|
104
|
+
|
|
105
|
+
### User Management
|
|
106
|
+
|
|
107
|
+
| Method | Endpoint | Description |
|
|
108
|
+
|--------|----------|-------------|
|
|
109
|
+
| `GET` | `/api/admin/users` | Paginated user list |
|
|
110
|
+
| `PATCH` | `/api/admin/users/:userId` | Update user (plan, isAdmin) |
|
|
111
|
+
|
|
112
|
+
**User List Query Parameters:**
|
|
113
|
+
|
|
114
|
+
| Parameter | Type | Default | Description |
|
|
115
|
+
|-----------|------|---------|-------------|
|
|
116
|
+
| `page` | number | 1 | Page number |
|
|
117
|
+
| `pageSize` | number | 20 | Users per page (max 100) |
|
|
118
|
+
| `search` | string | - | Filter by email or name |
|
|
119
|
+
|
|
120
|
+
**User Update Body:**
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
{
|
|
124
|
+
isAdmin?: boolean; // Grant or revoke admin status
|
|
125
|
+
plan?: string; // Change subscription plan
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Team Management
|
|
130
|
+
|
|
131
|
+
| Method | Endpoint | Description |
|
|
132
|
+
|--------|----------|-------------|
|
|
133
|
+
| `GET` | `/api/admin/teams` | Paginated team list |
|
|
134
|
+
| `GET` | `/api/admin/teams/:teamId` | Team details with members |
|
|
135
|
+
|
|
136
|
+
**Team List Query Parameters:**
|
|
137
|
+
|
|
138
|
+
| Parameter | Type | Default | Description |
|
|
139
|
+
|-----------|------|---------|-------------|
|
|
140
|
+
| `page` | number | 1 | Page number |
|
|
141
|
+
| `pageSize` | number | 20 | Teams per page (max 100) |
|
|
142
|
+
| `search` | string | - | Filter by team name |
|
|
143
|
+
| `includeArchived` | boolean | false | Include archived teams |
|
|
144
|
+
|
|
145
|
+
## Response Types
|
|
146
|
+
|
|
147
|
+
### AdminStats
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
interface AdminStats {
|
|
151
|
+
totalUsers: number;
|
|
152
|
+
totalTeams: number;
|
|
153
|
+
totalThreads: number;
|
|
154
|
+
totalMessages: number;
|
|
155
|
+
planDistribution: Record<string, number>;
|
|
156
|
+
newUsersLast30Days: number;
|
|
157
|
+
messagesLast30Days: number;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### UsageDataPoint
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
interface UsageDataPoint {
|
|
165
|
+
date: string; // "2024-01-15"
|
|
166
|
+
messages: number; // Count of messages
|
|
167
|
+
inputTokens: number; // Total input tokens
|
|
168
|
+
outputTokens: number;// Total output tokens
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### AdminUser
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
interface AdminUser {
|
|
176
|
+
id: string;
|
|
177
|
+
email: string;
|
|
178
|
+
name?: string | null;
|
|
179
|
+
avatarUrl?: string | null;
|
|
180
|
+
isAdmin: boolean;
|
|
181
|
+
plan: string;
|
|
182
|
+
messagesThisMonth: number;
|
|
183
|
+
credits: number;
|
|
184
|
+
emailVerified: boolean;
|
|
185
|
+
oauthProvider?: string | null;
|
|
186
|
+
createdAt: Date;
|
|
187
|
+
threadCount: number;
|
|
188
|
+
teamCount: number;
|
|
189
|
+
teams: AdminUserTeam[];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
interface AdminUserTeam {
|
|
193
|
+
id: string;
|
|
194
|
+
name: string;
|
|
195
|
+
role: string;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### AdminTeam / AdminTeamDetails
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
interface AdminTeam {
|
|
203
|
+
id: string;
|
|
204
|
+
name: string;
|
|
205
|
+
memberCount: number;
|
|
206
|
+
threadCount: number;
|
|
207
|
+
createdAt: Date;
|
|
208
|
+
archivedAt?: Date | null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface AdminTeamDetails extends AdminTeam {
|
|
212
|
+
context?: string | null;
|
|
213
|
+
members: AdminTeamMember[];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
interface AdminTeamMember {
|
|
217
|
+
id: string;
|
|
218
|
+
email: string;
|
|
219
|
+
name?: string | null;
|
|
220
|
+
avatarUrl?: string | null;
|
|
221
|
+
role: string;
|
|
222
|
+
joinedAt: Date;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Security Considerations
|
|
227
|
+
|
|
228
|
+
1. **Config-based access**: Admin emails are defined in server configuration, not user-editable
|
|
229
|
+
2. **Case-insensitive matching**: Email comparison is case-insensitive
|
|
230
|
+
3. **Self-protection**: Users cannot remove their own admin status
|
|
231
|
+
4. **Audit trail**: All user changes are logged with timestamps
|
|
232
|
+
5. **No destructive actions**: Admin can modify users but cannot delete accounts (preserves data integrity)
|
|
233
|
+
|
|
234
|
+
## Extending Admin Features
|
|
235
|
+
|
|
236
|
+
To add custom admin functionality:
|
|
237
|
+
|
|
238
|
+
1. **Add API endpoints** in `packages/server/src/api/admin.ts`
|
|
239
|
+
2. **Add types** in `packages/shared/src/types/admin.ts`
|
|
240
|
+
3. **Create pages** in `packages/client/src/pages/Admin*.tsx`
|
|
241
|
+
4. **Add routes** in `packages/client/src/App.tsx` wrapped with `<AdminRoute>`
|
|
242
|
+
|
|
243
|
+
Example adding a new admin page:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
// App.tsx
|
|
247
|
+
<Route
|
|
248
|
+
path="/admin/custom"
|
|
249
|
+
element={
|
|
250
|
+
<AdminRoute>
|
|
251
|
+
<AdminCustomPage />
|
|
252
|
+
</AdminRoute>
|
|
253
|
+
}
|
|
254
|
+
/>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The `AdminRoute` component handles authentication and admin access verification.
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
# API Keys
|
|
2
|
+
|
|
3
|
+
API Keys allow users to access the API programmatically. This is useful for building integrations, CLI tools, or automated workflows.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
Enable API keys in `config/app.config.ts`:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
api: {
|
|
11
|
+
enabled: true,
|
|
12
|
+
keyPrefix: 'myapp-', // Optional, default: "sk-"
|
|
13
|
+
allowedPlans: ['pro', 'enterprise'], // Optional: restrict to specific plans
|
|
14
|
+
allowedEndpoints: [ // Required: whitelist endpoints for API key access
|
|
15
|
+
'/api/chat',
|
|
16
|
+
'/api/threads',
|
|
17
|
+
'/api/threads/**',
|
|
18
|
+
],
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Configuration Options
|
|
23
|
+
|
|
24
|
+
| Option | Type | Default | Description |
|
|
25
|
+
|--------|------|---------|-------------|
|
|
26
|
+
| `enabled` | boolean | `false` | Enable API key creation and management |
|
|
27
|
+
| `keyPrefix` | string | `"sk-"` | Prefix for generated API keys |
|
|
28
|
+
| `allowedPlans` | string[] | `undefined` | If set, only these plans can create keys |
|
|
29
|
+
| `allowedEndpoints` | string[] | `[]` | Endpoints accessible via API keys (required) |
|
|
30
|
+
|
|
31
|
+
### Endpoint Patterns
|
|
32
|
+
|
|
33
|
+
The `allowedEndpoints` array supports pattern matching:
|
|
34
|
+
|
|
35
|
+
| Pattern | Matches | Does NOT Match |
|
|
36
|
+
|---------|---------|----------------|
|
|
37
|
+
| `/api/threads` | `/api/threads` (exact) | `/api/threads/123` |
|
|
38
|
+
| `/api/threads/*` | `/api/threads/123` | `/api/threads/123/messages` |
|
|
39
|
+
| `/api/threads/**` | `/api/threads/123`, `/api/threads/123/messages` | `/api/thread` |
|
|
40
|
+
|
|
41
|
+
**Pattern Types:**
|
|
42
|
+
- **Exact match**: `/api/chat` - matches only that exact path
|
|
43
|
+
- **Single segment wildcard (`*`)**: `/api/threads/*` - matches one path segment
|
|
44
|
+
- **Multi-segment wildcard (`**`)**: `/api/threads/**` - matches any depth
|
|
45
|
+
|
|
46
|
+
### Example Configurations
|
|
47
|
+
|
|
48
|
+
**Minimal (chat only):**
|
|
49
|
+
```typescript
|
|
50
|
+
api: {
|
|
51
|
+
enabled: true,
|
|
52
|
+
allowedEndpoints: ['/api/chat'],
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Full access:**
|
|
57
|
+
```typescript
|
|
58
|
+
api: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
allowedEndpoints: [
|
|
61
|
+
'/api/chat',
|
|
62
|
+
'/api/threads',
|
|
63
|
+
'/api/threads/**',
|
|
64
|
+
'/api/search',
|
|
65
|
+
'/api/export/*',
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Restricted to pro users with custom prefix:**
|
|
71
|
+
```typescript
|
|
72
|
+
api: {
|
|
73
|
+
enabled: true,
|
|
74
|
+
keyPrefix: 'myapp-',
|
|
75
|
+
allowedPlans: ['pro', 'enterprise'],
|
|
76
|
+
allowedEndpoints: [
|
|
77
|
+
'/api/chat',
|
|
78
|
+
'/api/threads',
|
|
79
|
+
'/api/threads/*',
|
|
80
|
+
],
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## User Interface
|
|
85
|
+
|
|
86
|
+
When API keys are enabled, users can manage their keys from the Settings modal.
|
|
87
|
+
|
|
88
|
+
### Settings Modal
|
|
89
|
+
|
|
90
|
+
A link to "Manage API Keys" appears in the Settings modal for users who have access to the feature (based on `allowedPlans`).
|
|
91
|
+
|
|
92
|
+
### API Keys Page
|
|
93
|
+
|
|
94
|
+
The dedicated `/api-keys` page allows users to:
|
|
95
|
+
|
|
96
|
+
1. **View existing keys** - Shows key name, prefix, scope, creation date, last used, and expiration
|
|
97
|
+
2. **Create new keys** - With options for:
|
|
98
|
+
- **Name**: A label for the key (e.g., "My CLI Tool")
|
|
99
|
+
- **Scope**: Personal or team (if teams are enabled)
|
|
100
|
+
- **Expiration**: Never, 30 days, 90 days, or 1 year
|
|
101
|
+
3. **Revoke keys** - Immediately invalidates a key
|
|
102
|
+
|
|
103
|
+
### Key Display
|
|
104
|
+
|
|
105
|
+
- Keys are shown with a masked prefix (e.g., `sk-a1b2c3...`)
|
|
106
|
+
- The full key is only displayed once at creation time
|
|
107
|
+
- Users must copy and securely store their key immediately
|
|
108
|
+
|
|
109
|
+
## API Key Format
|
|
110
|
+
|
|
111
|
+
Generated keys follow this format:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
{prefix}{48 random hex characters}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Examples:
|
|
118
|
+
- Default prefix: `sk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4`
|
|
119
|
+
- Custom prefix: `myapp-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4`
|
|
120
|
+
|
|
121
|
+
## Security
|
|
122
|
+
|
|
123
|
+
### Key Storage
|
|
124
|
+
|
|
125
|
+
- Keys are hashed with bcrypt before storage (like passwords)
|
|
126
|
+
- The full key cannot be retrieved after creation
|
|
127
|
+
- Only the prefix is stored in plain text for display purposes
|
|
128
|
+
|
|
129
|
+
### Key Validation
|
|
130
|
+
|
|
131
|
+
On each request:
|
|
132
|
+
1. The key prefix is used to find candidate keys
|
|
133
|
+
2. The full key is verified against the bcrypt hash
|
|
134
|
+
3. Expiration date is checked
|
|
135
|
+
4. For team-scoped keys, team membership is verified
|
|
136
|
+
|
|
137
|
+
### Endpoint Restrictions
|
|
138
|
+
|
|
139
|
+
- API keys can only access endpoints listed in `allowedEndpoints`
|
|
140
|
+
- If no endpoints are configured, API keys cannot access any endpoint
|
|
141
|
+
- Attempts to access non-whitelisted endpoints return 403 Forbidden
|
|
142
|
+
|
|
143
|
+
### Automatic Invalidation
|
|
144
|
+
|
|
145
|
+
Team-scoped keys are automatically invalidated if:
|
|
146
|
+
- The user is removed from the team
|
|
147
|
+
- The team is deleted
|
|
148
|
+
|
|
149
|
+
## Team-Scoped Keys
|
|
150
|
+
|
|
151
|
+
When teams are enabled, users can create keys scoped to a specific team.
|
|
152
|
+
|
|
153
|
+
### Behavior
|
|
154
|
+
|
|
155
|
+
| Key Scope | Behavior |
|
|
156
|
+
|-----------|----------|
|
|
157
|
+
| Personal | API requests operate as the user's personal account |
|
|
158
|
+
| Team | API requests use the team context (threads, projects, etc.) |
|
|
159
|
+
|
|
160
|
+
### Creating Team-Scoped Keys
|
|
161
|
+
|
|
162
|
+
1. In the "Create API Key" modal, select a team from the "Scope" dropdown
|
|
163
|
+
2. The user must be a member of the team to create a key for it
|
|
164
|
+
3. The key will have access to team resources only
|
|
165
|
+
|
|
166
|
+
### Team Context
|
|
167
|
+
|
|
168
|
+
When using a team-scoped key:
|
|
169
|
+
- Thread listing returns team threads
|
|
170
|
+
- New threads are created in the team context
|
|
171
|
+
- Team context is injected into AI prompts
|
|
172
|
+
- The `teamId` in request bodies is overridden by the key's team scope
|
|
173
|
+
|
|
174
|
+
## Using API Keys
|
|
175
|
+
|
|
176
|
+
### Authentication
|
|
177
|
+
|
|
178
|
+
Include the API key in the `Authorization` header:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
curl -H "Authorization: Bearer sk-your-api-key-here" \
|
|
182
|
+
https://your-app.com/api/threads
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Available Endpoints
|
|
186
|
+
|
|
187
|
+
The following endpoints can be enabled for API key access:
|
|
188
|
+
|
|
189
|
+
| Endpoint | Methods | Description |
|
|
190
|
+
|----------|---------|-------------|
|
|
191
|
+
| `/api/threads` | GET, POST | List threads, create new thread |
|
|
192
|
+
| `/api/threads/*` | GET, PATCH, DELETE | Get, update, delete a specific thread |
|
|
193
|
+
| `/api/threads/**` | Various | Thread sub-routes (messages, etc.) |
|
|
194
|
+
| `/api/chat` | POST | Send messages, streaming responses |
|
|
195
|
+
| `/api/search` | GET | Search threads by query |
|
|
196
|
+
| `/api/export/*` | GET | Export a thread (JSON, Markdown) |
|
|
197
|
+
| `/api/templates` | GET, POST, PATCH, DELETE | Prompt templates |
|
|
198
|
+
| `/api/user/settings` | GET, PATCH | User settings |
|
|
199
|
+
| `/api/user/usage` | GET | Usage statistics |
|
|
200
|
+
| `/api/projects` | GET, POST | Project management |
|
|
201
|
+
| `/api/projects/*` | GET, PATCH, DELETE | Specific project operations |
|
|
202
|
+
|
|
203
|
+
### Example: Create a Thread
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
curl -X POST \
|
|
207
|
+
-H "Authorization: Bearer sk-your-api-key" \
|
|
208
|
+
-H "Content-Type: application/json" \
|
|
209
|
+
-d '{"title": "New Thread"}' \
|
|
210
|
+
https://your-app.com/api/threads
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Example: Send a Message
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
curl -X POST \
|
|
217
|
+
-H "Authorization: Bearer sk-your-api-key" \
|
|
218
|
+
-H "Content-Type: application/json" \
|
|
219
|
+
-d '{"threadId": "thread-id", "content": "Hello!"}' \
|
|
220
|
+
https://your-app.com/api/chat
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Example: Stream Response (SSE)
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
curl -N \
|
|
227
|
+
-H "Authorization: Bearer sk-your-api-key" \
|
|
228
|
+
-H "Content-Type: application/json" \
|
|
229
|
+
-d '{"threadId": "thread-id", "content": "Hello!"}' \
|
|
230
|
+
https://your-app.com/api/chat
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The response is a Server-Sent Events stream with events:
|
|
234
|
+
- `thread` - Thread metadata
|
|
235
|
+
- `start` - Message ID
|
|
236
|
+
- `delta` - Content chunks
|
|
237
|
+
- `done` - Completion signal
|
|
238
|
+
|
|
239
|
+
## API Endpoints
|
|
240
|
+
|
|
241
|
+
### List API Keys
|
|
242
|
+
|
|
243
|
+
```http
|
|
244
|
+
GET /api/api-keys
|
|
245
|
+
Authorization: Bearer <jwt-token>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Returns the user's API keys (masked):
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"keys": [
|
|
253
|
+
{
|
|
254
|
+
"id": "key-id",
|
|
255
|
+
"name": "My CLI Tool",
|
|
256
|
+
"keyPrefix": "sk-a1b2c3",
|
|
257
|
+
"teamId": null,
|
|
258
|
+
"team": null,
|
|
259
|
+
"lastUsedAt": "2024-01-15T10:30:00Z",
|
|
260
|
+
"expiresAt": null,
|
|
261
|
+
"createdAt": "2024-01-01T00:00:00Z"
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Create API Key
|
|
268
|
+
|
|
269
|
+
```http
|
|
270
|
+
POST /api/api-keys
|
|
271
|
+
Authorization: Bearer <jwt-token>
|
|
272
|
+
Content-Type: application/json
|
|
273
|
+
|
|
274
|
+
{
|
|
275
|
+
"name": "My CLI Tool",
|
|
276
|
+
"teamId": "optional-team-id",
|
|
277
|
+
"expiresAt": "2024-12-31T23:59:59Z"
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Returns the full key (only shown once):
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"key": {
|
|
286
|
+
"id": "key-id",
|
|
287
|
+
"name": "My CLI Tool",
|
|
288
|
+
"keyPrefix": "sk-a1b2c3",
|
|
289
|
+
"teamId": null,
|
|
290
|
+
"teamName": null,
|
|
291
|
+
"createdAt": "2024-01-01T00:00:00Z",
|
|
292
|
+
"expiresAt": null
|
|
293
|
+
},
|
|
294
|
+
"secret": "sk-a1b2c3d4e5f6..."
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Delete API Key
|
|
299
|
+
|
|
300
|
+
```http
|
|
301
|
+
DELETE /api/api-keys/:keyId
|
|
302
|
+
Authorization: Bearer <jwt-token>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Check Access
|
|
306
|
+
|
|
307
|
+
```http
|
|
308
|
+
GET /api/api-keys/access
|
|
309
|
+
Authorization: Bearer <jwt-token>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Returns whether the user can create API keys:
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"canAccess": true
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Error Responses
|
|
321
|
+
|
|
322
|
+
### 401 Unauthorized
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{"error": "Invalid API key"}
|
|
326
|
+
{"error": "API key expired"}
|
|
327
|
+
{"error": "API key invalid - no longer a team member"}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 403 Forbidden
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
{"error": "API key access is not enabled for any endpoints"}
|
|
334
|
+
{"error": "API key access is not allowed for this endpoint"}
|
|
335
|
+
{"error": "API access not available for your plan"}
|
|
336
|
+
{"error": "You are not a member of this team"}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Database Schema
|
|
340
|
+
|
|
341
|
+
```prisma
|
|
342
|
+
model ApiKey {
|
|
343
|
+
id String @id @default(cuid())
|
|
344
|
+
userId String
|
|
345
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
346
|
+
teamId String?
|
|
347
|
+
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
|
348
|
+
name String
|
|
349
|
+
keyPrefix String // First chars for display
|
|
350
|
+
keyHash String // bcrypt hash
|
|
351
|
+
lastUsedAt DateTime?
|
|
352
|
+
expiresAt DateTime?
|
|
353
|
+
createdAt DateTime @default(now())
|
|
354
|
+
|
|
355
|
+
@@index([userId])
|
|
356
|
+
@@index([teamId])
|
|
357
|
+
@@index([keyPrefix])
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Best Practices
|
|
362
|
+
|
|
363
|
+
1. **Restrict Endpoints**: Only whitelist endpoints that are actually needed
|
|
364
|
+
2. **Use Plan Restrictions**: Limit API access to paid plans if appropriate
|
|
365
|
+
3. **Set Expiration Dates**: Encourage or require expiration for security
|
|
366
|
+
4. **Use Team Scoping**: For team-related integrations, use team-scoped keys
|
|
367
|
+
5. **Rotate Keys Regularly**: Periodically revoke and recreate keys
|
|
368
|
+
6. **Monitor Usage**: Check `lastUsedAt` to identify unused keys
|
|
369
|
+
7. **Custom Prefix**: Use a custom prefix to identify your app's keys
|
|
370
|
+
|
|
371
|
+
## Troubleshooting
|
|
372
|
+
|
|
373
|
+
### "API key access is not enabled for any endpoints"
|
|
374
|
+
|
|
375
|
+
The `allowedEndpoints` array is empty. Add the endpoints you want to allow:
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
api: {
|
|
379
|
+
enabled: true,
|
|
380
|
+
allowedEndpoints: ['/api/chat', '/api/threads/**'],
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### "API key access is not allowed for this endpoint"
|
|
385
|
+
|
|
386
|
+
The endpoint you're trying to access is not in the `allowedEndpoints` list. Add it:
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
allowedEndpoints: [
|
|
390
|
+
'/api/search', // Add missing endpoint
|
|
391
|
+
]
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### "API access not available for your plan"
|
|
395
|
+
|
|
396
|
+
The user's plan is not in the `allowedPlans` list. Either:
|
|
397
|
+
- Upgrade the user's plan
|
|
398
|
+
- Add their plan to `allowedPlans`
|
|
399
|
+
- Remove `allowedPlans` to allow all plans
|
|
400
|
+
|
|
401
|
+
### Keys not working after team removal
|
|
402
|
+
|
|
403
|
+
Team-scoped keys are invalidated when the user is removed from the team. The user needs to create a new personal key or be re-added to the team.
|