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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,6 @@ From `src/BikeTracking.Frontend`:

<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
shell commands, and other important information, read the current plan
shell commands, and other important information, read the current plan:
[specs/024-tauri-api-sidecar/plan.md](../specs/024-tauri-api-sidecar/plan.md)
<!-- SPECKIT END -->
12 changes: 12 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ jobs:
- name: Install Tauri system libraries
run: sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev

- name: Publish API sidecar binary (Linux x64)
run: |
dotnet publish src/BikeTracking.Api/BikeTracking.Api.csproj \
--configuration Release \
--self-contained true \
--runtime linux-x64 \
-p:PublishSingleFile=true \
--output src/BikeTracking.Frontend/src-tauri/binaries/
mv src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api \
src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api-x86_64-unknown-linux-gnu
chmod +x src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api-x86_64-unknown-linux-gnu

- name: Tauri config check
working-directory: src/BikeTracking.Frontend
run: npx tauri build --bundles deb --debug --ci
Expand Down
115 changes: 104 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
package-windows:
name: Package Windows (NSIS)
runs-on: windows-latest
needs: [build-frontend]
needs: [build-frontend, publish-api-windows]
timeout-minutes: 20

steps:
Expand Down Expand Up @@ -118,6 +118,12 @@ jobs:
working-directory: src/BikeTracking.Frontend
run: npm ci --ignore-scripts

- name: Download API binary (Windows)
uses: actions/download-artifact@v4
with:
name: api-binary-windows
path: src/BikeTracking.Frontend/src-tauri/binaries/

- name: Build Windows installer
working-directory: src/BikeTracking.Frontend
run: npx tauri build --bundles nsis --ci
Expand All @@ -135,7 +141,7 @@ jobs:
package-linux:
name: Package Linux (.deb)
runs-on: ubuntu-latest
needs: [build-frontend]
needs: [build-frontend, publish-api-linux]
timeout-minutes: 20

steps:
Expand Down Expand Up @@ -175,6 +181,15 @@ jobs:
working-directory: src/BikeTracking.Frontend
run: npm ci --ignore-scripts

- name: Download API binary (Linux)
uses: actions/download-artifact@v4
with:
name: api-binary-linux
path: src/BikeTracking.Frontend/src-tauri/binaries/

- name: Mark API binary executable
run: chmod +x src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api-x86_64-unknown-linux-gnu

- name: Build Linux .deb package
working-directory: src/BikeTracking.Frontend
run: npx tauri build --bundles deb --ci
Expand All @@ -186,6 +201,89 @@ jobs:
path: src/BikeTracking.Frontend/src-tauri/target/release/bundle/deb/BikeTracking_*_amd64.deb
retention-days: 1

# ---------------------------------------------------------------------------
# Job 2b: Publish self-contained API binary for Windows x64
# ---------------------------------------------------------------------------
publish-api-windows:
name: Publish API binary (Windows)
runs-on: windows-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup .NET from global.json
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json

- name: Restore .NET dependencies
run: dotnet restore BikeTracking.slnx

- name: Publish API self-contained (Windows x64)
run: |
dotnet publish src/BikeTracking.Api/BikeTracking.Api.csproj `
--configuration Release `
--self-contained true `
--runtime win-x64 `
-p:PublishSingleFile=true `
--output api-publish-win/ `
--no-restore

- name: Rename binary to Tauri sidecar naming convention
run: Rename-Item api-publish-win/BikeTracking.Api.exe BikeTracking.Api-x86_64-pc-windows-msvc.exe

- name: Upload API binary artefact (Windows)
uses: actions/upload-artifact@v4
with:
name: api-binary-windows
path: api-publish-win/BikeTracking.Api-x86_64-pc-windows-msvc.exe
retention-days: 1

# ---------------------------------------------------------------------------
# Job 2c: Publish self-contained API binary for Linux x64
# ---------------------------------------------------------------------------
publish-api-linux:
name: Publish API binary (Linux)
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup .NET from global.json
uses: actions/setup-dotnet@v5
with:
global-json-file: global.json

- name: Restore .NET dependencies
run: dotnet restore BikeTracking.slnx

- name: Publish API self-contained (Linux x64)
run: |
dotnet publish src/BikeTracking.Api/BikeTracking.Api.csproj \
--configuration Release \
--self-contained true \
--runtime linux-x64 \
-p:PublishSingleFile=true \
--output api-publish-linux/ \
--no-restore

- name: Rename binary and mark executable
run: |
mv api-publish-linux/BikeTracking.Api \
api-publish-linux/BikeTracking.Api-x86_64-unknown-linux-gnu
chmod +x api-publish-linux/BikeTracking.Api-x86_64-unknown-linux-gnu

- name: Upload API binary artefact (Linux)
uses: actions/upload-artifact@v4
with:
name: api-binary-linux
path: api-publish-linux/BikeTracking.Api-x86_64-unknown-linux-gnu
retention-days: 1

# ---------------------------------------------------------------------------
# Job 3b: API smoke test — verify .NET API starts and /health responds
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -279,8 +377,10 @@ jobs:
echo "AUTO_BUMP=${AUTO_BUMP}" >> "$GITHUB_OUTPUT"
echo "Resolved release tag: ${TAG}"

# T017a: Bump package.json + Cargo.toml when version was auto-incremented
- name: Bump version files
# Patch package.json + Cargo.toml in CI workspace only (no commit to main).
# release-please handles version bumps in the repo via PRs.
# This step ensures the built artifacts carry the correct version number.
- name: Patch version files for build (workspace only)
if: steps.tag.outputs.AUTO_BUMP == 'true'
run: |
NEW_VER="${TAG#v}"
Expand All @@ -289,13 +389,6 @@ jobs:
&& mv /tmp/pkg.json src/BikeTracking.Frontend/package.json
sed -i "0,/^version = /s/^version = .*/version = \"${NEW_VER}\"/" \
src/BikeTracking.Frontend/src-tauri/Cargo.toml
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add src/BikeTracking.Frontend/package.json \
src/BikeTracking.Frontend/src-tauri/Cargo.toml
git diff --cached --quiet || \
git commit -m "chore: bump version to ${NEW_VER} [skip ci]"
git push origin HEAD:main

# T018: isDraft-aware duplicate-tag guard
- name: Duplicate-tag guard
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ appsettings.Development.json
*.bak
*.cache
node_modules/

# Sidecar binaries — populated by CI; do not commit
src/BikeTracking.Frontend/src-tauri/binaries/*.exe
src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api-*
dist/
build/
coverage/
Expand Down
2 changes: 1 addition & 1 deletion .specify/feature.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"feature_directory": "specs/023-pwa-desktop-packaging"
"feature_directory": "specs/024-tauri-api-sidecar"
}
57 changes: 47 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,23 @@ These are ran in the .github\workflows\ci.yml pipeline on every PR

BikeTracking packages as native desktop installers for Windows (.exe) and Linux (.deb) via Tauri 2.

Flow: commit to main → release-please bumps version & tags → release.yml builds installers & publishes.
Flow: commit to main → release-please bumps version & tags → release.yml builds installers (including bundled API) & publishes.

**The installer is fully self-contained.** The .NET API is bundled as a Tauri sidecar binary — no separate installation or manual startup required. On launch, the Tauri shell spawns the API automatically; on close, it terminates it cleanly.

### Architecture: Tauri Sidecar

```
BikeTracking (Tauri shell)
├── React frontend (embedded in binary)
└── BikeTracking.Api sidecar (self-contained .NET binary)
└── SQLite DB (~/.local/share/BikeTracking/ or %APPDATA%\BikeTracking\)
```

- Sidecar spawned in `lib.rs setup()` via `tauri-plugin-shell`
- Sidecar killed on `WindowEvent::Destroyed` (no orphaned processes)
- API port: `5079` (fixed; configurable via `app.conf.json`)
- Frontend polls `GET /health` on startup; shows spinner until API ready, error if >10s

### Local Build (DevContainer)

Expand All @@ -263,14 +279,33 @@ sudo apt-get install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3
sudo dnf install webkit2gtk4.1-devel gtk3-devel libappindicator-gtk3-devel librsvg2-devel
```

For local Tauri dev, publish the API sidecar binary first:

```bash
# Linux
dotnet publish src/BikeTracking.Api/BikeTracking.Api.csproj \
--configuration Release --self-contained true --runtime linux-x64 \
-p:PublishSingleFile=true --output src/BikeTracking.Frontend/src-tauri/binaries/
mv src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api \
src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api-x86_64-unknown-linux-gnu
chmod +x src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api-x86_64-unknown-linux-gnu

# Windows (PowerShell)
dotnet publish src/BikeTracking.Api/BikeTracking.Api.csproj `
--configuration Release --self-contained true --runtime win-x64 `
-p:PublishSingleFile=true --output src/BikeTracking.Frontend/src-tauri/binaries/
Rename-Item src/BikeTracking.Frontend/src-tauri/binaries/BikeTracking.Api.exe `
BikeTracking.Api-x86_64-pc-windows-msvc.exe
```

Build dev binary with hot-reload:

```bash
cd src/BikeTracking.Frontend
npm run tauri:dev
```

Opens native window with live React HMR.
Opens native window. API sidecar starts automatically.

Build release installers (output → `src-tauri/target/release/bundle/`):

Expand All @@ -286,9 +321,11 @@ Outputs:
### Dependencies

- **@tauri-apps/cli@^2**: Desktop shell + Vite integration
- **@tauri-apps/api@^2**: JS API for native features (file I/O, window control)
- **Rust 1.80+**: Minimal shell binary (Cargo.toml → src/lib.rs)
- **@tauri-apps/api@^2**: JS API for native features
- **tauri-plugin-shell ^2**: Sidecar spawn/kill lifecycle
- **Rust 1.80+**: Minimal shell binary (`src-tauri/src/lib.rs`)
- **WebKit2GTK 4.1** (Linux): WebView renderer
- **.NET 10**: Compiled into sidecar binary (self-contained — not required on user machine)

See `package.json` + `src-tauri/Cargo.toml` for locked versions.

Expand All @@ -301,22 +338,22 @@ Triggered by:
Pipeline stages:

1. **release-please**: Monitors conventional commits on `main`. Opens release PR with bumped `package.json` + `Cargo.toml` versions + auto-generated `CHANGELOG.md`.
2. **build-frontend**: Single job. Runs `npm run build` → uploads `dist/` artifact.
3. **package-windows** (parallel): Downloads `dist/`, runs `tauri build --bundles nsis` on Windows runner.
4. **package-linux** (parallel): Downloads `dist/`, runs `tauri build --bundles deb` on Ubuntu runner. (Rust cached → ~6 min build time).
5. **publish-release**: Downloads both installers, computes SHA-256 checksums, creates GitHub Release with both `.exe` + `.deb` as downloadable assets.
2. **build-frontend** + **publish-api-windows** + **publish-api-linux** (parallel): Frontend builds `dist/`; API published as self-contained binary per platform.
3. **package-windows**: Downloads `dist/` + Windows API binary → places in `src-tauri/binaries/` → `tauri build --bundles nsis`.
4. **package-linux**: Downloads `dist/` + Linux API binary → places in `src-tauri/binaries/` → `tauri build --bundles deb`.
5. **smoke-test-api**: Validates `GET /health` returns 200 on published API binary.
6. **publish-release**: Downloads both installers, computes SHA-256 checksums, creates GitHub Release.

Versioning:
- Conventional commit prefixes → semver bumps: `feat:` → minor, `fix:` → patch, `feat!:` / `BREAKING CHANGE:` → major
- Example: After merging `feat: add weather data`, release-please bumps `0.1.0` → `0.2.0` + opens release PR
- Merge release PR → tag auto-created → pipeline triggers → installers published
- On manual dispatch without version input: version patched in CI workspace only (no commit to `main`); `release-please` owns version files in the repo

Release notes auto-generated from commits since previous tag. Grouped by type (Features, Bug Fixes, Chores).

### Pre-release Builds

Tag format: `v0.1.0-alpha`, `v0.1.0-rc.1` → marked `pre-release` on GitHub, not latest stable.

## Update SpecKit

https://github.com/github/spec-kit/blob/main/docs/upgrade.md
Expand Down
7 changes: 7 additions & 0 deletions docs/agent/delivery-and-git-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ Branching, PR, CI, and feature-flag governance.
## CI Expectations
- Validation checks must pass before merge.
- Include build, formatting/linting, unit/integration checks, and E2E.

## Release Pipeline
- Installers are fully self-contained: .NET API bundled as Tauri sidecar binary alongside React frontend.
- Release workflow (`release.yml`) runs: `build-frontend` + `publish-api-windows` + `publish-api-linux` (parallel) → `package-windows` + `package-linux` → `smoke-test-api` → `publish-release`.
- `release-please` owns version files (`package.json`, `Cargo.toml`) in the repo via PRs — never commit version bumps directly to `main`.
- On manual dispatch without version input: versions patched in CI workspace only (no commit); artifact carries correct version, repo files unchanged.
- Binary naming for sidecar must follow Tauri triple convention: `BikeTracking.Api-x86_64-pc-windows-msvc.exe` (Windows), `BikeTracking.Api-x86_64-unknown-linux-gnu` (Linux).
37 changes: 37 additions & 0 deletions specs/024-tauri-api-sidecar/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Specification Quality Checklist: Bundle .NET API as Tauri Sidecar

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-06-15
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- All checklist items pass. Spec is ready for `/speckit.plan`.
- macOS is explicitly out of scope (Windows x64 + Linux x64 only); documented in Assumptions.
- Code-signing is explicitly out of scope; documented in Assumptions.
- Concurrent multi-instance usage is out of scope; documented in Assumptions and Edge Cases.
Loading
Loading