Case study · Submissions

File Upload & Image Capture: getting media into an assessment, including inside a locked-down exam

Cadmus could only hold writing — everything else travelled by email, and we lost tenders over it. Two epics, both shipped, including camera capture inside a lockdown browser where file upload has to stay disabled.

My role
Product Manager — epics, user stories, QA, docs
Team
Design, Engineering, Product leadership
Adoption
6 of 12 enterprise tenants
Commercial model
Shipped as a billable add-on
The problem

Plenty of assessment isn't text

Two people were losing time, at opposite ends of the same assessment.

Student

No way to attach a file to a response. Work went out by email, or not at all.

Teacher

Chased those files by hand, then manually related and evaluated them alongside the submission being marked.

Why two months

A missing button is an inconvenience. A reconciliation workflow repeated for every student in a cohort is a recurring tax — and it capped Cadmus at writing-based assessment.

Commercial stake

Live in commercial conversations, including an active tender requiring audio-visual and viva-style assessment. Not shipping risked pilot conversions, not just satisfaction.

Competitive stake

Wiseflow already had an elaborate appendix management feature

  • Upload handwritten elements via webcam inside their lockdown environment (FlowLock).
  • Attach files to an assessment.
  • Draw diagrams in a built-in digital drawing tool and add them to a submission.
The read: this wasn't a nice-to-have gap, it was a column where a competitor had three ticks and we had none — in a category buyers were actively evaluating.
2man-months

Appetite set before solution. Two man-months, fixed. Shaping the solution to fit the time is what kept the out-of-scope list honest.

The constraint

A lockdown browser stops a student reaching their machine, so a file picker can't be allowed — but the exam need is identical. That asymmetry is why the work split in two.

Epic 1

File Upload

Attach existing files to a submission. Establishes the upload API, storage, virus scanning, and the file-state model everything else depends on.

Hard dependency
Epic 2

Image Capture

Photo in-place from the device camera. Depends on the upload pipeline, so it could only follow — and it unlocks the lockdown-exam case.

Why split

Epic 1 could ship and start earning while Epic 2 was still being proven. Bundling them would have held everything behind the harder half.

CapabilityStandard assessmentLockdown browser
File upload
✓ Available
✕ Disabled
Camera capture
✓ Available
✓ Available
Question sets
✕ Phase 2
✕ Phase 2

Proved it with a proof-of-concept on native browser media APIs before pitching — the feature hinged on whether it was possible at all.

The shape

Most of the work was in the states, not the happy path

Uploading a file that works is easy. The spec effort went into everything around it — where I caught a gap in my own.

Teacher setup — Classic assessment
Cadmus assessment editor showing the Enable File Upload toggle under Deliverables
Teacher setup — question level (MFA)
MFA question builder showing Enable File Upload and Camera Capture toggle on an extended response question

Per assessment in Classic, per question in MFA — the same capability exposed at the level each format is authored at.

Student view of a question with Camera and Upload buttons and a 200MB size limit
1 2 3
1Camera and Upload side by side — two routes to the same outcome, so the student doesn't need to know which one their exam mode permits.
2The size ceiling is stated up front rather than discovered on failure.
3Supported formats linked inline — the support article I wrote, reachable at the moment of need.

Sandbox tenant with a test student and placeholder question content.

State 01
Empty

Nothing attached yet. Needs to make the affordance obvious without implying it's mandatory.

State 02
Pre-upload error

Wrong format, or over the size cap. Has to fail before the upload starts, with a reason the student can act on.

State 03
Scanning

Uploaded, being virus-checked, not yet confirmed. The student needs to know their work is safe but not yet final.

Missing from my first spec
State 04
Success

Attached and confirmed, visible to the student and later to the marker alongside the submission.

Gap I caught

Scanning had no design. The state a student is most likely to see and misread — complete, but not confirmed. Catching it in review rather than production changed how I write state coverage.

Camera capture — photo or video
Camera modal open over a Cadmus assessment, showing photo and video tabs and a live webcam feed
Attached and confirmed
Student view showing an uploaded file chip with open and delete actions

Photo and video — what makes async vivas and OSCE-style questions possible, not just handwritten working. Comment anchoring to the file chip shipped and was well received.

Decisions & tradeoffs

Four calls, three of them cuts

50MB
MVP ceiling per file
Raised per tenant, only for the universities that asked
200MB
After customer demand
Decision

Fixed size cap, not a teacher-configurable one

No teacher-set limit in v1. A fixed ceiling meant far less data-handling dependency, so it shipped faster. When teachers surfaced the limit we raised it per tenant to 200MB.

One number, then raised selectively — not globally
Decision

Basic virus checking, not bulletproof virus handling

A file failing scanning after a deadline was real but speculative. De-prioritised to ship faster, basic checker kept. No incident since.

Chose speed to customer over a risk that hadn't materialised
Decision

Question sets excluded from phase 1

Substantial set-flow changes. Cut explicitly and named phase 2 — so it read as a decision, not an oversight.

Named the cut instead of hiding it
Decision

Feature-flagged for commercial packaging

Not a rollout-safety measure. It existed so the capability could be packaged and billed as an add-on rather than absorbed into the base tier.

Shipped as revenue, not as a giveaway
Written into the pitch as explicit no-gos

Two whole capability areas I ruled out before design started

Annotating the content of uploaded files
  • Markup on uploaded images, PDFs or slides
  • Comment anchors tied to content inside a file
  • Timestamped comments on video
Why: each is a marking-tool project in its own right. A marker can view, download and comment on the file as an object — that's enough to make the submission markable. Annotating inside it is a different bet.
Passing files to the LMS on submission
  • Sending uploaded files out to the LMS for submissions marked outside Cadmus Marker
Why: not every format is supported downstream and no two LMSs handle this the same way. Committing to it means owning an integration surface that varies per customer — for a v1, the cost is unbounded.
Quality

What my own QA passes caught

Two full QA passes, logged. Gaps that don't appear in a spec review — but would have appeared in the support queue.

1

Missing formats in the supported matrix — audio and older spreadsheet types students would obviously reach for.

2

Duplicate file handling was undefined — what should happen when a student attaches the same file twice hadn't been specified either way.

3

The virus-scan path wasn't verifiable — no way to test a rejection until a harmless standard test file was used to trigger one.

4

Selection state persisted when it shouldn't — a UI state carried over between contexts in a way that would have confused markers.

Also mine

Teacher setup and student submission, both written by me. Documentation is part of shipping — writing it finds the parts of a flow you can't explain simply.

Impact

Adoption and reach

6 / 12
enterprise tenants have it enabled. It opened Cadmus to assessment types it previously couldn't hold — photographed working, audio, video, and specialist engineering file formats added after launch on the same pipeline.
Hero item in the January release Comment anchoring on file chips — well received Camera capture works inside lockdown exams Two support articles authored & published Billable add-on

What I'd do differently

I specced from the happy path outward — the scanning state is the proof. I'd now enumerate states before flows: every condition, transient and failed, then the paths between them.

What I'd repeat

Shipping 50MB and moving it later. Waiting until several universities independently raised the limit made 200MB a two-line justification, not a debate.