diff --git a/BACKEND-BUILD-ENVIRONMENT.md b/BACKEND-BUILD-ENVIRONMENT.md deleted file mode 100644 index 9ecb7e6e..00000000 --- a/BACKEND-BUILD-ENVIRONMENT.md +++ /dev/null @@ -1,374 +0,0 @@ -# AyaNova v8 Backend Build Environment Documentation - -> **Purpose**: This document captures the complete backend build process for AyaNova v8, including all deployment targets and installers. - -## Overview - -The backend build produces **6 deployment packages** from **3 projects**: - -### Projects - -| Project | Framework | Purpose | -|---------|-----------|---------| -| AyaNova (server) | .NET 8.0 | Main ASP.NET Core web server | -| raven-launcher | .NET 8.0 | Windows launcher for standalone mode | -| AyaNovaQBI | .NET Framework 4.8 | QuickBooks Desktop integration (separate build) | - -### Deployment Targets - -| Target | Description | Output | -|--------|-------------|--------| -| Subscription Linux x64 | Your hosted service (DigitalOcean) | `ayanova-subscription-linux-x64-server.zip` | -| Perpetual Linux Server | Self-hosted Linux server | `ayanova-linux-x64-server.zip` | -| Perpetual Linux Desktop | Single-user Linux desktop | `ayanova-linux-x64-desktop.zip` | -| Windows Standalone | Self-contained single-user (includes .NET runtime + PostgreSQL) | `ayanova-windows-x64-single-setup.exe` | -| Windows LAN | Network server (requires separate .NET + PostgreSQL) | `ayanova-windows-x64-lan-setup.exe` | -| QuickBooks Integration | Windows desktop app | `ayanova-qbi-setup.exe` (separate build) | - ---- - -## Directory Structure - -``` -c:\data\code\ -├── raven\ # Main repository root -│ ├── build-release.bat # Master build script -│ ├── raven.sln # Visual Studio solution -│ ├── server\ -│ │ └── AyaNova\ # ASP.NET Core server project -│ │ ├── AyaNova.csproj -│ │ ├── Program.cs -│ │ ├── Startup.cs -│ │ ├── wwwroot\ # Frontend files copied here -│ │ └── resource\ # Report templates, etc. -│ ├── docs\ -│ │ └── 8.0\ -│ │ ├── ayanova\ # Main documentation (MkDocs) -│ │ │ └── mkdocs.yml -│ │ └── customer\ # Customer portal documentation -│ │ └── mkdocs.yml -│ ├── dist\ -│ │ ├── assets\ # Shared assets (license, configs, icons) -│ │ │ ├── LICENSE -│ │ │ ├── license.rtf -│ │ │ ├── linux-desktop\config.json -│ │ │ ├── linux-server\config.json -│ │ │ ├── lan-install-config.json -│ │ │ └── logo.ico -│ │ ├── install\ -│ │ │ └── windows\x64\ # Inno Setup scripts -│ │ │ ├── standalone.iss -│ │ │ └── lan.iss -│ │ ├── installers\ # Build output (generated) -│ │ ├── linux-x64\ # Linux build output (generated) -│ │ ├── subscription-build-linux-x64\ # Subscription build output (generated) -│ │ └── win-x64\ # Windows build output (generated) -│ │ ├── ayanova\ -│ │ │ ├── standalone\ # Self-contained build -│ │ │ └── framework-dependent\ # Requires .NET installed -│ │ ├── launcher\ # Launcher build output -│ │ └── postgres-standalone\ # Embedded PostgreSQL for standalone -│ └── graphics\ # Icons, logos -│ -├── raven-client\ # Frontend (separate repo/folder) -│ └── ayanova\ -│ -├── raven-launcher\ # Launcher project -│ ├── raven-launcher.csproj -│ └── config.json -│ -└── ravenqbi\ # QuickBooks integration (separate) - ├── AyaNovaQBI\ - │ └── AyaNovaQBI.csproj - └── install\ - └── qbi.iss -``` - ---- - -## Build Requirements - -### Software - -| Tool | Version | Purpose | -|------|---------|---------| -| .NET SDK | 8.0.x | Build ASP.NET Core projects | -| Node.js | 12.22.9 | Build frontend (see frontend docs) | -| Python | 3.11.x | Build MkDocs documentation | -| MkDocs | Latest | Documentation generator | -| Inno Setup | 6.x | Windows installer creation | -| 7-Zip | Latest | Create Linux distribution zips | -| Visual Studio 2022 | Latest | Build QBI project (.NET Framework 4.8) | - -### Paths (hardcoded in build scripts) - -The build scripts expect these exact paths: -- `C:\data\code\raven\` - Main repository -- `C:\data\code\raven-client\ayanova\` - Frontend project -- `C:\data\code\raven-launcher\` - Launcher project -- `C:\data\code\ravenqbi\` - QuickBooks integration -- `C:\Program Files\7-Zip\7z.exe` - 7-Zip -- `C:\Program Files (x86)\Inno Setup 6\ISCC.exe` - Inno Setup compiler - ---- - -## Build Process (build-release.bat) - -The master build script executes in this order: - -### 1. Clean Output Folders -```batch -rmdir c:\data\code\raven\server\AyaNova\wwwroot /s/q -mkdir c:\data\code\raven\server\AyaNova\wwwroot -rmdir C:\data\code\raven\dist\installers /s/q -mkdir C:\data\code\raven\dist\installers -``` - -### 2. Build Documentation (MkDocs) -```batch -cd c:\data\code\raven\docs\8.0\ayanova -mkdocs build - -cd c:\data\code\raven\docs\8.0\customer -mkdocs build -``` -Output goes to `wwwroot/docs` (configured in mkdocs.yml). - -### 3. Build Frontend (Vue.js) -```batch -cd c:\data\code\raven-client\ayanova -call npm run build -xcopy dist\* ..\raven\server\AyaNova\wwwroot\ /e -``` - -### 4. Build Subscription Linux x64 -```batch -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 -``` -Key flag: `-p:SUBSCRIPTION_BUILD=true` sets a compile-time constant for subscription-specific features. - -Then packages to zip with config: -```batch -7z a ayanova-subscription-linux-x64-server.zip subscription-build-linux-x64\* -7z a ayanova-subscription-linux-x64-server.zip assets\linux-server\config.json -``` - -### 5. Build Perpetual Linux x64 -```batch -dotnet publish --property:PublishDir=C:\data\code\raven\dist\linux-x64\ \ - -c Release -r linux-x64 --no-self-contained -p:SUBSCRIPTION_BUILD=false -``` - -Creates two packages (same build, different config): -- `ayanova-linux-x64-desktop.zip` (with desktop config) -- `ayanova-linux-x64-server.zip` (with server config) - -### 6. Build Windows Standalone (Self-Contained) -```batch -dotnet publish -c Release --property:PublishDir=C:\data\code\raven\dist\win-x64\ayanova\standalone\ \ - -r win-x64 --self-contained -``` -This includes the .NET runtime in the output (~150MB larger). - -### 7. Build Windows Framework-Dependent -```batch -dotnet publish -c Release --property:PublishDir=C:\data\code\raven\dist\win-x64\ayanova\framework-dependent\ \ - -r win-x64 --no-self-contained -``` -Requires .NET 8 runtime installed on target machine. - -### 8. Build Launcher -```batch -cd C:\data\code\raven-launcher\ -dotnet publish -c Release --property:PublishDir=C:\data\code\raven\dist\win-x64\launcher\ \ - -r win-x64 --self-contained -``` -The launcher is always self-contained (uses `PublishTrimmed` to reduce size). - -### 9. Create Windows Installers (Inno Setup) -```batch -ISCC.exe standalone.iss -ISCC.exe lan.iss -``` - ---- - -## Project-Specific Notes - -### AyaNova Server (AyaNova.csproj) - -**Conditional Compilation:** -```xml -$(DefineConstants);SUBSCRIPTION_BUILD -``` -Use `#if SUBSCRIPTION_BUILD` in code for subscription-only features. - -**Key Dependencies:** -- Entity Framework Core 8.0 with Npgsql (PostgreSQL) -- PuppeteerSharp for PDF report generation (downloads Chromium on first run) -- MailKit for email -- JWT authentication - -**Resource Files:** -Report templates and other resources are copied to output: -```xml - - Always - -``` - -### Launcher (raven-launcher.csproj) - -Simple console app that: -1. Starts embedded PostgreSQL (standalone mode only) -2. Starts the AyaNova server -3. Opens default browser to the login page -4. Waits for user to close - -Uses `PublishTrimmed` to reduce self-contained size. - -### QuickBooks Integration (AyaNovaQBI.csproj) - -**Important:** This is a .NET Framework 4.8 Windows Forms application, NOT .NET Core. - -- Requires Visual Studio 2022 (not VS Code) for the Windows Forms designer -- References `interop.QBFC14.dll` from QuickBooks SDK (must be installed) -- Targets x86 (32-bit) because QuickBooks SDK is 32-bit only -- Has a pre-build event that runs a timestamp utility - -**Why Visual Studio is required:** -The Windows Forms designer only works in Visual Studio. The code could theoretically be edited in VS Code, but the designer is essential for the UI work. - ---- - -## Windows Installer Details - -### Standalone (standalone.iss) - -Includes: -- Self-contained AyaNova server (with .NET runtime) -- Self-contained launcher -- Embedded PostgreSQL (`postgres-standalone` folder) -- Empty database template - -Creates desktop shortcut to launcher. User clicks one icon, everything starts. - -**Key paths:** -- App: `{autopf}\ayanova` -- Data: `{commonappdata}\ayanova\database` -- Logs: `{commonappdata}\ayanova\logs` - -### LAN (lan.iss) - -Includes: -- Framework-dependent AyaNova server (no .NET runtime) -- Config file for network mode - -Does NOT include PostgreSQL - user must install separately. - -Prompts user to download: -- ASP.NET Core Runtime Hosting Bundle -- PostgreSQL - ---- - -## Embedded PostgreSQL (Windows Standalone) - -The standalone installer includes a portable PostgreSQL in `dist\win-x64\postgres-standalone\`. - -This is a pre-configured PostgreSQL installation that: -- Runs without system installation -- Stores data in `{commonappdata}\ayanova\database` -- Is started/stopped by the launcher - -**Source:** You'll need to maintain this - it's a copy of a PostgreSQL Windows binary distribution with a pre-initialized data directory. - ---- - -## QuickBooks Integration Build (Separate) - -The QBI is built separately and not included in the main build script. - -```batch -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: `c:\data\code\ravenqbi\install\output\ayanova-qbi-setup.exe` - ---- - -## Version Management - -Versions must be updated in multiple places: - -| File | Location | -|------|----------| -| `AyaNova.csproj` | `8.2.4` | -| `standalone.iss` | `#define MyAppVersion "8.2.4"` | -| `lan.iss` | `#define MyAppVersion "8.2.4"` | -| `qbi.iss` | `#define MyAppVersion "8.0.2"` | -| `package.json` (frontend) | `"version": "8.2.4"` | - -Consider creating a version file or script to update all at once. - ---- - -## Containerization Considerations - -### What CAN be containerized (for build): - -1. **Frontend build** - Already done (Dockerfile.frontend) -2. **Documentation build** - Already done (Dockerfile.docs) -3. **Linux server builds** - .NET SDK in Docker can cross-compile for Linux -4. **Windows framework-dependent build** - Can be built in Docker - -### What CANNOT be easily containerized: - -1. **Windows self-contained builds** - Need Windows container or Windows host -2. **Inno Setup installers** - Windows-only tool -3. **QuickBooks Integration** - .NET Framework 4.8, Windows Forms, requires Visual Studio -4. **Embedded PostgreSQL** - Windows-specific binaries - -### Recommendation: - -For a VPS-based build: -- Use Docker/Linux for: Frontend, Docs, Linux targets -- Keep Windows laptop for: Windows installers, QBI -- Or: Use a Windows VM/GitHub Actions for Windows builds - ---- - -## Troubleshooting - -### "PuppeteerSharp failed to download Chromium" - -The server downloads Chromium on first run for PDF generation. If this fails: -1. Check internet connectivity -2. Check firewall/proxy settings -3. Pre-download Chrome and set `REPORT_RENDER_BROWSER_PATH` environment variable - -### "SUBSCRIPTION_BUILD not defined" - -Ensure you're passing the flag correctly: -```batch -dotnet publish ... -p:SUBSCRIPTION_BUILD=true -``` - -### Inno Setup errors - -- Ensure all source paths exist -- Check that previous build steps completed -- Verify 7-Zip and Inno Setup are installed at expected paths - ---- - -## Version History - -| Date | Change | -|------|--------| -| 2026-02-01 | Initial documentation created | diff --git a/BUILD-ENVIRONMENT.md b/BUILD-ENVIRONMENT.md deleted file mode 100644 index ca4a76d4..00000000 --- a/BUILD-ENVIRONMENT.md +++ /dev/null @@ -1,271 +0,0 @@ -# AyaNova v8 Build Environment Documentation - -> **Purpose**: This document captures the exact build environment for AyaNova v8 as of February 2026. Use this to recreate the build environment on a new machine or in a container. - -## Overview - -AyaNova v8 consists of three main build components: - -1. **Frontend** - Vue.js 2 application (JavaScript, not TypeScript) -2. **Documentation** - MkDocs with Material theme -3. **Backend** - ASP.NET Core 8.0 server (C#) - -The frontend and docs are built first, then copied into the backend project's `wwwroot` folder before the backend is built and packaged for distribution. - ---- - -## Current Build Machine Specifications - -| Component | Version | Notes | -|-----------|---------|-------| -| Operating System | Windows 11 | ThinkPad X13 Gen 3 | -| Node.js | v12.22.9 | **End-of-life** - do not upgrade without testing | -| npm | (check with `npm -v`) | Comes with Node | -| Python | 3.11.1 | For MkDocs | -| .NET SDK | 8.0.x | For backend build | - ---- - -## Frontend Build Environment - -### Directory Structure - -``` -c:\data\code\ -├── raven-client\ -│ └── ayanova\ # Vue.js frontend project -│ ├── src\ # Source code -│ ├── public\ # Static assets -│ ├── dist\ # Build output (generated) -│ ├── package.json -│ ├── vue.config.js -│ └── buildrelease.bat -├── raven\ -│ ├── server\ -│ │ └── AyaNova\ -│ │ └── wwwroot\ # Frontend files copied here after build -│ └── docs\ -│ └── 8.0\ -│ └── ayanova\ # MkDocs source -│ └── mkdocs.yml -``` - -### Node.js Version: Critical Information - -**Current version: Node.js 12.22.9** - -This project uses an old Node version because: - -1. The `fibers` package (used by sass-loader for faster Sass compilation) is a native C++ addon that stopped being maintained and doesn't compile on newer Node versions -2. Various other dependencies have peer dependency requirements that break on Node 14+ - -**Do not upgrade Node without first testing in an isolated environment.** - -### Key Dependencies - -From `package.json`: - -| Package | Version | Purpose | -|---------|---------|---------| -| vue | 2.6.14 | Core framework (Vue 2, end-of-life Dec 2023) | -| vuetify | 2.6.6 | UI component library | -| @vue/cli-service | 4.5.15 | Build tooling | -| webpack | 4.46.0 | Module bundler | -| sass | 1.52.3 | Sass compiler | -| fibers | 4.0.3 | **Problematic** - native addon for Sass | -| monaco-editor | 0.30.1 | Code editor component | - -### Build Process - -The frontend build is executed via `buildrelease.bat`: - -```batch -@echo ************************************************************** -@echo ******************** BUILD CLIENT **************************** -@echo ************************************************************** -rmdir c:\data\code\raven\server\AyaNova\wwwroot /s/q -mkdir c:\data\code\raven\server\AyaNova\wwwroot -cd c:\data\code\raven\docs\8.0\ayanova -mkdocs build -cd c:\data\code\raven-client\ayanova -call npm run build -xcopy c:\data\code\raven-client\ayanova\dist\* C:\data\code\raven\server\AyaNova\wwwroot\ /e -pause -``` - -This does: -1. Clears and recreates the backend's wwwroot folder -2. Builds the MkDocs documentation (output goes directly to wwwroot/docs via mkdocs.yml config) -3. Runs `npm run build` which calls `vue-cli-service build` -4. Copies the built frontend from `dist/` to the backend's `wwwroot/` - -### Known Build Warnings (Safe to Ignore) - -These warnings appear during every build and do not affect the output: - -1. **Browserslist warning**: "caniuse-lite is outdated" - - Harmless - just means browser compatibility database is old - -2. **Dart Sass division warnings**: "Using / for division is deprecated" - - Come from Vuetify's stylesheets, not your code - - Will continue working until Dart Sass 2.0 - -3. **Asset size warnings**: Various files exceed 244 KiB - - Expected with Monaco editor (ts.worker.js is 4.5MB) - - Application still works correctly - -### NPM Scripts - -```json -{ - "serve": "vue-cli-service serve", // Development server - "build": "vue-cli-service build", // Production build - "lint": "vue-cli-service lint" // Code linting -} -``` - ---- - -## Documentation Build Environment - -### MkDocs Configuration - -From `mkdocs.yml`: - -| Setting | Value | -|---------|-------| -| Theme | Material | -| Output directory | `../../../server/AyaNova/wwwroot/docs` | -| Site URL | https://ayanova.com/docs/ | - -### Required Python Packages - -```bash -pip install mkdocs mkdocs-material -``` - -The `pymdownx` extensions (highlight, superfences) come bundled with mkdocs-material. - -### Build Command - -```bash -cd c:\data\code\raven\docs\8.0\ayanova -mkdocs build -``` - -Output goes directly to the backend's wwwroot/docs folder. - ---- - -## Backend Build Environment - -### .NET Version - -- **Target Framework**: .NET 8.0 -- **Project Type**: ASP.NET Core - -### Build Tools Required - -- .NET 8.0 SDK -- Visual Studio 2022 or VS Code with C# extension - -### Build Outputs - -The backend build produces multiple deployment targets: -1. Linux hosted (DigitalOcean service) -2. Windows networked (IIS hosted) -3. Windows single-user (self-contained) -4. Linux server -5. Linux desktop - -Windows installers are created with Inno Setup. - ---- - -## Recreating the Build Environment - -### Option 1: Native Installation (Windows) - -1. Install Node.js 12.22.9 specifically: - - Download from https://nodejs.org/dist/v12.22.9/ - - Or use nvm-windows: `nvm install 12.22.9 && nvm use 12.22.9` - -2. Install Python 3.11: - - Download from python.org - - Ensure it's in PATH - -3. Install MkDocs: - ```bash - pip install mkdocs mkdocs-material - ``` - -4. Install .NET 8.0 SDK: - - Download from https://dotnet.microsoft.com/download - -5. Clone/checkout repository from SVN - -6. Install frontend dependencies: - ```bash - cd c:\data\code\raven-client\ayanova - npm ci - ``` - Note: Use `npm ci` (not `npm install`) to install exact versions from package-lock.json - -### Option 2: Docker (Recommended for Reproducibility) - -See `Dockerfile.frontend` and `Dockerfile.docs` in this repository for containerized builds that don't require any local installation except Docker. - ---- - -## Troubleshooting - -### "fibers" fails to install - -This native module requires: -- Python 2.7 or 3.x -- Visual Studio Build Tools (Windows) or build-essential (Linux) -- Specific Node.js version compatibility - -If it fails, you can try removing it (it's optional): -1. Remove `"fibers": "^4.0.3"` from package.json -2. Remove the `fiber: require("fibers")` line from webpack.config.js -3. Run `npm install` again - -The build will be slightly slower but should work. - -### Node version mismatch - -If you see errors about incompatible Node versions: -1. Check your Node version: `node -v` -2. It must be 12.22.9 for guaranteed compatibility -3. Use nvm to switch versions if needed - -### "Module not found" errors - -Try: -```bash -rm -rf node_modules -rm package-lock.json -npm install -``` - ---- - -## Future Modernization Notes - -When time permits, consider: - -1. **Remove fibers dependency** - It's optional and causes most build issues -2. **Upgrade to Vue 3 + Vite** - Much faster builds, better tooling, active support -3. **Migrate to TypeScript** - Better IDE support and fewer runtime errors -4. **Update Node to LTS** - Current LTS is Node 20.x - -These are significant changes that should be done incrementally with thorough testing. - ---- - -## Version History - -| Date | Change | -|------|--------| -| 2026-02-01 | Initial documentation created | diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..982ab7aa --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,100 @@ +# AyaNova v8 — instructions for Claude Code + +Loaded in every session started in this repo, and imported by the CLAUDE.md files in +`raven-client` and `raven-test-integration`. Keep it short: detail lives in `devdocs/`. + +Statements marked **[unverified]** came from older notes and have not been checked against +the code. Check one before relying on it, then fix the statement or remove the marker. + +## What this is + +AyaNova v8: commercial service management software (ayanova.com), sold since 1998, +built and maintained by one developer, John. It is a production product. Hosted +subscription customers and self-hosted customers on Windows and Linux run this code, and +deployed clients call its API routes. + +## Repositories + +Separate Git repos under `C:\data\code\`, hosted on a self-hosted Gitea. The build scripts +hardcode these paths: do not move or rename the folders. + +| Folder | What | Stack | +|---|---|---| +| `raven` | **This repo, the master.** Back-end server, customer manual, build and installer scripts | ASP.NET Core 8, C#, EF Core 8, Npgsql, PostgreSQL | +| `raven-client` | Front end, in `ayanova/` | Vue 2.6, Vuetify 2.6, Vuex, Vue Router, plain JavaScript, Node 12.22.9 | +| `raven-test-integration` | API integration tests against a running server | xUnit, .NET 8 | +| `raven-launcher` | Windows standalone launcher | .NET 8, self-contained, trimmed | +| `ravenqbi` | QuickBooks Desktop integration | .NET Framework 4.8 WinForms, x86, Visual Studio only | +| `sockeye` | Internal licensing server, a near-copy of this codebase, **already ported to .NET 10** (tag `8.1.0`) **[unverified: folder name]** | same as `raven` | + +Cypress E2E tests (Cypress 9.7.0, targeting remote devtest servers) also exist +**[unverified: which folder]**. + +## Layout of this repo + +- `server/AyaNova/` — the application, `AyaNova.csproj`. Publish this csproj directly, never `raven.sln`. +- `docs/` — the **customer** help manual (MkDocs). Not developer documentation. Do not edit unless asked. +- `devdocs/modernization/` and `devdocs/build/` — current developer docs. Anything else in `devdocs/` is old historical notes: ignore unless asked. +- `dist/` — packaging assets, Inno Setup scripts, build outputs. +- `build-release.bat` — master release build. + +## Current work: .NET 10 port, branch `net10-port` + +Move the server from .NET 8 to .NET 10 and every back-end package to its current release. +Front end: minimal or no change. + +**Before any port work, read `devdocs/modernization/NET10-PORT.md`.** It holds the plan, +the checklist and the decisions still open. Update its checklist and log in the same +commit as the change they record. + +Sockeye went through the same port first. When a port question comes up, look at how +Sockeye solved it: `git -C ..\sockeye log --oneline net6-baseline..8.1.0`. + +The rest of the modernization plan: `devdocs/modernization/ROADMAP.md`. + +## Working rules + +- No change to production code without John's explicit approval. Propose a plan first for anything beyond a one-line fix. +- One concern per commit, so a regression can be found with `git log` and undone with `git revert`. The version bump is always the first commit on a release branch. +- Do not mix refactoring, bug fixes and features. If you spot something worth refactoring during the port, add it to "Deferred" in `NET10-PORT.md` instead of doing it. +- Dependency changes: back-end packages only, and only on `net10-port`. No front-end dependency changes (Node is pinned at 12.22.9 because of `fibers`). +- Do not add `[ApiController]` to controllers that lack it. It changes model binding and error responses on routes deployed clients call. +- No new features. +- Git: keep it simple and explicit. Do not push, tag, merge or rewrite history unless asked. Tags are annotated and pushed by name. +- Nothing is accepted blindly: show the diff and say why. +- Secrets and customer data never go in a repo. Fixtures that contain customer data live outside the repo and are found through an environment variable. + +## Environment + +- Windows 11, PowerShell, VS Code. Visual Studio only for `ravenqbi`. +- .NET 10 SDK installed alongside the .NET 8 runtime **[unverified: check `dotnet --info`]**. +- Local server: `http://localhost:7575`, API base `/api/v8/`. +- Compile-time constant `SUBSCRIPTION_BUILD` (`-p:SUBSCRIPTION_BUILD=true`) distinguishes the hosted build; use `#if SUBSCRIPTION_BUILD`. + +## Commands + +```powershell +dotnet build server\AyaNova\AyaNova.csproj +dotnet run --project server\AyaNova + +# integration tests: the server must be running first +cd ..\raven-test-integration; dotnet test raven-integration.csproj + +# hosted (subscription) Linux build, as build-release.bat does it +dotnet publish server\AyaNova\AyaNova.csproj -c Release -r linux-x64 --no-self-contained -p:SUBSCRIPTION_BUILD=true + +# full release: docs, client, all five packages, installers +.\build-release.bat +``` + +## Reference (read when relevant, not every session) + +| File | Covers | +|---|---| +| `devdocs/modernization/NET10-PORT.md` | The current port: plan, checklist, open questions, log | +| `devdocs/modernization/ROADMAP.md` | Modernization steps and their status | +| `devdocs/modernization/PROJECT-OVERVIEW.md` | Products, deployment targets, business context | +| `devdocs/modernization/CODEBASE-REFERENCE.md` | Stack, structure, configuration, API conventions | +| `devdocs/modernization/TESTING.md` | Test suites and their state | +| `devdocs/build/BUILD.md` | Release build, packaging, version numbers | +| `devdocs/build/DEV-VM-SETUP.md` | Rebuilding the Windows build VM from scratch | diff --git a/devdocs/build/BUILD.md b/devdocs/build/BUILD.md new file mode 100644 index 00000000..14f46209 --- /dev/null +++ b/devdocs/build/BUILD.md @@ -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` | `` | 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. diff --git a/V8-DEV-VM-SETUP-GUIDE.md b/devdocs/build/DEV-VM-SETUP.md similarity index 90% rename from V8-DEV-VM-SETUP-GUIDE.md rename to devdocs/build/DEV-VM-SETUP.md index ee330fcf..4a65139e 100644 --- a/V8-DEV-VM-SETUP-GUIDE.md +++ b/devdocs/build/DEV-VM-SETUP.md @@ -1,7 +1,8 @@ -# AyaNova v8 Build VM Setup Guide +# 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. -test for commit + +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 @@ -237,7 +238,7 @@ Using winget (run in PowerShell as Administrator): # 7-Zip winget install --id 7zip.7zip -e -# Git (useful even if using SVN) +# Git winget install --id Git.Git -e # VS Code @@ -294,15 +295,7 @@ This is needed for the QuickBooks Integration project (.NET Framework 4.8, Windo 5. Click **Install** 6. Wait (this takes 20-40 minutes and downloads several GB) -### 4.7 Install TortoiseSVN (if using SVN) - -```powershell -winget install --id TortoiseSVN.TortoiseSVN -e -``` - -Reboot after installation (adds shell integration). - -### 4.8 Verify All Installations +### 4.7 Verify All Installations Open a new PowerShell window and run: @@ -360,29 +353,21 @@ All items should show versions or [OK]. ## Part 5: Set Up Source Code -### 5.1 Check Out from SVN - -If your SVN server is accessible from the VM: +### 5.1 Clone from Gitea ```powershell cd C:\data\code - -# Check out main repository -svn checkout https://your-svn-server/path/to/raven raven - -# Check out frontend -svn checkout https://your-svn-server/path/to/raven-client raven-client - -# Check out launcher -svn checkout https://your-svn-server/path/to/raven-launcher raven-launcher - -# Check out QBI -svn checkout https://your-svn-server/path/to/ravenqbi ravenqbi +git clone /raven.git raven +git clone /raven-client.git raven-client +git clone /raven-launcher.git raven-launcher +git clone /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 SVN isn't accessible, use VirtualBox shared folders: +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 @@ -524,10 +509,10 @@ When to re-export: ```powershell cd C:\data\code\raven -svn update +git pull cd C:\data\code\raven-client -svn update +git pull # etc. ``` @@ -545,7 +530,6 @@ 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 -4. **SVN Commit**: Commit build outputs to repo (not recommended for large binaries) ### 8.5 Snapshots for Safety @@ -582,19 +566,6 @@ ThinkPads are generally excellent Linux laptops. The X13 Gen 3 AMD should work w - **SSD**: VM performance is heavily dependent on disk speed; SSD is essential - **RAM**: 32GB on host would be more comfortable than 16GB -### 9.4 Used ThinkPad Recommendations - -If you're looking at a used/refurbished ThinkPad for Linux: - -| Model | Era | Notes | -|-------|-----|-------| -| X1 Carbon Gen 9/10 | 2021-2022 | Excellent, lightweight | -| T14s Gen 2/3 | 2021-2022 | Good value, business-class | -| T480/T480s | 2018 | Older but very well supported, cheap | -| P14s | 2020+ | More RAM options (up to 48GB) | - -Look for 32GB RAM models if possible. Check that the specific CPU is supported (Intel generally has better Linux support than AMD, though AMD works fine too). - --- ## Appendix A: Troubleshooting @@ -620,10 +591,10 @@ If `npm ci` fails with native module errors: - Check that 3D acceleration is enabled - Use SSD, not spinning disk -### Can't Access SVN Server +### Can't Reach Gitea - Check VM network mode (NAT vs Bridged) -- Verify SVN server is accessible from host +- Verify Gitea is reachable from the host - Check firewall settings on both host and VM --- @@ -665,7 +636,7 @@ msbuild C:\data\code\ravenqbi\AyaNovaQBI\AyaNovaQBI.csproj /p:Configuration=Rele |------|------| | 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\2022\Community\MSBuild\Current\Bin\MSBuild.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 | --- @@ -674,3 +645,4 @@ msbuild C:\data\code\ravenqbi\AyaNovaQBI\AyaNovaQBI.csproj /p:Configuration=Rele | Date | Change | |------|--------| | 2026-02-01 | Initial guide created | +| 2026-10-22 | SVN steps replaced with Git; moved to `devdocs/build/` | diff --git a/devdocs/modernization/CODEBASE-REFERENCE.md b/devdocs/modernization/CODEBASE-REFERENCE.md new file mode 100644 index 00000000..3082bad4 --- /dev/null +++ b/devdocs/modernization/CODEBASE-REFERENCE.md @@ -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);SUBSCRIPTION_BUILD +``` + +```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: }` | +| GET | 200, `{ data: }` | +| DELETE | 204, no body | +| PUT on Customer, QuoteItem, PMItem | 200, `{ data: { Concurrency: N } }` (concurrency only) | +| PUT on Quote, PM, Contract, WorkOrder headers | 200, `{ data: }` | +| 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`. diff --git a/devdocs/modernization/NET10-PORT.md b/devdocs/modernization/NET10-PORT.md new file mode 100644 index 00000000..7434a8c3 --- /dev/null +++ b/devdocs/modernization/NET10-PORT.md @@ -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 +``` + +**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())` 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 `, then `pg_restore --no-owner --no-privileges --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 -m "" + git push origin + git ls-remote --tags origin + ``` + `--no-ff` keeps a merge commit, so the whole port can be backed out with `git revert -m 1 ` +- [ ] 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 | +|---|---|---| +| | | | diff --git a/devdocs/modernization/PROJECT-OVERVIEW.md b/devdocs/modernization/PROJECT-OVERVIEW.md new file mode 100644 index 00000000..59e7874c --- /dev/null +++ b/devdocs/modernization/PROJECT-OVERVIEW.md @@ -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 diff --git a/devdocs/modernization/ROADMAP.md b/devdocs/modernization/ROADMAP.md new file mode 100644 index 00000000..d322d71a --- /dev/null +++ b/devdocs/modernization/ROADMAP.md @@ -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 diff --git a/devdocs/modernization/TESTING.md b/devdocs/modernization/TESTING.md new file mode 100644 index 00000000..2e65a14e --- /dev/null +++ b/devdocs/modernization/TESTING.md @@ -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.