Skip to content

Commit c426998

Browse files
committed
Bugfixes for moved subscription
1 parent 898fe58 commit c426998

4 files changed

Lines changed: 49 additions & 16 deletions

File tree

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Tech Hub is a **modern .NET 10 web application** built with Blazor that serves a
99
| **Backend** | ASP.NET Core Minimal API, .NET 10, C# 13 |
1010
| **Frontend** | Blazor InteractiveServer with prerendering |
1111
| **Orchestration** | .NET Aspire (service discovery, telemetry, health checks) |
12-
| **Database** | PostgreSQL (Dapper) or FileSystem (no database) |
12+
| **Database** | PostgreSQL (Dapper) |
1313
| **Infrastructure** | Azure Container Apps, Bicep IaC, GitHub Actions CI/CD |
1414
| **Testing** | xUnit v3, bUnit, Playwright, Pester |
1515

@@ -49,7 +49,6 @@ See **[docs/running-and-testing.md](docs/running-and-testing.md)** for the full
4949

5050
- **TechHub.Core** — Domain models and interfaces (framework-agnostic)
5151
- **TechHub.Infrastructure** — Dapper repositories, markdown processing, caching
52-
- **collections/** — Markdown content (news, videos, blogs, community, roundups) synced to database at startup
5352

5453
See **[docs/architecture.md](docs/architecture.md)** for full details.
5554

@@ -59,11 +58,9 @@ See **[docs/architecture.md](docs/architecture.md)** for full details.
5958
|-----------|---------|
6059
| `src/` | Application source code (API, Web, Core, Infrastructure, AppHost) |
6160
| `tests/` | Unit, integration, component, E2E, and PowerShell tests |
62-
| `collections/` | Markdown content organized by collection type |
6361
| `docs/` | Functional and technical documentation |
6462
| `scripts/` | PowerShell automation (build, deploy, content processing) |
6563
| `infra/` | Bicep IaC templates for Azure Container Apps |
66-
| `specs/` | Feature specifications (SpecKit format) |
6764

6865
See **[docs/repository-structure.md](docs/repository-structure.md)** for the complete breakdown.
6966

docs/repository-structure.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ See [src/AGENTS.md](../src/AGENTS.md) for general .NET development patterns and
8181
- `_news/` - Sample news items
8282
- `_roundups/` - Sample roundup posts
8383
- `_videos/` - Sample video content
84-
- `DatabaseFixture.cs` - In-memory database setup for integration tests
85-
- `TechHubApiFactory.cs` - WebApplicationFactory for API testing
8684
- `TestCollectionsSeeder.cs` - Seeds test database from TestCollections
8785
- See [tests/TechHub.TestUtilities/AGENTS.md](../tests/TechHub.TestUtilities/AGENTS.md)
8886

scripts/Manage-EntraId.ps1

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
Deployment SP Key Vault roles (staging/production only):
2323
The GitHub Actions deployment service principal (sp-techhubms, appId: 91fe5f39-bee3-48b1-b976-e8ba4e41d84e)
2424
is separate from the TechHub OIDC app registration. It uses OIDC federated credentials (no secret)
25-
and needs two roles on the subscription to write secrets and manage Key Vault network firewall rules
26-
during deploy:
27-
- Key Vault Secrets Officer (write/read/delete secrets)
28-
- Key Vault Contributor (manage network ACL rules)
25+
and needs three roles on the subscription to write secrets, manage Key Vault network firewall rules,
26+
and create/update subscription-scoped policy assignments during deploy:
27+
- Key Vault Secrets Officer (write/read/delete secrets)
28+
- Key Vault Contributor (manage network ACL rules)
29+
- Resource Policy Contributor (create/update policy assignments in infrastructure.bicep)
2930
Pass -DeploymentSpObjectId <OID> to assign these roles automatically.
3031
3132
Secret delivery:
@@ -621,8 +622,9 @@ if (-not $isLocalhost -and $DeploymentSpObjectId) {
621622
$subscriptionScope = "/subscriptions/$subscriptionId"
622623

623624
$kvRoles = @(
624-
@{ Name = 'Key Vault Secrets Officer'; Reason = 'write/read/delete secrets during deploy' },
625-
@{ Name = 'Key Vault Contributor'; Reason = 'manage network ACL firewall rules' }
625+
@{ Name = 'Key Vault Secrets Officer'; Reason = 'write/read/delete secrets during deploy' },
626+
@{ Name = 'Key Vault Contributor'; Reason = 'manage network ACL firewall rules' },
627+
@{ Name = 'Resource Policy Contributor'; Reason = 'create/update subscription-scoped policy assignments in infrastructure.bicep' }
626628
)
627629

628630
foreach ($kvRole in $kvRoles) {

src/TechHub.Infrastructure/Services/Newsletter/NewsletterService.cs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,31 @@ public async Task<bool> SendCombinedWeeklyAsync(IReadOnlyList<string> roundupSlu
143143
successful++;
144144
}
145145

146-
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: true, succeeded: emailSent, ct);
146+
#pragma warning disable CA1031 // Best-effort: status recording must not affect the send result
147+
try
148+
{
149+
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: true, succeeded: emailSent, ct);
150+
}
151+
catch (Exception dbEx) when (dbEx is not OperationCanceledException)
152+
{
153+
_logger.LogWarning(dbEx, "Failed recording weekly send status for subscriber — continuing");
154+
}
155+
#pragma warning restore CA1031
147156
}
148157
#pragma warning disable CA1031 // Best-effort: continue with other subscribers if one fails
149158
catch (Exception ex) when (ex is not OperationCanceledException)
150159
{
151160
_logger.LogWarning(ex, "Failed sending weekly newsletter to subscriber — skipping");
152-
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: true, succeeded: false, CancellationToken.None);
161+
#pragma warning disable CA1031 // Best-effort: status recording must not abort the loop
162+
try
163+
{
164+
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: true, succeeded: false, CancellationToken.None);
165+
}
166+
catch (Exception dbEx) when (dbEx is not OperationCanceledException)
167+
{
168+
_logger.LogWarning(dbEx, "Failed recording weekly send failure status for subscriber — continuing");
169+
}
170+
#pragma warning restore CA1031
153171
}
154172
#pragma warning restore CA1031
155173
}
@@ -421,13 +439,31 @@ public async Task<bool> SendDailyOverviewAsync(DateOnly day, CancellationToken c
421439
sent++;
422440
}
423441

424-
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: false, succeeded: emailSent, ct);
442+
#pragma warning disable CA1031 // Best-effort: status recording must not affect the send result
443+
try
444+
{
445+
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: false, succeeded: emailSent, ct);
446+
}
447+
catch (Exception dbEx) when (dbEx is not OperationCanceledException)
448+
{
449+
_logger.LogWarning(dbEx, "Failed recording daily send status for subscriber — continuing");
450+
}
451+
#pragma warning restore CA1031
425452
}
426453
#pragma warning disable CA1031 // Best-effort: continue with other subscribers if one fails
427454
catch (Exception ex) when (ex is not OperationCanceledException)
428455
{
429456
_logger.LogWarning(ex, "Failed sending daily newsletter to subscriber — skipping");
430-
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: false, succeeded: false, CancellationToken.None);
457+
#pragma warning disable CA1031 // Best-effort: status recording must not abort the loop
458+
try
459+
{
460+
await _subscriberRepository.RecordSubscriberSendAsync(subscriber.Email, isWeekly: false, succeeded: false, CancellationToken.None);
461+
}
462+
catch (Exception dbEx) when (dbEx is not OperationCanceledException)
463+
{
464+
_logger.LogWarning(dbEx, "Failed recording daily send failure status for subscriber — continuing");
465+
}
466+
#pragma warning restore CA1031
431467
}
432468
#pragma warning restore CA1031
433469
}

0 commit comments

Comments
 (0)