Live classroom exercise for two managerial accounting cases. Six teams work a shared worksheet; the teacher paces the room from one dashboard.
| Case | Organisation | Steps |
|---|---|---|
| Problem 4B-5 (LO4-11) | Woodbury Hospital | 3, step-down into three billing centers |
| Case 4B-6 (LO4-10, LO4-11) | Highland Publishing | 6, step-down then direct, with the rate comparison |
| Page | |
|---|---|
index.html |
Lobby: name, then pick a team (ids in TEAM_IDS) |
team.html |
The team's shared worksheet |
teacher.html |
Dashboard, password gated |
solo.html |
Same exercise, single player, no backend |
Students open the site, enter a name, pick a team. Everything a teammate types appears in the others' boxes within a second, and a name tag shows who is in which cell.
The teacher sets the pace: students can only open the selected step, and everything past it reads "Not open yet". A master toggle switches the whole room between cases.
There is no answer checking. Teams type what they think and mark themselves ready. The teacher's Side by side table shows every team's figures for the current step, correct in green and wrong in red, with the answer row on top. Project it and the disagreements between groups become the discussion.
The × beside a name removes a student; ↩ or Let everyone back in reverses it.
Visual language follows artificialanalysis.ai: true black on white, hairline rules, one blue-grey tint doing the surface work, serif display headings over a 14px Inter UI, no shadows. Light only, as theirs is. Two deliberate departures, both for the subject matter: money stays right-aligned with tabular figures because accounting needs decimal alignment, and correct/wrong keeps a colour because the dashboard exists to show it, with a dotted underline so colour is not the only signal.
Static files on GitHub Pages, Firebase Realtime Database for shared state. No build step.
index.html team.html teacher.html solo.html
assets/
config.js Firebase config, team count, password hash
db.js storage layer
data.js both cases and their arithmetic
exercise.js worksheet and step logic
style.css
database.rules.json
Wired to Firebase project ad2102-43142. Blank the config and every page falls back to
local demo mode: still works, one browser, nothing syncs. The apiKey is public by design;
access is controlled by database.rules.json.
The teacher password is a client-side gate. hello123 is stored only as a SHA-256 hash,
but DevTools gets past it.
Anyone can also read /session, so a student who goes looking can pull classmates' uids out
of members and write to /session/banned/, or flip /session/meta. The rules validate the
shape of those writes so nothing can corrupt other people's pages, and Let everyone back
in undoes a mass removal in one click, but the writes themselves cannot be blocked without
server-verified identity.
Fixing that takes one click in the Firebase console: Authentication → Get Started, enable
Anonymous and Email/Password, add a teacher account. Rules can then key on auth.uid and
auth.token.email. The management API cannot do this on the free tier.
The kick itself is server-enforced. The rules refuse any write adding a banned uid to a team:
"members": {
"$uid": {
".write": "!newData.exists() || !root.child('session/banned').child($uid).exists()"
}
}A removed student gets Permission denied from Firebase. The !newData.exists() clause is
what still lets the teacher delete them. Clearing browser storage gets a fresh uid and evades
it, which is the right level for a classroom.
/session/teams/<id>/members/<uid> = {name, at}
/session/teams/<id>/work/<case>/<step> = {pool, base, rate, alloc:{dept:val}, by, at}
/session/teams/<id>/ready/<case>/<step> = true
/session/teams/<id>/focus/<uid> = {field, name}
/session/banned/<uid> = {name, team, at}
/session/meta/problem = 4B-5 | 4B-6
/session/meta/step = 1..6
Nothing students see comes from the answer key. Totals are computed from what they typed, so
a wrong entry shows as that wrong entry. Only teacher.html reads the solution.
Three details that matter:
- Work is written with
update()on leaf paths (alloc/food), neverset()on the whole step. Otherwise two teammates filling different cells each write a full object built from their own screen and the last one wins, erasing the other with no error. - A field is never overwritten from the server while focused or within 2.5s of a keystroke, with a reconcile pass afterwards so the two sides cannot stay apart.
onDisconnectfires on any drop and is registered per connection on a shared uid, so a phone locking its screen or a second tab closing would delete a seat still in use. The page re-asserts membership on reconnect, when a snapshot shows it missing, and on a 6s tick.
Storage is tried localStorage → sessionStorage → memory. Safari private browsing and "block all cookies" make localStorage throw, which otherwise left the student with no name and bounced them out of every worksheet.
ES modules need a real origin:
python3 -m http.server 8899
# http://localhost:8899/Talks to the same live Firebase, so two browser profiles are enough to test syncing.
Push to main; .github/workflows/pages.yml publishes to
https://klaud-cold.github.io/AD2102/ in about 20 seconds.
Change the password by hashing a new one into assets/config.js:
node -e 'console.log(require("crypto").createHash("sha256").update("NEW").digest("hex"))'Reset whole session clears every answer and removal. Anyone still on the page re-takes their seat within a few seconds, which is intended.
Requirement 3 of 4B-6, bidding the job. Needs a different worksheet shape. For the board:
| Machine-hours | Direct labor-hours | |
|---|---|---|
| Printing | 15,400 | 900 |
| Binding | 800 | 2,000 |
Step-down: 15,400 × $6.12 + 2,000 × $3.90 = $102,048 Direct: 15,400 × $5.8433 + 2,000 × $4.1371 = $98,262
The job is printing-heavy, so the direct method under-costs it by about $3,800.
| Housekeeping | Food | Admin | Laboratory | Radiology | General | Total | |
|---|---|---|---|---|---|---|---|
| Departmental costs | 87,000 | 301,060 | 249,020 | 405,900 | 520,500 | 475,800 | 2,039,280 |
| 1. Housekeeping @ $0.60/sq ft on 145,000 | (87,000) | 7,800 | 3,900 | 6,000 | 4,500 | 64,800 | |
| 2. Food @ $4.3017/meal on 71,800 | (308,860) | 3,441 | 8,603 | 4,302 | 292,514 | ||
| 3. Admin @ $5.5731/file on 46,000 | (256,361) | 78,023 | 39,012 | 139,327 | |||
| Total | 0 | 0 | 0 | 498,526 | 568,313 | 972,440 | 2,039,280 |
Housekeeping's base excludes its own 5,000 sq ft: 145,000, not 150,000. Each pool grows on the way down: Food allocates 308,860, not 301,060.
| Personnel | Custodial | Maintenance | Printing | Binding | Total | |
|---|---|---|---|---|---|---|
| Budgeted overhead | 360,000 | 141,000 | 201,000 | 525,000 | 373,500 | 1,600,500 |
| 1. Personnel @ $1,800/employee on 200 | (360,000) | 27,000 | 45,000 | 72,000 | 216,000 | |
| 2. Custodial @ $1.20/sq ft on 140,000 | (168,000) | 24,000 | 96,000 | 48,000 | ||
| 3. Maintenance @ $1.50/MH on 180,000 | (270,000) | 225,000 | 45,000 | |||
| Total | 0 | 0 | 0 | 918,000 | 682,500 | 1,600,500 |
Rates: Printing $6.12/MH, Binding $3.90/DLH.
Personnel's base drops its own 10 employees (200). Custodial's base drops two departments, Personnel's 4,000 sq ft and its own 6,000, giving 140,000.
Same budgeted costs again. Nothing accumulates; nothing reaches a service department.
| Personnel | Custodial | Maintenance | Printing | Binding | Total | |
|---|---|---|---|---|---|---|
| Budgeted overhead | 360,000 | 141,000 | 201,000 | 525,000 | 373,500 | 1,600,500 |
| 4. Personnel @ $2,250/employee on 160 | (360,000) | 90,000 | 270,000 | |||
| 5. Custodial @ $1.175/sq ft on 120,000 | (141,000) | 94,000 | 47,000 | |||
| 6. Maintenance @ $1.1167/MH on 180,000 | (201,000) | 167,500 | 33,500 | |||
| Total | 0 | 0 | 0 | 876,500 | 724,000 | 1,600,500 |
Rates: Printing $5.8433/MH, Binding $4.1371/DLH.
Printing costs more under step-down because Maintenance carries what it picked up from Personnel and Custodial, and Printing runs almost all the machine-hours.
Figures turn green on the dashboard within ±$1.50, so rounding to whole dollars or carrying decimals both read as correct.