Commit Graph

21 Commits

Author SHA1 Message Date
kitadmin bbebc31624 fix(mailer): add TLS settings for internal SMTP relay
- rejectUnauthorized: false (relay cert is for mail.keylinkit.net, not 172.17.0.1)
- connection/greeting/socket timeouts for reliability

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 03:23:44 +00:00
kitadmin b31d6637a7 feat: Docker, docker-compose, and deployment config (Task 13)
- Dockerfile: two-stage build (builder installs all deps + vite build; runtime copies dist + server)
- docker-compose.yml: 127.0.0.1:3004:8080, named volume for SQLite, env var interpolation
- .env.example: all required environment variables documented
- .dockerignore: exclude node_modules, dist, data, .env from build context
- vite.config.ts: outDir → ../client/dist, /api proxy to :3001 for dev
- .gitignore: remove Docker entries (files should be tracked for deployment)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:26:32 +00:00
kitadmin c9c12a4c2c feat: admin panel with user table and stats (Task 12)
- AdminPage: password gate (sessionStorage), user table, stats banner
- Auto-login using stored sessionStorage password on mount
- App.tsx: route to admin when pathname === '/admin'
- Fix: remove redundant setPassword in auto-login effect (useState already seeds from sessionStorage)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:23:15 +00:00
kitadmin 10afc2bbb0 feat: game practice loop with audio, scoring, and level-up modal (Task 11)
- useMorseAudio: wraps MorseAudioEngine, exposes currentSignal for FlashArea
- useProgress: fetches /api/progress + /api/mnemonics, recordAnswer with local stats
- FlashArea: gold flash on signal, height varies dot/dash
- ScoreBar: level name, score, streak display
- PracticeCard: play button, answer input, correct/incorrect feedback with mnemonic
- GamePage: full practice loop, level-up modal at streak%10, anti-repeat history
- Fix: incorrect attempt recorded only once per challenge (no stat inflation on retries)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:19:58 +00:00
kitadmin 8415e569dd feat: onboarding mnemonic builder with step-through UI (Task 10)
- MnemonicBuilder: 12 NOVICE_LETTERS, real-time validatePhrase, save/skip
- OnboardingPage: wraps builder, passes token and onComplete
- App.tsx: post-auth fetch /api/mnemonics, route to onboarding if <12 saved
- Fix: validatePhrase called with letter (not Morse pattern) as second arg

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:14:46 +00:00
kitadmin 7c9386f125 feat: auth hook and login page (Task 9)
- useAuth: session token from URL/localStorage, /api/auth/me validation, logout
- LoginPage: email form with POST /api/auth/request, error handling
- App.tsx: use useAuth hook, LoginPage, 'sent' confirmation route
- Fix: auto-route to game covers both 'login' and 'sent' routes when authenticated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:10:38 +00:00
kitadmin 2dd6402c86 feat: React app shell with global styles and state-based routing (Task 8)
- index.css: brand CSS custom properties, .btn, input styles, .app-shell layout
- App.tsx: session token extraction from URL, /api/auth/me validation, 4-route shell
- main.tsx: renders App with StrictMode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:07:19 +00:00
kitadmin 85ba992432 feat: server HTTP API with auth, progress, and admin routes (Tasks 6+7)
- server.js: Node HTTP server with all API routes, static file serving, SPA fallback
- Path traversal protection on static file serving
- Async handler wrapped with .catch() to prevent unhandled rejections
- readBody: size limit (1MB) + error handler
- letter validation: single [A-Z] char check on progress/mnemonics routes
- phrase length limit (500 chars) on POST /api/mnemonics
- requireAdmin reads ADMIN_PASSWORD at request time for testability
- logout uses session.token from requireAuth (not re-read from header)
- 51 server tests passing (auth, progress, admin routes + edge cases)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 02:04:57 +00:00
kitadmin 339fa60455 feat: mailer with magic link email (allegiance pattern, MorseQuest branding) 2026-04-30 01:02:43 +00:00
kitadmin b229e6871f fix(db): transactional useMagicToken, O(2) getSession, ?? for displayName
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 01:00:20 +00:00
kitadmin d8de79ce7d fix(db): atomic saveMnemonic, const normalizedLetter, updateProfileSeen guard, ?? 0 for avgScore
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:46:05 +00:00
kitadmin 2d96d37866 fix(db): instance-scoped closures, FK constraints, letter normalization, test coverage
- Remove module-level `let db` singleton; all query functions now close
  over the local `instance` from their `initDb` call, preventing
  cross-contamination when multiple callers each invoke `initDb`
- Add REFERENCES … ON DELETE CASCADE to profile_id in magic_tokens,
  sessions, user_progress, user_mnemonics, and letter_stats so that
  the already-enabled foreign_keys pragma is actually enforced by DDL
- recordAnswer: normalise letter to uppercase before storing stats so
  lowercase 'a' and uppercase 'A' are never tracked separately
- updateLevel: call getOrCreateProgress first to avoid a silent no-op
  UPDATE when no progress row exists yet
- saveMnemonic: replace SELECT-then-INSERT with an atomic UPSERT
  (INSERT … ON CONFLICT DO UPDATE) and detect first-save by checking
  whether created_at equals the current timestamp
- getSession: re-fetch the row after updating last_seen so the returned
  object reflects the freshly written timestamp
- db.test.js: add tests for findProfileById, findProfileById (null),
  updateProfileSeen, updateLevel (normal + no-row-yet), getAdminUsers,
  and getAdminStats (21 tests total, all pass)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:41:40 +00:00
kitadmin 9b31119c7a feat: database layer with better-sqlite3, full schema and query functions
Implements Task 4 (TDD): wrote failing tests first, then the full SQLite
database layer covering profiles, magic tokens, sessions, user progress,
mnemonics, and letter stats. All 14 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:34:59 +00:00
kitadmin cf2081f643 fix(audio): correct re-play-after-stop bug, strengthen tests
Use pendingCancel flag (consumed once) to suppress stop-before-play while
allowing subsequent play() calls to proceed normally. Add afterEach timer
cleanup, re-play test, and behavioral assertion for off().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:29:08 +00:00
kitadmin f62490820a feat: MorseAudioEngine with Web Audio API and event emitter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:23:30 +00:00
kitadmin 1bfd5a22fe test(morse): add missing coverage for DEFAULT_WPM, DEFAULT_TIMING, and derived timing fields
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:17:33 +00:00
kitadmin f7ad8aa3cc feat: morse data library with validation and challenge selection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:10:58 +00:00
kitadmin 6e83b16c4b feat: project scaffold — Vite + React + TS + test setup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:06:14 +00:00
kitadmin f4fab89809 Add MVP implementation plan (14 tasks, full code)
Covers scaffold, morse data, audio engine, DB layer, mailer, server
routes, React app shell, auth, onboarding, game loop, admin panel,
and Docker deployment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 23:57:46 +00:00
kitadmin cb0ffb7e6b Add MVP design spec and update .gitignore
Covers architecture, schema, user flows, audio engine, mnemonic
validation, scoring, content data, Docker deployment, and brand
implementation for the Pack 404 pilot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 22:41:15 +00:00
allen 7ea8f12a31 Initial commit: MorseQuest - Complete amateur radio education platform
- Complete Product Requirements Document with full technical specs
- MorseQuest adventure-based branding and visual identity
- All logos, icons, and brand assets ready for development
- Freemium business model ($9.95/year, first year free launch strategy)
- Ready for Keylink IT Forge platform deployment

Phase 1 MVP ready to begin (10-12 week timeline)
2026-04-29 15:18:08 -05:00