Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 15 additions & 5 deletions .github/workflows/debug-pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,27 @@ jobs:
# No CodesignKey/EnableCodeSigning -> the build applies only an ad-hoc signature
# (all an internal test build needs; testers still have to clear the Gatekeeper
# quarantine flag — see the release notes text in publish-release).
# Passing BOTH RIDs in a single RuntimeIdentifier value is how the .NET MAUI Mac
# Catalyst targets emit a universal (lipo'd x64 + arm64) binary. Release builds do
# this by default; a Debug build has to state it explicitly. See
# https://learn.microsoft.com/dotnet/maui/mac-catalyst/deployment/publish-unsigned
# PublishMacUniversal=true flips a conditional PropertyGroup in StageFright.App.csproj
# that sets the *plural* <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</...>,
# which is what makes MAUI's Mac Catalyst targets emit a universal (lipo'd x64 + arm64)
# .app. It has to be set inside the .csproj, not passed here as -p:RuntimeIdentifier(s):
# * the singular RuntimeIdentifier is validated by the .NET SDK as ONE RID and rejects
# a `;`-list with "NETSDK1083: ... 'maccatalyst-x64;maccatalyst-arm64' is not
# recognized";
# * passing -p:RuntimeIdentifiers on the CLI makes it a global property that leaks the
# `;`-list verbatim into every ProjectReference (the plain non-maccatalyst class
# libraries), which then fail the same NETSDK1083.
# As a project property it is evaluated locally and MAUI fans out per-RID inner builds
# that hand a single concrete RID to the referenced libraries. Release builds get this
# universal RID set by MAUI automatically; a Debug build has to opt in. See the
# dotnet/macios .NET 8 release notes and dotnet/maui's Controls.TestCases.HostApp.csproj.
- name: Publish unsigned universal .app
run: >
dotnet publish ${{ env.APP_PROJECT }}
-f ${{ env.TFM }}
-c Debug
-p:CreatePackage=false
-p:RuntimeIdentifier="maccatalyst-x64;maccatalyst-arm64"
-p:PublishMacUniversal=true

# `ditto` is Apple's supported way to archive an .app bundle for transport — it
# preserves the symlinks, permissions, and resource forks that a plain `zip`
Expand Down
4 changes: 1 addition & 3 deletions .specify/feature.json
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
{
"feature_directory": "specs/026-past-agm-committee-report"
}
{"feature_directory":"specs\\029-first-run-language-seed"}
26 changes: 20 additions & 6 deletions CLAUDE.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Localization" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="10.0.10" />
<PackageVersion Include="Microsoft.Maui.Controls" Version="10.0.90" />
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The master branch will always contain the code for the most recent release. The
Make a fork of this repo and use that as your private scratch pad. When you are ready for a review and merge, create a pull request to dev.

## Tools used
* Claude Code -Sonnet 5 model (https://www.anthropic.com/claudecode)
* Github Spec Kit (https://github.com/github/spec-kit)
* SpecKit Companion (https://github.com/alfredoperez/speckit-companion)

Expand Down
1 change: 1 addition & 0 deletions StageFrightCommunity.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<Project Path="tests/StageFright.Core.Tests/StageFright.Core.Tests.csproj" />
<Project Path="tests/StageFright.Data.Tests/StageFright.Data.Tests.csproj" />
<Project Path="tests/StageFright.Integration.Tests/StageFright.Integration.Tests.csproj" />
<Project Path="tests/StageFright.Localization.Tests/StageFright.Localization.Tests.csproj" />
<Project Path="tests/StageFright.Reports.Tests/StageFright.Reports.Tests.csproj" />
<Project Path="tests/StageFright.TestPlugin/StageFright.TestPlugin.csproj" />
<Project Path="tests/StageFright.UI.Tests/StageFright.UI.Tests.csproj" />
Expand Down
9 changes: 7 additions & 2 deletions capabilities/app-host/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ The app shell MUST ask a setup-completion service whether initial configuration

### The setup wizard captures required configuration through validated steps before anything else can run

The wizard MUST require organisation identity and tax details, fee/renewal configuration, and GST treatment before allowing submission, gating advancement on a per-step validation pass rather than only validating at final submit. Completion MUST persist configuration through one setup service call and then route straight into the app.
The wizard MUST require organisation identity, fee/renewal configuration, and sales-tax treatment (applicability, rate, and per-fee tax codes) before allowing submission, gating advancement on a per-step validation pass rather than only validating at final submit. Completion MUST persist configuration through one setup service call and then route straight into the app.

#### Scenario: user attempts to advance past an incomplete step
- **WHEN** required fields for the current step fail validation
Expand All @@ -73,7 +73,7 @@ The wizard MUST require organisation identity and tax details, fee/renewal confi

### Optional sample-data seeding is a debug-only, opt-in, non-blocking capability

Sample-data seeding MUST NOT be offered or reachable in release builds, MUST require explicit user opt-in even when available, and MUST run without freezing the setup UI, reporting incremental progress back to it. It MUST also be safe to invoke against a database that already has data. The opt-in control lives on the Organisation Settings tab (the wizard's first tab), and selecting it disables the Chart of Accounts, Opening Balances, and Committee tabs — sample data supplies that information itself, so manual entry on those tabs is bypassed rather than merely optional.
Sample-data seeding MUST NOT be offered or reachable in release builds, MUST require explicit user opt-in even when available, and MUST run without freezing the setup UI, reporting incremental progress back to it. It MUST also be safe to invoke against a database that already has data. The opt-in control lives on the Organisation Settings tab (the wizard's first tab), and selecting it disables the Chart of Accounts, Opening Balances, and Committee tabs — sample data supplies that information itself, so manual entry on those tabs is bypassed rather than merely optional. The seeder likewise stamps its own generated organisation name and fee schedule over the Organisation Settings inputs, so the sample dataset is internally consistent regardless of the placeholder values entered to satisfy the wizard's own validation; currency, language and sales-tax treatment are the exception and follow what the coordinator configured.

#### Scenario: release build reaches the setup wizard
- **WHEN** no debug seeder is registered in the container
Expand All @@ -95,6 +95,11 @@ Sample-data seeding MUST NOT be offered or reachable in release builds, MUST req
- **WHEN** the checkbox is checked after an account, opening balance, or committee title was already queued
- **THEN** every queued entry is discarded so it is never submitted alongside the seeded sample data

#### Scenario: sample data overrides the organisation identity and fee inputs
- **WHEN** the seeder runs after setup was submitted with a placeholder organisation name and fee figures
- **THEN** the persisted settings carry the seeder's generated organisation name, annual fee, attendance fee and renewal configuration instead
- **AND** the currency, language and sales-tax treatment chosen during setup are left unchanged

### Plugin assemblies are discovered and loaded in isolation from each other and from the host

The host MUST scan a known plugins directory for assemblies at startup, load each in its own isolated load context, and contain any single assembly's load failure so it neither aborts discovery of the remaining assemblies nor crashes startup. A missing plugins directory MUST NOT be treated as an error.
Expand Down
4 changes: 2 additions & 2 deletions capabilities/audit-trail/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ In the MVP, every audit entry SHALL attribute the action to a fixed "system" ide

### Audit history ages out on a rolling retention window instead of soft-delete

Unlike other entities, audit entries carry no soft-delete fields — they SHALL instead be hard-deleted once older than a fixed retention period (12 months), evaluated at application startup. This keeps the audit log bounded over time without ever allowing an individual entry to be edited or archived.
Unlike other entities, audit entries carry no soft-delete fields — they SHALL instead be hard-deleted once older than the organisation's configured retention period, evaluated at application startup. The retention period is user-configurable from 1 to 7 years (`Settings.AuditRetentionYears`) and defaults to **5 years** on a new dataset; an existing dataset keeps whatever value it was already configured with. This keeps the audit log bounded over time without ever allowing an individual entry to be edited or archived.

#### Scenario: startup retention purge runs

- **WHEN** the application starts
- **THEN** all audit entries older than 12 months are permanently removed from the store
- **THEN** all audit entries older than the configured retention period (default 5 years) are permanently removed from the store

### Retention purge failures never block application startup

Expand Down
2 changes: 1 addition & 1 deletion capabilities/data-access/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Member and account balance queries (`GetMemberBalanceAsync`, `GetAccountBalanceA
- **THEN** a `ValidationException` naming the reason is thrown before any database write is attempted

#### Scenario: archiving a system account
- **WHEN** any of the seeded system accounts (Cash, Member Receivable, Bad Debt Expense, GST Collected/Paid, Opening Balance Equity, Accumulated Surplus) is archived
- **WHEN** any of the seeded system accounts (Cash, Member Receivable, Bad Debt Expense, Tax Collected, Tax Receivable, Opening Balance Equity, Accumulated Surplus) is archived
- **THEN** the operation is rejected regardless of whether it is referenced by transactions

### Account numbers are allocated deterministically within a fixed range per account type
Expand Down
8 changes: 4 additions & 4 deletions capabilities/domain-model/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ Every type in `StageFright.Core/Exceptions/` SHALL be a `sealed class` deriving

### Fields that snapshot state at posting/accrual time are immutable and never retroactively rewritten

Several entities stamp a value at the moment of creation that reflects "the rule in force then," and that value SHALL NOT be updated even if the organization-wide rule later changes: `Transaction.GstCode`, `Transaction.GLAccount`, and `Fee.GstCode` are all fixed at posting/accrual time; `Account.AccountNumber` is fixed at account creation. Historical rows are read literally, never recalculated against current settings.
Several entities stamp a value at the moment of creation that reflects "the rule in force then," and that value SHALL NOT be updated even if the organization-wide rule later changes: `Transaction.TaxCode`, `Transaction.GLAccount`, and `Fee.TaxCode` are all fixed at posting/accrual time; `Account.AccountNumber` is fixed at account creation. Historical rows are read literally, never recalculated against current settings.

#### Scenario: GST registration status changes
#### Scenario: sales-tax applicability changes

- **WHEN** an organisation's `Settings.IsGstRegistered` flag changes after some fees/transactions were already posted
- **THEN** existing `Fee.GstCode` and `Transaction.GstCode` values on prior rows are left untouched; only newly created rows use the new setting
- **WHEN** an organisation's `Settings.IsTaxApplicable` flag changes after some fees/transactions were already posted
- **THEN** existing `Fee.TaxCode` and `Transaction.TaxCode` values on prior rows are left untouched; only newly created rows use the new setting

#### Scenario: an account's legacy number scheme is queried

Expand Down
Loading