Skip to content
Draft
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0133842
Initial framework commit
seanmcilvenna Jul 1, 2026
2550390
Add user role administration with system admin capabilities and intro…
seanmcilvenna Jul 6, 2026
e445ba9
Introduce user status management with support for enabling/disabling …
seanmcilvenna Jul 6, 2026
649bfe4
Integrate NHSN React Core package and apply SASS support in the UI.
seanmcilvenna Jul 6, 2026
7ad2e7e
Refactor navigation component into standalone `NavigationRail` to imp…
seanmcilvenna Jul 6, 2026
bae6976
Add `baseUrl` configuration for customizable routing in NHSNLink comp…
seanmcilvenna Jul 6, 2026
0d9addd
Add `apiBaseUrl` support for configurable backend API routing in NHSN…
seanmcilvenna Jul 7, 2026
040b93c
Add HtmlWebpackPlugin to embed configuration for generating web compo…
seanmcilvenna Jul 7, 2026
eb0ec5c
Refactor user role model and permissions structure:
seanmcilvenna Jul 13, 2026
4b4351f
Implement signed JWT support for lower-environment testing and remove…
seanmcilvenna Jul 16, 2026
85f9b1d
Removing concept of NHSNLINKSYSADMIN from NHSN-Admin-BFF and NHSN-Adm…
seanmcilvenna Jul 20, 2026
68730f2
Resetting migrations and updating default configs for swagger/openapi…
seanmcilvenna Jul 20, 2026
ec36892
Merge branch 'dev' into nhsn-app-component
dvargaslantana Jul 21, 2026
0df49e5
Remove `SimulationEndpoints` and lower-environment `IsLowerEnvironmen…
seanmcilvenna Jul 21, 2026
9cf1391
Merge remote-tracking branch 'origin/nhsn-app-component' into nhsn-ap…
seanmcilvenna Jul 21, 2026
5b372ca
Initial check in for the onboarding proof of concept
dvargaslantana Jul 23, 2026
e1341c9
Updated max and min pull time to be a time input control.
dvargaslantana Jul 27, 2026
cf585b6
Merge branch 'dev' into nhsn-app-component
seanmcilvenna Jul 30, 2026
f864ca6
Adding localization/internationalization support for the NHSN App Int…
seanmcilvenna Jul 31, 2026
053a62c
Added API support section
dvargaslantana Aug 3, 2026
40622be
Added reporting status viewer
dvargaslantana Aug 3, 2026
82b6789
Updated API support page to a single save button
dvargaslantana Aug 3, 2026
6c8cf72
Updated Report Details page to include pre qual results
dvargaslantana Aug 5, 2026
fb6300a
Added initial MRN intake form. Updated API support
dvargaslantana Aug 10, 2026
d00065a
Updating MRN intake form. Still a work in progress
dvargaslantana Aug 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .docker/create-dbs.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-tenant') CREATE DA
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-validation') CREATE DATABASE [link-validation];
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-querydispatch') CREATE DATABASE [link-querydispatch];
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-account') CREATE DATABASE [link-account];
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-submission') CREATE DATABASE [link-submission];
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-submission') CREATE DATABASE [link-submission];
IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = 'link-nhsn-app-bff') CREATE DATABASE [link-nhsn-app-bff];
49 changes: 48 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
## tenant: 8074
## validation: 8075
## terminology: 8076
## nhsn-app-bff: 8079
## nhsn-app-ui: 8090

services:

Expand Down Expand Up @@ -527,6 +529,49 @@ services:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8063/api/health"]

nhsn-app-bff:
image: link-nhsn-app-bff
container_name: link-nhsn-app-bff
environment:
ASPNETCORE_ENVIRONMENT: Docker
EnableSwagger: "true"
ConnectionStrings__DatabaseConnection: Server=tcp:mssql,1433;Initial Catalog=link-nhsn-app-bff;Persist Security Info=False;User ID=sa;Password=${LINK_DB_PASS};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;
ports:
- "8079:8079"
build:
context: .
dockerfile: nhsn/NHSN-App-BFF/Dockerfile
args:
BUILD_CONFIGURATION: Debug
networks:
- link-nw
depends_on:
mssql_init:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8079/health"]
start_period: 5s
interval: 5s
retries: 10

nhsn-app-ui:
image: link-nhsn-app-ui
container_name: link-nhsn-app-ui
environment:
NHSN_APP_UI_DEFAULT_JWT_ISSUER: https://docker-nhsn-app.example.org
NHSN_APP_UI_DEFAULT_JWT_KEY_ID: '399E34CBAADFE1B9EBF3484198B5B451C6FD3800'
NHSN_APP_UI_DEFAULT_JWT_PRIVATE_KEY_PEM: '-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8bBAWSvX80TrIXvT\niuwm0MhA2Babh4aomKZtnoszZfihRANCAAQNoNqXozIM+J/ZIq6fa/vhsayZ+GlY\nE2kQAYPpDGfo3boxro6EDvNAj5D+EbY5650CZZhBQTin3r3Ahk6/nNk2\n-----END PRIVATE KEY-----'
ports:
- "8090:8090"
build:
context: ./nhsn/NHSN-App-UI
dockerfile: Dockerfile
networks:
- link-nw
depends_on:
nhsn-app-bff:
condition: service_healthy

audit:
image: link-audit
Expand Down Expand Up @@ -1026,7 +1071,6 @@ services:
Telemetry__EnableOtelCollector: true
Telemetry__OtelCollectorEndpoint: http://otel-collector:4317
EnableSwagger: true
Authentication__EnableAnonymousAccess: true
volumes:
- terminology_data:/data
ports:
Expand Down Expand Up @@ -1070,3 +1114,6 @@ volumes:
driver: local
automation_ui_keys:
driver: local



42 changes: 42 additions & 0 deletions link-cloud.sln
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{C98B4989-107
EndProject
Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "Admin.UI", "Web\Admin.UI\Admin.UI.esproj", "{472A561B-EF7F-467E-96ED-1FB130E43292}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHSN-App-BFF", "nhsn\NHSN-App-BFF\NHSN-App-BFF.csproj", "{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}"
EndProject
Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "NHSN-App-UI", "nhsn\NHSN-App-UI\NHSN-App-UI.esproj", "{D120BFC7-7897-4172-9916-AE0A102618CF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataAcquisition.Domain", "DotNet\DataAcquisition.Domain\DataAcquisition.Domain.csproj", "{CEBB1A00-0629-4791-A2A3-35FC05D00F0B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{554985B2-5CA6-49D3-8F07-08080C4EACEA}"
Expand Down Expand Up @@ -300,6 +304,42 @@ Global
{C4070261-D248-4CA5-A532-6AAA71AACC35}.Release|x86.Build.0 = Release|Any CPU
{472A561B-EF7F-467E-96ED-1FB130E43292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{472A561B-EF7F-467E-96ED-1FB130E43292}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Debug|x64.ActiveCfg = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Debug|x64.Build.0 = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Debug|x86.ActiveCfg = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Debug|x86.Build.0 = Debug|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.NoVariablesDefault|Any CPU.ActiveCfg = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.NoVariablesDefault|Any CPU.Build.0 = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.NoVariablesDefault|x64.ActiveCfg = NoVariablesDefault|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.NoVariablesDefault|x64.Build.0 = NoVariablesDefault|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.NoVariablesDefault|x86.ActiveCfg = NoVariablesDefault|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.NoVariablesDefault|x86.Build.0 = NoVariablesDefault|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Release|Any CPU.Build.0 = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Release|x64.ActiveCfg = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Release|x64.Build.0 = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Release|x86.ActiveCfg = Release|Any CPU
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5}.Release|x86.Build.0 = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Debug|x64.ActiveCfg = Debug|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Debug|x64.Build.0 = Debug|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Debug|x86.ActiveCfg = Debug|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Debug|x86.Build.0 = Debug|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.NoVariablesDefault|Any CPU.ActiveCfg = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.NoVariablesDefault|Any CPU.Build.0 = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.NoVariablesDefault|x64.ActiveCfg = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.NoVariablesDefault|x64.Build.0 = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.NoVariablesDefault|x86.ActiveCfg = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.NoVariablesDefault|x86.Build.0 = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Release|Any CPU.Build.0 = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Release|x64.ActiveCfg = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Release|x64.Build.0 = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Release|x86.ActiveCfg = Release|Any CPU
{D120BFC7-7897-4172-9916-AE0A102618CF}.Release|x86.Build.0 = Release|Any CPU
{472A561B-EF7F-467E-96ED-1FB130E43292}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{472A561B-EF7F-467E-96ED-1FB130E43292}.Debug|x64.ActiveCfg = Debug|x64
{472A561B-EF7F-467E-96ED-1FB130E43292}.Debug|x86.ActiveCfg = Debug|x86
Expand Down Expand Up @@ -530,6 +570,8 @@ Global
GlobalSection(NestedProjects) = preSolution
{C4070261-D248-4CA5-A532-6AAA71AACC35} = {37C302AB-8C98-4CC8-828E-0647AF098586}
{472A561B-EF7F-467E-96ED-1FB130E43292} = {C98B4989-1078-4632-BC7D-9CE52A40B360}
{A45F7139-0648-4ED6-B3F7-1F97F8E4A9A5} = {C98B4989-1078-4632-BC7D-9CE52A40B360}
{D120BFC7-7897-4172-9916-AE0A102618CF} = {C98B4989-1078-4632-BC7D-9CE52A40B360}
{F25C619A-50DC-4A67-9406-F8A2DB07AA22} = {554985B2-5CA6-49D3-8F07-08080C4EACEA}
{E34B41C5-3093-05C2-C945-BCB49AC34E7F} = {554985B2-5CA6-49D3-8F07-08080C4EACEA}
EndGlobalSection
Expand Down
21 changes: 21 additions & 0 deletions nhsn/NHSN-App-BFF/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Build output
/bin/
/obj/

# User-specific / IDE
*.user
*.rsuser
*.suo
*.DotSettings.user
.vs/

# Local-only config
appsettings.Local.json
appsettings.local.json

# Logs / diagnostics
*.log

# Coverage / test artifacts
coverage/
TestResults/
6 changes: 6 additions & 0 deletions nhsn/NHSN-App-BFF/Application/Interfaces/IApi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Interfaces;

public interface IApi
{
void RegisterEndpoints(WebApplication app);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using LantanaGroup.Link.Nhsn.App.Bff.Application.Models;

namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Interfaces;

public interface IFacilityAdministrationService
{
Task<FacilitySummaryResponse?> UpdateFacilityOnboardingAsync(string facilityId, string actingFacilityId, bool isFacilityAdmin, UpdateFacilityOnboardingRequest request, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Interfaces;

public interface ILocalizationResourceService
{
Task<LocalizationResourceResult> GetNamespaceAsync(string locale, string namespaceName, CancellationToken cancellationToken);
}

public sealed record LocalizationResourceResult(
LocalizationResourceStatus Status,
string? JsonPayload = null,
string? ETag = null,
DateTimeOffset? LastModified = null,
string? Message = null
);

public enum LocalizationResourceStatus
{
Ok,
InvalidLocale,
InvalidNamespace,
NotFound,
MalformedJson,
DirectoryUnavailable
}
9 changes: 9 additions & 0 deletions nhsn/NHSN-App-BFF/Application/Interfaces/IUserInfoService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Security.Claims;
using LantanaGroup.Link.Nhsn.App.Bff.Application.Models;

namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Interfaces;

public interface IUserInfoService
{
Task<UserInfoResponse> GetUserInfoAsync(ClaimsPrincipal principal, HttpRequest request, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Models;

public class FacilitySummaryResponse
{
public Guid Id { get; set; }
public string FacilityId { get; set; } = string.Empty;
public bool IsOnboarded { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Models;

public class UpdateFacilityOnboardingRequest
{
public bool IsOnboarded { get; set; }
}
15 changes: 15 additions & 0 deletions nhsn/NHSN-App-BFF/Application/Models/UserInfoResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Models;

public class UserInfoResponse
{
public string AccessState { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public bool IsFacilityAdmin { get; set; }
public bool IsOnboarded { get; set; }
public bool HasFacility { get; set; }
public string? FacilityId { get; set; }
public IReadOnlyCollection<string> Groups { get; set; } = [];
public IReadOnlyCollection<string> AvailableNavigation { get; set; } = [];
public string? AccessRequestUrl { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using LantanaGroup.Link.Nhsn.App.Bff.Application.Interfaces;
using LantanaGroup.Link.Nhsn.App.Bff.Application.Models;
using LantanaGroup.Link.Nhsn.App.Bff.Persistence;
using Microsoft.EntityFrameworkCore;

namespace LantanaGroup.Link.Nhsn.App.Bff.Application.Services;

public class FacilityAdministrationService : IFacilityAdministrationService
{
private readonly NhsnAppDbContext _dbContext;

public FacilityAdministrationService(NhsnAppDbContext dbContext)
{
_dbContext = dbContext;
}

public async Task<FacilitySummaryResponse?> UpdateFacilityOnboardingAsync(string facilityId, string actingFacilityId, bool isFacilityAdmin, UpdateFacilityOnboardingRequest request, CancellationToken cancellationToken = default)
{
if (!isFacilityAdmin)
{
throw new InvalidOperationException("FACADMIN is required to update facility onboarding.");
}

if (!string.Equals(facilityId, actingFacilityId, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("Facility onboarding may only be updated for the authenticated facility context.");
}

var facility = await _dbContext.Facilities.SingleOrDefaultAsync(x => x.FacilityId == facilityId, cancellationToken);
if (facility is null)
{
return null;
}

facility.IsOnboarded = request.IsOnboarded;
await _dbContext.SaveChangesAsync(cancellationToken);

return new FacilitySummaryResponse
{
Id = facility.Id,
FacilityId = facility.FacilityId,
IsOnboarded = facility.IsOnboarded
};
}
}
Loading
Loading