Contributor guide
Adding Questions
Everything lives in data/questions.js. Edit it in any text editor
and reload the browser. There is no build step.
Add one question
Append an object to window.QUESTION_BANK, before the closing ];.
{set:"doctrine", ref:"SEC. 19", q:"When does the right to object not apply?",
hint:"No right under the DPA is absolute. Say that first.", pts:[
"It yields where processing rests on a legal obligation.",
"It yields where processing is necessary to fulfil a contract the subject entered.",
"Say plainly that no right under the DPA is absolute — that framing scores."
], cite:"Secs. 16(b), 19, RA 10173"},
The fields
| Field | Type | Notes |
|---|---|---|
| set | string | Must match an id in QUESTION_SETS. Never "all" — that is the view showing everything |
| ref | string | Short docket reference shown on the card. Keep it under about 14 characters |
| q | string | The question, phrased the way an interviewer would say it |
| hint | string | Optional. Shown when the user presses hint. Say what the question is really getting at — never the answer |
| pts | array | Points a good answer hits. Wrap emphasis in <em> |
| cite | string | The authority. This is what you are really memorising |
← swipe tables sideways
You almost certainly dropped a comma. Trailing commas between objects are fine; a missing one is not. Open the browser console with F12 and look for a syntax error on the line you touched.
Add a whole set
Two steps.
1. Register the set
Add it to QUESTION_SETS at the top of data/questions.js.
window.QUESTION_SETS = [
{ id:"all", label:"Full docket" },
{ id:"basics", label:"Start here" },
{ id:"role", label:"The role" },
{ id:"doctrine", label:"Doctrine" },
{ id:"enforce", label:"Enforcement" },
{ id:"build", label:"Software" },
{ id:"scenario", label:"Scenarios" },
{ id:"fintech", label:"Fintech" } // new
];
2. Tag the questions
Give them set:"fintech". The tab, the count, the welcome-screen card, and the filter all appear on their own.
Order in QUESTION_SETS is the order of the tabs and of the welcome picker. Keep "all" first.
Optional: a welcome-screen description
Add a one-line blurb in the BLURB object near the top of assets/js/app.js, keyed by set id. Without one, the card simply shows no description.
var BLURB = {
basics: "Plain-language foundations. Start here if privacy is new to you.",
fintech: "BSP overlay, SIM registration, e-wallet KYC. For a bank or lender."
};
Writing good practice questions
Phrase it the way a person would say it
"Walk me through the breach notification decision" beats "Discuss breach notification requirements." You are rehearsing a conversation, not an exam.
Points, not a script
You will never reproduce a paragraph under pressure, and trying to makes you sound rehearsed. Four to six points you can hit in any order is what a fluent answer is actually made of.
Lead with the framing move
The best answers open with a distinction rather than a fact — "start by saying it is prohibited by default", "do not lead with no". Put that as the first point.
One authority per card
If you cannot name what backs the answer, the question is probably too vague to be useful.
Write hints that reframe, never answer
A good hint says what kind of question this is — "conflict of interest, say the phrase out loud", "three conditions, all required". A bad hint leaks a point from the answer.
Could someone score well on the card using only the hint? If yes, rewrite it.
Include the trap
Where candidates commonly go wrong, say so in a point: "there is no adequacy regime like the GDPR — a common candidate mistake." Rehearsing the correction is what stops you making it.
Suggested sector sets
Worth building once you know the employer's industry. Sector-specific answers separate a candidate who read the Act from one who understands the job.
| Sector | Add questions on |
|---|---|
| Fintech / banking | BSP circulars on consumer protection and IT risk, the SIM Registration Act, AMLA interaction with the Sec. 4 exclusion, e-wallet KYC data |
| Healthcare | DOH and PhilHealth data rules, medical records retention, the Sec. 13(e) medical treatment basis, telemedicine platforms |
| BPO / outsourcing | PIP obligations end to end, client-as-PIC relationships, cross-border flows, PEZA and client audit requirements |
| Education | DepEd and CHED issuances, minors' data and parental consent, learning platform vendors |
| Government | Public sector registration duties, Sec. 36 disqualification, FOI interaction, agency data sharing |
Tuning the drill
Near the top of assets/js/app.js.
var MISS_GAP = 3; // how many cards until a missed question returns
var TARGET = 90; // clock turns amber here
var LONG = 150; // clock turns red here
- Lower
MISS_GAPto hammer weak areas harder. - Lower
TARGETif a recruiter screens you first — those calls move faster and reward tighter answers.
Keyboard shortcuts
| Key | Does |
|---|---|
| space | Reveal the points to hit |
| 1 | Knew it — retires for the session |
| 2 | Shaky — back of the queue |
| 3 | Missed it — returns three cards later |
| h | Show the hint |
| s | Skip to the back without grading |
Progress is held in memory only and clears on reload. That is deliberate — you want to answer cold each time, not accumulate a comforting score.
The question bank ships as a plain script rather than JSON loaded by fetch, so the app runs from file:// with no local server. That is why you edit a .js file rather than a .json one.