@sx4im/skillcheck 0.2.1 → 0.2.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/README.md +8 -3
- package/dist/src/adapters/nvidia-nim.d.ts +3 -1
- package/dist/src/adapters/nvidia-nim.js +7 -8
- package/dist/src/adapters/nvidia-nim.js.map +1 -1
- package/dist/src/cache.d.ts +9 -1
- package/dist/src/cache.js +15 -1
- package/dist/src/cache.js.map +1 -1
- package/dist/src/cli.js +30 -13
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +15 -0
- package/dist/src/config.js +61 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/env.js +1 -1
- package/dist/src/env.js.map +1 -1
- package/dist/src/eval.js +5 -1
- package/dist/src/eval.js.map +1 -1
- package/dist/src/grade.js +5 -2
- package/dist/src/grade.js.map +1 -1
- package/dist/src/run.js +11 -2
- package/dist/src/run.js.map +1 -1
- package/dist/src/ui.d.ts +10 -1
- package/dist/src/ui.js +41 -4
- package/dist/src/ui.js.map +1 -1
- package/dist/src/verify.js +6 -2
- package/dist/src/verify.js.map +1 -1
- package/docs/skillcheck-cloud-build-plan.md +644 -0
- package/examples/dashboard/README.md +15 -0
- package/examples/dashboard/index.html +393 -0
- package/package.json +1 -1
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
# Skillcheck Dashboard Plan
|
|
2
|
+
|
|
3
|
+
This document is the build plan for a separate Skillcheck Cloud dashboard and API. The goal is:
|
|
4
|
+
|
|
5
|
+
- Users install the CLI with one command.
|
|
6
|
+
- On first CLI run, users paste the Skillcheck API URL.
|
|
7
|
+
- Users can sign up in a dashboard.
|
|
8
|
+
- Users can create a Skillcheck token.
|
|
9
|
+
- The CLI calls your backend, not the upstream model provider directly.
|
|
10
|
+
- Your upstream provider secret stays only on the backend.
|
|
11
|
+
|
|
12
|
+
## Target Deployment
|
|
13
|
+
|
|
14
|
+
Use two separate deploys:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
Vercel
|
|
18
|
+
app.skillcheck.yourdomain.com
|
|
19
|
+
Next.js dashboard, marketing, auth pages, API key management, usage UI
|
|
20
|
+
|
|
21
|
+
Render
|
|
22
|
+
api.skillcheck.yourdomain.com
|
|
23
|
+
Node/Fastify or Hono API, OpenAI-compatible proxy, rate limits, usage tracking
|
|
24
|
+
|
|
25
|
+
Postgres
|
|
26
|
+
Render Postgres or Neon/Supabase Postgres
|
|
27
|
+
Users, API keys, usage events, runs, billing state
|
|
28
|
+
|
|
29
|
+
Redis
|
|
30
|
+
Upstash Redis or Render Key Value
|
|
31
|
+
Fast per-token and per-IP rate limits
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The CLI setup URL should be:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
https://api.skillcheck.yourdomain.com/v1
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Recommended Repos
|
|
41
|
+
|
|
42
|
+
Build this separately from the CLI repo.
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
skillcheck-dashboard/
|
|
46
|
+
apps/web/ Next.js dashboard deployed to Vercel
|
|
47
|
+
apps/api/ Node API deployed to Render
|
|
48
|
+
packages/db/ Prisma/Drizzle schema and migrations
|
|
49
|
+
packages/shared/ shared types, token helpers, validation schemas
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
If you want to move fast, a single repo with `apps/web` and `apps/api` is better than two repos because shared types and database migrations stay together.
|
|
53
|
+
|
|
54
|
+
## Product Flow
|
|
55
|
+
|
|
56
|
+
### User Flow
|
|
57
|
+
|
|
58
|
+
1. User installs CLI:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -g @sx4im/skillcheck
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
2. User signs up on the dashboard.
|
|
65
|
+
3. Dashboard shows onboarding:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
skillcheck setup
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
4. User pastes:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
https://api.skillcheck.yourdomain.com/v1
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
5. If private beta, dashboard also gives a token:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
export SKILLCHECK_TOKEN=sk_live_...
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
6. User runs:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
skillcheck
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
7. CLI opens file/folder picker and calls your backend.
|
|
90
|
+
8. Dashboard usage page shows requests, tokens, cost estimate, verdict counts, and recent runs.
|
|
91
|
+
|
|
92
|
+
### Admin Flow
|
|
93
|
+
|
|
94
|
+
1. Admin logs into dashboard.
|
|
95
|
+
2. Admin sees total usage, active users, failed requests, spend estimate.
|
|
96
|
+
3. Admin can revoke tokens, ban abusive IPs, adjust quotas, and inspect error logs.
|
|
97
|
+
|
|
98
|
+
## Frontend: Vercel Dashboard
|
|
99
|
+
|
|
100
|
+
Use Next.js App Router.
|
|
101
|
+
|
|
102
|
+
Recommended stack:
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
Next.js
|
|
106
|
+
TypeScript
|
|
107
|
+
Tailwind CSS
|
|
108
|
+
shadcn/ui or custom components
|
|
109
|
+
Clerk for auth if you want fastest launch
|
|
110
|
+
Stripe later for billing
|
|
111
|
+
PostHog or simple internal analytics later
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Pages:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
/
|
|
118
|
+
Marketing page: what Skillcheck does, install command, demo result card.
|
|
119
|
+
|
|
120
|
+
/login
|
|
121
|
+
Auth page.
|
|
122
|
+
|
|
123
|
+
/onboarding
|
|
124
|
+
Shows setup commands and asks user to create first token.
|
|
125
|
+
|
|
126
|
+
/dashboard
|
|
127
|
+
Overview: total checks, pass/fail/verdict mix, monthly usage, active token.
|
|
128
|
+
|
|
129
|
+
/tokens
|
|
130
|
+
Create, list, revoke Skillcheck tokens.
|
|
131
|
+
Show token only once after creation.
|
|
132
|
+
|
|
133
|
+
/usage
|
|
134
|
+
Table of requests with date, token prefix, model, status, prompt tokens, completion tokens, cost estimate.
|
|
135
|
+
|
|
136
|
+
/runs
|
|
137
|
+
Optional later: user-submitted check summaries if CLI uploads metadata.
|
|
138
|
+
|
|
139
|
+
/settings
|
|
140
|
+
User profile, org settings, billing, delete account.
|
|
141
|
+
|
|
142
|
+
/admin
|
|
143
|
+
Admin-only usage, errors, users, abuse controls.
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Vercel environment variables:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
NEXT_PUBLIC_API_URL=https://api.skillcheck.yourdomain.com
|
|
150
|
+
AUTH_SECRET=...
|
|
151
|
+
CLERK_SECRET_KEY=...
|
|
152
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=...
|
|
153
|
+
DATABASE_URL=...
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
If you use Clerk, do not expose backend admin secrets in the browser. Only expose `NEXT_PUBLIC_*` variables that are safe for the client.
|
|
157
|
+
|
|
158
|
+
## Backend: Render API
|
|
159
|
+
|
|
160
|
+
Use Node.js with Fastify or Hono. Fastify is a good default for this API because plugins, hooks, and logging are straightforward.
|
|
161
|
+
|
|
162
|
+
Core responsibility:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
Accept CLI OpenAI-compatible requests.
|
|
166
|
+
Authenticate Skillcheck tokens.
|
|
167
|
+
Rate limit by token and IP.
|
|
168
|
+
Forward requests to upstream provider.
|
|
169
|
+
Track usage and errors.
|
|
170
|
+
Return OpenAI-compatible responses to the CLI.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Render environment variables:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
PORT=10000
|
|
177
|
+
DATABASE_URL=postgres://...
|
|
178
|
+
REDIS_URL=redis://...
|
|
179
|
+
|
|
180
|
+
FRONTEND_ORIGIN=https://app.skillcheck.yourdomain.com
|
|
181
|
+
|
|
182
|
+
SKILLCHECK_TOKEN_PEPPER=long-random-secret
|
|
183
|
+
ALLOW_ANONYMOUS=false
|
|
184
|
+
ANONYMOUS_DAILY_LIMIT=20
|
|
185
|
+
|
|
186
|
+
PROVIDER_BASE_URL=https://integrate.api.nvidia.com/v1
|
|
187
|
+
PROVIDER_API_KEY=...
|
|
188
|
+
DEFAULT_MODEL=minimaxai/minimax-m2.7
|
|
189
|
+
|
|
190
|
+
REQUEST_TIMEOUT_MS=120000
|
|
191
|
+
REQUEST_DELAY_MS=5000
|
|
192
|
+
MAX_ATTEMPTS=8
|
|
193
|
+
MAX_RETRY_DELAY_MS=60000
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Only the Render API should know `PROVIDER_API_KEY`.
|
|
197
|
+
|
|
198
|
+
## Backend Endpoints
|
|
199
|
+
|
|
200
|
+
### OpenAI-compatible CLI endpoint
|
|
201
|
+
|
|
202
|
+
The CLI already expects this:
|
|
203
|
+
|
|
204
|
+
```http
|
|
205
|
+
POST /v1/chat/completions
|
|
206
|
+
Authorization: Bearer sk_live_...
|
|
207
|
+
Content-Type: application/json
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Backend behavior:
|
|
211
|
+
|
|
212
|
+
1. Parse authorization header.
|
|
213
|
+
2. If token is missing:
|
|
214
|
+
- If `ALLOW_ANONYMOUS=true`, apply strict IP rate limit.
|
|
215
|
+
- Otherwise return `401`.
|
|
216
|
+
3. Hash provided token and find it in `api_keys`.
|
|
217
|
+
4. Check revoked status.
|
|
218
|
+
5. Rate limit by key and IP.
|
|
219
|
+
6. Forward request body to upstream provider.
|
|
220
|
+
7. Record request usage.
|
|
221
|
+
8. Return upstream response unchanged where possible.
|
|
222
|
+
|
|
223
|
+
### Dashboard API endpoints
|
|
224
|
+
|
|
225
|
+
```http
|
|
226
|
+
GET /health
|
|
227
|
+
GET /api/me
|
|
228
|
+
GET /api/usage
|
|
229
|
+
GET /api/tokens
|
|
230
|
+
POST /api/tokens
|
|
231
|
+
DELETE /api/tokens/:id
|
|
232
|
+
GET /api/runs
|
|
233
|
+
POST /api/runs
|
|
234
|
+
GET /api/admin/users
|
|
235
|
+
GET /api/admin/usage
|
|
236
|
+
POST /api/admin/tokens/:id/revoke
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Dashboard endpoints can live in the Render API, not Vercel serverless, to keep all auth, DB, and token logic in one backend.
|
|
240
|
+
|
|
241
|
+
## Database Schema
|
|
242
|
+
|
|
243
|
+
Use Postgres.
|
|
244
|
+
|
|
245
|
+
```sql
|
|
246
|
+
create table users (
|
|
247
|
+
id uuid primary key default gen_random_uuid(),
|
|
248
|
+
email text unique not null,
|
|
249
|
+
name text,
|
|
250
|
+
auth_provider text not null,
|
|
251
|
+
auth_provider_id text not null,
|
|
252
|
+
created_at timestamptz not null default now(),
|
|
253
|
+
updated_at timestamptz not null default now()
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
create table organizations (
|
|
257
|
+
id uuid primary key default gen_random_uuid(),
|
|
258
|
+
name text not null,
|
|
259
|
+
slug text unique not null,
|
|
260
|
+
owner_user_id uuid not null references users(id),
|
|
261
|
+
created_at timestamptz not null default now()
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
create table memberships (
|
|
265
|
+
id uuid primary key default gen_random_uuid(),
|
|
266
|
+
organization_id uuid not null references organizations(id),
|
|
267
|
+
user_id uuid not null references users(id),
|
|
268
|
+
role text not null check (role in ('owner', 'admin', 'member')),
|
|
269
|
+
created_at timestamptz not null default now(),
|
|
270
|
+
unique (organization_id, user_id)
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
create table api_keys (
|
|
274
|
+
id uuid primary key default gen_random_uuid(),
|
|
275
|
+
organization_id uuid not null references organizations(id),
|
|
276
|
+
name text not null,
|
|
277
|
+
prefix text not null,
|
|
278
|
+
token_hash text unique not null,
|
|
279
|
+
last_four text not null,
|
|
280
|
+
created_by_user_id uuid not null references users(id),
|
|
281
|
+
created_at timestamptz not null default now(),
|
|
282
|
+
last_used_at timestamptz,
|
|
283
|
+
revoked_at timestamptz
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
create table usage_events (
|
|
287
|
+
id uuid primary key default gen_random_uuid(),
|
|
288
|
+
organization_id uuid references organizations(id),
|
|
289
|
+
api_key_id uuid references api_keys(id),
|
|
290
|
+
request_id text,
|
|
291
|
+
path text not null,
|
|
292
|
+
model text,
|
|
293
|
+
status_code integer not null,
|
|
294
|
+
prompt_tokens integer not null default 0,
|
|
295
|
+
completion_tokens integer not null default 0,
|
|
296
|
+
total_tokens integer not null default 0,
|
|
297
|
+
estimated_cost_usd numeric(12, 6) not null default 0,
|
|
298
|
+
ip_hash text,
|
|
299
|
+
error_code text,
|
|
300
|
+
created_at timestamptz not null default now()
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
create table skill_runs (
|
|
304
|
+
id uuid primary key default gen_random_uuid(),
|
|
305
|
+
organization_id uuid references organizations(id),
|
|
306
|
+
api_key_id uuid references api_keys(id),
|
|
307
|
+
skill_name text,
|
|
308
|
+
skill_format text,
|
|
309
|
+
verdict text,
|
|
310
|
+
effect_pp numeric,
|
|
311
|
+
with_skill_pass numeric,
|
|
312
|
+
no_skill_pass numeric,
|
|
313
|
+
tasks integer,
|
|
314
|
+
trials integer,
|
|
315
|
+
created_at timestamptz not null default now()
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
create table audit_logs (
|
|
319
|
+
id uuid primary key default gen_random_uuid(),
|
|
320
|
+
organization_id uuid references organizations(id),
|
|
321
|
+
user_id uuid references users(id),
|
|
322
|
+
action text not null,
|
|
323
|
+
metadata jsonb not null default '{}',
|
|
324
|
+
created_at timestamptz not null default now()
|
|
325
|
+
);
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Token Design
|
|
329
|
+
|
|
330
|
+
Token format:
|
|
331
|
+
|
|
332
|
+
```text
|
|
333
|
+
sk_live_<random>
|
|
334
|
+
sk_test_<random>
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Token generation:
|
|
338
|
+
|
|
339
|
+
```text
|
|
340
|
+
random = 32 bytes from crypto.randomBytes
|
|
341
|
+
token = sk_live_ + base64url(random)
|
|
342
|
+
prefix = first 12 visible characters
|
|
343
|
+
last_four = last 4 characters
|
|
344
|
+
token_hash = sha256(token + SKILLCHECK_TOKEN_PEPPER)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Rules:
|
|
348
|
+
|
|
349
|
+
- Show token only once after creation.
|
|
350
|
+
- Store only `token_hash`, prefix, and last four.
|
|
351
|
+
- Never log full tokens.
|
|
352
|
+
- Redact auth headers from logs.
|
|
353
|
+
- Let users revoke tokens instantly.
|
|
354
|
+
|
|
355
|
+
## Rate Limits
|
|
356
|
+
|
|
357
|
+
Start with simple quotas:
|
|
358
|
+
|
|
359
|
+
```text
|
|
360
|
+
Free anonymous:
|
|
361
|
+
5 checks per IP per day
|
|
362
|
+
|
|
363
|
+
Logged-in free:
|
|
364
|
+
50 checks per org per month
|
|
365
|
+
10 requests per minute
|
|
366
|
+
|
|
367
|
+
Paid:
|
|
368
|
+
Plan-based monthly quota
|
|
369
|
+
30 requests per minute
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Implement with Redis token buckets:
|
|
373
|
+
|
|
374
|
+
```text
|
|
375
|
+
ratelimit:ip:<hash>:day
|
|
376
|
+
ratelimit:key:<api_key_id>:minute
|
|
377
|
+
ratelimit:org:<org_id>:month
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
If Redis is unavailable, fail closed for anonymous traffic and fail soft for authenticated paid users with logging.
|
|
381
|
+
|
|
382
|
+
## Proxy Logic
|
|
383
|
+
|
|
384
|
+
For `/v1/chat/completions`:
|
|
385
|
+
|
|
386
|
+
1. Accept the CLI request body.
|
|
387
|
+
2. Force or override model if needed:
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
body.model = process.env.DEFAULT_MODEL;
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
3. Forward to upstream provider:
|
|
394
|
+
|
|
395
|
+
```http
|
|
396
|
+
POST ${PROVIDER_BASE_URL}/chat/completions
|
|
397
|
+
Authorization: Bearer ${PROVIDER_API_KEY}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
4. Return upstream response as-is.
|
|
401
|
+
5. Record usage from `response.usage`.
|
|
402
|
+
|
|
403
|
+
Do not stream in v1. The current CLI sends `stream: false`, so non-streaming is enough.
|
|
404
|
+
|
|
405
|
+
## Security Checklist
|
|
406
|
+
|
|
407
|
+
- Store provider secrets only in Render environment variables.
|
|
408
|
+
- Store dashboard auth secrets only in Vercel or Render env vars as needed.
|
|
409
|
+
- Never put provider secrets in CLI, frontend code, or public docs.
|
|
410
|
+
- Hash Skillcheck tokens before storing.
|
|
411
|
+
- Use HTTPS only in production.
|
|
412
|
+
- CORS allow only:
|
|
413
|
+
|
|
414
|
+
```text
|
|
415
|
+
https://app.skillcheck.yourdomain.com
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
- CLI requests do not need browser CORS, but dashboard API calls do.
|
|
419
|
+
- Log request IDs, not full payloads.
|
|
420
|
+
- Redact prompts by default in production logs.
|
|
421
|
+
- Add abuse controls before public launch.
|
|
422
|
+
|
|
423
|
+
## Vercel Deployment Plan
|
|
424
|
+
|
|
425
|
+
1. Create `skillcheck-dashboard` repo.
|
|
426
|
+
2. Add `apps/web` Next.js app.
|
|
427
|
+
3. Push to GitHub.
|
|
428
|
+
4. Import repo in Vercel.
|
|
429
|
+
5. Set root directory to `apps/web`.
|
|
430
|
+
6. Add environment variables.
|
|
431
|
+
7. Set production domain:
|
|
432
|
+
|
|
433
|
+
```text
|
|
434
|
+
app.skillcheck.yourdomain.com
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
8. Add dashboard pages.
|
|
438
|
+
9. Add auth.
|
|
439
|
+
10. Add API token UI.
|
|
440
|
+
|
|
441
|
+
Official note: Vercel environment variables are configured outside source code and apply to new deployments, not old deployments: https://vercel.com/docs/projects/environment-variables
|
|
442
|
+
|
|
443
|
+
## Render Deployment Plan
|
|
444
|
+
|
|
445
|
+
1. Add `apps/api` Node service.
|
|
446
|
+
2. Add `Dockerfile` or simple Node build/start commands.
|
|
447
|
+
3. Create Render Web Service from GitHub repo.
|
|
448
|
+
4. Set root directory to `apps/api`.
|
|
449
|
+
5. Set build command:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
npm install && npm run build
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
6. Set start command:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
npm run start
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
7. Add Render Postgres.
|
|
462
|
+
8. Add Redis/Key Value.
|
|
463
|
+
9. Add environment variables.
|
|
464
|
+
10. Set production domain:
|
|
465
|
+
|
|
466
|
+
```text
|
|
467
|
+
api.skillcheck.yourdomain.com
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Official notes:
|
|
471
|
+
|
|
472
|
+
- Render environment variables are configured per service: https://render.com/docs/configure-environment-variables/
|
|
473
|
+
- Render Postgres can host the production database: https://render.com/docs/postgresql
|
|
474
|
+
|
|
475
|
+
## MVP Build Order
|
|
476
|
+
|
|
477
|
+
### Phase 1: Working Proxy
|
|
478
|
+
|
|
479
|
+
Goal: CLI can run against your backend.
|
|
480
|
+
|
|
481
|
+
- Create `apps/api`.
|
|
482
|
+
- Implement `GET /health`.
|
|
483
|
+
- Implement `POST /v1/chat/completions`.
|
|
484
|
+
- Add provider forwarding.
|
|
485
|
+
- Add request timeout and retry.
|
|
486
|
+
- Deploy API to Render.
|
|
487
|
+
- Run:
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
skillcheck setup
|
|
491
|
+
skillcheck check path/to/SKILL.md
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Phase 2: Token Auth
|
|
495
|
+
|
|
496
|
+
Goal: users need a Skillcheck token.
|
|
497
|
+
|
|
498
|
+
- Add Postgres.
|
|
499
|
+
- Add `api_keys` table.
|
|
500
|
+
- Add token generation endpoint.
|
|
501
|
+
- Verify `Authorization: Bearer ...`.
|
|
502
|
+
- Add usage logging.
|
|
503
|
+
- Add revoke endpoint.
|
|
504
|
+
|
|
505
|
+
### Phase 3: Dashboard
|
|
506
|
+
|
|
507
|
+
Goal: users can self-serve.
|
|
508
|
+
|
|
509
|
+
- Create `apps/web`.
|
|
510
|
+
- Add auth.
|
|
511
|
+
- Add onboarding page.
|
|
512
|
+
- Add create token page.
|
|
513
|
+
- Add usage page.
|
|
514
|
+
- Deploy to Vercel.
|
|
515
|
+
|
|
516
|
+
### Phase 4: Abuse and Billing
|
|
517
|
+
|
|
518
|
+
Goal: safe public launch.
|
|
519
|
+
|
|
520
|
+
- Add Redis rate limits.
|
|
521
|
+
- Add org monthly quotas.
|
|
522
|
+
- Add admin dashboard.
|
|
523
|
+
- Add Stripe subscriptions.
|
|
524
|
+
- Add email alerts for quota exceeded and suspicious usage.
|
|
525
|
+
|
|
526
|
+
### Phase 5: Run History
|
|
527
|
+
|
|
528
|
+
Goal: dashboard becomes useful beyond API keys.
|
|
529
|
+
|
|
530
|
+
- Add optional CLI metadata upload.
|
|
531
|
+
- Store `skill_runs`.
|
|
532
|
+
- Show verdict trend by skill.
|
|
533
|
+
- Show helps/placebo/harms counts.
|
|
534
|
+
- Add shareable run page.
|
|
535
|
+
|
|
536
|
+
## Suggested Backend File Structure
|
|
537
|
+
|
|
538
|
+
```text
|
|
539
|
+
apps/api/src/
|
|
540
|
+
index.ts
|
|
541
|
+
env.ts
|
|
542
|
+
db.ts
|
|
543
|
+
auth/
|
|
544
|
+
tokens.ts
|
|
545
|
+
middleware.ts
|
|
546
|
+
routes/
|
|
547
|
+
health.ts
|
|
548
|
+
chat-completions.ts
|
|
549
|
+
tokens.ts
|
|
550
|
+
usage.ts
|
|
551
|
+
runs.ts
|
|
552
|
+
admin.ts
|
|
553
|
+
services/
|
|
554
|
+
provider.ts
|
|
555
|
+
rate-limit.ts
|
|
556
|
+
usage.ts
|
|
557
|
+
audit.ts
|
|
558
|
+
lib/
|
|
559
|
+
hash.ts
|
|
560
|
+
errors.ts
|
|
561
|
+
logger.ts
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
## Suggested Frontend File Structure
|
|
565
|
+
|
|
566
|
+
```text
|
|
567
|
+
apps/web/app/
|
|
568
|
+
page.tsx
|
|
569
|
+
login/page.tsx
|
|
570
|
+
onboarding/page.tsx
|
|
571
|
+
dashboard/page.tsx
|
|
572
|
+
tokens/page.tsx
|
|
573
|
+
usage/page.tsx
|
|
574
|
+
runs/page.tsx
|
|
575
|
+
settings/page.tsx
|
|
576
|
+
admin/page.tsx
|
|
577
|
+
|
|
578
|
+
apps/web/components/
|
|
579
|
+
AppShell.tsx
|
|
580
|
+
UsageChart.tsx
|
|
581
|
+
TokenTable.tsx
|
|
582
|
+
CreateTokenDialog.tsx
|
|
583
|
+
CopyCommand.tsx
|
|
584
|
+
RunCard.tsx
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
## MVP API Pseudocode
|
|
588
|
+
|
|
589
|
+
```ts
|
|
590
|
+
app.post('/v1/chat/completions', async (req, reply) => {
|
|
591
|
+
const token = getBearerToken(req.headers.authorization);
|
|
592
|
+
const auth = await authenticateTokenOrAnonymous(token, req.ip);
|
|
593
|
+
|
|
594
|
+
await rateLimit(auth);
|
|
595
|
+
|
|
596
|
+
const startedAt = Date.now();
|
|
597
|
+
const upstream = await fetch(`${env.PROVIDER_BASE_URL}/chat/completions`, {
|
|
598
|
+
method: 'POST',
|
|
599
|
+
headers: {
|
|
600
|
+
authorization: `Bearer ${env.PROVIDER_API_KEY}`,
|
|
601
|
+
'content-type': 'application/json'
|
|
602
|
+
},
|
|
603
|
+
body: JSON.stringify({
|
|
604
|
+
...req.body,
|
|
605
|
+
model: env.DEFAULT_MODEL,
|
|
606
|
+
stream: false
|
|
607
|
+
})
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
const text = await upstream.text();
|
|
611
|
+
await recordUsage({
|
|
612
|
+
auth,
|
|
613
|
+
statusCode: upstream.status,
|
|
614
|
+
responseText: text,
|
|
615
|
+
latencyMs: Date.now() - startedAt
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
reply
|
|
619
|
+
.status(upstream.status)
|
|
620
|
+
.header('content-type', upstream.headers.get('content-type') ?? 'application/json')
|
|
621
|
+
.send(text);
|
|
622
|
+
});
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
## What To Build First
|
|
626
|
+
|
|
627
|
+
Build this order:
|
|
628
|
+
|
|
629
|
+
1. Render API with `/health`.
|
|
630
|
+
2. Render API `/v1/chat/completions` proxy.
|
|
631
|
+
3. Point local CLI to Render API with `skillcheck setup`.
|
|
632
|
+
4. Add Postgres token table.
|
|
633
|
+
5. Add dashboard token creation.
|
|
634
|
+
6. Add usage logging.
|
|
635
|
+
7. Add rate limits.
|
|
636
|
+
8. Add billing/admin later.
|
|
637
|
+
|
|
638
|
+
Do not start with billing or a polished dashboard. First prove:
|
|
639
|
+
|
|
640
|
+
```text
|
|
641
|
+
user installs CLI -> runs setup -> checks skill -> backend records usage
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
That is the real MVP.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Skillcheck dashboard
|
|
2
|
+
|
|
3
|
+
A single static file (`index.html`) where a user pastes their Skillcheck API URL and gets the commands to start using the CLI, a connection test, and an in-browser "with vs without skill" preview.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# open it directly
|
|
7
|
+
xdg-open index.html # macOS: open index.html · Windows: start index.html
|
|
8
|
+
|
|
9
|
+
# or serve it
|
|
10
|
+
npx --yes serve .
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Nothing to build or configure — the API URL and optional token are entered at runtime and stored in the browser's localStorage.
|
|
14
|
+
|
|
15
|
+
The live preview calls `POST <apiUrl>/chat/completions`, so the API must allow the page's origin via CORS. The bundled `../nvidia-proxy` already returns `access-control-allow-origin: *`, so the preview works even from `file://`. See [`../../dashboard.md`](../../dashboard.md) for the full write-up and [`../../docs/skillcheck-cloud.md`](../../docs/skillcheck-cloud.md) for the API contract.
|