Reorganize developer docs into devdocs/; new CLAUDE.md and .NET 10 port plan

This commit is contained in:
2026-10-22 11:52:52 -07:00
parent 47c3f9bc28
commit 2dd8a4bb04
10 changed files with 716 additions and 692 deletions

134
devdocs/build/BUILD.md Normal file
View File

@@ -0,0 +1,134 @@
# AyaNova v8 release build
How a full release is built: tools, folder layout, what `build-release.bat` does, and where
version numbers live. Written for .NET 8 (8.2.4); the .NET 10 port updates it.
To set up a machine that can run this from scratch, see `DEV-VM-SETUP.md`.
## What gets built
| Project | Framework | Output |
|---|---|---|
| AyaNova server (`raven/server/AyaNova`) | .NET 8 | Five packages, below |
| Launcher (`raven-launcher`) | .NET 8, self-contained, `PublishTrimmed` | Inside the Windows standalone installer |
| QBI (`ravenqbi/AyaNovaQBI`) | .NET Framework 4.8 | `ayanova-qbi-setup.exe`, built separately |
| Package | Build |
|---|---|
| `ayanova-subscription-linux-x64-server.zip` | linux-x64, framework-dependent, `SUBSCRIPTION_BUILD=true`, server `config.json` |
| `ayanova-linux-x64-server.zip` | linux-x64, framework-dependent, server `config.json` |
| `ayanova-linux-x64-desktop.zip` | Same build, desktop `config.json` |
| `ayanova-windows-x64-single-setup.exe` | win-x64 self-contained server, launcher, embedded PostgreSQL |
| `ayanova-windows-x64-lan-setup.exe` | win-x64 framework-dependent server |
## Tools
| Tool | Version | Used for |
|---|---|---|
| .NET SDK | 8.0.x | Server and launcher |
| Node.js | **12.22.9 exactly** | Front end. Newer versions break `fibers` |
| Python | 3.11 | MkDocs |
| MkDocs + mkdocs-material | current | Customer manual (`pip install mkdocs mkdocs-material`) |
| Inno Setup | 6.x | Windows installers |
| 7-Zip | current | Linux zips |
| Visual Studio | **[unverified: 2022 or 18/2026]** | QBI only |
The scripts hardcode these paths:
- `C:\data\code\raven\`, `C:\data\code\raven-client\ayanova\`, `C:\data\code\raven-launcher\`, `C:\data\code\ravenqbi\`
- `C:\Program Files\7-Zip\7z.exe`
- `C:\Program Files (x86)\Inno Setup 6\ISCC.exe`
## Folder layout
```
C:\data\code\
├── raven\
│ ├── build-release.bat master build script
│ ├── raven.sln
│ ├── server\AyaNova\ AyaNova.csproj, wwwroot\ (generated), resource\
│ ├── docs\8.0\ayanova\ customer manual, mkdocs.yml
│ ├── docs\8.0\customer\ customer portal docs, mkdocs.yml
│ ├── devdocs\ developer docs (this file)
│ ├── dist\
│ │ ├── assets\ LICENSE, license.rtf, logo.ico, lan-install-config.json,
│ │ │ linux-server\config.json, linux-desktop\config.json
│ │ ├── install\windows\x64\ standalone.iss, lan.iss
│ │ ├── win-x64\postgres-standalone\ embedded PostgreSQL (maintained by hand)
│ │ └── installers\ final packages (generated)
│ │ (also generated: linux-x64\, subscription-build-linux-x64\, win-x64\ayanova\..., win-x64\launcher\)
│ └── graphics\
├── raven-client\ayanova\ Vue front end
├── raven-launcher\ raven-launcher.csproj, config.json
└── ravenqbi\ AyaNovaQBI\AyaNovaQBI.csproj, install\qbi.iss
```
## `build-release.bat`, step by step
1. **Clean** `raven\server\AyaNova\wwwroot` and `raven\dist\installers`.
2. **Customer manual**: `mkdocs build` in `docs\8.0\ayanova` and `docs\8.0\customer`. Output goes straight to `wwwroot\docs` (`site_dir` in `mkdocs.yml`).
3. **Front end**: `npm run build` in `raven-client\ayanova`, then `xcopy dist\* ...\raven\server\AyaNova\wwwroot\ /e`. The .NET build does not produce `wwwroot`: whatever is there is what ships.
4. **Subscription Linux**:
```bat
dotnet publish --property:PublishDir=C:\data\code\raven\dist\subscription-build-linux-x64\ -c Release -r linux-x64 --no-self-contained -p:SUBSCRIPTION_BUILD=true
```
Zipped with `assets\linux-server\config.json`.
5. **Perpetual Linux**: the same with `-p:SUBSCRIPTION_BUILD=false` into `dist\linux-x64\`. One build, two zips: desktop and server `config.json`.
6. **Windows standalone**: `-r win-x64 --self-contained` into `dist\win-x64\ayanova\standalone\` (includes the .NET runtime, about 150 MB more).
7. **Windows framework-dependent**: `-r win-x64 --no-self-contained` into `dist\win-x64\ayanova\framework-dependent\`. Needs the .NET runtime on the target.
8. **Launcher**: `dotnet publish -c Release -r win-x64 --self-contained` in `raven-launcher` into `dist\win-x64\launcher\`.
9. **Installers**: `ISCC.exe standalone.iss` and `ISCC.exe lan.iss`.
`raven-client\ayanova\buildrelease.bat` runs steps 1–3 alone (main manual only, not the
customer portal docs).
### Windows installers
- **Standalone** (`standalone.iss`): self-contained server, launcher, embedded PostgreSQL, empty database template, desktop shortcut to the launcher. App in `{autopf}\ayanova`; data in `{commonappdata}\ayanova\database`; logs in `{commonappdata}\ayanova\logs`. The launcher starts PostgreSQL, starts the server, opens the browser at the login page and waits.
- **LAN** (`lan.iss`): framework-dependent server plus network config. No PostgreSQL. Prompts the user to download the ASP.NET Core Hosting Bundle and PostgreSQL.
### QBI (separate)
```bat
cd C:\data\code\ravenqbi\AyaNovaQBI
msbuild /p:Configuration=Release
cd C:\data\code\ravenqbi\install
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" qbi.iss
```
Output: `ravenqbi\install\output\ayanova-qbi-setup.exe`. Has a pre-build event that runs a
timestamp utility.
## Version numbers
Set in five places for every release:
| File | Setting | At 8.2.4 |
|---|---|---|
| `raven\server\AyaNova\AyaNova.csproj` | `<Version>` | 8.2.4 |
| `raven\dist\install\windows\x64\standalone.iss` | `#define MyAppVersion` | 8.2.4 |
| `raven\dist\install\windows\x64\lan.iss` | `#define MyAppVersion` | 8.2.4 |
| `raven-client\ayanova\package.json` | `"version"` | 8.2.4 |
| `ravenqbi\install\qbi.iss` | `#define MyAppVersion` | 8.0.2 (own cycle) |
## Front-end build notes
- Install dependencies with `npm ci`, never `npm install`: it installs the exact versions in `package-lock.json`.
- Warnings that appear on every build and are harmless: Browserslist "caniuse-lite is outdated"; Dart Sass "Using / for division is deprecated" (from Vuetify); asset size warnings (Monaco's `ts.worker.js` is about 4.5 MB).
- Webpack content-hash file names change on every build even when contents do not. Compare file contents, not names.
## Docker builds
`Dockerfile.frontend` and `Dockerfile.docs` build the front end and the manual in containers
**[unverified: where they live]**. The Linux server packages and the Windows
framework-dependent build could also build in Docker. Windows self-contained builds, Inno
Setup, QBI and the embedded PostgreSQL need Windows.
## Troubleshooting
- **`fibers` fails to install**: it needs Python, Visual Studio Build Tools, and Node exactly 12.22.9. Last resort: remove `"fibers"` from `package.json` and the `fiber: require("fibers")` line from `webpack.config.js`; the build still works, a little slower.
- **Node version errors**: `node -v` must print `v12.22.9`.
- **"Module not found"**: delete `node_modules`, then `npm ci`.
- **PuppeteerSharp cannot download the browser**: check connectivity, or point the server at an installed browser through its browser-path setting.
- **`SUBSCRIPTION_BUILD` not applied**: the flag is `-p:SUBSCRIPTION_BUILD=true` on `dotnet publish`.
- **Inno Setup errors**: an earlier step failed, or 7-Zip / Inno Setup are not at the expected paths.

View File

@@ -0,0 +1,648 @@
# AyaNova v8 build VM setup
> **Purpose**: Step-by-step instructions to create a portable Windows virtual machine containing the complete AyaNova v8 build environment. This VM can run on Windows or Linux hosts.
Written February 2026 for the .NET 8 build. The .NET 10 port adds the .NET 10 SDK (see `../modernization/NET10-PORT.md`, section 5).
---
## Overview
This guide will help you create a VirtualBox VM that:
- Contains all tools needed to build every AyaNova v8 target
- Is portable (can be moved between machines)
- Can be snapshotted (save known-good states)
- Works on both Windows and Linux host machines
**Time estimate**: 3-4 hours for initial setup
---
## Part 1: Prerequisites and Purchases
### 1.1 Windows License
You'll need a legitimate Windows license for the VM. Options:
| Option | Approximate Cost | Notes |
|--------|------------------|-------|
| Windows 11 Pro (Retail) | $200 USD | Transferable to new hardware, recommended |
| Windows 11 Pro (OEM) | $120-150 USD | Tied to "one machine" but works for VMs |
| Windows 11 Home | $140 USD | Works but Pro has Hyper-V/dev features |
| Windows 10 Pro | $120-150 USD | Still fully supported, lighter weight |
**Recommendation**: Windows 11 Pro retail license. It's transferable and will remain supported longest.
**Where to buy**:
- Microsoft Store (microsoft.com) - Full retail price, guaranteed legitimate
- Amazon - Often has retail boxed copies
- Newegg - Same as Amazon
**Avoid**: Grey market key resellers (G2A, Kinguin, etc.) - Keys may be revoked.
### 1.2 Host Machine Requirements
Your Linux laptop will need:
- **RAM**: 16GB minimum (8GB for VM + 8GB for host)
- **Disk**: 100GB free space for VM
- **CPU**: 4+ cores recommended (VM will use 2-4)
- **Virtualization**: VT-x/AMD-V enabled in BIOS
Your current ThinkPad X13 (16GB RAM, Ryzen 7) will work, though it'll be tight on RAM. A machine with 32GB would be more comfortable.
### 1.3 Software to Download (All Free)
Download these before starting:
1. **VirtualBox** (host machine)
- https://www.virtualbox.org/wiki/Downloads
- Get the version for your Linux distribution
- Also get the Extension Pack (same page)
2. **Windows 11 ISO** (for VM)
- https://www.microsoft.com/software-download/windows11
- Download the ISO directly (not the Media Creation Tool)
---
## Part 2: Create the Virtual Machine
### 2.1 Install VirtualBox on Linux Host
For Ubuntu/Debian-based:
```bash
sudo apt update
sudo apt install virtualbox virtualbox-ext-pack
```
For Fedora:
```bash
sudo dnf install VirtualBox
```
Or download from virtualbox.org for other distributions.
### 2.2 Create New VM
1. Open VirtualBox Manager
2. Click **New**
3. Configure:
- **Name**: `AyaNova-Build-v8`
- **Folder**: Choose a location with plenty of space
- **ISO Image**: Select the Windows 11 ISO you downloaded
- **Type**: Microsoft Windows
- **Version**: Windows 11 (64-bit)
- Check "Skip Unattended Installation" (gives you more control)
4. Click **Next**
### 2.3 Hardware Configuration
| Setting | Value | Notes |
|---------|-------|-------|
| Base Memory | 8192 MB (8GB) | Minimum for VS 2022 |
| Processors | 4 CPUs | More if your host has them |
| Enable EFI | Yes | Required for Windows 11 |
Click **Next**
### 2.4 Virtual Hard Disk
| Setting | Value | Notes |
|---------|-------|-------|
| Create Virtual Hard Disk | Yes | |
| Disk Size | 120 GB | VS alone is 20-40GB |
| Pre-allocate Full Size | No | Saves initial space |
Click **Next**, then **Finish**
### 2.5 Additional VM Settings
Before starting the VM, click **Settings**:
**System → Motherboard:**
- Enable EFI: ✓ (should already be set)
- TPM: v2.0 (required for Windows 11)
**Display:**
- Video Memory: 128 MB
- Graphics Controller: VBoxSVGA
- Enable 3D Acceleration: ✓
**Storage:**
- Verify Windows ISO is attached to IDE Controller
**Shared Folders** (optional, configure later):
- Can share folders between host and VM
**Network:**
- Attached to: NAT (default, fine for building)
- Or: Bridged Adapter (if you need VM on your network)
Click **OK**
---
## Part 3: Install Windows
### 3.1 Start VM and Install
1. Start the VM
2. Press any key to boot from ISO when prompted
3. Follow Windows 11 installer:
- Language: Your preference
- Click "Install now"
- Enter your product key (or "I don't have a product key" to enter later)
- Select **Windows 11 Pro**
- Accept license terms
- Choose **Custom: Install Windows only**
- Select the virtual drive, click **Next**
- Wait for installation (10-20 minutes)
### 3.2 Initial Windows Setup
When Windows restarts:
1. Select region and keyboard layout
2. **Network**: If asked, choose "I don't have internet" → "Continue with limited setup"
- This avoids Microsoft account requirement
3. Create a local account:
- Username: `builder` (or your preference)
- Password: Something simple but memorable
4. Disable all the telemetry/tracking options (your choice)
5. Wait for setup to complete
### 3.3 Install VirtualBox Guest Additions
This enables better display, shared folders, clipboard sharing:
1. In VirtualBox menu: **Devices → Insert Guest Additions CD image**
2. Open File Explorer in Windows
3. Navigate to the CD drive
4. Run **VBoxWindowsAdditions.exe**
5. Accept all defaults, click Install
6. Reboot when prompted
After reboot:
- VM window can be resized freely
- Enable shared clipboard: **Devices → Shared Clipboard → Bidirectional**
### 3.4 Windows Updates
Before installing dev tools, get Windows fully updated:
1. **Settings → Windows Update**
2. Click "Check for updates"
3. Install all updates
4. Reboot as needed
5. Repeat until no more updates
This may take 30-60 minutes. Be patient.
### 3.5 Activate Windows
1. **Settings → System → Activation**
2. Click "Change product key"
3. Enter your Windows license key
4. Click Activate
---
## Part 4: Install Build Tools
### 4.1 Create Standard Folders
Open PowerShell as Administrator and run:
```powershell
mkdir C:\data
mkdir C:\data\code
```
### 4.2 Install Package Manager (Winget or Chocolatey)
Winget is built into Windows 11. Verify it works:
```powershell
winget --version
```
If not available, install Chocolatey as alternative:
```powershell
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```
### 4.3 Install Core Tools
Using winget (run in PowerShell as Administrator):
```powershell
# 7-Zip
winget install --id 7zip.7zip -e
# Git
winget install --id Git.Git -e
# VS Code
winget install --id Microsoft.VisualStudioCode -e --source winget
# Python 3.11
winget install --id Python.Python.3.11 -e --source winget
# .NET 8 SDK
winget install --id Microsoft.DotNet.SDK.8 -e --source winget
# Inno Setup
winget install --id JRSoftware.InnoSetup -e --source winget
```
Close and reopen PowerShell after these installs.
### 4.4 Install Node.js 12.22.9 (Specific Version)
Node 12 isn't in winget, so install manually:
1. Download from: https://nodejs.org/dist/v12.22.9/node-v12.22.9-x64.msi
2. Run the installer
3. Accept all defaults
4. Verify:
```powershell
node -v
# Should show: v12.22.9
```
### 4.5 Install MkDocs
```powershell
pip install mkdocs mkdocs-material
```
Verify:
```powershell
mkdocs --version
```
### 4.6 Install Visual Studio 2022 Community
This is needed for the QuickBooks Integration project (.NET Framework 4.8, Windows Forms).
1. Download from: https://visualstudio.microsoft.com/vs/community/
2. Run the installer
3. When Workloads screen appears, select:
- ✓ **.NET desktop development** (includes Windows Forms)
- ✓ **ASP.NET and web development** (optional but useful)
4. In Individual Components tab, verify:
- ✓ .NET Framework 4.8 SDK
- ✓ .NET Framework 4.8 targeting pack
5. Click **Install**
6. Wait (this takes 20-40 minutes and downloads several GB)
### 4.7 Verify All Installations
Open a new PowerShell window and run:
```powershell
# Create a verification script
@"
Write-Host "=== AyaNova Build Environment Check ===" -ForegroundColor Cyan
Write-Host ""
Write-Host "Node.js:" -NoNewline
node -v
Write-Host "npm:" -NoNewline
npm -v
Write-Host "Python:" -NoNewline
python --version
Write-Host "pip:" -NoNewline
pip --version
Write-Host ".NET SDK:" -NoNewline
dotnet --version
Write-Host "MkDocs:" -NoNewline
mkdocs --version
Write-Host ""
Write-Host "Checking paths..." -ForegroundColor Cyan
$tools = @(
"C:\Program Files\7-Zip\7z.exe",
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
)
foreach ($tool in $tools) {
if (Test-Path $tool) {
Write-Host "[OK] $tool" -ForegroundColor Green
} else {
Write-Host "[MISSING] $tool" -ForegroundColor Red
}
}
Write-Host ""
Write-Host "=== Check Complete ===" -ForegroundColor Cyan
"@ | Out-File -FilePath "check-env.ps1"
# Run it
.\check-env.ps1
```
All items should show versions or [OK].
---
## Part 5: Set Up Source Code
### 5.1 Clone from Gitea
```powershell
cd C:\data\code
git clone <gitea-url>/raven.git raven
git clone <gitea-url>/raven-client.git raven-client
git clone <gitea-url>/raven-launcher.git raven-launcher
git clone <gitea-url>/ravenqbi.git ravenqbi
```
The folder names must be exactly these: the build scripts hardcode the paths.
### 5.2 Alternative: Copy from Host via Shared Folder
If Gitea isn't reachable from the VM, use VirtualBox shared folders:
1. In VirtualBox: **Devices → Shared Folders → Shared Folders Settings**
2. Click the folder+ icon
3. **Folder Path**: Your code folder on Linux host
4. **Folder Name**: `code`
5. Check "Auto-mount"
6. Click OK
The shared folder appears as a network drive in Windows. Copy files from there to `C:\data\code\`.
### 5.3 Install Frontend Dependencies
```powershell
cd C:\data\code\raven-client\ayanova
npm ci
```
This installs exact versions from package-lock.json. May take 5-10 minutes.
---
## Part 6: Test the Build
### 6.1 Run Full Build
```powershell
cd C:\data\code\raven
.\build-release.bat
```
Watch for errors. The build should:
1. Build main docs ✓
2. Build customer docs ✓
3. Build frontend ✓
4. Build subscription Linux ✓
5. Build perpetual Linux ✓
6. Build Windows standalone ✓
7. Build Windows framework-dependent ✓
8. Build launcher ✓
9. Create standalone installer ✓
10. Create LAN installer ✓
### 6.2 Verify Outputs
Check that all expected files were created:
```powershell
dir C:\data\code\raven\dist\installers
```
Expected files:
- `ayanova-subscription-linux-x64-server.zip`
- `ayanova-linux-x64-desktop.zip`
- `ayanova-linux-x64-server.zip`
- `ayanova-windows-x64-single-setup.exe`
- `ayanova-windows-x64-lan-setup.exe`
### 6.3 Test QBI Build (Separate)
```powershell
cd C:\data\code\ravenqbi\AyaNovaQBI
# Build using MSBuild (comes with VS)
& "C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe" /p:Configuration=Release
# Or open in Visual Studio and build from there
```
---
## Part 7: Create Snapshot and Backup
### 7.1 Clean Up Before Snapshot
Inside the VM:
```powershell
# Clear temp files
Remove-Item -Recurse -Force $env:TEMP\*
# Clear Windows temp
Remove-Item -Recurse -Force C:\Windows\Temp\* -ErrorAction SilentlyContinue
# Empty recycle bin
Clear-RecycleBin -Force -ErrorAction SilentlyContinue
```
Shut down the VM cleanly: **Start → Power → Shut down**
### 7.2 Create Snapshot
In VirtualBox Manager:
1. Select your VM
2. Click **Snapshots** (next to Details)
3. Click **Take** (camera icon)
4. Name: `Fresh-Build-Environment-Working`
5. Description: `Clean install with all build tools. Full build tested and working.`
6. Click OK
This snapshot lets you restore to this exact state if anything breaks later.
### 7.3 Export VM for Backup
For a portable backup you can store on an external drive:
1. **File → Export Appliance**
2. Select your VM, click Next
3. Choose location (external drive recommended)
4. Format: OVF 2.0
5. File: `AyaNova-Build-VM-v8.ova`
6. Click Next, then Export
This creates a single file (~30-50GB) that can be imported into VirtualBox on any machine.
### 7.4 Backup Strategy
Store the exported .ova file:
- On an external drive (your monthly backup drives)
- Separate from your regular backups (it's a different kind of asset)
When to re-export:
- After major tool updates (new .NET SDK version, etc.)
- After significant build process changes
- Quarterly, as a habit
---
## Part 8: Day-to-Day Usage
### 8.1 Starting the VM
1. Open VirtualBox
2. Select `AyaNova-Build-v8`
3. Click **Start**
4. Wait for Windows to boot
5. Log in
### 8.2 Updating Source Code
```powershell
cd C:\data\code\raven
git pull
cd C:\data\code\raven-client
git pull
# etc.
```
### 8.3 Running Builds
```powershell
cd C:\data\code\raven
.\build-release.bat
```
### 8.4 Getting Files Out of the VM
Options:
1. **Shared Folders**: Copy to a shared folder visible on host
2. **Network**: If VM is bridged, access via network share
3. **USB Drive**: Attach a USB drive to the VM
### 8.5 Snapshots for Safety
Before making any changes to the build environment:
1. Shut down VM
2. Take a snapshot
3. Start VM
4. Make changes
5. If something breaks: Restore snapshot
---
## Part 9: Linux Host Notes
### 9.1 Recommended Linux Distributions
For a development workstation, these work well with VirtualBox:
| Distribution | Notes |
|--------------|-------|
| Ubuntu 22.04/24.04 LTS | Most compatible, largest community |
| Linux Mint | Ubuntu-based, more Windows-like feel |
| Fedora Workstation | Cutting edge, good hardware support |
| Pop!_OS | Good for laptops, System76's distro |
### 9.2 ThinkPad Linux Compatibility
ThinkPads are generally excellent Linux laptops. The X13 Gen 3 AMD should work well with Ubuntu or Fedora out of the box.
### 9.3 Performance Tips
- **Enable VT-x/AMD-V**: In BIOS settings, ensure virtualization is enabled
- **Nested Virtualization**: May be needed if VM uses Hyper-V features (usually not needed for this use case)
- **SSD**: VM performance is heavily dependent on disk speed; SSD is essential
- **RAM**: 32GB on host would be more comfortable than 16GB
---
## Appendix A: Troubleshooting
### Windows 11 Won't Install (TPM Error)
VirtualBox 7.0+ supports TPM 2.0 emulation. If you get TPM errors:
1. VM Settings → System → Motherboard
2. Ensure TPM is set to v2.0
### Build Fails: Node Module Errors
If `npm ci` fails with native module errors:
1. Delete `node_modules` folder
2. Try `npm install` instead of `npm ci`
3. If still failing, verify Node version is exactly 12.22.9
### VM Performance is Poor
- Increase VM RAM (if host has headroom)
- Increase CPU cores
- Ensure VirtualBox Guest Additions are installed
- Check that 3D acceleration is enabled
- Use SSD, not spinning disk
### Can't Reach Gitea
- Check VM network mode (NAT vs Bridged)
- Verify Gitea is reachable from the host
- Check firewall settings on both host and VM
---
## Appendix B: Quick Reference
### Build Commands
```powershell
# Full build
cd C:\data\code\raven
.\build-release.bat
# Frontend only
cd C:\data\code\raven-client\ayanova
npm run build
# Docs only
cd C:\data\code\raven\docs\8.0\ayanova
mkdocs build
# QBI only (in Visual Studio or command line)
msbuild C:\data\code\ravenqbi\AyaNovaQBI\AyaNovaQBI.csproj /p:Configuration=Release
```
### Key Paths
| What | Path |
|------|------|
| Main repo | `C:\data\code\raven` |
| Frontend | `C:\data\code\raven-client\ayanova` |
| Launcher | `C:\data\code\raven-launcher` |
| QBI | `C:\data\code\ravenqbi` |
| Build outputs | `C:\data\code\raven\dist\installers` |
### Tool Locations
| Tool | Path |
|------|------|
| 7-Zip | `C:\Program Files\7-Zip\7z.exe` |
| Inno Setup | `C:\Program Files (x86)\Inno Setup 6\ISCC.exe` |
| MSBuild | `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` **[unverified]**: 6.3 was changed to `18` (Visual Studio 2026) while 4.6 still says install VS 2022. Confirm which is installed |
---
## Version History
| Date | Change |
|------|--------|
| 2026-02-01 | Initial guide created |
| 2026-10-22 | SVN steps replaced with Git; moved to `devdocs/build/` |

View File

@@ -0,0 +1,132 @@
# AyaNova v8 codebase reference
Technical facts about the v8 code, gathered from notes written in February–March 2026.
Version numbers are a snapshot from then: **`AyaNova.csproj` and `package.json` are the
truth**. Anything marked **[unverified]** has not been checked against the code.
## Back end — `raven/server/AyaNova/`
### Stack (February 2026, before the .NET 10 port)
| Component | Version | Notes |
|---|---|---|
| .NET / ASP.NET Core | 8.0 | |
| Entity Framework Core | 8.0.8 | |
| Npgsql.EntityFrameworkCore.PostgreSQL | 8.0.4 | |
| Microsoft.AspNetCore.Authentication.JwtBearer | 8.0.4 | Custom JWT implementation |
| PuppeteerSharp | 17.0.0 | PDF reports through headless Chrome |
| MailKit | 4.5.0 | Email |
| Swashbuckle.AspNetCore | 6.5.0 | OpenAPI |
| NLog.Web.AspNetCore | 5.3.11 | Logging |
| Asp.Versioning.Mvc | — | API versioning **[unverified]** |
### Structure
```
raven/server/AyaNova/
├── AyaNova.csproj
├── Program.cs, Startup.cs
├── resource/ report templates and static resources, copied to output
│ └── rpt/ report templates (.ayrt)
└── wwwroot/ built front end and customer manual, copied in by the build
```
Older notes also list `Controllers/`, `Models/`, `Services/` and `Data/` folders
**[unverified]**: that list reads like a generic template, not the actual layout.
Data-list classes live in the `AyaNova.DataList` namespace, and their class names are the
list keys (`WorkOrderDataList`, `CustomerDataList` …).
### Hosted vs self-hosted
```xml
<DefineConstants Condition=" '$(SUBSCRIPTION_BUILD)' == 'true' ">$(DefineConstants);SUBSCRIPTION_BUILD</DefineConstants>
```
```csharp
#if SUBSCRIPTION_BUILD
// hosted-subscription-only code
#endif
```
### Reports
PuppeteerSharp renders PDFs in headless Chrome, downloaded on first run. A customer
setting holds extra browser launch parameters, and an environment variable can point at
an existing browser instead of downloading one (`REPORT_RENDER_BROWSER_PATH` in older
notes **[unverified]**).
### Configuration
Older notes list `ConnectionStrings__DefaultConnection`, `JWT_SECRET` and
`ASPNETCORE_ENVIRONMENT` as the server's settings **[unverified]**. Sockeye, the near-copy,
reads `SOCKEYE_*` keys from a `config.json` beside the app (`SOCKEYE_DB_CONNECTION`,
`SOCKEYE_USE_URLS`, `SOCKEYE_JWT_SECRET`, `SOCKEYE_DATA_PATH` …), so AyaNova likely does the
same with its own prefix. The Linux packages ship a `config.json` from
`dist/assets/linux-server/` or `dist/assets/linux-desktop/`, which supports that.
### API conventions
Confirmed by the integration tests. Base `http://localhost:7575/api/v8/`.
| Call | Response |
|---|---|
| POST | 201, `{ data: <full object> }` |
| GET | 200, `{ data: <full object> }` |
| DELETE | 204, no body |
| PUT on Customer, QuoteItem, PMItem | 200, `{ data: { Concurrency: N } }` (concurrency only) |
| PUT on Quote, PM, Contract, WorkOrder headers | 200, `{ data: <full object> }` |
| Concurrency conflict | 409 |
| Referential integrity violation | 400, `error.code = 2200` |
| Not found | 404, `error.code = 2010` |
Saved data-list filters: `/data-list-filter` (not the older `data-list-view`); list with
`GET /data-list-filter/list?ListKey=WorkOrderDataList`.
## Front end — `raven-client/ayanova/`
### Stack
| Package | Version | Notes |
|---|---|---|
| vue | 2.6.14 | End of life December 2023 |
| vuetify | 2.6.6 | |
| vue-router | 3.5.4 | |
| vuex | 3.6.2 | plus `vuex-persistedstate` 2.7.1 |
| @vue/cli-service | 4.5.15 | |
| webpack | 4.46.0 | |
| sass / sass-loader | 1.52.3 / 8.0.2 | |
| fibers | 4.0.3 | Deprecated native addon; the reason Node is pinned |
| monaco-editor | 0.30.1 | Large worker files |
| others | | chart.js 2.9, luxon 1.28, marked 1.2, dompurify 2.3, jwt-decode 3.1, papaparse 5.3 |
Node.js **12.22.9**, pinned. Plain JavaScript, no TypeScript.
### Structure
```
raven-client/ayanova/
├── src/
│ ├── api/ API utilities, auth, error handling
│ ├── components/ ~80 components
│ ├── views/ ~100 page components
│ ├── plugins/ Vuetify configuration
│ ├── App.vue, main.js, router.js, store.js
├── public/
├── package.json, vue.config.js, webpack.config.js
```
View prefixes: `acc-` accounting (rates, taxes), `adm-` administration, `cust-` customers,
`home-` dashboard and user home, `inv-` inventory, `ops-` server operations, `svc-` service
(work orders, quotes, PMs).
## QuickBooks integration — `ravenqbi/`
.NET Framework 4.8, Windows Forms, x86 only (the QuickBooks SDK is 32-bit). References
`interop.QBFC14.dll`, which needs the QuickBooks SDK installed on the build machine.
Visual Studio is required for the Forms designer. Not part of `build-release.bat`.
## Customer manual — `raven/docs/8.0/`
MkDocs with the Material theme, two sites: `ayanova/` (main manual) and `customer/`
(customer portal). Each `mkdocs.yml` sets `site_dir` to build straight into the server's
`wwwroot/docs`.

View File

@@ -0,0 +1,179 @@
# AyaNova 8 back end → .NET 10
The plan and running record for the port. Tick items and add a log line **in the same
commit** as the change they record. Anything found along the way that is out of scope goes
under "Deferred", not into the branch.
| | |
|---|---|
| Starting point | AyaNova 8.2.4: ASP.NET Core 8, EF Core 8 |
| Target | `net10.0`, every back-end package at its current release |
| Front end | Minimal or no change. Rebuild only if needed (open question) |
| Branch | `net10-port` in `raven` (and `raven-client` only if the client changes) |
| Baseline tag | `net8-baseline`, on the last commit before the port |
| Release version | Not yet decided (open question) |
## Where this plan comes from
Sockeye, the internal licensing server, is a near-copy of this codebase. It was ported from
.NET 6 to .NET 10 in September–October 2026 and released as `8.1.0`. This plan is that
port's carry-forward list (Appendix A of the Sockeye migration runbook), arranged as a
checklist.
**AyaNova starts from .NET 8, not .NET 6.** So every item is "check whether this applies",
not "this will apply". Several items will turn out to be already done or not present. Mark
those `n/a` with a one-line reason rather than deleting them.
When an item is unclear, look at how Sockeye did it:
```powershell
git -C ..\sockeye log --oneline net6-baseline..8.1.0
git -C ..\sockeye show <commit>
```
**Where AyaNova differs from Sockeye:** customers choose their own database role names and
passwords, every customer uses reports, and AyaNova *verifies* licences rather than issuing
them. Items touching those three areas carry more weight here than they did in Sockeye.
## Scope
- **In:** target framework; all NuGet packages in `server/AyaNova`; code changes those require; the Sockeye-found fixes in section 3, each as its own commit.
- **Out:** front-end dependency changes; refactoring (Roadmap step D); new features; PostgreSQL major upgrades.
- **Undecided:** see "Open questions".
## Working method
- Version bump first. One concern per commit.
- Prove each gate on the **unmodified** code before changing anything, so a later failure points at the port, not at the test.
- Packages that must move together: framework-matched `Microsoft.*` packages all go to 10.x in one step. `BouncyCastle.Cryptography` 2.x goes with MailKit/MimeKit 4.x, because MimeKit 3.x pulls in `Portable.BouncyCastle` and the assemblies clash.
- Publish `server\AyaNova\AyaNova.csproj` directly, never the solution, so no test project can reach the artifact.
---
## 0. Before changing anything
- [ ] Record any port work already done in earlier sessions (branch, commits) here first, and reconcile it with this list
- [ ] `raven` and `raven-client` clean on `main` and pushed
- [ ] Annotated tag `net8-baseline` on the pre-port commit in `raven` and `raven-client`, pushed by name (`git push origin net8-baseline`), checked with `git ls-remote --tags origin`
- [ ] Branch `net10-port` created and pushed with upstream
- [ ] **First commit: version bump** in every place listed in `devdocs/build/BUILD.md` → "Version numbers"
- [ ] Dev machine has the .NET 10 SDK and keeps the .NET 8 runtime for baseline comparisons
### Gates (prove on the unmodified code)
- [ ] **Integration suite baseline.** Run `raven-test-integration` against the unmodified build and record the counts in the log below. Expected: everything passes except the three known server-side failures listed in that repo's CLAUDE.md
- [ ] **Licence verification gate.** Find out exactly how AyaNova 8 verifies a v8 licence: library, public key, and when it re-checks. If it uses BouncyCastle, write a test that runs every v8 row of Sockeye's `alicense` fixture through AyaNova's own verification routine. The fixture is customer data: it stays outside the repo and is found through an environment variable, as Sockeye's re-sign harness does with `SOCKEYE_RESIGN_FIXTURE`. Must be green on unmodified code. A regression here would reject licences customers already have installed
- [ ] **Report baseline.** Render the advanced reports on the unmodified build and keep the PDFs for comparison. Sockeye shares only one report with AyaNova, so Sockeye's testing says little about AyaNova's reports
- [ ] **E2E baseline.** Cypress run against a devtest server on the unmodified build
## 1. Framework and packages
- [ ] `net8.0` → `net10.0`, with every framework-matched `Microsoft.*` package to 10.x in the same step
- [ ] **Hosting model.** `WebHost`, `IWebHost` and `WebHostBuilder` are obsolete in .NET 10 (ASPDEPR008, ASPDEPR004). `Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(web => web.UseStartup<Startup>())` keeps the `Startup` class unchanged
- [ ] **Asp.Versioning.** Older notes say AyaNova already uses `Asp.Versioning.Mvc` **[unverified]**. If not: rename from `Microsoft.AspNetCore.Mvc.Versioning`; `ApiVersion` moves to `Asp.Versioning`; wiring is `services.AddApiVersioning(...).AddMvc().AddApiExplorer(...)`. Leave AV0014 warnings: **do not add `[ApiController]`**
- [ ] **Npgsql / EF Core 10.**
- Check `Npgsql.EnableLegacyTimestampBehavior`. Sockeye's was commented out. If AyaNova sets it, `DateTime.Kind` is a real port item
- Check for `ConfigureWarnings(w => w.Throw())`. If present, every new EF warning becomes an exception naming its ID: fix the query, or move that ID to `.Log(...)`
- Exercise LINQ-based queries screen by screen. Data-list filters build raw SQL and are unaffected
- [ ] **BouncyCastle.** If AyaNova references `BouncyCastle`, it becomes `BouncyCastle.Cryptography` 2.x, moved together with MailKit/MimeKit 4.x. In Sockeye, `PemReader` still yields an `AsymmetricCipherKeyPair` for a PKCS#1 key
- [ ] **Swashbuckle 10 / OpenAPI.NET 2.** `Microsoft.OpenApi.Models` merged into `Microsoft.OpenApi`. Bearer requirement becomes `c.AddSecurityRequirement(document => new OpenApiSecurityRequirement { [new OpenApiSecuritySchemeReference("Bearer", document)] = [] })`. No explicit `Microsoft.OpenApi` reference
- [ ] **NLog 6.** `ArchiveNumbering` is gone; `NLogBuilder.ConfigureNLog` is replaced by `NLog.LogManager.Configuration = logConfig`. Archive numbers keep incrementing and the un-numbered file is always current. If the log viewer in the UI sorts by file name, the order breaks past 99
- [ ] **Newtonsoft.Json.** `Mvc.NewtonsoftJson` 10.x sets a 13.0.3 floor (NU1605). Pin it as a direct reference
- [ ] **JwtBearer 10.x**, which also retires the vulnerable IdentityModel 6.10.0 dependency if AyaNova still resolves it
- [ ] **SMTP.** Any use of `System.Net.Mail.SmtpClient` (SYSLIB0014) moves to MailKit 4.x, as in Sockeye and contact
- [ ] **PuppeteerSharp → 25.x.** Reporting is AyaNova's main Puppeteer surface
- `BrowserFetcher.DefaultChromiumRevision` is gone: call `DownloadAsync()` with no argument
- `IJSHandle.ExecutionContext` is gone: evaluate on the handle. Evaluate results are `JsonElement?`
- The default download is Chrome for Testing, into `Chrome/` and `ChromeHeadlessShell/` beside the app. AyaNova 8.2.0 already moved from Chromium to Chrome to follow Puppeteer's default, so the browser choice is settled
- Launch arguments must be separate array elements (`--no-sandbox` on its own). **This includes the report-render browser params setting** customers can edit
- AppArmor restricts unprivileged user namespaces on Ubuntu 24.04+, which affects the Chrome sandbox
- [ ] Remaining packages to current releases
- [ ] Warnings: CA2022 → `ReadExactly`; ASP0019 → header indexer instead of `Headers.Append`
- [ ] **MiniProfiler.** Confirm it is absent: `git grep -i -e miniprofiler -e mini-profiler -e StackExchange.Profiling` in **both** `raven` and `raven-client`
- [ ] **BinaryFormatter.** Confirm it is unused, or that `EnableUnsafeBinaryFormatterSerialization` is already false
- [ ] **`System.GC.Server`.** Keep the Web SDK default (`true`). On one vCPU the runtime uses workstation GC anyway, and DATAS keeps server GC lean since .NET 9
- [ ] **`InvariantGlobalization`.** Decide on EF Core string comparison and date-parsing grounds. Still open in Sockeye too
## 2. Configuration behaviour to check
- [ ] **URL binding precedence.** An in-code `UseUrls` beats `ASPNETCORE_URLS`. Find where AyaNova takes its URLs from (Sockeye: `SOCKEYE_USE_URLS` in `config.json`) and make sure the documented setting is the one that wins
- [ ] **Logging providers.** `appsettings.json` very likely sets the Debug and Console providers to `Trace`, as Sockeye's does. Check whether `Program.cs` calls `ClearProviders()` before adding NLog. If it does not, `Trace` floods the journal under systemd. Fix the levels in the repo either way
- [ ] **Data Protection keys.** Only matters if AyaNova encrypts anything with Data Protection and runs under a service account with no home directory: then the key ring must be persisted explicitly. A JWT-only API is unaffected
## 3. Fixes found through Sockeye (each its own commit)
These are bugs, not port mechanics, so each is a separate commit that can be reverted alone.
Sockeye included its equivalents in the port branch. John decides per item whether they go
in this branch or a follow-up release.
- [ ] **Case 4676: data-list SQL injection — priority.** The numeric and role filters in `DataListSqlFilterCriteriaBuilder` built SQL from input. In AyaNova any authenticated user who can open a data list could reach them. Port the Sockeye fix
- [ ] **`DbUtil.AdminConnectionString`.** If it is `_dbConnectionString.Replace(_dbName, "postgres")`, any customer whose role name, password or host contains the database name as text gets a mangled admin connection, and the boot check authenticates as the wrong user. Fix: `new NpgsqlConnectionStringBuilder(cs) { Database = "postgres" }.ConnectionString`
- [ ] **Backup `pg_dump` call.** If it builds a `postgresql://user:password@host:port/db` URI with the raw password and runs it through a shell for a `> file` redirect, a password with spaces or `@ : / ? # %` breaks backups. Fix: password in `PGPASSWORD` in the process environment, connection parameters as separate arguments through `ProcessStartInfo.ArgumentList` (no shell), output with `-f`
- [ ] **Drop-and-recreate database.** Without `CREATEDB` it drops the database and then fails to create it. Test the permission before dropping, or change the order
- [ ] **Report browser download location.** Point it under the data directory in code. Beside the app it is read-only under a hardened systemd unit (`ProtectSystem=strict`), and a redeploy that replaces the app folder deletes it
- [ ] **Report failures must not kill the server.** On the Sockeye destination a failed browser download was an unhandled exception that ended the whole process (systemd `core-dump`, then restart); the client saw only `TypeError … reading 'length'`. Catch download and launch failures, log them through NLog, and return an error to the client
- [ ] **Data-list date filters, small fixes.** `>=` and `<` should use `ZeroSeconds`, not `MaxSeconds`; date `NotEqual` should exclude the whole minute (`< ZeroSeconds OR > MaxSeconds`). In DEBUG builds, `DataListField.UiFieldDataType` is read before `DataListField` is null-checked
- [ ] **Relative date tokens use the server's time zone** (`*today*`, `*yesterday*` …), which is wrong for any user in a different zone from the server. The fix builds the range from `clientTimeStamp.Offset`, with care for ranges that cross a DST change. **This changes behaviour** and affects the integration tests' `TIME_ZONE_ADJUSTMENT`. Probably better as a follow-up release
Not port items, listed so they are not forgotten: the three server bugs the integration
suite is waiting on (case 4653, case 4654, the contract issue).
## 4. Test under realistic conditions
- [ ] **Database role.** Run under a non-superuser role **named like the database**, with a password containing spaces and `@ : / ? # %`. Boot, on-demand backup, scheduled backup, restore. Sockeye ran as `postgres` for years and never exercised either bug in section 3
- [ ] **Restore with a dedicated role.** `createdb -O <role>`, then `pg_restore --no-owner --no-privileges --role=<role>`. Without `--role`, a superuser restore leaves every table owned by `postgres`, and the integrity check, which counts through `information_schema`, fails. Compare with the restore instructions in the customer manual (`docs/`) and note any change needed
- [ ] **Reports, all advanced reports**, compared with the baseline PDFs. On Windows and on Linux. On Linux also: `ldd` on the downloaded browser binary for missing libraries (install exactly what is reported; several Ubuntu 24.04+ names carry a `t64` suffix); the sandbox under the service account; no orphaned `chrome` processes after a cancelled render
- [ ] Integration suite: same result as the baseline
- [ ] Licence verification gate: green
- [ ] Cypress E2E against a devtest server running the .NET 10 build
- [ ] `build-release.bat` produces all five packages; install and start each one: Windows standalone, Windows LAN, Linux server, Linux desktop, subscription Linux
## 5. Release
- [ ] **Every host that runs a framework-dependent build needs the .NET 10 runtime** before it gets the release:
- Hosted subscription droplets (Ubuntu 24.04). How `aspnetcore-runtime-10.0` is obtained on 24.04 needs checking **[unverified]**. On 26.04 it is in Ubuntu's own archive
- Self-hosted Linux customers (server and desktop zips are framework-dependent)
- Windows LAN: `lan.iss` prompts for the ASP.NET Core Hosting Bundle. Update its text and link to .NET 10
- Windows standalone and the launcher are self-contained: no runtime needed on the customer's machine
- [ ] Customer manual (`docs/`): system requirements and upgrade instructions for self-hosted customers
- [ ] Build VM: install the .NET 10 SDK; update `devdocs/build/DEV-VM-SETUP.md` and `devdocs/build/BUILD.md`
- [ ] Final gate runs on the finished code
- [ ] Merge, per repo:
```powershell
git switch net10-port; git status; git push; git fetch origin
git switch main; git pull
git log --oneline net10-port..main # must print nothing: main untouched
git merge --no-ff net10-port -m "Merge net10-port: .NET 10 port"
git diff net10-port main # must print nothing: main is exactly what was tested
git push origin main
git tag -a <version> -m "<release note>"
git push origin <version>
git ls-remote --tags origin
```
`--no-ff` keeps a merge commit, so the whole port can be backed out with `git revert -m 1 <merge>`
- [ ] Rebuild the client from `main`, publish, and test **the published artifact itself**
- [ ] Rollout: own test droplet first, then customer droplets by time zone, as in the weekly routine
- [ ] After release: delete `net10-port` locally and on the remote
---
## Open questions
- Release version number (Sockeye's port was released as 8.1.0)
- `raven-launcher` (.NET 8, self-contained): move to .NET 10 in the same release?
- `raven-test-integration`: move to `net10.0` (separate commit) or leave on `net8.0`? It only talks HTTP to the server
- Does the client need a rebuild in this pass, or can its current output be carried across?
- Section 3: which fixes go in this branch, which in a follow-up
- How the .NET 10 runtime gets onto Ubuntu 24.04 hosts
## Deferred
Found during the port, out of scope. One line each.
-
## Log
| Date | Step | Result |
|---|---|---|
| | | |

View File

@@ -0,0 +1,71 @@
# AyaNova project overview
Background for anyone, human or AI, working on this code: what the products are, who runs
them where, and the development setup.
## Business
Ground Zero Tech-Works Inc. sells AyaNova, commercial service management software
(https://ayanova.com), directly to customers online since 1998. One person, John, does all
development, support and administration.
Revenue comes from three streams:
- **Hosted subscriptions**: AyaNova v8 run by Ground Zero on DigitalOcean droplets. Built with `SUBSCRIPTION_BUILD=true`
- **Self-hosted v8 licences** with yearly support and update subscriptions. Customers install it on their own Windows or Linux machines
- **v7 legacy support**: maintenance only
Practical consequence for code changes: a change can reach customer-run servers that
Ground Zero cannot see or update, and deployed clients cannot be pushed an update. API
routes, licence handling and database behaviour have to stay compatible.
## Products
| Product | Stack | Status |
|---|---|---|
| **AyaNova v8** | ASP.NET Core 8, C#, PostgreSQL; Vue 2 front end | Active. Customers are slowly moving to it from v7 |
| **AyaNova v7** | Windows desktop app, C#, 20+ years old, Firebird database | Sunset: maintenance only. Depends on discontinued commercial components. Builds in an isolated Windows 7 VirtualBox VM. Customers were told in 2022 it may become unsupportable |
| **Sockeye** | Same stack as v8, a near-copy of its code | Internal: licensing, customer database, cases (history back to FogBugz). Ported to .NET 10 in October 2026 |
| **AyaNova QBI** | .NET Framework 4.8, Windows Forms | QuickBooks Desktop integration for v8. Separate release cycle, rarely changes |
## v8 deployment targets
`build-release.bat` produces five packages; QBI is built separately.
| Target | Package | Runtime |
|---|---|---|
| Hosted subscription, Linux | `ayanova-subscription-linux-x64-server.zip` | Framework-dependent |
| Self-hosted Linux server | `ayanova-linux-x64-server.zip` | Framework-dependent |
| Self-hosted Linux desktop (single user) | `ayanova-linux-x64-desktop.zip` | Framework-dependent |
| Windows standalone (single user) | `ayanova-windows-x64-single-setup.exe` | Self-contained, embedded PostgreSQL, launcher |
| Windows LAN server | `ayanova-windows-x64-lan-setup.exe` | Framework-dependent; customer installs the ASP.NET Core Hosting Bundle and PostgreSQL |
| QuickBooks integration | `ayanova-qbi-setup.exe` | .NET Framework 4.8 |
Hosted customers run on DigitalOcean Ubuntu droplets. They are updated by hand weekly:
Ground Zero's own test droplet first, then customers through the day by time zone.
## Development environment
- **Workstation:** Beelink SER9 Pro+, 32 GB, Windows 11 Pro. Backup: ThinkPad X13 Gen 3
- **Editors:** VS Code for everything except QBI, which needs Visual Studio for the Windows Forms designer
- **Build VM:** a complete Windows 11 build environment in VirtualBox, exported and backed up to several drives (`devdocs/build/DEV-VM-SETUP.md`)
- **Source control:** Git on a self-hosted Gitea on DigitalOcean. Moved from SVN in early 2026
- **Location:** off-grid, Starlink internet, solar power. The workstation is not left running overnight in winter, so do not plan work that depends on overnight runs on it
### Pinned tool versions
| Tool | Version | Why |
|---|---|---|
| Node.js | 12.22.9 | Newer versions break `fibers` |
| Python | 3.11 | MkDocs for the customer manual |
| .NET SDK | 8.0.x, plus 10.x for the port | Server, launcher |
| .NET Framework | 4.8 | QBI only |
| Inno Setup | 6.x | Windows installers |
| 7-Zip | current | Linux zips |
## Working style
- Reliability over speed; patient with build times
- Keep all historical data: cases, emails, old releases
- Careful about backups and disaster recovery
- Changes are reviewed before they are committed; nothing is accepted blindly

View File

@@ -0,0 +1,44 @@
# Modernization roadmap
The order of the modernization work and where each step stands. Steps are lettered as in
the original plan (February–March 2026). Statuses are as of October 2026; any marked
**[unverified]** were not recorded anywhere recent and need John to confirm.
| Step | What | Status |
|---|---|---|
| — | SVN → Git, self-hosted Gitea | ✅ Done |
| — | Build process documented; Docker builds for front end and docs; Windows build VM exported and backed up | ✅ Done |
| A1 | E2E tests with Cypress 9.7.0, targeting remote devtest servers, with version validation and environment-based config | **[unverified]**: the March notes listed it as both done and in progress |
| A2 | Fix the outdated integration tests in `raven-test-integration` | ✅ Done, March 2026: compiles on `net8.0`, broken tests removed or rewritten |
| A3 | Data-list filter and sort integration tests | ✅ Done, March 2026, together with Tier 1–3 gap coverage. February notes still called them stubs; the March notes supersede that **[unverified]** |
| — | Fix the three server bugs the integration suite is waiting on: case 4653, case 4654, the contract issue | Open |
| ▶ | **.NET 10 port of the back end** | **Current**: `NET10-PORT.md` |
| B | Git baseline: tag plus refactor branch | **[unverified]**. The port's `net8-baseline` tag covers the tag half |
| C | Architecture review | Not started |
| D | Refactor: remove redundant code, simplify, improve performance. No behaviour changes | Not started |
| E | Lower-level tests: unit and integration | Not started |
| F | Remaining dependency updates (see below) | Back end: in progress as the .NET 10 port. Front end: not started |
| G | New features, from the case database backlog | Not started |
## Why the .NET 10 port comes before step D
It pulls the back-end half of step F forward. Sockeye, which shares most of this codebase,
was ported first, so the work is mapped out and comes with a list of fixes found along the
way. The integration suite from A2/A3 is the regression gate for it, as it will be for D.
## Step F, front end (not part of the current port)
In this order, each step tested before the next:
1. Remove `fibers`. It is optional for `sass-loader`; builds get a little slower
2. Move Node from 12.22.9 to a current LTS
3. Update the safe dependencies
4. Vue 2 → Vue 3 and Vuetify 2 → Vuetify 3
5. Webpack → Vite
6. Optional: Options API → Composition API; TypeScript for new files only
## Before step D starts
1. The integration suite passes, apart from the three known server bugs
2. Fix those three bugs
3. Then refactor, letting the tests catch regressions

View File

@@ -0,0 +1,37 @@
# Testing
What test suites exist, what they protect, and the rules for adding to them.
## Suites
| Suite | Where | What it covers | State |
|---|---|---|---|
| API integration tests | `raven-test-integration` | Tier 1–3 API coverage against a running server | Green apart from three known server bugs (March 2026). Details in that repo's `CLAUDE.md` |
| E2E | Cypress 9.7.0 **[unverified: which folder]** | User workflows in a browser, against remote devtest servers, with version validation and environment-based config | **[unverified]** |
| Licence verification gate | To be written (`NET10-PORT.md`, section 0) | Every stored v8 licence still verifies | Not started |
| Unit tests | none | — | Roadmap step E |
The old regression and load-test project was disabled as flaky; nothing runs it.
## Critical paths
These must never break. Coverage is checked against this list before refactoring:
1. Authentication and authorization (JWT, roles, 401/403)
2. Customer management
3. Work order creation, status flow, through to invoicing
4. Quotes, PMs and contracts
5. Scheduling
6. Inventory and parts
7. Reports
8. Data lists: filtering, sorting, saved filters, paging
9. Licence verification
## Rules
- **Prove a gate on the unmodified code** before changing anything, so a later failure points at the change, not at the test.
- **Fix or delete a broken test.** Never leave it failing without a recorded reason. A known failure waiting on a server fix is recorded with its case number.
- **Do not test what cannot be seeded.** Tests that need IDs not known at test time (such as warehouse IDs for stock levels) are left out and listed as such.
- **`data-testid` attributes** for anything Cypress selects, so tests do not depend on CSS classes.
- **Fixtures with customer data stay outside the repo**, found through an environment variable.
- New tests go where they protect the most: back-end API first, then browser workflows.