org-bim-catalyst/hydra

C#

0

161 commits

updated Oct 4, 2026

See the code

README

Ask Lucy

An enterprise AI Workspace, built on the Clean Architecture / CQRS / React stack defined in .specify/memory/constitution.md and docs/. Migrated from a legacy .NET 7 ASP.NET Core MVC application ("ChatGPT Client") — see specs/000-legacy-modernization/spec.md for the migration history; the legacy project has been decommissioned.

Solution structure

Ask Lucy.sln

src/
├── AskLucy.Domain/           # entities, value objects — no external dependencies
├── AskLucy.Application/      # CQRS commands/queries/handlers, interfaces (MediatR, FluentValidation)
├── AskLucy.Infrastructure/   # IAIProvider→OpenAIProvider, JWT, file storage, email
├── AskLucy.Persistence/      # EF Core DbContext, ASP.NET Identity, repositories
└── AskLucy.Web/              # controllers, JWT auth, rate limiting, Problem Details, OpenAPI
    └── ClientApp/             # React 19 + TypeScript + Vite + Material UI — built into
                                # wwwroot on every build (see AskLucy.Web.csproj); served
                                # by the same process as the API

tests/
├── AskLucy.Domain.Tests/
├── AskLucy.Application.Tests/
├── AskLucy.Infrastructure.Tests/
├── AskLucy.Persistence.Tests/
├── AskLucy.Web.Tests/
└── AskLucy.E2E.Tests/         # Playwright — requires a live deployment, see its own header comment

Running locally

Backend

dotnet user-secrets set "ConnectionStrings:DefaultConnection" "<your SQL Server connection string>" --project src/AskLucy.Web
dotnet user-secrets set "Jwt:SigningKey" "<a random 32+ character string>" --project src/AskLucy.Web
dotnet user-secrets set "OpenAI:ApiKey" "<your OpenAI API key>" --project src/AskLucy.Web
dotnet user-secrets set "Smtp:Username" "<your SMTP username, if the host requires auth>" --project src/AskLucy.Web
dotnet user-secrets set "Smtp:Password" "<your SMTP password, if the host requires auth>" --project src/AskLucy.Web
dotnet user-secrets set "Geocoding:GoogleMapsApiKey" "<a server-side Google Maps key>" --project src/AskLucy.Web

cd src/AskLucy.Web/ClientApp && npm install && cd ../../..   # once, before the first build/run
dotnet build "Ask Lucy.sln"
dotnet run --project src/AskLucy.Web

AskLucy.Web.csproj runs npm run build and copies ClientApp's output into wwwroot before every build (including hitting Run in Visual Studio) — one process serves both the API and the SPA. This needs npm install to have been run in ClientApp at least once; it does not run install/ci itself, to keep every build fast.

In the Development environment, email is never actually sent — ConsoleEmailSender logs it instead, so the Smtp:* secrets above are only needed once you run outside Development.

Geocoding:GoogleMapsApiKey is optional but strongly recommended. Without it the app falls back to NominatimGeocodingProvider, whose candidate importance is a Wikipedia-popularity score rather than a match-quality one — an ordinary local place scores ~0.08 where Google reports 0.40-0.90, so LocationResolution:MinimumImportanceFloor behaves quite differently on the two. Use a server-side key (unrestricted or IP-restricted); the domain-restricted browser key in ClientApp/.env (VITE_GOOGLE_MAPS_API_KEY) is rejected by server-to-server calls. Which provider is live is logged once at startup:

Geocoding provider: GoogleMaps (Geocoding:GoogleMapsApiKey configured).

Never put real secrets in appsettings.json — see the _comment_secrets note in src/AskLucy.Web/appsettings.json and constitution §8.

Frontend (active UI development)

The build above always reflects ClientApp as of its last npm run build — for hot-reload during active frontend work, run the Vite dev server separately instead:

cd src/AskLucy.Web/ClientApp
npm install
npm run dev

Tests

dotnet test                                          # all backend test projects
cd src/AskLucy.Web/ClientApp && npm run test         # frontend unit tests

Deployment prerequisites

  • Tesseract OCR language data (SPEC-015 Document Intelligence Pipeline, TesseractOcrEngine): the Tesseract NuGet package brings its own native Windows engine binaries, but it does not ship any .traineddata language files, and App_Data/ (where TesseractOcr:DataPath in appsettings.json points, App_Data/tessdata) is gitignored — it is never populated by a fresh clone, a CI build, or a deploy. On any new deployment host/container image, the needed .traineddata files (at minimum eng.traineddata; add others from the tessdata repo to match the languages your users upload) must be placed under App_Data/tessdata manually before OCR will produce any text. Missing a language pack is not fatal — TesseractOcrEngine falls back to whichever trained data is actually present (defaulting to eng) rather than failing the pipeline — but a missing eng.traineddata means OCR silently returns no text for every document.

  • Supertonic 3 voice model (specs/070, SupertonicTextToSpeechEngine): Lucy's on-server voice needs the fp32 ONNX model and voice styles under App_Data/Models/supertonic-3 (Supertonic:ModelDirectory). Like tessdata, it is gitignored and never deployed by a build — run scripts/download-supertonic.ps1 (pinned revision, SHA-256 verified) and copy the resulting onnx/ and voice_styles/ folders to the host. The loaded model adds roughly 450 MB of resident memory (weights are 398 MB), so the host plan must allow it. A missing model is not fatal: the voice router fails over to the next provider (ElevenLabs) and logs why. Before making Supertonic Lucy's voice in production, the OpenRAIL-M use restrictions in docs/THIRD_PARTY_NOTICES.md must be passed through to users.

Documentation

  • .specify/memory/constitution.md — the project's engineering constitution; supersedes all other guidance.
  • docs/ — target architecture, database, API, security, testing, and design system standards.
  • docs/adr/ — Architecture Decision Records.
  • specs/ — feature specifications, plans, and tasks (Spec Kit workflow).
  • CONTRIBUTING.md — branch protection and required CI secrets.

org-bim-catalyst/hydra

C#

0

161 commits

updated Oct 4, 2026

See the code

README

Ask Lucy

An enterprise AI Workspace, built on the Clean Architecture / CQRS / React stack defined in .specify/memory/constitution.md and docs/. Migrated from a legacy .NET 7 ASP.NET Core MVC application ("ChatGPT Client") — see specs/000-legacy-modernization/spec.md for the migration history; the legacy project has been decommissioned.

Solution structure

Ask Lucy.sln

src/
├── AskLucy.Domain/           # entities, value objects — no external dependencies
├── AskLucy.Application/      # CQRS commands/queries/handlers, interfaces (MediatR, FluentValidation)
├── AskLucy.Infrastructure/   # IAIProvider→OpenAIProvider, JWT, file storage, email
├── AskLucy.Persistence/      # EF Core DbContext, ASP.NET Identity, repositories
└── AskLucy.Web/              # controllers, JWT auth, rate limiting, Problem Details, OpenAPI
    └── ClientApp/             # React 19 + TypeScript + Vite + Material UI — built into
                                # wwwroot on every build (see AskLucy.Web.csproj); served
                                # by the same process as the API

tests/
├── AskLucy.Domain.Tests/
├── AskLucy.Application.Tests/
├── AskLucy.Infrastructure.Tests/
├── AskLucy.Persistence.Tests/
├── AskLucy.Web.Tests/
└── AskLucy.E2E.Tests/         # Playwright — requires a live deployment, see its own header comment

Running locally

Backend

dotnet user-secrets set "ConnectionStrings:DefaultConnection" "<your SQL Server connection string>" --project src/AskLucy.Web
dotnet user-secrets set "Jwt:SigningKey" "<a random 32+ character string>" --project src/AskLucy.Web
dotnet user-secrets set "OpenAI:ApiKey" "<your OpenAI API key>" --project src/AskLucy.Web
dotnet user-secrets set "Smtp:Username" "<your SMTP username, if the host requires auth>" --project src/AskLucy.Web
dotnet user-secrets set "Smtp:Password" "<your SMTP password, if the host requires auth>" --project src/AskLucy.Web
dotnet user-secrets set "Geocoding:GoogleMapsApiKey" "<a server-side Google Maps key>" --project src/AskLucy.Web

cd src/AskLucy.Web/ClientApp && npm install && cd ../../..   # once, before the first build/run
dotnet build "Ask Lucy.sln"
dotnet run --project src/AskLucy.Web

AskLucy.Web.csproj runs npm run build and copies ClientApp's output into wwwroot before every build (including hitting Run in Visual Studio) — one process serves both the API and the SPA. This needs npm install to have been run in ClientApp at least once; it does not run install/ci itself, to keep every build fast.

In the Development environment, email is never actually sent — ConsoleEmailSender logs it instead, so the Smtp:* secrets above are only needed once you run outside Development.

Geocoding:GoogleMapsApiKey is optional but strongly recommended. Without it the app falls back to NominatimGeocodingProvider, whose candidate importance is a Wikipedia-popularity score rather than a match-quality one — an ordinary local place scores ~0.08 where Google reports 0.40-0.90, so LocationResolution:MinimumImportanceFloor behaves quite differently on the two. Use a server-side key (unrestricted or IP-restricted); the domain-restricted browser key in ClientApp/.env (VITE_GOOGLE_MAPS_API_KEY) is rejected by server-to-server calls. Which provider is live is logged once at startup:

Geocoding provider: GoogleMaps (Geocoding:GoogleMapsApiKey configured).

Never put real secrets in appsettings.json — see the _comment_secrets note in src/AskLucy.Web/appsettings.json and constitution §8.

Frontend (active UI development)

The build above always reflects ClientApp as of its last npm run build — for hot-reload during active frontend work, run the Vite dev server separately instead:

cd src/AskLucy.Web/ClientApp
npm install
npm run dev

Tests

dotnet test                                          # all backend test projects
cd src/AskLucy.Web/ClientApp && npm run test         # frontend unit tests

Deployment prerequisites

  • Tesseract OCR language data (SPEC-015 Document Intelligence Pipeline, TesseractOcrEngine): the Tesseract NuGet package brings its own native Windows engine binaries, but it does not ship any .traineddata language files, and App_Data/ (where TesseractOcr:DataPath in appsettings.json points, App_Data/tessdata) is gitignored — it is never populated by a fresh clone, a CI build, or a deploy. On any new deployment host/container image, the needed .traineddata files (at minimum eng.traineddata; add others from the tessdata repo to match the languages your users upload) must be placed under App_Data/tessdata manually before OCR will produce any text. Missing a language pack is not fatal — TesseractOcrEngine falls back to whichever trained data is actually present (defaulting to eng) rather than failing the pipeline — but a missing eng.traineddata means OCR silently returns no text for every document.

  • Supertonic 3 voice model (specs/070, SupertonicTextToSpeechEngine): Lucy's on-server voice needs the fp32 ONNX model and voice styles under App_Data/Models/supertonic-3 (Supertonic:ModelDirectory). Like tessdata, it is gitignored and never deployed by a build — run scripts/download-supertonic.ps1 (pinned revision, SHA-256 verified) and copy the resulting onnx/ and voice_styles/ folders to the host. The loaded model adds roughly 450 MB of resident memory (weights are 398 MB), so the host plan must allow it. A missing model is not fatal: the voice router fails over to the next provider (ElevenLabs) and logs why. Before making Supertonic Lucy's voice in production, the OpenRAIL-M use restrictions in docs/THIRD_PARTY_NOTICES.md must be passed through to users.

Documentation

  • .specify/memory/constitution.md — the project's engineering constitution; supersedes all other guidance.
  • docs/ — target architecture, database, API, security, testing, and design system standards.
  • docs/adr/ — Architecture Decision Records.
  • specs/ — feature specifications, plans, and tasks (Spec Kit workflow).
  • CONTRIBUTING.md — branch protection and required CI secrets.

Languages

C#

59.8%

TypeScript

27.6%

HTML

7.6%

Python

3.8%