Skip to content

Commit 8039f8b

Browse files
Comprehensive README (#124)
1 parent 3bfea53 commit 8039f8b

1 file changed

Lines changed: 140 additions & 0 deletions

File tree

README.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Apply to transfer an academy – External Applications Web
2+
3+
This repository contains the Razor Pages frontend for submitting applications to transfer academies into another trust. It uses a Clean Architecture layout (Domain ➜ Application ➜ Infrastructure ➜ Web) and drives every screen from JSON form templates delivered by the External Applications API. Template-driven pages, conditional logic, file uploads, and contributor management are all orchestrated in the web layer while persistence and validation live in the API.
4+
5+
## Features
6+
- 🧩 Template-driven form engine: tasks/pages/fields come from template schemas fetched via `ITemplatesClient` and parsed into domain models.
7+
- 🔀 Dynamic logic: conditional visibility/requirements, collection flows, and derived collection flows handled server-side in `RenderForm`.
8+
- 👥 Contributor management: invite/remove contributors before entering the form and keep application state in session + API.
9+
- 🔐 Secure authentication: DfE Sign-in (OIDC) plus optional internal/test schemes; session-based token refresh and permissions caching.
10+
- 🛡️ File uploads with AV protection: files posted to the API, scanned asynchronously, and cleaned/blacklisted when `ScanResultConsumer` receives an infected result.
11+
- 📢 Notifications and events: publishes `TransferApplicationSubmittedEvent` to Azure Service Bus after successful submission; renders API-sourced notifications to users.
12+
- 🚀 Production-ready concerns: redis + memory hybrid caching, gzip compression, Application Insights, GovUK Frontend rebrand, and MassTransit transport setup.
13+
- 🛠️ Admin tools: role-restricted admin pages let you view the current template metadata, clear caches/sessions, and publish a new template version directly through the UI (with validation and cache invalidation).
14+
15+
## Architecture Overview 🧱
16+
- **Web (Razor Pages)**: UI, request pipeline, auth, cookies, session, and form rendering (`Pages/FormEngine`, `Pages/Applications`, feedback, notifications).
17+
- **Application**: Interfaces for form orchestration, state, validation, uploads, and event mapping.
18+
- **Domain**: Template and form primitives (`FormTemplate`, `TaskGroup`, `Task`, `Page`, `Field`, `ConditionalLogic`, `EventMapping`).
19+
- **Infrastructure**: Implementations that call the External Applications API (`IApplicationsClient`, `ITemplatesClient`, `INotificationsClient`), template stores/parsers, MassTransit consumers, redis-backed caching, and file upload handling.
20+
- **Tests**: Unit tests for infrastructure/web and Cypress end-to-end specs.
21+
22+
## System Flow (happy path) 🔄
23+
1. **Sign in** via DfE Sign-in (or test/internal auth in non-prod). Permissions are cached and refreshed via `TokenRefresh` settings.
24+
2. **Dashboard** shows the user’s applications for the configured template; “Create” calls `CreateApplicationAsync`, stores IDs in session, and clears cached form data.
25+
3. **Contributors** page lets the lead applicant manage collaborators before entering the form.
26+
4. **Form engine** loads the current template (cached via `FormTemplateProvider` + `ApiTemplateStore`), restores response data from the API/session, and renders pages with conditional logic, collection flows, and complex fields (autocomplete, upload).
27+
5. **File uploads** are sent to the API; scan results arrive on Azure Service Bus and `ScanResultConsumer` removes infected files, clears redis cache, and raises a user notification.
28+
6. **Validation and navigation** are handled server-side; task completion is tracked per-task and persisted back through `IApplicationResponseService`.
29+
7. **Submit** posts final responses to the API and publishes `TransferApplicationSubmittedEvent` to the Service Bus using the configured event mapping for the transfer template.
30+
31+
Example event publication in the form engine:
32+
33+
```3554:3592:src/DfE.ExternalApplications.Web/Pages/FormEngine/RenderForm.cshtml.cs
34+
/// Publishes the TransferApplicationSubmittedEvent to the service bus
35+
/// Uses the event data mapper to extract and transform form data according to the configured mapping
36+
private async Task PublishApplicationSubmittedEventAsync(ApplicationDto application)
37+
{
38+
var eventData = await _eventDataMapper.MapToEventAsync<TransferApplicationSubmittedEvent>(
39+
FormData,
40+
Template,
41+
"transfer-application-submitted-v1",
42+
application.ApplicationId,
43+
application.ApplicationReference);
44+
await publishEndpoint.PublishAsync(eventData, messageProperties, CancellationToken.None);
45+
}
46+
```
47+
48+
## Key configuration ⚙️
49+
All settings are standard ASP.NET Core configuration keys (appsettings or environment variables). Important ones:
50+
51+
| Key | Purpose | Dev value / notes |
52+
| --- | --- | --- |
53+
| `DfESignIn:Authority` / `ClientId` / `ClientSecret` / `RedirectUri` | OIDC login | Dev authority `https://test-oidc.signin.education.gov.uk`; set secrets locally. |
54+
| `ExternalApplicationsApiClient:BaseUrl` | Backend API endpoint | `https://api.dev.apply-transfer-academy.service.gov.uk` (see `appsettings.Development.json`). |
55+
| `ExternalApplicationsApiClient:ClientId` / `ClientSecret` / `Authority` / `Scope` | API auth (Azure AD) | ClientId preset; supply `ClientSecret` via user-secrets/env. |
56+
| `Template:Id` | Template to render | Default transfer template `9A4E9C58-9135-468C-B154-7B966F7ACFB7`. |
57+
| `FormEngine:ComplexFields` | External search endpoints | Dev APIs for trusts and establishments are prefilled in `appsettings.Development.json`. |
58+
| `MassTransit:Transport` / `AzureServiceBus:ConnectionString` | Service Bus for events & AV scan results | Provide connection string to receive scan results and publish submissions. |
59+
| `ConnectionStrings:Redis` | Redis for hybrid caching and sessions | Default `localhost:6379`. |
60+
| `ApplicationInsights:ConnectionString` | Telemetry | Optional locally; required in cloud. |
61+
| `TokenRefresh:*` | Session/token refresh windows | Defaults provided in `appsettings.json`. |
62+
| `InternalServiceAuth:*` | Service-to-service auth | Used for internal APIs and virus-scan cleanup. |
63+
64+
## Running locally 🖥️
65+
Prerequisites: .NET 8 SDK, Redis (local or container), Node/npm if running Cypress, and access to the dev External Applications API + Azure AD app registration.
66+
67+
1) Clone and restore
68+
```bash
69+
dotnet restore DfE.ExternalApplications.Web.sln
70+
```
71+
72+
2) Configure secrets (examples)
73+
```bash
74+
# Auth & token refresh
75+
dotnet user-secrets set "DfESignIn:ClientSecret" "<oidc-client-secret>" --project src/DfE.ExternalApplications.Web
76+
dotnet user-secrets set "TokenRefresh:ClientSecret" "<oidc-client-secret>" --project src/DfE.ExternalApplications.Web
77+
78+
# External Applications API auth
79+
dotnet user-secrets set "ExternalApplicationsApiClient:ClientSecret" "<api-client-secret>" --project src/DfE.ExternalApplications.Web
80+
81+
# Messaging / telemetry / cache
82+
dotnet user-secrets set "MassTransit:AzureServiceBus:ConnectionString" "<sb-connection>" --project src/DfE.ExternalApplications.Web
83+
dotnet user-secrets set "ApplicationInsights:ConnectionString" "<ai-connection>" --project src/DfE.ExternalApplications.Web
84+
dotnet user-secrets set "ConnectionStrings:Redis" "localhost:6379" --project src/DfE.ExternalApplications.Web
85+
86+
# Internal service-to-service auth
87+
dotnet user-secrets set "InternalServiceAuth:SecretKey" "<internal-signing-key>" --project src/DfE.ExternalApplications.Web
88+
dotnet user-secrets set "InternalServiceAuth:Services:0:ApiKey" "<internal-api-key>" --project src/DfE.ExternalApplications.Web
89+
90+
# Optional: secured downstream APIs for complex fields (if required) 🔒
91+
# Matching structure:
92+
# {
93+
# "Id": "TrustComplexField",
94+
# "ApiEndpoint": "https://api.dev.academies.education.gov.uk/trusts?page=1&count=10&groupname={0}&ukprn={0}&companieshousenumber={0}&status=Open",
95+
# "ApiKey": "<trusts-api-key>"
96+
# },
97+
# {
98+
# "Id": "EstablishmentComplexField",
99+
# "ApiEndpoint": "https://api.dev.academies.education.gov.uk/v4/establishments?page=1&count=10&name={0}&urn={0}&ukprn={0}&matchAny=true&excludeClosed=true",
100+
# "ApiKey": "<establishments-api-key>"
101+
# }
102+
dotnet user-secrets set "FormEngine:ComplexFields:0:ApiKey" "<trusts-api-key>" --project src/DfE.ExternalApplications.Web
103+
dotnet user-secrets set "FormEngine:ComplexFields:1:ApiKey" "<establishments-api-key>" --project src/DfE.ExternalApplications.Web
104+
```
105+
106+
3) Use the dev API configuration
107+
`ASPNETCORE_ENVIRONMENT=Development` uses `appsettings.Development.json`, which already points to `https://api.dev.apply-transfer-academy.service.gov.uk` and the dev academies search endpoints.
108+
109+
4) Run the web app
110+
```bash
111+
dotnet run --project src/DfE.ExternalApplications.Web/DfE.ExternalApplications.Web.csproj
112+
```
113+
Browse to `https://localhost:5001` (or the HTTPS port shown in the console) and sign in with a dev DfE Sign-in account.
114+
115+
5) Optional: receive virus-scan events
116+
Ensure the Service Bus connection string is set so `ScanResultConsumer` can process `ScanResultEvent` messages and clean infected uploads.
117+
118+
## Tests ✅
119+
- Unit tests: `dotnet test DfE.ExternalApplications.Web.sln`
120+
- Cypress (E2E): from `Tests/DfE.ExternalApplications.CypressTests`, install deps then run `npm test` or `npx cypress run`.
121+
122+
## Example workflow 📋
123+
1. Create a new application from the dashboard (uses the configured template ID).
124+
2. Add contributors and proceed to the form.
125+
3. Complete tasks/pages; upload supporting documents (they will be virus-scanned).
126+
4. Submit; the app persists responses to the External Applications API and publishes `TransferApplicationSubmittedEvent` to Service Bus for downstream processing.
127+
128+
## Admin pages (template management) 🛠️
129+
- Access: available to users in role `Admin`; entry point at `/Admin/Admin` with a link to `/Admin/TemplateManager`.
130+
- Admin dashboard: shows the current template ID/name/description/version, task group count, cache key status, and tokens; provides a “clear all” to wipe session and template cache.
131+
- Template Manager:
132+
- Displays the current template JSON and latest version (fetched from the API; cache is cleared before loading).
133+
- “Add template version” flow validates the provided JSON against the form template schema, base64-encodes it, and calls `CreateTemplateVersionAsync`.
134+
- Auto-suggests the next patch version, and after creating a version, clears and verifies cache so the new schema is served immediately.
135+
- Includes “clear all” to drop session and cache and return to dashboard if the template ID is lost.
136+
137+
## Notes 🧠
138+
- Clean Architecture boundaries are enforced: web depends on application interfaces, implementations live in Infrastructure, and templates are domain-driven JSON schemas.
139+
- If you change template IDs or event mappings, update `Template:Id` and the mapping under `EventMappings/<template>/`.
140+

0 commit comments

Comments
 (0)