Repository navigation
refactor: split into backend/ + frontend/ monorepo layout - #3
Merged
Merged
Conversation
Move the entire Python/Flask app into backend/ ahead of the Next.js frontend rebuild. Pure relocation — 227 file renames with no content changes; the app derives all paths from __file__, so nothing in the runtime needed editing. - git mv app.py, config.py, routes/, services/, problems/, prompts/, migrations/, tests/, scripts/, static/, templates/, and Python config (pyproject.toml, requirements*.txt, .env.example) into backend/ - Shared infra (docker-compose.yml, .pgdata/) stays at the repo root - ci.yml: run install/lint/test from backend/ via working-directory - README.md + docs/ARCHITECTURE.md: document the backend/+frontend/ split Verified parity from backend/: pytest 230 passed, ruff clean, Flask app boots with all 24 routes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1 of the frontend rebuild. A standalone Next.js 16 (App Router) + TypeScript + Tailwind v4 + Zustand app in frontend/, consuming the Flask API via a /api/* rewrite proxy so the Flask-Login cookie stays same-origin. - Terminal/hacker-brutalist design system (amber phosphor on near-black, grid + CRT scanline overlay, VT323 wordmark over JetBrains Mono) - Problem picker wired to live /api/problems + /api/sessions: filter sidebar (topic/difficulty/warm-up/sort), search, status dots from past verdicts, and a ⌘K command palette - Zustand store + pure selectVisibleProblems selector replace the old global mutable state for this view - Styled placeholder routes for /study/[id] and /interview/[id] - Proxy targets 127.0.0.1 (not localhost) to dodge the macOS AirPlay Receiver on port 5000; documented in README + next.config.ts Verified: tsc clean, eslint clean, next build green, proxy serves 158 problems through :3000, picker renders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 2 of the frontend rebuild. Gates the whole app behind authentication
using the existing Flask-Login session cookie (carried via the /api proxy).
- lib/api.ts: apiPost helper + getMe/login/register/logout, surfacing the
backend's {error} message as ApiError
- store/auth.ts: Zustand auth store (loading | authed | anon) with check()
- AuthGate wraps the app in layout.tsx: boot screen → AuthOverlay → app
- AuthOverlay: terminal-styled login/register form with mode toggle,
inline error display, and the 8-char password rule
- TopBar: signed-in email + "exit" sign-out button
Verified through the proxy: anon→overlay, register sets the session cookie,
authed /api/sessions returns 200 (was 401), bad-login and short-password
errors surface, and logout clears the session. tsc/eslint/build all clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 3 of the frontend rebuild: the core interview experience, replacing
the legacy CodeMirror 5 / vanilla-JS view.
- lib/sse.ts: streamSSE() — fetch + ReadableStream port of the old
readSSEStream, dispatching {content}/{test_results}/{error} events
- lib/api.ts: session lifecycle (createSession, run, run-tests, save-code,
set-language, end), getConfig, getProblem; apiPut helper for PUT routes
- CodeMirror 6 via @uiw/react-codemirror with a custom amber-phosphor theme
(cmTheme.ts), python/javascript/typescript modes
- react-markdown + remark-math + rehype-katex for interviewer/tutor messages,
scoped terminal markdown styles in globals.css
- store/interview.ts: single-session orchestrator (chat stream, code,
run/tests output panel, tutor) with a latest-wins init guard so React
StrictMode's double mount can't create duplicate sessions
- Components: InterviewView, InterviewTopBar (timer/tutor/end), ChatPanel,
EditorPanel + OutputPanel, TestResults, TutorSidebar, Markdown
- /interview/[id] now renders the live view (was a placeholder)
Verified through the proxy against the claude provider: config/check-key,
python+js code execution, session creation, /start SSE streaming the
interviewer intro, and /run-tests returning structured per-case results.
tsc/eslint/build all clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 5 of the frontend rebuild — completes the text-only app. - Study view (/study/[id]): full problem detail (scenario, constraints, examples, concepts, explanation, references, follow-ups) + a research chat streaming /api/research/chat - History drawer: lists past interviews from /api/sessions, resume or delete; resume loads an existing session via the new /interview/session/[sid] route + interview store resume() - Progress drawer: overall + per-topic attempt counts derived from the picker's problems + attempts - Settings modal: provider/model/effort/default-language, persisted to localStorage (store/settings.ts, zustand persist); model+effort+language now flow into createSession and research/tutor requests - store/ui.ts for drawer/modal open state; reusable Drawer + Modal shells - TopBar wired: history / settings buttons + progress chip open panels - Removed the ComingSoon placeholder (both routes now real) Verified through the proxy: config models shape, session create with model+effort, resume GET, research-chat SSE, and delete. tsc/eslint/build clean; routes /, /interview/[id], /interview/session/[sid], /study/[id]. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 6 (part 1 — UI polish; legacy-frontend deletion deferred pending the voice port). - Interview + study views: mobile tab switch (chat/code, problem/chat) so the panels no longer vanish on narrow screens; tutor sidebar overlays full-width on mobile - TopBar: condense to icons on small screens, hide the cosmetic mode toggle - prefers-reduced-motion: drop CRT scanlines, cursor blink, and animations - Terminal-amber favicon (app/icon.svg); removed the default Next favicon and unused public/*.svg starter assets - Styled 404 (not-found) page; richer metadata + title template - Interview error hint is now provider-neutral (not "OpenAI key") tsc / eslint / next build all clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Picker (page.tsx): pin the page to the viewport on desktop and give the filter sidebar and problem list their own scroll, so scrolling one no longer moves the other. Mobile keeps normal page scroll. - Study view: the research-chat panel is now horizontally resizable via a new reusable ResizeHandle (pointer-capture drag, amber-on-hover rule with grip dots), clamped to 300–720px via a --chat-w CSS var. Desktop-only; mobile stays tabbed. tsc / eslint / next build clean; / and /study/[id] render; the var-width class is present in the built CSS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Save the resizable research-chat width to localStorage (studyChatWidth) and restore it via an SSR-safe lazy initializer; suppressHydrationWarning on the panel covers the server-default vs client-restored difference. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Move the entire Python/Flask app into backend/ ahead of the Next.js
frontend rebuild. Pure relocation — 227 file renames with no content
changes; the app derives all paths from file, so nothing in the
runtime needed editing.
migrations/, tests/, scripts/, static/, templates/, and Python config
(pyproject.toml, requirements*.txt, .env.example) into backend/
Verified parity from backend/: pytest 230 passed, ruff clean, Flask app
boots with all 24 routes.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com