FTM401 · Examination paper
90 minutes · written · open book (notes) · no internet · 40 marks · pass 20
Section A — surface, service, file (16 marks, 8 × 2)
Section titled “Section A — surface, service, file (16 marks, 8 × 2)”For each URL, name the surface, the service that answers, and the file you would open first.
https://www.fixthemusic.com/browse/londonhttps://musicians.staging.fixthemusic.com/pandemoniums/messages/https://admin.staging.fixthemusic.com/admin/booking/enquiry/https://www.fixthemusic.com/blog/some-posthttps://staging.fixthemusic.com/api/routing/https://musicians.staging.fixthemusic.com/musician-api/v0/messages/https://help.fixthemusic.com/(orfrontend-help)https://staging.fixthemusic.com/enquiries/u63n1ym6d1
Section B — cacheability (10 marks, 2 × 5)
Section titled “Section B — cacheability (10 marks, 2 × 5)”For each, say whether the response can be cached by the CDN, what makes it cacheable or not, and the header you would set.
B1. A public band profile page. B2. The dashboard thread page above, as a logged-in musician.
Section C — find the defect (8 marks)
Section titled “Section C — find the defect (8 marks)”"use client";export default function Thread({ id }) { const [msgs, setMsgs] = useState([]); useEffect(() => { fetch(`/api/messages/${id}`).then(r => setMsgs(r.json())); }, []); return msgs.map((m, i) => <div key={i}>{m.body}</div>);}Name three defects, the class of each, and the fix. One defect is about error handling, one about React keys, one about a promise.
Section D — supervise the change (6 marks)
Section titled “Section D — supervise the change (6 marks)”You are asked to add a “mark all read” button to the dashboard thread list.
State: which surface and file, whether it needs a client boundary, how the request should be issued (Unpoly or fetch, and why), and what must be true for the action to be authorised.
Marking guide
Section titled “Marking guide”| Section | Marks |
|---|---|
| A | 2 each: 1 surface/service, 1 file |
| B | 5 each: 2 verdict, 2 reason, 1 header |
| C | 8: ~2.5 per defect, 0.5 for the fix |
| D | 6: 1 surface/file, 2 boundary, 2 request shape, 1 authorisation |
Pass 20/40. Distinction 28.
Expected answers:
- 1 public site, Next.js,
frontend/src/app/browse/[[...slug]]/page.js - 2 dashboard, Django SSR,
bands/dashboard/message_views.py+bands/templates/dashboard/ - 3 admin, Django admin,
booking/admin*.py - 4 Astro blog, Cloudflare Pages,
frontend-blog/ - 5 Django,
routing.urls,ftm/urls.py:117 - 6 Ninja API,
bands/api_v2/routers/messages.py - 7 Astro (help),
frontend-help/ - 8 public site, Next.js,
frontend/src/app/enquiries/ - B1 cacheable; no session read;
public, s-maxage=300, stale-while-revalidate=600 - B2 not cacheable; session-dependent;
private, no-store - C
r.json()returns a promise — needs.then(r => r.json()).then(setMsgs)or an async fn;.then()with no.catchswallows failures (a 500 renders as empty); index keys break when the list reorders; andr.okis never checked, so an error body is treated as data. - D dashboard,
bands/dashboard/message_views.py+ template; no client boundary needed (Unpoly form/link);up-targetto the list fragment so only the list updates; authorisation must check band membership server-side per request, and the POST needs CSRF.