No description
Find a file
2026-07-14 09:42:41 +09:00
src Polish EOD screen with 2-column grid, balance display, tighter money calibration (£260 start, £250/day bills). Fix EOD timer transition. 2026-07-14 00:39:41 +09:00
.gitignore Remove node_modules and dist from tracking, add .gitignore 2026-07-14 09:42:41 +09:00
index.html Initial commit: Approve, Please — Papers Please x Bank Change Management hackathon prototype 2026-07-13 23:32:03 +09:00
package-lock.json Polish EOD screen with 2-column grid, balance display, tighter money calibration (£260 start, £250/day bills). Fix EOD timer transition. 2026-07-14 00:39:41 +09:00
package.json Polish EOD screen with 2-column grid, balance display, tighter money calibration (£260 start, £250/day bills). Fix EOD timer transition. 2026-07-14 00:39:41 +09:00
README.md Add README with install, play, and project structure docs 2026-07-14 09:42:26 +09:00
tsconfig.json Initial commit: Approve, Please — Papers Please x Bank Change Management hackathon prototype 2026-07-13 23:32:03 +09:00
vite.config.ts Initial commit: Approve, Please — Papers Please x Bank Change Management hackathon prototype 2026-07-13 23:32:03 +09:00

Approve, Please

A "Papers, Please"-inspired bank change approval simulator. You are an RTB (Run The Bank) Change Approver. BTB developers submit change requests. You approve or deny based on policy, risk, and regulatory requirements. Your decisions have consequences — incidents, blocked releases, and a family that depends on your salary.

Built for a 6-hour hackathon. Stack: React + TypeScript + Vite. Zero backend, zero database. All game state in useReducer.

Quick Start

npm install
npm run dev

Open http://localhost:5173 in a browser.

Production Build

npm run build
npm run preview

Static files land in dist/.

How to Play

Key Action
A APPROVE change request
D DENY change request
I INSPECT attachments (reveals violations)
R Rulebook (policies + market holidays)
N Next (advance to next CR or end of day)
Enter Dismiss faxes, overlays, advance screens
Esc Close modals

Game Rules

  • 60-second day timer. Process as many CRs as you can before the shift ends.
  • £100 per correct decision. Wrong decisions earn nothing.
  • £250 daily household bills. Rent, school, groceries. If you can't pay, family health drops.
  • Family of three. Keiko (spouse), Ren (son, 11), Yuki (daughter, 7). All family dead = game over.
  • Rules accumulate each day. Friday high-risk restrictions, exchange co-ordination, regulatory freeze, segregation of duties.
  • Inspect before you decide. Violations only appear after you click INSPECT.
  • BTB will spam you. Developers, release managers, and directors message your inbox during review.
  • Consequences play out in real time. Citations, incident banners, faxes — all arrive in your inbox after a decision.

Project Structure

src/
├── main.tsx              Entry point
├── App.tsx               Main component — game loop, keyboard, screen routing
├── App.css               All styles (~1100 lines)
├── types.ts              TypeScript interfaces
├── scenarios.ts          Game content — 9 handcrafted CRs, 6 rules, holidays, newspapers, filler templates
├── useGameState.ts       Reducer + side effects (timer, spam, consequence queue)
└── components/
    ├── TopBar.tsx         Date, freeze badge, money, timer
    ├── ChangeRequestPanel.tsx  CR form with signoffs, violations, inspect
    ├── InboxPanel.tsx     Teams-style message feed
    ├── CitationOverlay.tsx    Paper printout citations/faxes
    ├── IncidentBanner.tsx     Red P1 banner
    ├── RulebookModal.tsx      Policies + holiday calendar table
    └── InspectModal.tsx       Attachment review findings

Adding Content

New Change Request (handcrafted)

Add an entry to _SCENARIOS_RAW in src/scenarios.ts:

{
  id: "S10", dayIndex: 2,           // dayIndex: 0=Dec1, 1=Dec5, 2=Dec12, 3=Dec13, 4=Dec20
  changeRequest: {
    id: "CR-5000",
    title: "Your change title",
    service: "Service Name",
    riskLevel: "low",                // "low" | "medium" | "high"
    plan: "Implementation details...",
    testPlan: "Test evidence...",    // null = triggers violation
    backoutPlan: "Rollback plan...", // null = triggers violation
    // ...
  },
  inspectFindings: [...],
  activeRuleIds: ["window_check", "backout_required", ...],
  timeLimit: 45,
  approve: { score: 10, cascade: cleanApproveCascade("Service Name") },
  deny: { score: -5, cascade: [...] },
  correctOutcome: "approve",        // "approve" | "deny" | "ambiguous"
}

New Rule

Add to RULES array in src/scenarios.ts. The check function receives the change request + calendar state and returns a RuleCheckResult. Reference the activeRuleIds in the scenarios where it should fire.

Filler CR Templates

Edit FILLER_TEMPLATES in src/scenarios.ts. Template format:

{ title: "Update {service} ...", risk: "low", testPlan: true, backoutPlan: true, correctOutcome: "approve", plan: "..." }

{service} and {lib} are replaced at random from FILLER_SERVICES and FILLER_LIBS.

Known Gaps

  • No sound effects (stamp thump, fax whine, incident siren)
  • No localStorage persistence (refresh = lose progress)
  • Background tab throttling affects setTimeout consequence delivery
  • No responsive layout (<768px)
  • No test suite configured

License

Hackathon prototype — do whatever you want with it.