Spec 09 Screens and Routes Student and Public - SekiroKenjii/Quizzivy GitHub Wiki

Section of Quizzivy — Frontend Portal & Data Model Specification · Previous · Next

9. Screens & routes — student and public

StudentLayout is the deck's student shell: a 60px top bar, no sidebar, safe-area padding, and one route outlet that stays mounted at every width. It branches at 768px. From 768 the bar holds the destinations beside the logo (Home, Classes). Below 768 they are a bottom tab bar (Home, Classes, Me), and a detail screen (the intro, the result, Settings) swaps the logo for a back arrow and its title and hides the tabs. A destination whose module has not shipped is absent: Learn, Grades, Messages and the bell in v0.9.0. Home's item carries a badge, the papers still to do that close within seven days (DG-82). The avatar button opens the account menu: Settings, the light or dark theme, Sign out. Each page is one centred column with its own maximum width (§12). The focus engine has no navigator column and no stored width. AuthLayout is the brand frame for sign-in, forgot password, the Google callback, change password and join. The brand panel shows from 900px, except on join and its Joined state, which stay one column at every width. The system pages use SystemFrame.

Route Layout Key behaviour
/join, /join/:code Auth (one column) §6.2: inline preview, then Joined. Every failed lookup shows one plain message, with no hint about which classes exist. /join/:code/confirm redirects to /join/:code.
/login Auth Password form + "Tiếp tục với Google". One message for an unknown email, a wrong password and a disabled account; a 429 shows the server's message. In a join context the subtitle names the class and a successful sign-in continues the join.
/forgot-password Auth Static help (§5.4); no request.
/app Student Home. A greeting for the time of day and one line about what is next. The resume card for the attempt in progress that closes soonest; "Tiếp tục làm bài" resumes it at once. Coming up: every other paper still to do, each row a link to its intro, with a pill (in progress, due today or tomorrow inside 24 hours, open now, opens …). Recent results, newest first: the score if allowed, "being graded" or "submitted", each a link to its result. No filters. Only the intro starts the clock. A student in no class with nothing assigned is offered the Join dialog (§6.2).
/app/assignments/:id Student Intro: class and title, three facts (time limit, questions, attempts used of allowed), and "Trước khi bắt đầu": the rules stated plainly, generated from the stored policy and dates (availability, the timer, fullscreen, copy and paste, leaving, the audio plays per §11.4, what the result shows). "Bắt đầu làm bài" asks "Bắt đầu ngay?" first; "Tiếp tục làm bài" resumes at once. A test not yet open, closed or with no attempts left says so in the button's place. A start the server refuses says why above the button: 409 MAINTENANCE_SCHEDULED, for a start that would run into a maintenance window, with the server's message. When the teacher wrote a note for the students, it is drawn between "Trước khi bắt đầu" and the button: the teacher's initials, "Ghi chú từ {name}" and the text, as plain text with its line breaks; with no note nothing is drawn. The score sentence says "sau khi nộp bài" for a result released on submit and "sau khi bài đóng" for one released after the close.
/app/attempts/:id Focus The engine (below). §10, §11.3.
/app/attempts/:id/result Student The summary card (the score ring if allowed, the class, the title, one sentence on where grading stands), tiles, then every answer honoring review.*, with the transcript if showTranscriptAfterSubmit. While answers wait for the teacher the ring shows the score so far and the tiles say what waits. A line names what the policy hides. A result released after the close is withheld until then: the ring is a lock, no score, mark, answer key, explanation or grader's comment is sent, and the line and the summary say when it is released (releasesAt). When the server sends classAverage, one muted line under the summary sentence reads "Điểm trung bình của lớp: {n}%." Filters All / Wrong / Waiting: Wrong only when scores are shown, Waiting only when something waits; an empty filter says so and offers all questions. The phone header reads "Kết quả".
/app/classes Student The classes joined, as cards: name, description, teacher (with photo), when and where it meets, and "Next", the paper that comes next in that class. A card is not a link, and nothing here leaves a class. One action, "Tham gia lớp", opens the Join dialog (§6.2).
/app/settings/:section? Student Profile (default: name, email read-only, language), Sign-in (password, Google) and Appearance (theme, "Chữ lớn hơn khi làm bài"), under a segmented switcher. Every section stays mounted, so a form survives a change of section or of width. The old slugs redirect: security to sign-in, preferences and any unknown slug to Profile.

Shared:

  • /change-password (§5.4).
  • /403, and the 404 page for any unknown route.
  • The unexpected-error page, with a copyable error ID (the server's requestId when there is one).
  • The maintenance page.

"Home" on these pages is the caller's console, or /login when signed out. The system pages (403, the 404 page, the unexpected-error page and the maintenance page) ship in the entry chunk, so they render when a lazy chunk cannot load; /change-password is a lazy route.

Boot splash. The app starts behind the deck's splash. Before the bundle runs, index.html paints the mark, the track with the first step's 12% fill and the version line; the step label stays empty until the bundle writes it.

  • It shows three steps, and the bar moves only when a step is done, with no minimum duration:
    1. "Đang kiểm tra phiên đăng nhập…" — refresh and /auth/me.
    2. "Đang tải lớp học của bạn…" — the first route's code.
    3. "Sắp xong rồi…" — the hand-over.
  • Slow: eight seconds without a step shows "Tải lâu hơn bình thường" and "Tải lại".
  • Offline: a session restore that got no HTTP response shows "Mất kết nối" and retries after a ten-second countdown, or as soon as the browser is back online.

Overlays stand over a mounted page, which becomes inert; focus moves into the overlay. They follow the theme over every console.

  • Maintenance closes when GET /public/status reports no window under way. It checks on "Kiểm tra lại", and every minute while the user is active. Closing refetches everything.
  • Sign in again (§5.2).
  • A newer build. /version.json is checked when the tab becomes visible and every ten minutes while the user is active. A different build shows "Quizzivy vừa được cập nhật" at the next navigation, never on the engine's route. A route whose code cannot load shows it at once.
  • Precedence: maintenance, then sign in again, then a newer build.

The engine shows one question at a time, except that a run of a cloze's gaps is one screen ("A cloze" below).

  • Header. The ✕ ("Thoát khỏi bài làm"), from 768 the title over the save line, the timer, and "Nộp bài". The ✕ asks first, except on a locked paper, which it leaves at once and without saving. Leaving saves what is unsaved and goes to /app; a save that fails keeps the student on the paper. Below 768 the header has no save line. A strip under it carries one only when a save has failed or the device is offline with an answer unsaved, never for a save on its way, and carries the strike count where the assignment sets a limit (§10.2). A locked paper (taken over, out of time, ended) says why in a bar under the header at every width. Once the server has said the time is up, the timer and the Submit dialog's time left read 00:00. A deadline lock rearms automatic submission at the device's recorded deadline, whichever request was refused and even after a second refusal. Submission can still fail and retry. A deadline refusal never replaces a closed or superseded lock.
  • Section head. Above every question the question column states its section's title over its instructions, so a part's instructions are read on each of its questions, not only on the first. A paper of one section with no instructions has no head, nor has a section with neither a title nor instructions. A group's own instructions stay in the stimulus pane, under its heading.
  • Panes. A question whose group has shared content (a material or a recording) shows the stimulus pane beside the question pane from 768, each scrolling by itself. The question pane is then on the sidebar's surface with its column at most 600px wide; alone, or on a phone, it is on the page's background at most 720px wide. The stimulus pane leads with the group's title as a kicker over the heading of its first material with something to read; a material that is only a recording has no heading, and a shared recording's card stands at its audio node (§11.3). Below 768 the question fills the screen and the shared content is a drawer from the left over it, 88% of the width and at most 420px, above a darkened backdrop. A handle at the left edge ("Mở ngữ liệu", or "Mở bài nghe" for a recording, with a dot while the group's recording plays) or a swipe to the right opens it; a swipe back, Esc, the backdrop or its close button closes it and returns focus to the handle. Until the student has opened a group's drawer once in the attempt, the handle nudges (not under reduced motion) and a tip beside it says what is there. A closed drawer stays mounted and inert, so the place in the passage and a playing recording survive. Every move to another question closes it, and so does a gap tapped inside it, which lands on its question or blank; while it is open the keys that answer or flag do nothing. Crossing 768 with it open shows both panes, with nothing remounted.
  • Navigation. Under the question pane: Previous, a middle, and Next, which is "Hoàn tất" on the last screen. The sections rail ("Các phần"), a 236px column before the panes, shows when the engine is at least 900px wide on a question with no shared content and at least 1180px wide on one with it, and never below 768, so from 900 to 1179px it comes and goes between questions. It holds one block per section, the section's title beside "n / m" answered over a five-column grid of squares, and the legend at its foot. While it shows, the footer's middle is the key hint ("← → để chuyển câu · A–D để chọn đáp án"; "để chuyển · A–D để chọn" beside shared content; "để chuyển câu" on a question with no options). Otherwise, at every width, the middle is the grid button, "Câu 4 · đã làm 3 trên 8" ("4 · 3/8" beside shared content from 768 and below 420px), which opens the question sheet: a bottom sheet below 768 and a 560px card from 768, with the same blocks in six columns and the legend; its name and the answered total are for a screen reader only. It opens on the open question's square, keeps focus inside, closes on Esc, the backdrop or a square, and closes when the engine grows past the rail's threshold. A square is answered (filled), partly answered (a fill-in with some of its blanks typed, which still counts as unanswered) or empty; the open question's square is ringed in lime and a flag is an amber dot. There is no strip of numbered squares.
  • A cloze. Two or more consecutive single-choice members of a group, each bound by a gap of one material and none with an image or audio of its own, are one screen: "Câu 23–27 trên 34 · Điền từ vào đoạn văn · 5 chỗ trống". It prints their shared plain prompt once (or each member's own prompt in the gap card), a chip per gap, and the open gap's card with its options and its worth; a choice opens the next gap with no answer, going round. Previous, Next and the arrows step over the whole run. Every gap stays a question with its own number, square, flag, points and result row: the squares are tied within a row ("Cùng màn hình" in the legend) and all ringed while the run is open. A member with media, or a gap left alone, is a question of its own whose line says "Điền từ vào đoạn văn · 1 trong 5 chỗ trống".
  • Submitting. "Nộp bài" in the header and "Hoàn tất" open the Submit dialog, the only way a student hands a paper in: answered, flagged, time left, and a "Đến câu" chip for each unanswered question. There is no review page. Submitting saves what is unsaved first. A submission that fails says so in the dialog, which stays open. The submitted screen offers Home and the submitted paper.
  • An unknown type. A question of a type the page has no renderer for shows a block that names it and offers a reload, and takes no answer.
  • Local drafts. Student answers awaiting server confirmation are cached locally per student, attempt and session until saved or closed. They may be restored before the server deadline after a reload. A draft a closed tab left behind is sent under the session that wrote it before the student is given a new session by "Tiếp tục làm bài" on Home or the intro. The server saves it if that session is still the attempt's. If it is refused with one of the attempt's own codes (SESSION_SUPERSEDED, DEADLINE_PASSED, ATTEMPT_CLOSED) or as a body that can never be accepted (VALIDATION_FAILED), it is dropped: a superseded session must not overwrite a newer session's answers. On any other failure the draft is kept and the attempt is not resumed. Explicit sign-out clears the local cache, the sessions the tab holds included.
  • Held session. A tab names the session it holds each time it reads an attempt. An in-progress paper taken over elsewhere is answered as superseded: it stays read-only after a reload or refetch, reads no local draft, and removes a draft only if its own session wrote it. It writes again only when the student continues the attempt there. A tab that holds no session is given the current one. Such a read still replaces the attempt's beacon token, and two tabs of one browser can share a session. "Tiếp tục làm bài" in a tab that holds a session for the attempt reads it with that session and starts no resume, so the tab never takes over from itself. When that read answers superseded, another tab or device has taken the attempt, and Continue then resumes, which takes it back and records the takeover, and the tab keeps its session if that resume fails. A tab that holds none resumes. A tab that learns it was superseded, by a 409 SESSION_SUPERSEDED on a save or a play or by a read that answers superseded, sends the events it holds once, under its own session, through the bearer events request, drops them whatever the answer, and records nothing until it holds a session again. An attempt that has ended releases the tab's held session, and a paper sealed as ended or superseded stops its deadline timer.
  • Keys. A–E choose an option, on a cloze for the open gap; a sixth has no key, because F flags the question. The arrows move between screens, as Previous and Next do, and stop at either end. Esc closes a dialog, the sheet or the drawer. None acts in a text field or another control that owns the key, with Ctrl, Alt or the command key held, while a dialog or the question sheet is open, or on a locked paper.

Section of Quizzivy — Frontend Portal & Data Model Specification · Previous · Next


Generated from docs/quizzivy-spec-v0.3.md. Edit that file in the repository; changes made on this page are overwritten.

⚠️ **GitHub.com Fallback** ⚠️