7bf3935c81
- User.archetype/utmSource/utmMedium/utmCampaign fields + migration - register flow reads ?archetype/?utm_* and saves them on the User row - dashboard ArchetypeBanner: per-archetype 'твой путь' block - lesson gate after wow-moment lesson (WOW_MOMENT_LESSON_ID=obs-start-l2-006) → tripwire + full-course offer Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
63 lines
2.0 KiB
Markdown
63 lines
2.0 KiB
Markdown
# Quiz-Lead Task 3 — Implementation Report
|
|
|
|
Date: 20260622
|
|
|
|
## STATUS: DONE
|
|
|
|
## Files created/modified
|
|
|
|
| File | Action |
|
|
|------|--------|
|
|
| `src/app/api/internal/quiz-lead/route.ts` | CREATED |
|
|
| `.env.example` | MODIFIED — added QUIZ_LEAD_SECRET, LISTMONK_URL, LISTMONK_USER, LISTMONK_TOKEN, LISTMONK_QUIZ_LIST_ID |
|
|
| `src/middleware.ts` | NOT MODIFIED — `/api/internal` already in PUBLIC_ROUTES with startsWith match; covers /api/internal/quiz-lead without changes |
|
|
|
|
## Test infra
|
|
|
|
`grep -E 'vitest|jest' package.json` → no output (empty).
|
|
No test framework present. Verification done via `npx tsc --noEmit` + manual reasoning.
|
|
|
|
## Commands and output
|
|
|
|
### `npm run type-check`
|
|
```
|
|
> lms-sb@0.1.0 type-check
|
|
> tsc --noEmit
|
|
|
|
(no output = clean)
|
|
```
|
|
Exit code: 0
|
|
|
|
### `npm run lint` (new file only)
|
|
```
|
|
grep 'quiz-lead' in lint output → no results (no errors in new file)
|
|
```
|
|
|
|
Pre-existing lint errors in repo (36 total, 20 errors) are NOT related to this task:
|
|
- `.claude/plugins/superpowers/` scripts using CommonJS require
|
|
- `quick-enroll-modal.tsx` — react-hooks/immutability (pre-existing)
|
|
- `kinescope-player.tsx` — react-hooks/set-state-in-effect (pre-existing)
|
|
|
|
## Commit
|
|
|
|
Base: `9fbb7ae`
|
|
New: `5e65ad6`
|
|
|
|
```
|
|
5e65ad6 Add quiz-lead internal endpoint for Typebot → Listmonk funnel
|
|
```
|
|
|
|
## Implementation notes
|
|
|
|
- Auth: `x-quiz-secret` header vs `QUIZ_LEAD_SECRET` env var; 401 on mismatch/missing
|
|
- Validation: email regex, archetype against const tuple, Number.isFinite(score); 400 on failure
|
|
- Upsert logic: POST create → 409 → GET by email SQL query → PUT update; 502 on Listmonk errors
|
|
- Middleware: `/api/internal` already in PUBLIC_ROUTES with `startsWith` — no changes needed
|
|
- TypeScript strict mode: no `any` used; typed interfaces for Listmonk response shapes
|
|
- No production Listmonk list created; LISTMONK_QUIZ_LIST_ID left as empty placeholder in .env.example
|
|
- No git push; no deploy
|
|
|
|
## Concerns
|
|
|
|
None. The pre-existing lint errors in the repo are unrelated to this task and were already present before this commit.
|