Application Architecture
Structure
Application
Census 2026
Module
Census
Single-application, single-module structure. Keeps dependencies minimal and the codebase straightforward to follow during implementation.
Data Model
Entities & Relationships
creates (1:N) uploads (1:N)
User
int
Id
PK
text
Name
text
Username
email
Email
text
Password
CensusData
int
Id
PK
text
Name
text
Surname
date
DOB
int
CreatedBy
FK
dttm
CreatedOn
CensusBulkUploadLog
int
Id
PK
text
Filename
text
FileExtension
text
BlobName
int
AddedBy
FK
dttm
CreatedOn
bool
IsProcessed
dttm
ProcessedOn
Legend:
PKPrimary Key
FKForeign Key
One-to-Many (1:N)

User Stories

10 stories covering the full implementation. Click any story to expand.

As an Architect, I want to create the Census 2026 application with a single Census module and set up all required database entities so the team has a clean foundation to build on.
Story Points
2 Setup / configuration
Acceptance Criteria
  • Application "Census 2026" and module "Census" are created and published successfully.
  • All three entities (User, CensusData, CensusBulkUploadLog) exist with correct field names and data types.
  • Foreign key relationships are configured between User and both child entities.
Validation Scenarios
  • Publish succeeds with no errors or warnings in Service Studio.
  • FK constraints are enforced — inserting a record with an invalid UserId is rejected by the database.
Done Done Checklist
  • Application and module created and published.
  • All 3 entities present with correct fields and types.
  • FK relationships configured and verified in database.
  • No broken references or publish warnings.
Service StudioEntitiesData Model
As a User, I want to view a paginated list of survey records and add new entries so I can manage census data directly from the application.
Story Points
3 Screen + form + server action
Acceptance Criteria
  • Survey List screen displays Name, Surname, and DOB columns with pagination at 50 records per page.
  • Clicking "Add Survey" opens the form and saves a new record to the CensusData entity on submit.
  • All fields are mandatory — attempting to submit with empty values shows an inline error.
Validation Scenarios
  • Submit with empty Name field — validation error shown, no record saved.
  • Enter a future date as DOB — validation error shown.
  • Enter valid data — record is saved and appears in the list.
Done Done Checklist
  • Survey List screen loads with paginated data.
  • Add Survey form opens, validates, and saves correctly.
  • New record is visible in the list immediately after save.
  • Validation messages display for all invalid inputs.
ScreenAggregateServer ActionValidation
As a User, I want to upload an Excel file through a popup on the Survey List screen so I can add many records at once without entering them one by one.
Story Points
2 Popup + file picker UI
Acceptance Criteria
  • Clicking "Upload Bulk Records" opens the upload popup.
  • Only .xlsx files are accepted — all other formats are rejected with an error message.
  • A confirmation message is displayed after a successful upload.
Validation Scenarios
  • Attempt to upload a .csv or .pdf file — error message is shown, upload is blocked.
  • Click Upload without selecting a file — upload button remains disabled.
  • Upload a valid .xlsx file — confirmation message appears.
Done Done Checklist
  • Popup opens and closes correctly from the Survey List screen.
  • File type validation fires before the upload is submitted.
  • Success confirmation shown after upload completes.
  • Popup state resets when closed.
PopupFile UploadClient Validation
As a Backend Process, I want to persist the uploaded file in Azure Blob Storage so it is safely stored before processing begins — without any credentials hardcoded in application logic.
Story Points
3 Blob upload + log insert
Acceptance Criteria
  • A CensusBulkUploadLog record is inserted with IsProcessed = False before the file is uploaded.
  • BlobName is constructed using the log Id, a timestamp, and the original filename.
  • The file is successfully stored in Azure Blob using AzureBlobConnector.
  • Connection string and container name are read exclusively from Site Properties.
Validation Scenarios
  • Incorrect Site Property value — exception is caught and a user-friendly error is shown.
  • Successful upload — BlobName is stored in the log record and file is visible in Azure container.
  • Code review confirms no hardcoded credentials anywhere in the module.
Done Done Checklist
  • Log record created with IsProcessed = False before blob upload.
  • BlobName constructed correctly (Id + timestamp + filename).
  • File confirmed present in Azure Blob container after upload.
  • Connection string and container name stored in Site Properties only.
Azure BlobAzureBlobConnectorSite PropertiesServer Action
As a BPT Process, I want to automatically read the uploaded file from Azure Blob, validate each row, and insert valid records into CensusData — running entirely in the background without blocking the user.
Story Points
5 BPT + row loop + validation logic
Download Sample Survey Data File (sample_survey_data.xlsx)
Acceptance Criteria
  • BPT is triggered asynchronously — the user is not blocked after uploading the file.
  • Each row is validated: Name and Surname must not be empty; DOB must be a valid non-future date.
  • Valid rows are inserted into CensusData; invalid rows are logged with the row number and reason.
Validation Scenarios
  • Row with empty Name — skipped and recorded in the error log.
  • Row with a future DOB — skipped and recorded in the error log.
  • File with all valid rows — all rows inserted into CensusData without errors.
Done Done Checklist
  • BPT created and triggered asynchronously from the upload flow.
  • File downloaded from Azure Blob and processed row by row.
  • Valid records inserted into CensusData entity.
  • Invalid rows captured in error log with row number and reason.
BPTAsync ProcessingExcel ReadError Logging
As a BPT Process, I want to send an email to the uploader once file processing is complete — including a summary of how many records were processed, inserted, and failed.
Story Points
2 SendEmail at BPT completion
Acceptance Criteria
  • Email is sent to the user who uploaded the file upon BPT completion.
  • Email subject is "Census 2026 – Bulk Upload Complete" and body includes total, inserted, and failed counts.
  • CensusBulkUploadLog is updated: IsProcessed = True and ProcessedOn is set.
Validation Scenarios
  • BPT completes processing — email is received with correct record counts.
  • Log record reflects IsProcessed = True and ProcessedOn is populated.
Done Done Checklist
  • SendEmail action triggered at the end of the BPT flow.
  • Email body contains total, inserted, and failed counts.
  • BulkUploadLog IsProcessed = True and ProcessedOn is set correctly.
  • Email delivery confirmed — no errors in Service Center logs.
SendEmailBPTEmail Template
As a User, I want to export all census records to an Excel file by clicking the Download button — with a loading spinner that blocks further interaction until the export is ready.
Story Points
3 Export + spinner + UI block
Acceptance Criteria
  • Clicking Download shows a full-screen spinner and blocks all user interaction during export.
  • All records are fetched without pagination and exported using ExcelUtils.
  • File downloads with the name SurveyData_{CurrentDate}.xlsx.
  • Spinner is hidden on successful completion and also on error.
Validation Scenarios
  • Click Download — spinner appears and screen is blocked immediately.
  • Export completes — file downloads and spinner is hidden.
  • Server error during export — spinner is hidden and a user-friendly error message is shown.
Done Done Checklist
  • Spinner displayed on Download click, screen interaction blocked.
  • All records included in export (pagination bypassed).
  • File name includes current date.
  • Spinner hidden correctly on both success and error paths.
ExcelUtilsBinary DownloadLoading Spinner
As a User, I want to click a Refresh button on the Survey List to reload the latest data without triggering a full page reload.
Story Points
1 Ajax Refresh on aggregate
Acceptance Criteria
  • The Refresh button calls Ajax Refresh on the GetSurveys aggregate — no full page reload occurs.
  • Pagination resets to page 1 after each refresh.
  • The latest records are shown after the refresh completes.
Validation Scenarios
  • A record added in a separate session — clicking Refresh shows it in the list.
  • Confirm via browser network tab that no full page request is made.
Done Done Checklist
  • Refresh button wired to Ajax Refresh on the aggregate.
  • Table updates in-place; pagination resets to page 1.
  • No full page reload triggered on Refresh.
Ajax RefreshAggregate
As a Background Timer, I want to call the third-party vendor's REST API every night at 10:00 PM, retrieve new census records, and insert them into CensusData — skipping any records already present in the system.
Story Points
5 Timer + REST API + dedup logic
View API Document
Acceptance Criteria
  • Timer SyncVendorSurveyData runs automatically every day at 22:00.
  • New records from the vendor API are inserted into the CensusData entity.
  • Duplicate records — matched on Name + Surname + DOB — are skipped without error.
  • Each sync run is logged in VendorSyncLog with run time, records fetched, inserted, and status.
Validation Scenarios
  • API returns new records — all are inserted correctly.
  • API returns records already in the system — duplicates are skipped, no error thrown.
  • API call fails — exception is handled gracefully and log entry is created with error status.
Done Done Checklist
  • Timer created in Service Studio and scheduled at 22:00 in Service Center.
  • Vendor REST API consumed with auth headers injected via OnBeforeRequest.
  • Duplicate check (Name + Surname + DOB) working before each insert.
  • VendorSyncLog captures each run with full counts and status.
TimerREST APIOnBeforeRequestDuplicate CheckVendorSyncLog
As a User, I want the dashboard to display real-time census KPIs — total members, weekly additions, Gen Z statistics, and an age group chart — refreshing automatically every 60 seconds.
Story Points
5 KPIs + chart + auto-refresh
Acceptance Criteria
  • Dashboard displays: total survey members and count added in the current week.
  • Gen Z count (DOB within last 25 years) and percentage of total are shown.
  • Members-by-age-group column chart renders correctly on page load.
  • Dashboard data refreshes every 60 seconds and the Last Refreshed timestamp updates each cycle.
Validation Scenarios
  • Add a new record — total member count updates on the next auto-refresh cycle.
  • Verify Gen Z percentage matches a manual calculation against the database.
  • Last Refreshed timestamp changes visibly after each 60-second interval.
Done Done Checklist
  • Aggregate GetDashboardKPIs returns correct member counts.
  • Gen Z filter applied as: DOB > (CurrDate minus 25 years).
  • Column chart grouped by age category renders without errors.
  • setInterval + Ajax Refresh runs every 60 seconds — no full page reload.
  • Last Refreshed timestamp updates on every refresh cycle.
AggregateSQL QueryChartsetIntervalAjax Refresh

Common Acceptance Criteria — Applies to All Stories

  • All input fields must be validated on the client side before any server call is made.
  • Every server action must include exception handling and return a clear, user-friendly error message on failure.
  • No credentials, connection strings, or API keys are hardcoded — all must be stored in Site Properties.
  • All background processes (BPT, Timer) must log each execution with its outcome and relevant counts.
  • Duplicate records must be detected and skipped — never silently overwritten.