Document Attachment to Activities
Feature Detail
Description
Document Attachment to Activities allows peer mentors and coordinators to attach supporting files — such as event invitations, Facebook screenshots, or scanned forms — to individual activity registrations. The document attach widget appears on the activity summary screen and the activity detail view, supporting both camera capture and file picker flows. Attached documents are stored securely and linked to the activity record, making them retrievable during Bufdir audit reviews. This feature is specifically requested by NHF for documentary evidence requirements.
Analysis
NHF requires documentary evidence for Bufdir audit purposes — invitations, promotional screenshots, and printed announcements must be traceable to the activity they support. Without in-app attachment, coordinators resort to maintaining parallel paper or email archives, undermining the goal of a single source of truth. Digitizing this evidence chain within the activity record eliminates a significant compliance risk: if Bufdir requests supporting documentation, coordinators can retrieve it instantly rather than searching email archives or physical folders. The feature also future-proofs integrations with accounting systems that may require receipt-level evidence for reimbursement claims.
File handling uses Flutter's image_picker for camera and gallery capture and file_picker for document selection, with size validation (max 10 MB per file, max 5 files per activity) enforced client-side before upload. Files are uploaded to a Supabase Storage bucket with a path structure of {org_id}/{activity_id}/{filename}, with RLS bucket policies restricting access to members of the owning organization. The Document Storage Service generates signed URLs with short TTLs (15 minutes) for secure inline display. Thumbnails for images are generated via Supabase Edge Functions at upload time and stored as separate objects to avoid loading full-resolution files in list views. The activity_documents table records file metadata (name, mime type, size, storage path) linked to the activity_id foreign key with cascade delete.
Dependencies
Definition of Done
Components (5)
User Stories (13)
As a As a user
I want I want to remove an incorrectly attached document from an activity
So that So that I can correct mistakes and ensure only relevant and accurate documentary evidence is associated with the activity record
- Given the user is viewing the document attach widget, when they tap the remove control on a document thumbnail, then a confirmation dialog appears asking them to confirm deletion
- Given the user confirms deletion, when the delete operation completes, then the document thumbnail is removed from the attach widget and the metadata record is deleted from the activity_documents table
- Given the document is deleted from the database, when the deletion propagates, then the corresponding file and thumbnail are also removed from the Supabase Storage bucket
- +2 more
As a As a user
I want I want to remove an incorrectly attached document from an activity
So that So that I can correct mistakes and ensure only relevant and accurate documentary evidence is associated with the activity record
- Given the user is viewing the document attach widget, when they tap the remove control on a document thumbnail, then a confirmation dialog appears asking them to confirm deletion
- Given the user confirms deletion, when the delete operation completes, then the document thumbnail is removed from the attach widget and the metadata record is deleted from the activity_documents table
- Given the document is deleted from the database, when the deletion propagates, then the corresponding file and thumbnail are also removed from the Supabase Storage bucket
- +2 more
As a As a Coordinator
I want I want to review document attachments across activities when preparing Bufdir reports
So that So that I can verify that activities requiring documentary evidence have the necessary files attached before submitting the grant report, reducing the risk of incomplete audit trails
- Given a coordinator is reviewing activities for a reporting period, when they open an activity detail screen, then the document attach widget shows all attached documents for that activity
- Given an activity has no attached documents, when a coordinator views it, then the empty state is clearly visible indicating no evidence has been uploaded
- Given a coordinator identifies a missing document for an activity, when they add a document on behalf of the activity record, then the document is saved and linked to that activity with their user context
- +1 more
As a As a user
I want I want to receive clear, actionable error messages when a file upload fails or violates size or count limits
So that So that I understand exactly what went wrong and what I need to do to successfully attach my document without having to guess or retry blindly
- Given the user selects a file larger than 10 MB, when client-side validation runs, then an error message clearly states 'File is too large. Maximum size is 10 MB.' before any upload attempt
- Given the activity already has 5 documents attached, when the user tries to add another, then a message clearly states the maximum of 5 documents per activity has been reached
- Given a valid file is selected and the upload fails due to a network error, when the error occurs, then a descriptive message is shown with a retry button
- +2 more
As a As a user
I want I want to capture a photo directly using my device camera from within the app and attach it as evidence to an activity
So that So that I can photograph printed invitations, posters, or physical announcements on the spot without needing to use a separate scanning app
- Given the user opens the file upload screen, when they tap the camera option, then the device camera is launched via image_picker
- Given the device camera permission has not been granted, when the camera option is tapped, then a permission request dialog appears and the camera opens only after the user grants permission
- Given the user captures a photo, when the image file size exceeds 10 MB, then the upload is rejected with a clear error message before any upload attempt
- +3 more
As a As a user
I want I want to select an existing file from my device gallery or file picker and attach it to an activity
So that So that I can attach Facebook event screenshots, downloaded flyers, or PDF invitations that I already have on my device without needing to recapture them
- Given the user opens the file upload screen, when they tap the gallery option, then the device photo gallery opens via image_picker allowing selection of an image
- Given the user opens the file upload screen, when they tap the file picker option, then the device file picker opens via file_picker allowing selection of documents (PDF, images)
- Given the user selects a file larger than 10 MB from the gallery or file picker, then an error is shown and the file is not uploaded
- +3 more
As a As a user
I want I want to view all documents attached to an activity when I open its detail view
So that So that I can verify what evidence has been submitted and access the attached files for reference or review
- Given the user opens an activity detail screen that has attached documents, when the document attach widget loads, then it displays thumbnails of all attached documents in a horizontal scroll list
- Given the user taps a document thumbnail, when the document opens, then it is displayed using a signed URL with a 15-minute TTL generated by the Document Storage Service
- Given the activity has no attached documents, when the document attach widget loads, then an empty state message is shown with an option to add a document
- +2 more
As a As a user
I want I want to attach a supporting document to an activity directly from the activity summary screen
So that So that documentary evidence such as event invitations, flyers, or Facebook screenshots is permanently linked to the specific activity record for Bufdir audit purposes
- Given the user is on the activity summary screen, when the document attach widget is displayed, then it shows a horizontal scroll list of existing attachments (empty state if none) and an add button
- Given the user taps the add button, when the file upload screen opens, then the user is presented with options to capture a photo via camera, pick from gallery, or select a file from the device
- Given the user selects a file, when the file size exceeds 10 MB, then an error message is shown client-side and the upload is blocked before any network request is made
- +3 more
As a As a user
I want I want to receive clear, actionable error messages when a file upload fails or violates size or count limits
So that So that I understand exactly what went wrong and what I need to do to successfully attach my document without having to guess or retry blindly
- Given the user selects a file larger than 10 MB, when client-side validation runs, then an error message clearly states 'File is too large. Maximum size is 10 MB.' before any upload attempt
- Given the activity already has 5 documents attached, when the user tries to add another, then a message clearly states the maximum of 5 documents per activity has been reached
- Given a valid file is selected and the upload fails due to a network error, when the error occurs, then a descriptive message is shown with a retry button
- +2 more
As a As a user
I want I want to capture a photo directly using my device camera from within the app and attach it as evidence to an activity
So that So that I can photograph printed invitations, posters, or physical announcements on the spot without needing to use a separate scanning app
- Given the user opens the file upload screen, when they tap the camera option, then the device camera is launched via image_picker
- Given the device camera permission has not been granted, when the camera option is tapped, then a permission request dialog appears and the camera opens only after the user grants permission
- Given the user captures a photo, when the image file size exceeds 10 MB, then the upload is rejected with a clear error message before any upload attempt
- +3 more
As a As a user
I want I want to select an existing file from my device gallery or file picker and attach it to an activity
So that So that I can attach Facebook event screenshots, downloaded flyers, or PDF invitations that I already have on my device without needing to recapture them
- Given the user opens the file upload screen, when they tap the gallery option, then the device photo gallery opens via image_picker allowing selection of an image
- Given the user opens the file upload screen, when they tap the file picker option, then the device file picker opens via file_picker allowing selection of documents (PDF, images)
- Given the user selects a file larger than 10 MB from the gallery or file picker, then an error is shown and the file is not uploaded
- +3 more
As a As a user
I want I want to view all documents attached to an activity when I open its detail view
So that So that I can verify what evidence has been submitted and access the attached files for reference or review
- Given the user opens an activity detail screen that has attached documents, when the document attach widget loads, then it displays thumbnails of all attached documents in a horizontal scroll list
- Given the user taps a document thumbnail, when the document opens, then it is displayed using a signed URL with a 15-minute TTL generated by the Document Storage Service
- Given the activity has no attached documents, when the document attach widget loads, then an empty state message is shown with an option to add a document
- +2 more
As a As a user
I want I want to attach a supporting document to an activity directly from the activity summary screen
So that So that documentary evidence such as event invitations, flyers, or Facebook screenshots is permanently linked to the specific activity record for Bufdir audit purposes
- Given the user is on the activity summary screen, when the document attach widget is displayed, then it shows a horizontal scroll list of existing attachments (empty state if none) and an add button
- Given the user taps the add button, when the file upload screen opens, then the user is presented with options to capture a photo via camera, pick from gallery, or select a file from the device
- Given the user selects a file, when the file size exceeds 10 MB, then an error message is shown client-side and the upload is blocked before any network request is made
- +3 more