@launchframe/mcp 1.1.1 → 1.1.3
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/.claude/settings.local.json +8 -0
- package/dist/content/content/auth/overview.md +3 -3
- package/dist/content/content/database/schema.md +472 -0
- package/dist/content/content/variants/overview.md +1 -1
- package/dist/server.js +2 -0
- package/dist/tools/auth.js +3 -3
- package/dist/tools/database.d.ts +2 -0
- package/dist/tools/database.js +6 -0
- package/package.json +1 -1
|
@@ -15,14 +15,14 @@ All routes are protected by default via the global `BetterAuthGuard` (registered
|
|
|
15
15
|
|------|-------------|
|
|
16
16
|
| `business_user` | Default role for all registered users |
|
|
17
17
|
| `superadmin` | Granted via admin panel; full access |
|
|
18
|
-
| `
|
|
18
|
+
| `customer` | B2B2C variant only — end-customer of the SaaS |
|
|
19
19
|
|
|
20
20
|
## Session Flow
|
|
21
21
|
|
|
22
22
|
1. Request hits `BetterAuthGuard`
|
|
23
23
|
2. Guard checks for `@AllowAnonymous` / `@OptionalAuth` metadata
|
|
24
24
|
3. Calls `auth.api.getSession({ headers })` via Better Auth
|
|
25
|
-
4. Rejects `
|
|
25
|
+
4. Rejects `customer` on non-`@CustomerPortal` routes
|
|
26
26
|
5. Attaches `request.session` and `request.user`
|
|
27
27
|
|
|
28
28
|
## Decorators
|
|
@@ -32,7 +32,7 @@ All routes are protected by default via the global `BetterAuthGuard` (registered
|
|
|
32
32
|
| `@AllowAnonymous()` | Route is fully public — no auth check |
|
|
33
33
|
| `@Public()` | Alias for `@AllowAnonymous()` |
|
|
34
34
|
| `@OptionalAuth()` | Auth checked but not required; `request.user` may be undefined |
|
|
35
|
-
| `@CustomerPortal()` | Allows `
|
|
35
|
+
| `@CustomerPortal()` | Allows `customer` role (B2B2C variant) |
|
|
36
36
|
| `@UserSession()` | Param decorator — injects the `User` from session |
|
|
37
37
|
| `@Session()` | Param decorator — injects full `{ user, session }` object |
|
|
38
38
|
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# Database Schema
|
|
2
|
+
|
|
3
|
+
## Tables & Columns
|
|
4
|
+
|
|
5
|
+
### Auth
|
|
6
|
+
|
|
7
|
+
#### `users`
|
|
8
|
+
| Column | Type | Nullable | Default |
|
|
9
|
+
|--------|------|----------|---------|
|
|
10
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
11
|
+
| name | varchar | YES | |
|
|
12
|
+
| email | varchar | NO | |
|
|
13
|
+
| email_verified | boolean | NO | false |
|
|
14
|
+
| image | varchar | YES | |
|
|
15
|
+
| role | varchar | NO | 'business_user' |
|
|
16
|
+
| is_active | boolean | NO | true |
|
|
17
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
18
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
19
|
+
|
|
20
|
+
Roles: `business_user`, `superadmin`, `customer` (B2B2C variant)
|
|
21
|
+
|
|
22
|
+
#### `sessions`
|
|
23
|
+
| Column | Type | Nullable | Default |
|
|
24
|
+
|--------|------|----------|---------|
|
|
25
|
+
| id | uuid (PK) | NO | |
|
|
26
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
27
|
+
| token | varchar | NO | |
|
|
28
|
+
| expires_at | timestamp | NO | |
|
|
29
|
+
| ip_address | varchar | YES | |
|
|
30
|
+
| user_agent | text | YES | |
|
|
31
|
+
| created_at | timestamp | NO | now() |
|
|
32
|
+
| updated_at | timestamp | NO | now() |
|
|
33
|
+
|
|
34
|
+
#### `accounts`
|
|
35
|
+
| Column | Type | Nullable | Default |
|
|
36
|
+
|--------|------|----------|---------|
|
|
37
|
+
| id | uuid (PK) | NO | |
|
|
38
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
39
|
+
| account_id | varchar | NO | |
|
|
40
|
+
| provider_id | varchar | NO | |
|
|
41
|
+
| access_token | text | YES | |
|
|
42
|
+
| refresh_token | text | YES | |
|
|
43
|
+
| access_token_expires_at | timestamp | YES | |
|
|
44
|
+
| refresh_token_expires_at | timestamp | YES | |
|
|
45
|
+
| scope | text | YES | |
|
|
46
|
+
| id_token | text | YES | |
|
|
47
|
+
| password | text | YES | |
|
|
48
|
+
| created_at | timestamp | NO | now() |
|
|
49
|
+
| updated_at | timestamp | NO | now() |
|
|
50
|
+
|
|
51
|
+
#### `verification`
|
|
52
|
+
| Column | Type | Nullable |
|
|
53
|
+
|--------|------|----------|
|
|
54
|
+
| id | uuid (PK) | NO |
|
|
55
|
+
| identifier | text | NO |
|
|
56
|
+
| value | text | NO |
|
|
57
|
+
| expires_at | timestamp | NO |
|
|
58
|
+
| created_at | timestamp | NO |
|
|
59
|
+
| updated_at | timestamp | NO |
|
|
60
|
+
|
|
61
|
+
#### `oauth_tokens`
|
|
62
|
+
| Column | Type | Nullable | Default |
|
|
63
|
+
|--------|------|----------|---------|
|
|
64
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
65
|
+
| token_type | text | NO | |
|
|
66
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
67
|
+
| access_token | text | NO | |
|
|
68
|
+
| refresh_token | text | NO | |
|
|
69
|
+
| expires_at | timestamp | NO | |
|
|
70
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
71
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### Subscriptions
|
|
76
|
+
|
|
77
|
+
#### `subscription_plans`
|
|
78
|
+
| Column | Type | Nullable | Default |
|
|
79
|
+
|--------|------|----------|---------|
|
|
80
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
81
|
+
| name | varchar | NO | |
|
|
82
|
+
| code | varchar | NO | |
|
|
83
|
+
| description | text | YES | |
|
|
84
|
+
| price | numeric | NO | |
|
|
85
|
+
| billing_interval | varchar | NO | |
|
|
86
|
+
| trial_period_unit | varchar | YES | |
|
|
87
|
+
| trial_period_value | integer | YES | |
|
|
88
|
+
| features | jsonb | YES | |
|
|
89
|
+
| polar_product_id | varchar | YES | |
|
|
90
|
+
| polar_price_id | varchar | YES | |
|
|
91
|
+
| monthly_credits | integer | YES | |
|
|
92
|
+
| overage_rate | numeric | YES | |
|
|
93
|
+
| is_active | boolean | NO | true |
|
|
94
|
+
| sort_order | integer | NO | 0 |
|
|
95
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
96
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
97
|
+
|
|
98
|
+
#### `user_subscriptions`
|
|
99
|
+
| Column | Type | Nullable | Default |
|
|
100
|
+
|--------|------|----------|---------|
|
|
101
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
102
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
103
|
+
| plan_id | integer (FK → subscription_plans.id) | NO | |
|
|
104
|
+
| status | varchar | NO | |
|
|
105
|
+
| current_period_start | timestamp | YES | |
|
|
106
|
+
| current_period_end | timestamp | YES | |
|
|
107
|
+
| canceled_at | timestamp | YES | |
|
|
108
|
+
| payment_provider | varchar | YES | 'paypal' |
|
|
109
|
+
| provider_subscription_id | varchar | YES | |
|
|
110
|
+
| provider_order_id | varchar | YES | |
|
|
111
|
+
| trial_end | timestamp | YES | |
|
|
112
|
+
| cancel_at_period_end | boolean | NO | false |
|
|
113
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
114
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
115
|
+
| deleted_at | timestamp | YES | |
|
|
116
|
+
|
|
117
|
+
Status values: `active`, `trialing`, `canceled`, `past_due`, `incomplete`
|
|
118
|
+
|
|
119
|
+
#### `subscription_payments`
|
|
120
|
+
| Column | Type | Nullable | Default |
|
|
121
|
+
|--------|------|----------|---------|
|
|
122
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
123
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
124
|
+
| subscription_id | integer (FK → user_subscriptions.id) | NO | |
|
|
125
|
+
| paypal_order_id | varchar | NO | |
|
|
126
|
+
| amount | numeric | NO | |
|
|
127
|
+
| currency | varchar | NO | |
|
|
128
|
+
| status | varchar | NO | 'CREATED' |
|
|
129
|
+
| billing_period_start | timestamp | NO | |
|
|
130
|
+
| billing_period_end | timestamp | NO | |
|
|
131
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
132
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
133
|
+
|
|
134
|
+
#### `user_subscription_logs`
|
|
135
|
+
| Column | Type | Nullable |
|
|
136
|
+
|--------|------|----------|
|
|
137
|
+
| id | integer (PK, serial) | NO |
|
|
138
|
+
| subscription_id | integer (FK → user_subscriptions.id) | NO |
|
|
139
|
+
| event | varchar | NO |
|
|
140
|
+
| metadata | jsonb | YES |
|
|
141
|
+
| previous_status | varchar | YES |
|
|
142
|
+
| new_status | varchar | YES |
|
|
143
|
+
| previous_plan | varchar | YES |
|
|
144
|
+
| new_plan | varchar | YES |
|
|
145
|
+
| description | text | YES |
|
|
146
|
+
| created_at | timestamp | NO |
|
|
147
|
+
|
|
148
|
+
#### `subscription_plan_features`
|
|
149
|
+
| Column | Type | Nullable | Default |
|
|
150
|
+
|--------|------|----------|---------|
|
|
151
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
152
|
+
| name | varchar | NO | |
|
|
153
|
+
| code | varchar | NO | |
|
|
154
|
+
| description | text | YES | |
|
|
155
|
+
| feature_type | varchar | NO | |
|
|
156
|
+
| default_value | jsonb | YES | |
|
|
157
|
+
| template | text | YES | |
|
|
158
|
+
| is_active | boolean | NO | true |
|
|
159
|
+
| sort_order | integer | NO | 0 |
|
|
160
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
161
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
162
|
+
|
|
163
|
+
#### `subscription_plan_feature_values`
|
|
164
|
+
| Column | Type | Nullable |
|
|
165
|
+
|--------|------|----------|
|
|
166
|
+
| id | integer (PK, serial) | NO |
|
|
167
|
+
| subscription_plan_id | integer (FK → subscription_plans.id) | NO |
|
|
168
|
+
| feature_id | integer (FK → subscription_plan_features.id) | NO |
|
|
169
|
+
| value | jsonb | NO |
|
|
170
|
+
| created_at | timestamp | NO |
|
|
171
|
+
| updated_at | timestamp | NO |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### Credits
|
|
176
|
+
|
|
177
|
+
#### `user_credits`
|
|
178
|
+
| Column | Type | Nullable | Default |
|
|
179
|
+
|--------|------|----------|---------|
|
|
180
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
181
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
182
|
+
| balance | integer | NO | 0 |
|
|
183
|
+
| included_credits_used | integer | NO | 0 |
|
|
184
|
+
| overage_credits_used | integer | NO | 0 |
|
|
185
|
+
| created_at | timestamp | NO | now() |
|
|
186
|
+
| updated_at | timestamp | NO | now() |
|
|
187
|
+
|
|
188
|
+
#### `credit_transactions`
|
|
189
|
+
| Column | Type | Nullable |
|
|
190
|
+
|--------|------|----------|
|
|
191
|
+
| id | integer (PK, serial) | NO |
|
|
192
|
+
| user_id | integer (FK → users.id) | NO |
|
|
193
|
+
| amount | integer | NO |
|
|
194
|
+
| type | enum (credit_transaction_type) | NO |
|
|
195
|
+
| description | text | YES |
|
|
196
|
+
| reference_id | varchar | YES |
|
|
197
|
+
| created_at | timestamp | NO |
|
|
198
|
+
|
|
199
|
+
Transaction types: `purchase`, `deduction`, `grant`, `refund`, `expiry`
|
|
200
|
+
|
|
201
|
+
#### `credit_packs`
|
|
202
|
+
| Column | Type | Nullable | Default |
|
|
203
|
+
|--------|------|----------|---------|
|
|
204
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
205
|
+
| name | varchar(255) | NO | |
|
|
206
|
+
| credits | integer | NO | |
|
|
207
|
+
| price | numeric | NO | |
|
|
208
|
+
| polar_product_id | varchar(255) | NO | |
|
|
209
|
+
| polar_price_id | varchar(255) | YES | |
|
|
210
|
+
| is_active | boolean | NO | true |
|
|
211
|
+
| expiry_days | integer | YES | |
|
|
212
|
+
| created_at | timestamp | NO | now() |
|
|
213
|
+
| updated_at | timestamp | NO | now() |
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### Payments
|
|
218
|
+
|
|
219
|
+
#### `payment_transactions`
|
|
220
|
+
| Column | Type | Nullable | Default |
|
|
221
|
+
|--------|------|----------|---------|
|
|
222
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
223
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
224
|
+
| paypal_order_id | varchar | NO | |
|
|
225
|
+
| amount | numeric | NO | |
|
|
226
|
+
| currency | varchar(3) | NO | |
|
|
227
|
+
| credits | integer | NO | |
|
|
228
|
+
| status | varchar | NO | 'CREATED' |
|
|
229
|
+
| description | text | YES | |
|
|
230
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
231
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### API / Webhooks
|
|
236
|
+
|
|
237
|
+
#### `api_keys`
|
|
238
|
+
| Column | Type | Nullable | Default |
|
|
239
|
+
|--------|------|----------|---------|
|
|
240
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
241
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
242
|
+
| key | varchar | NO | |
|
|
243
|
+
| name | varchar | NO | |
|
|
244
|
+
| is_active | boolean | NO | true |
|
|
245
|
+
| permissions | jsonb | YES | |
|
|
246
|
+
| requests_count | bigint | NO | 0 |
|
|
247
|
+
| last_used_at | timestamp | YES | |
|
|
248
|
+
| created_at | timestamp | NO | now() |
|
|
249
|
+
|
|
250
|
+
#### `webhooks`
|
|
251
|
+
| Column | Type | Nullable | Default |
|
|
252
|
+
|--------|------|----------|---------|
|
|
253
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
254
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
255
|
+
| uuid | uuid | NO | uuid_generate_v4() |
|
|
256
|
+
| signing_secret | varchar | NO | |
|
|
257
|
+
| url | varchar | NO | |
|
|
258
|
+
| created_at | timestamp | NO | now() |
|
|
259
|
+
| updated_at | timestamp | NO | now() |
|
|
260
|
+
|
|
261
|
+
#### `webhook_logs`
|
|
262
|
+
| Column | Type | Nullable | Default |
|
|
263
|
+
|--------|------|----------|---------|
|
|
264
|
+
| id | uuid (PK) | NO | uuid_generate_v4() |
|
|
265
|
+
| provider | varchar(50) | NO | |
|
|
266
|
+
| event_type | varchar(255) | NO | |
|
|
267
|
+
| webhook_id | varchar(255) | YES | |
|
|
268
|
+
| payload | jsonb | NO | |
|
|
269
|
+
| headers | jsonb | YES | |
|
|
270
|
+
| processed | boolean | NO | false |
|
|
271
|
+
| processed_at | timestamp | YES | |
|
|
272
|
+
| processing_error | text | YES | |
|
|
273
|
+
| retry_count | integer | NO | 0 |
|
|
274
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
275
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### Projects / Multi-Tenancy
|
|
280
|
+
|
|
281
|
+
#### `projects`
|
|
282
|
+
| Column | Type | Nullable | Default |
|
|
283
|
+
|--------|------|----------|---------|
|
|
284
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
285
|
+
| uuid | uuid | YES | uuid_generate_v4() |
|
|
286
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
287
|
+
| title | varchar | NO | |
|
|
288
|
+
| slug | varchar | NO | |
|
|
289
|
+
| description | text | YES | |
|
|
290
|
+
| created_at | timestamp | NO | now() |
|
|
291
|
+
| updated_at | timestamp | NO | now() |
|
|
292
|
+
|
|
293
|
+
#### `project_domain`
|
|
294
|
+
| Column | Type | Nullable | Default |
|
|
295
|
+
|--------|------|----------|---------|
|
|
296
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
297
|
+
| project_id | integer (FK → projects.id) | NO | |
|
|
298
|
+
| domain | varchar | NO | |
|
|
299
|
+
| added_to_cloudflare | boolean | NO | false |
|
|
300
|
+
| dns_verification_status | enum | NO | 'pending' |
|
|
301
|
+
| created_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
302
|
+
| updated_at | timestamp | NO | CURRENT_TIMESTAMP |
|
|
303
|
+
|
|
304
|
+
DNS status values: `pending`, `verified`, `failed`
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### Admin
|
|
309
|
+
|
|
310
|
+
#### `admin_settings`
|
|
311
|
+
| Column | Type | Nullable |
|
|
312
|
+
|--------|------|----------|
|
|
313
|
+
| key | varchar (PK) | NO |
|
|
314
|
+
| value | varchar | NO |
|
|
315
|
+
| created_at | timestamp | NO |
|
|
316
|
+
| updated_at | timestamp | NO |
|
|
317
|
+
|
|
318
|
+
#### `user_settings`
|
|
319
|
+
| Column | Type | Nullable | Default |
|
|
320
|
+
|--------|------|----------|---------|
|
|
321
|
+
| id | integer (PK, serial) | NO | nextval |
|
|
322
|
+
| user_id | integer (FK → users.id) | NO | |
|
|
323
|
+
| allow_overage | boolean | NO | true |
|
|
324
|
+
| max_overage_credits | integer | YES | |
|
|
325
|
+
| theme_mode | varchar(20) | NO | 'light' |
|
|
326
|
+
| density | varchar(20) | NO | 'comfortable' |
|
|
327
|
+
| created_at | timestamp | NO | now() |
|
|
328
|
+
| updated_at | timestamp | NO | now() |
|
|
329
|
+
|
|
330
|
+
#### `user_businesses` (B2B2C variant)
|
|
331
|
+
| Column | Type | Nullable |
|
|
332
|
+
|--------|------|----------|
|
|
333
|
+
| id | integer (PK, serial) | NO |
|
|
334
|
+
| user_id | integer (FK → users.id) | NO |
|
|
335
|
+
| business_id | integer | NO |
|
|
336
|
+
| created_at | timestamp | NO |
|
|
337
|
+
| updated_at | timestamp | NO |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Common Questions → SQL Queries
|
|
342
|
+
|
|
343
|
+
### Users & Auth
|
|
344
|
+
|
|
345
|
+
```sql
|
|
346
|
+
-- How many users are there?
|
|
347
|
+
SELECT COUNT(*) FROM users;
|
|
348
|
+
|
|
349
|
+
-- How many verified users?
|
|
350
|
+
SELECT COUNT(*) FROM users WHERE email_verified = true;
|
|
351
|
+
|
|
352
|
+
-- How many active users?
|
|
353
|
+
SELECT COUNT(*) FROM users WHERE is_active = true;
|
|
354
|
+
|
|
355
|
+
-- List all users (recent first)
|
|
356
|
+
SELECT id, name, email, role, email_verified, created_at FROM users ORDER BY created_at DESC LIMIT 20;
|
|
357
|
+
|
|
358
|
+
-- How many active sessions?
|
|
359
|
+
SELECT COUNT(*) FROM sessions WHERE expires_at > NOW();
|
|
360
|
+
|
|
361
|
+
-- How many superadmins?
|
|
362
|
+
SELECT COUNT(*) FROM users WHERE role = 'superadmin';
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Subscriptions
|
|
366
|
+
|
|
367
|
+
```sql
|
|
368
|
+
-- Which subscription plans exist?
|
|
369
|
+
SELECT name, code, price, billing_interval, is_active FROM subscription_plans ORDER BY sort_order;
|
|
370
|
+
|
|
371
|
+
-- What's the most expensive subscription plan?
|
|
372
|
+
SELECT name, price FROM subscription_plans ORDER BY price DESC LIMIT 1;
|
|
373
|
+
|
|
374
|
+
-- How many active subscriptions?
|
|
375
|
+
SELECT COUNT(*) FROM user_subscriptions WHERE status = 'active' AND deleted_at IS NULL;
|
|
376
|
+
|
|
377
|
+
-- Subscriptions by status
|
|
378
|
+
SELECT status, COUNT(*) FROM user_subscriptions WHERE deleted_at IS NULL GROUP BY status;
|
|
379
|
+
|
|
380
|
+
-- Which users have active subscriptions?
|
|
381
|
+
SELECT u.email, sp.name AS plan, us.status, us.current_period_end
|
|
382
|
+
FROM user_subscriptions us
|
|
383
|
+
JOIN users u ON u.id = us.user_id
|
|
384
|
+
JOIN subscription_plans sp ON sp.id = us.plan_id
|
|
385
|
+
WHERE us.status = 'active' AND us.deleted_at IS NULL
|
|
386
|
+
ORDER BY us.created_at DESC;
|
|
387
|
+
|
|
388
|
+
-- Recent subscription payments
|
|
389
|
+
SELECT * FROM subscription_payments ORDER BY created_at DESC LIMIT 10;
|
|
390
|
+
|
|
391
|
+
-- Subscription plan feature values for a plan
|
|
392
|
+
SELECT sp.name AS plan, spf.code AS feature, spfv.value
|
|
393
|
+
FROM subscription_plan_feature_values spfv
|
|
394
|
+
JOIN subscription_plans sp ON sp.id = spfv.subscription_plan_id
|
|
395
|
+
JOIN subscription_plan_features spf ON spf.id = spfv.feature_id
|
|
396
|
+
ORDER BY sp.name, spf.code;
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Credits
|
|
400
|
+
|
|
401
|
+
```sql
|
|
402
|
+
-- Credit balance totals (sum and average)
|
|
403
|
+
SELECT SUM(balance), AVG(balance), MIN(balance), MAX(balance) FROM user_credits;
|
|
404
|
+
|
|
405
|
+
-- Users with the most credits
|
|
406
|
+
SELECT u.email, uc.balance FROM user_credits uc JOIN users u ON u.id = uc.user_id ORDER BY uc.balance DESC LIMIT 10;
|
|
407
|
+
|
|
408
|
+
-- Recent credit transactions
|
|
409
|
+
SELECT ct.type, ct.amount, ct.description, u.email, ct.created_at
|
|
410
|
+
FROM credit_transactions ct
|
|
411
|
+
JOIN users u ON u.id = ct.user_id
|
|
412
|
+
ORDER BY ct.created_at DESC LIMIT 20;
|
|
413
|
+
|
|
414
|
+
-- Credit transactions by type
|
|
415
|
+
SELECT type, COUNT(*), SUM(amount) FROM credit_transactions GROUP BY type;
|
|
416
|
+
|
|
417
|
+
-- Which credit packs are available?
|
|
418
|
+
SELECT name, credits, price, is_active FROM credit_packs ORDER BY price;
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Payments
|
|
422
|
+
|
|
423
|
+
```sql
|
|
424
|
+
-- Recent payments (credit pack purchases)
|
|
425
|
+
SELECT pt.amount, pt.currency, pt.credits, pt.status, u.email, pt.created_at
|
|
426
|
+
FROM payment_transactions pt
|
|
427
|
+
JOIN users u ON u.id = pt.user_id
|
|
428
|
+
ORDER BY pt.created_at DESC LIMIT 10;
|
|
429
|
+
|
|
430
|
+
-- Total revenue from credit packs
|
|
431
|
+
SELECT SUM(amount) AS total_revenue, COUNT(*) AS total_transactions
|
|
432
|
+
FROM payment_transactions WHERE status = 'COMPLETED';
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### API & Webhooks
|
|
436
|
+
|
|
437
|
+
```sql
|
|
438
|
+
-- How many active API keys?
|
|
439
|
+
SELECT COUNT(*) FROM api_keys WHERE is_active = true;
|
|
440
|
+
|
|
441
|
+
-- Most used API keys
|
|
442
|
+
SELECT name, requests_count, last_used_at FROM api_keys WHERE is_active = true ORDER BY requests_count DESC LIMIT 10;
|
|
443
|
+
|
|
444
|
+
-- How many unprocessed webhooks?
|
|
445
|
+
SELECT COUNT(*) FROM webhook_logs WHERE processed = false;
|
|
446
|
+
|
|
447
|
+
-- Unprocessed webhook logs
|
|
448
|
+
SELECT provider, event_type, retry_count, created_at FROM webhook_logs WHERE processed = false ORDER BY created_at DESC;
|
|
449
|
+
|
|
450
|
+
-- Webhook logs with errors
|
|
451
|
+
SELECT provider, event_type, processing_error, retry_count FROM webhook_logs WHERE processing_error IS NOT NULL ORDER BY created_at DESC LIMIT 10;
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Projects
|
|
455
|
+
|
|
456
|
+
```sql
|
|
457
|
+
-- How many projects are there?
|
|
458
|
+
SELECT COUNT(*) FROM projects;
|
|
459
|
+
|
|
460
|
+
-- Projects per user
|
|
461
|
+
SELECT u.email, COUNT(p.id) AS project_count FROM projects p JOIN users u ON u.id = p.user_id GROUP BY u.email ORDER BY project_count DESC;
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Admin
|
|
465
|
+
|
|
466
|
+
```sql
|
|
467
|
+
-- All admin settings
|
|
468
|
+
SELECT key, value FROM admin_settings ORDER BY key;
|
|
469
|
+
|
|
470
|
+
-- Get a specific admin setting
|
|
471
|
+
SELECT value FROM admin_settings WHERE key = 'credits_strategy';
|
|
472
|
+
```
|
|
@@ -20,7 +20,7 @@ Extends Base by adding workspace/project isolation.
|
|
|
20
20
|
|
|
21
21
|
### B2B2C
|
|
22
22
|
Extends Base by adding a separate customer-facing experience (end-users of your customers).
|
|
23
|
-
- Adds `
|
|
23
|
+
- Adds `customer` role
|
|
24
24
|
- Adds `customers-portal` frontend service
|
|
25
25
|
- Adds `@CustomerPortal()` route decorator for customer-only endpoints
|
|
26
26
|
- B2B2C can also be combined with multi-tenancy
|
package/dist/server.js
CHANGED
|
@@ -10,6 +10,7 @@ import { registerEntityTools } from './tools/entities.js';
|
|
|
10
10
|
import { registerEnvTools } from './tools/env.js';
|
|
11
11
|
import { registerVariantTools } from './tools/variants.js';
|
|
12
12
|
import { registerCliTools } from './tools/cli.js';
|
|
13
|
+
import { registerDatabaseTools } from './tools/database.js';
|
|
13
14
|
export function createServer() {
|
|
14
15
|
const server = new McpServer({ name: 'launchframe-mcp', version: '1.0.0' });
|
|
15
16
|
registerAuthTools(server);
|
|
@@ -23,5 +24,6 @@ export function createServer() {
|
|
|
23
24
|
registerEnvTools(server);
|
|
24
25
|
registerVariantTools(server);
|
|
25
26
|
registerCliTools(server);
|
|
27
|
+
registerDatabaseTools(server);
|
|
26
28
|
return server;
|
|
27
29
|
}
|
package/dist/tools/auth.js
CHANGED
|
@@ -28,8 +28,8 @@ import { User } from '../users/user.entity';
|
|
|
28
28
|
@OptionalAuth()
|
|
29
29
|
@Get('route')
|
|
30
30
|
handler(@UserSession() user?: User) { ... }`,
|
|
31
|
-
customer_portal: `// Accessible by
|
|
32
|
-
// Without this decorator,
|
|
31
|
+
customer_portal: `// Accessible by customer role (B2B2C variant only)
|
|
32
|
+
// Without this decorator, customer gets 401
|
|
33
33
|
import { CustomerPortal, UserSession } from '../auth/auth.decorator';
|
|
34
34
|
import { User } from '../users/user.entity';
|
|
35
35
|
|
|
@@ -81,7 +81,7 @@ handler(@Session() session: { user: any; session: any }) {
|
|
|
81
81
|
// Source: src/modules/auth/better-auth.guard.ts
|
|
82
82
|
// Applied globally in app.module.ts as APP_GUARD.
|
|
83
83
|
// Allows: business_user, superadmin
|
|
84
|
-
// Blocks: unauthenticated,
|
|
84
|
+
// Blocks: unauthenticated, customer (unless @CustomerPortal())
|
|
85
85
|
// You never need to add this manually.`,
|
|
86
86
|
credits: `// CreditsGuard — deducts credits per request based on @DeductCredits(n).
|
|
87
87
|
// Source: src/modules/credits/guards/credits.guard.ts
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { loadContent } from '../lib/content.js';
|
|
2
|
+
export function registerDatabaseTools(server) {
|
|
3
|
+
server.tool('database_schema', 'Returns the full database schema (all tables, columns, types, relations) plus ready-made SQL snippets for common questions like user counts, active sessions, subscription plans, credit balances, etc. Call this before running cli_database_query when the user asks a data question.', {}, async () => ({
|
|
4
|
+
content: [{ type: 'text', text: loadContent('database/schema.md') }],
|
|
5
|
+
}));
|
|
6
|
+
}
|