Skip to content
Closed
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,33 @@ jobs:
with:
dotnet-version: "10.0.x"

- name: Detect backend tests
id: detect-backend-tests
shell: pwsh
run: |
$hasTests = (Get-ChildItem -Path backend -Recurse -Include *.Tests.csproj,*.UnitTests.csproj,*.IntegrationTests.csproj -ErrorAction SilentlyContinue | Select-Object -First 1) -ne $null
if (-not $hasTests) {
$hasTests = (Get-ChildItem -Path backend -Recurse -Filter *Test*.cs -ErrorAction SilentlyContinue | Select-Object -First 1) -ne $null
}
"has_tests=$($hasTests.ToString().ToLower())" >> $env:GITHUB_OUTPUT

- name: Run Backend Tests
if: steps.detect-backend-tests.outputs.has_tests == 'true'
run: task test:backend

- name: Skip backend tests (none found)
if: steps.detect-backend-tests.outputs.has_tests == 'false'
run: echo "No backend tests found. Skipping backend test steps."

- name: Upload backend test results
if: always()
if: always() && steps.detect-backend-tests.outputs.has_tests == 'true'
uses: actions/upload-artifact@v4
with:
name: backend-test-results
path: backend/TestResults/*.trx

- name: Publish backend test report
if: always()
if: always() && steps.detect-backend-tests.outputs.has_tests == 'true'
uses: dorny/test-reporter@v1
with:
name: Backend Tests
Expand Down Expand Up @@ -71,18 +86,33 @@ jobs:
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Detect frontend tests
id: detect-frontend-tests
shell: bash
run: |
if find frontend -type f \( -name "*.test.*" -o -name "*.spec.*" \) | grep -q .; then
echo "has_tests=true" >> "$GITHUB_OUTPUT"
else
echo "has_tests=false" >> "$GITHUB_OUTPUT"
fi

- name: Run Frontend Tests
if: steps.detect-frontend-tests.outputs.has_tests == 'true'
run: task test:frontend

- name: Skip frontend tests (none found)
if: steps.detect-frontend-tests.outputs.has_tests == 'false'
run: echo "No frontend tests found. Skipping frontend test steps."

- name: Upload frontend test results
if: always()
if: always() && steps.detect-frontend-tests.outputs.has_tests == 'true'
uses: actions/upload-artifact@v4
with:
name: frontend-test-results
path: frontend/test-results/junit.xml

- name: Publish frontend test report
if: always()
if: always() && steps.detect-frontend-tests.outputs.has_tests == 'true'
uses: dorny/test-reporter@v1
with:
name: Frontend Tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
RID=linux-x64
fi

dotnet publish backend/src/SlideGenerator.Presentation/SlideGenerator.Presentation.csproj \
dotnet publish backend/SlideGenerator.Ipc/SlideGenerator.Ipc.csproj \
-c Release \
-r $RID \
--self-contained false \
Expand Down
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "backend/src/SlideGenerator.Framework"]
path = backend/src/SlideGenerator.Framework
[submodule "backend/SlideGenerator.Framework"]
path = backend/SlideGenerator.Framework
url = https://github.com/thnhmai06/SlideGenerator.Framework
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"args": [
"run",
"--project",
"${workspaceFolder}/backend/src/SlideGenerator.Presentation/SlideGenerator.Presentation.csproj"
"${workspaceFolder}/backend/SlideGenerator.Ipc/SlideGenerator.Ipc.csproj"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
Expand Down
11 changes: 9 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ git pull

1. **Via Visual Studio:**
- Open `SlideGenerator.sln`.
- Set `SlideGenerator.Presentation` as the startup project.
- Set `SlideGenerator.Ipc` as the startup project.
- Start Debugging (F5).

2. **Via VS Code:**
Expand All @@ -98,7 +98,7 @@ git pull
3. **Via CLI:**
```bash
cd backend
dotnet run --project src/SlideGenerator.Presentation
dotnet run --project SlideGenerator.Ipc
```

#### Frontend
Expand Down Expand Up @@ -162,6 +162,13 @@ task format

This will run `dotnet format` for the backend and `npm run format` for the frontend.

Backend coding convention (including `backend/src` and `backend/tests`):

- Prefer **one standalone top-level type per file** (`class`, `interface`, `record`, `enum`, `struct`).
- Nested composite types inside their parent type are allowed in the same file.
- Avoid adding 2+ standalone top-level types in the same `.cs` file unless there is a strong reason.
- The backend includes analyzer rule `SA1402` as a suggestion to remind this convention during development.

## Documentation

**Backend:**
Expand Down
8 changes: 3 additions & 5 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: '3'
vars:
RUNTIME: '{{default "win-x64" .RUNTIME}}'
BACKEND_BUILD_DIR: 'frontend/backend'
BACKEND_PROJECT: 'backend/src/SlideGenerator.Presentation/SlideGenerator.Presentation.csproj'
BACKEND_PROJECT: 'backend/SlideGenerator.Ipc/SlideGenerator.Ipc.csproj'
BACKEND_SOLUTION: 'backend/SlideGenerator.slnx'

tasks:
Expand Down Expand Up @@ -46,11 +46,9 @@ tasks:
- task: test:frontend

test:backend:
desc: Run Backend unit tests
desc: Backend tests removed
cmds:
- echo "Running Backend Tests..."
- dotnet restore {{.BACKEND_SOLUTION}}
- dotnet test {{.BACKEND_SOLUTION}} --no-restore --logger "trx;LogFileName=backend-tests.trx" --results-directory backend/TestResults
- echo "Backend tests removed"

test:frontend:
desc: Run Frontend unit tests
Expand Down
18 changes: 18 additions & 0 deletions backend/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*.cs]
# Prefer one standalone top-level type per file on backend.
# Nested composite types inside their parent are allowed.
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.LayoutRules.severity = none
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.MaintainabilityRules.severity = none
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.NamingRules.severity = none
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = none
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.ReadabilityRules.severity = none
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpacingRules.severity = none
dotnet_diagnostic.SA0001.severity = none
dotnet_diagnostic.SA1402.severity = suggestion

[tests/**/*.cs]
# Apply the same standalone-type convention for backend test code.
dotnet_diagnostic.SA1402.severity = suggestion
61 changes: 61 additions & 0 deletions backend/.github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copilot Instructions

## Source of Truth
- Read and follow [Constructon](../construction.md) before making architectural decisions.
- If `copilot-instructions.md` and `Constructon` differ, prefer `Constructon` for project-specific architecture/runtime rules.

## General Guidelines
- Keep changes minimal and scoped to the requested feature.
- Prefer fixing root causes over adding temporary workarounds.
- Do not introduce unrelated refactors while implementing a task.
- Keep public APIs stable unless the task explicitly requests breaking changes.

## Code Style
- Use C# 12+ style already used in this repo (`sealed`, file-scoped namespaces, explicit async APIs).
- Use meaningful names; avoid one-letter variables except in trivial loops.
- Add XML doc comments for public types and public methods in touched files.
- Prefer expression clarity over clever code.
- Preserve existing indentation and formatting conventions.
- Keep method bodies short and intention-revealing; extract private helpers when a method handles multiple concerns.
- Validate external inputs early (guard clauses) and fail fast with explicit exception types.
- Prefer `async`/`await` end-to-end for I/O paths; avoid sync-over-async patterns (`.Result`, `.Wait()`).
- Return structured results/models instead of loosely typed objects or magic dictionaries.
- Use `ILogger<T>` for operational logs; keep logs concise, contextual, and free of sensitive data.
- Avoid hidden side effects: methods should do what their names describe and keep state transitions explicit.
- Follow object-oriented design by default:
- Encapsulate behavior in classes/services instead of top-level script style.
- Keep methods focused and single-purpose; extract private helper methods when logic grows.
- Prefer dependency inversion (interfaces/contracts) for cross-project dependencies.
- Keep mutable state private and expose minimal public surface.

## Project-Specific Rules
- Keep architecture boundaries strict:
- `Framework`: reusable low-level features (slide/sheet/image/cloud services), no app orchestration. Can be published as NuGet.
- `Features`: domain entities/models (Configs, Jobs orchestration with persistence/workflow, Slides/Sheets domain models).
- `Services`: application services (ScanService, GenerateService, DownloadService, FaceDetectorModelManager, ValidationService).
- `Ipc`: JSON-RPC transport adapter.
- Configuration access for non-`Features` projects currently uses `IConfigProvider` mapping from singleton `ConfigManager` (in `Features.Configs`).
- Register `ConfigManager` once in DI and map provider interfaces from it.
- Avoid passing raw `Config` as root dependency unless taking a runtime snapshot in an internal service.
- Prefer Dependency Injection from `Program.cs` (`Microsoft.Extensions.DependencyInjection`).
- Avoid manual `new` for service wiring in constructors.
- Face detection lifecycle contract:
- Model initialization ownership is in `FaceDetectorModelManager` (in `Services`).
- In `Framework`, `DetectAsync` must throw when model is not initialized.
- `Framework` returns all detections; score filtering is handled by caller/business layer.
- Download behavior:
- Use `DownloadService` (in `Services.Generating`, uses Downloader library) for remote downloads in Generate flow.
- Avoid direct ad-hoc `HttpClient` download logic in generation pipeline.
- IPC endpoint structure:
- Keep request DTO in `Services.Generating.Models` (for GenerateSlidesRequest) or `SlideGenerator.Ipc/Contracts/Requests`.
- Keep RPC handlers in partial `RpcEndpoint.*.cs` files and call `BackendService` (in `Features.Jobs`) for orchestration.
- Framework reuse:
- If logic already exists in `Framework` services, use it instead of duplicating logic in `Services` or `Features`.
- Data shape conventions:
- Use `Entities` for domain/runtime entities (in `Features`).
- Use `Models` for supporting option/value model types (in `Features` or `Services`).
- **Current architecture**: Solution organized into 4 projects:
- `Framework` (low-level reusable library)
- `Features` (domain entities, Jobs, Configs, domain models)
- `Services` (application services for scan/generate/download/validation)
- `Ipc` (JSON-RPC transport layer)
15 changes: 15 additions & 0 deletions backend/.idea/.idea.SlideGenerator/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/.idea/.idea.SlideGenerator/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions backend/.idea/.idea.SlideGenerator/.idea/discord.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions backend/.idea/.idea.SlideGenerator/.idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions backend/.idea/.idea.SlideGenerator/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 4 additions & 11 deletions backend/backend.config.sample.yaml → backend/Configs.sample.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
# SlideGenerator Backend Configuration
# This file configures the backend server and image processing options
# SlideGenerator Configuration

# Server configuration
server:
host: 127.0.0.1
port: 5000
debug: false

# Download configuration
## Download configuration
download:
max_chunks: 5
limit_bytes_per_second: 0
Expand All @@ -22,11 +15,11 @@ download:
password: ''
domain: ''

# Job configuration
## Jobs configuration
job:
max_concurrent_jobs: 2

# Image processing configuration
## Image processing configuration
image:
# Face detection settings
face:
Expand Down
10 changes: 7 additions & 3 deletions backend/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<Project>
<PropertyGroup>
<NoWarn>$(NoWarn);NU1902;NU1903;NETSDK1206</NoWarn>
</PropertyGroup>
<PropertyGroup>
<NoWarn>$(NoWarn);NU1902;NU1903;NETSDK1206</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all"/>
</ItemGroup>
</Project>
Loading
Loading