You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Signed package generation is CI-oriented and uses .github/workflows/build-signed-package.yml.
Pushes to released / flight-released also automatically create a GitHub Release in that workflow (release job): release notes are generated by GitHub Models (openai/gpt-4o) from commits since the previous same-channel release (commits matching fix(<scope>-dev): are filtered out as dev-internal), and the signed MSIX artifacts are attached. Flight releases are tagged v<version>-flight and marked prerelease; stable releases are tagged v<version>.
The same workflow's publish_store job publishes to the Microsoft Store via the Microsoft Store Developer CLI (msstore, set up by microsoft/microsoft-store-apppublisher@v1.1). It builds a StoreUpload .msixupload bundle (x86|x64|arm64) with the checked-in Store identity — the sideload identity swap (Set PUBLISHER, icon override) and SignPath signing must NOT be applied to it. released publishes the stable channel; flight-released publishes to the Package Flight in the STORE_FLIGHT_ID repo variable. msstore publish commits the submission and starts certification automatically. For a store-only retry, dispatch the workflow with store_only=true; this skips the build job and therefore also skips its dependent R2 and GitHub Release jobs. Requires PARTNER_CENTER_TENANT_ID / PARTNER_CENTER_CLIENT_ID / PARTNER_CENTER_CLIENT_SECRET / PARTNER_CENTER_SELLER_ID secrets and the STORE_PRODUCT_ID variable.
Expect client packaging to require a Windows machine with the proper WinUI/Windows App SDK toolchain.
Lint And Analyzer Guidance
No dedicated repo-level lint script was found.
Treat dotnet build as the main analyzer/lint pass for C# projects.
NUnit analyzers are enabled in both test projects, so test builds also surface style/test issues.
Docs site currently has build/dev scripts but no checked-in lint script.
Use .editorconfig plus existing file style as the formatting authority.
Test Commands
Run all server tests: dotnet test GalgameManager.Server.Test/GalgameManager.Server.Test.csproj
Run all client tests: dotnet test GalgameManager.Test/GalgameManager.Test.csproj
The client test project automatically uses GalgameManager.Test/test.runsettings.
That runsettings file forces x64 and excludes tests in Category("Phraser") by default.
Repo rule from .kilocode/rules/project-info-galgamemanager.md: after editing client code, run GalgameManager.Test.
If you did not change parser code, you can skip parser tests because they call external services and are slow.
Running A Single Test
Preferred pattern: dotnet test <project> --filter "FullyQualifiedName~Namespace.Class.Method"
Single server test example:
dotnet test GalgameManager.Server.Test/GalgameManager.Server.Test.csproj --filter "FullyQualifiedName~GalgameManager.Server.Test.Services.GalgameServiceRedirectTests.GetGalgameAsync_WithRedirect_ReturnsTargetGame"
Single client test example:
dotnet test GalgameManager.Test/GalgameManager.Test.csproj --filter "FullyQualifiedName~GalgameManager.Test.ProjectTest.Version_ShouldMatch_PackageAppxmanifest"
To run a whole test class, filter on the class name instead of the method name.
Be aware that the default client runsettings still excludes Phraser tests.
Phraser tests hit external APIs; only run them when changing parser/scraper logic.
Some upgrade/E2E tests launch the built client executable and are more environment-sensitive.
Server Run Commands
Initialize local secrets once: dotnet user-secrets init --project GalgameManager.Server/GalgameManager.Server.csproj
Set secrets as needed with: dotnet user-secrets set "Key" "Value" --project GalgameManager.Server/GalgameManager.Server.csproj
Run the server locally: dotnet run --project GalgameManager.Server/GalgameManager.Server.csproj
Docker-based local deploy is documented in GalgameManager.Server/README.md.
The checked-in Docker compose flow lives under GalgameManager.Server/.
Server Configuration Expectations
PostgreSQL is required.
JWT secret is required and should be at least 64 characters.
S3-compatible object storage settings are required for normal operation.
GalgameManager.Server/Program.cs validates required configuration at startup and exits early if it is invalid.
Core C# Style
Use file-scoped namespaces.
Keep using directives outside the namespace.
Prefer System.* usings before other usings when organizing imports.
Use 4 spaces for indentation; do not use tabs.
Preserve final newlines and trim trailing whitespace.
Preserve the existing line endings of the file you edit; C# files are typically CRLF here.
Use Allman braces for types, methods, properties, and control blocks.
Short guard clauses without braces exist in this repo; follow local style when editing nearby code.
Types And Language Features
ImplicitUsings is enabled in main projects; do not add redundant usings.
Nullable reference types are enabled in client, server, and test projects; respect nullability annotations.
GalgameManager.Core does not explicitly enable nullable in its project file, so be extra careful crossing that boundary.
Use ? for truly optional references.
Use ! sparingly and only when the invariant is already established.
Match local style on var versus explicit types; this repo uses both.
Explicit types are common for service, model, DTO, and interface variables.
var is common when the right-hand side is obvious.
Target-typed new(), collection expressions like [], and modern C# syntax are already in use.
Naming Conventions
Use PascalCase for classes, structs, enums, methods, properties, and public members.
Interfaces should start with I.
Private fields should use _camelCase.
Injected dependencies are usually stored in private readonly _camelCase fields in the client.
Server code often uses primary constructors for controllers and services.
Test method names are usually descriptive sentence-style names with underscores.
Dependency Injection And Architecture
The overall architecture is MVVM on the client and layered controller/service/repository on the server.
Prefer constructor injection over service location.
Client ViewModels should keep UI state and orchestration logic, not heavy persistence/networking logic.
Business logic should live in services/models rather than in XAML code-behind.
Code-behind is acceptable for view-only behavior, event wiring, or platform-specific UI glue.
Client MVVM Patterns
Use CommunityToolkit.Mvvm patterns already present in the codebase.
Prefer ObservableObject/ObservableRecipient for ViewModels and observable helpers.
Prefer [ObservableProperty] over hand-written backing boilerplate when consistent with the file.
Prefer [RelayCommand] and related toolkit attributes for commands.
Use partial ViewModels where source generators are expected.
Follow existing patterns for INavigationAware and service-backed page initialization.
XAML And UI Conventions
Prefer x:Bind over classic {Binding} when working with ViewModel-backed pages.
Use typed templates with x:DataType where the surrounding file already does so.
Reuse existing custom controls and patterns instead of inventing new ones.
Common custom controls called out by repo docs: Setting, SettingToggleSwitch, ComboBoxWithI18N, and Panel.
Keep UI additions consistent with the existing WinUI 3 style and MVVM structure.
Localization Rules
XAML localization uses x:Uid.
C# localization typically uses "Key".GetLocalized() or ResourceExtensions.GetLocalized(...).
For ContentDialog, localize the root with x:Uid and use .Title, .PrimaryButtonText, and .SecondaryButtonText keys.
For child controls, use the expected suffix like .Text, .Label, .Content, or .ToolTipService.ToolTip.
Do not directly edit .resw files.
Use GalgameManager/Strings/resw_tool.py to search, add, or update localization entries.
Error Handling
On the client, catch exceptions at UI/page boundaries and route them through IInfoService when appropriate.
InfoService is the central notification/logging path and writes logs through Serilog.
Avoid silently swallowing exceptions unless the code is intentionally best-effort and the surrounding style already does so.
On the server, validate early and use meaningful exceptions such as ArgumentException and UnauthorizedAccessException.
Controllers commonly translate service exceptions into HTTP 400/404 responses.
Test Conventions
NUnit is the test framework across both test projects.
Server tests commonly use Moq plus EF Core InMemory.
GalgameManager.Server.Test/TestBase.cs provides the shared in-memory DataContext setup/teardown pattern.
Arrange/Act/Assert comments are common in server tests; keep them if you touch existing tests.
Client tests use categories such as Phraser and E2E.
Default client test runs exclude Phraser tests via runsettings.
Some E2E tests are non-parallel and require a built unpackaged x64 client executable.
Practical Editing Advice
Follow the existing file's local style before applying generic preferences.
Do not rewrite large areas just to normalize style.
When touching localization-backed UI, update strings through resw_tool.py and keep x:Uid naming consistent.
When adding settings, follow the existing pattern: setting key, default value, ViewModel property, UI control, localization.
When changing server DTOs/entities, expect downstream API client generation and possibly EF migrations to matter.
Quick Pre-PR Checklist
Build the relevant project(s).
Run the most relevant tests; at minimum run the test project for the area you changed.
For client changes, run GalgameManager.Test unless the change is clearly isolated and non-code.
For parser changes, explicitly consider Phraser tests.
For docs changes, run npm run build in PotatoVN.Doc/.