diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..c3cd0cc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,97 @@ +name: Bug report +description: Something in the app behaves differently from what it should. +labels: [bug] +body: + - type: markdown + attributes: + value: | + For a wrong answer key, a duplicated question or a broken question, + please use **Question error report** instead — it asks for the chapter + and index needed to find the row. + + - type: textarea + id: what-happened + attributes: + label: What happened + description: What you saw, in one or two sentences. + validations: + required: true + + - type: textarea + id: expected + attributes: + label: What you expected instead + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: Numbered steps starting from a fresh page load. + placeholder: | + 1. Open /app/practice + 2. Pick Chapter 3 + 3. Answer the first question + 4. ... + validations: + required: true + + - type: input + id: url + attributes: + label: Page or route + placeholder: /app/practice/topic/book-ch3 + validations: + required: false + + - type: dropdown + id: area + attributes: + label: Which part of the app + options: + - Landing page + - Dashboard + - Practice (chapter / topic / quick / custom) + - Mock tests + - Study hub + - Flashcards + - Bookmarks + - Progress + - Profile / Settings + - Not sure + validations: + required: true + + - type: input + id: environment + attributes: + label: Device and browser + description: > + Please be specific. A large share of users are on entry-level Android + over mobile data, and several bugs only appear there. + placeholder: Android 11, Chrome 120, 3G + validations: + required: true + + - type: textarea + id: console + attributes: + label: Console errors + description: > + Open DevTools (or `chrome://inspect` on Android) and paste anything red. + render: text + validations: + required: false + + - type: checkboxes + id: progress-loss + attributes: + label: Did this lose study progress? + description: > + All progress lives in this browser's `localStorage`. There is no account + and no server copy, so lost progress cannot be recovered — these reports + are triaged first. + options: + - label: Yes, saved progress, bookmarks or quiz history disappeared + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..b8b22eb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Question or idea to discuss first + url: https://github.com/SamirWagle/EngineeringLisenseProject/discussions + about: Not sure it is a bug or a feature yet? Start here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..3e3be44 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,59 @@ +name: Feature request +description: Propose something the app should do that it does not do yet. +labels: [enhancement] +body: + - type: textarea + id: problem + attributes: + label: What problem does this solve for someone studying for the NEC exam + description: > + Describe the situation you are in when you need this, not the feature. + The strongest requests come from someone who hit a wall while revising. + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: What you would like it to do + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: What you do instead today + description: The workaround, if there is one. + validations: + required: false + + - type: dropdown + id: scope + attributes: + label: Does this need a server + description: > + The app is currently frontend-only: all data is static JSON and all + state is in this browser's `localStorage`. Anything needing an account, + sync across devices, or a leaderboard depends on the backend work that + is still in progress, and will be scheduled behind it. + options: + - No, it can work entirely in the browser + - Yes, it needs accounts or cross-device sync + - Not sure + validations: + required: true + + - type: checkboxes + id: constraints + attributes: + label: Constraints you have considered + options: + - label: > + It does not meaningfully grow the initial page download. CI fails + above 180 kB of gzipped initial-load JavaScript, because much of the + audience is on entry-level Android over 3G. + required: false + - label: It works offline, or degrades cleanly without a network. + required: false + - label: I would be willing to open a PR for this. + required: false diff --git a/.github/ISSUE_TEMPLATE/question_error.yml b/.github/ISSUE_TEMPLATE/question_error.yml new file mode 100644 index 0000000..05a3a57 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question_error.yml @@ -0,0 +1,86 @@ +name: Question error report +description: A question has the wrong answer, bad options, or is a duplicate. +title: '[question] ' +labels: [question-bank] +body: + - type: markdown + attributes: + value: | + A wrong answer key teaches the wrong thing, so these are the highest + priority reports in the project. + + Before filing, it helps to know that `scripts/validate-questions.mjs` + already catches several classes of defect automatically, and that + questions it proved unanswerable are listed in + `frontend/src/data/quarantine.json` and withheld from practice. If the + question you hit is already in that file, there is nothing to report — + though a suggested correction is very welcome. + + `docs/question-format.md` explains the data format and every failure + mode the validator checks. + + - type: dropdown + id: chapter + attributes: + label: Chapter + description: Shown in the practice header, and in the URL as `book-chN`. + options: + - ch1 + - ch2 + - ch3 + - ch4 + - ch5 + - ch6 + - ch7 + - ch8 + - ch9 + - ch10 + - Not sure + validations: + required: true + + - type: textarea + id: stem + attributes: + label: The question text + description: > + Copy it exactly. This is what we search the JSON for, so an exact copy + locates the row faster than anything else. + render: text + validations: + required: true + + - type: dropdown + id: defect + attributes: + label: What is wrong with it + options: + - The marked correct answer is wrong + - Two or more options are identical + - No option is correct + - More than one option is correct + - The question text is cut off or incomplete + - It is a duplicate of another question + - Typo or formatting only + - Other + validations: + required: true + + - type: textarea + id: correction + attributes: + label: What it should be + description: > + Which option is actually correct, and ideally why — a textbook section, + a formula, or a past paper. A correction with a source can be applied + directly; one without needs independent verification first. + validations: + required: true + + - type: markdown + attributes: + value: | + **Note on option order.** Options are deliberately reordered before they + are shown to you, because the authored bank has a severe answer-position + bias. "Option B is marked correct but it should be C" is therefore + ambiguous — please quote the option *text*, not its letter or number. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..8d50cce --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,60 @@ + + +## What changed and why + + + +## How it was tested + + + +## Explain the diff in your own words + + + +--- + +### Checklist + +- [ ] `npx tsc -b`, `npm run lint`, `npx vitest run` and `npm run build` all pass locally +- [ ] `node scripts/validate-questions.mjs` passes — required if this touches question data or the loader +- [ ] Initial-load JS is still within budget (the `Frontend` CI job prints the number) +- [ ] No new `eslint-disable`, `@ts-ignore`, `@ts-expect-error` or skipped test; if there is one, the PR explains why +- [ ] `frontend/src/data/bookChapters.generated.ts` is regenerated and committed, if chapter JSONs changed +- [ ] The README and `docs/` still describe what the code actually does + +### If this changes question data + +- [ ] Every row has `correct_option_index` **1-based** and `correct_option` matching the text at that index exactly +- [ ] No duplicate option text within a question, and no duplicate stems against the existing bank +- [ ] The correct answer is not always in the same position — see `docs/question-format.md` +- [ ] Any ids removed from `frontend/src/data/quarantine.json` have had their underlying rows actually fixed diff --git a/.github/scripts/bundle-budget.mjs b/.github/scripts/bundle-budget.mjs new file mode 100644 index 0000000..870f33a --- /dev/null +++ b/.github/scripts/bundle-budget.mjs @@ -0,0 +1,205 @@ +#!/usr/bin/env node +/** + * bundle-budget.mjs + * + * Fails the build when initial-load JavaScript grows past its budget. + * + * Why a hard gate rather than a dashboard: most of this app's audience sits on + * entry-level Android handsets on 3G in Nepal. On a 400 kbit/s effective link, + * every 50 kB of gzipped JavaScript is roughly another second before anything is + * interactive - and that is before the phone has to parse and compile it. A + * budget that nothing enforces is a number in a README; this one blocks the PR. + * + * What counts as "initial-load": exactly the JavaScript the browser fetches + * before it can render the landing page. Vite declares that set in dist/index.html + * as the entry - - -