Visage
The project is an app to manage events for OSS community events promoting inclusiveness and diversity
Install / Use
/learn @HackerspaceMumbai/VisageREADME
The problem
We are the largest Open Source Software[OSS] community with its longest running(> 10 years) tech meetup in Bombay. Most of our events are houseful.
- We have to curate the registrants based on the theme and also to ensure we are inclusive, diverse, and have a good mix of attendees.
- We have to ensure that the attendees are checked-in to the event and also to the individual sessions. This is important for us to understand the attendee interest and also to ensure that we are able to provide the best experience to the attendees. Most importantly, we need to record the checkout time so as to comply with building/civic code.
- With DPDP (India's equivalent of GDPR) coming into effect, we have to ensure that the data we collected is secure, is not misused, and resides within the jurisdiction of India.
The solution
We will build a solution on the latest .NET version, that takes full advantage of AI and Azure services to solve the problem. The solution will have the following components:
- Aspire
- Microsoft .NET AI extensions
- Blazor Hybrid Web App
- Azure Open AI
For further reading on architecture, please check our website here
Prerequisites
Before running the Visage project, ensure you have the following installed:
- .NET 10 SDK - Download here
- Docker Desktop - Required for containerized SQL Server and services (Download)
- Visual Studio 2025 or VS Code with C# Dev Kit
- Aspire workload - Install via:
dotnet workload install aspire
Running the Project
- Start Docker Desktop - Ensure Docker is running before launching the application
- Run the AppHost:
cd Visage.AppHost dotnet run - Access the Aspire Dashboard - Opens automatically at
https://localhost:17044/ - Verify Health Status:
- ✅ SQL Server resource shows "Healthy" (green)
- ✅ Both
registrationdbandeventingdbdatabases are listed - ✅ Registration and Eventing services show "Healthy"
- ✅ Frontend web application is accessible
Note: The first run may take longer as Docker downloads SQL Server images. Subsequent runs are faster.
Database Management
Aspire automatically manages SQL Server - no manual installation required! Connection strings are injected automatically via Aspire's service discovery.
- View database schema: Connect via connection string shown in Aspire dashboard
- Run migrations: Automatic on service startup (or manually via
dotnet ef database update) - Reset database: Stop AppHost → Delete Docker container → Restart AppHost
For detailed setup and troubleshooting, see Aspire SQL Server Quickstart.
Testing Guidelines
Since this is an Aspire based solution we are predominantly doing Integration testing using TUnit, Fluent Assertions, & Playwright. We will strive to have 100% test coverage. External connections are mocked via NSubstitute, and load testing by NBomber. We will also include security testing using OWASP ZAP and Stryker for chaos.
Below are the guidelines for writing and running tests:
Running Unit Tests
Unit testing is restricted for crucial Blazor Hybrid components using bunit. Unit testing is restricted for crucial Blazor Hybrid components using bunit.
Running Integration Tests
To run the integration tests, execute the following command:
dotnet test tests/Visage.Tests.Integration/Visage.Tests.Integration.csproj
Note: To keep dotnet test fast for local development, this repository defaults to running Smoke tests (home page validation) when running dotnet test without any filters. Use scripts/test-all.ps1 to run the broader test suite locally:
# Run default and non-auth tests
pwsh -File ./scripts/test-all.ps1
To run full validation (including RequiresAuth tests), either use pwsh -File ./scripts/test-all.ps1 -RunAuth (with Auth secrets set) or run a direct CLI filter:
dotnet test --filter "Category!=RequiresAuth&Category!=AspireHealth"
dotnet test --filter "Category=RequiresAuth" # requires secrets
Configurable Tests
Our tests are configurable to run on different endpoints for local workstations and CI/CD environments. Ensure you have the appropriate configuration set in your environment variables.
Writing New Tests
When writing new tests, follow these guidelines:
- Use TUnit and FluentAssertions for unit and integration tests.
- Use Playwright for end-to-end tests.
- Ensure tests are clear, maintainable, and cover critical functionalities.
- Document any new tests added to the suite.
For more detailed instructions and examples, refer to the test project files in the tests directory.
By following these guidelines, we can ensure that our codebase remains reliable, maintainable, and of high quality.
Project Architecture and Components
The Visage project is built using a modular architecture to ensure scalability, maintainability, and ease of development. Below is an overview of the project's architecture and its main components:
The following diagram illustrates how the components of Visage interact with each other and how data flows through the system
Detailed Diagram:
flowchart TD
%% Define the user and their interactions
User(["User"])
%% Top layer: User Interfaces
subgraph "User Interfaces"
direction TB
WebClient["Blazor Hybrid Web Client"]:::client
WebServer["Blazor Web (server-hosted)"]:::client
MAUI[".NET MAUI Mobile/Desktop App"]:::client
SharedUI["Shared UI Library"]:::client
end
%% Middle layer: AppHost
AppHost["Visage.AppHost"]:::aspire
%% Lower layer: Microservices
subgraph "Microservices"
direction TB
Eventing["Visage.Services.Eventing"]:::aspire
Registrations["Visage.Services.Registrations"]:::aspire
Cloudinary["Cloudinary Image Signing (Node.js)"]:::aspire
end
%% Bottom layer: Data Stores
subgraph "Data Stores"
direction TB
EventDB[(EventDB)]:::data
RegistrantDB[(RegistrantDB)]:::data
end
%% Bottom layer: External Services
subgraph "External Services"
direction TB
AzureAI["Azure AI Foundry"]:::azure
AzureContainer["Azure Container Apps"]:::azure
Insights["Azure Monitor & App Insights"]:::azure
CloudinaryStorage["Cloudinary"]:::azure
end
%% Connections
User -->|Interacts with| WebClient
User -->|Interacts with| WebServer
User -->|Interacts with| MAUI
WebClient -->|"HTTPS/REST"| AppHost
WebServer -->|"HTTPS/REST"| AppHost
MAUI -->|"HTTPS/REST"| AppHost
WebClient -->|"HTTPS/REST"| Cloudinary
WebServer -->|"HTTPS/REST"| Cloudinary
MAUI -->|"HTTPS/REST"| Cloudinary
AppHost -->|"HTTP/REST"| Eventing
AppHost -->|"HTTP/REST"| Registrations
AppHost -->|"Node Hosting Extension"| Cloudinary
Eventing -->|"EF Core"| EventDB
Registrations -->|"EF Core"| RegistrantDB
AppHost -->|"Azure SDK"| AzureAI
Eventing -->|"Azure SDK"| AzureAI
Registrations -->|"Azure SDK"| AzureAI
AppHost ---|"Containerized"| AzureContainer
Eventing ---|"Containerized"| AzureContainer
Registrations ---|"Containerized"| AzureContainer
Cloudinary ---|"Containerized"| AzureContainer
AppHost -->|"Monitoring"| Insights
Eventing -->|"Monitoring"| Insights
Registrations -->|"Monitoring"| Insights
Cloudinary -->|"Monitoring"| Insights
Cloudinary -->|"Media Storage"| CloudinaryStorage
%% Dependencies
WebClient --> SharedUI
WebServer --> SharedUI
MAUI --> SharedUI
%% Legend
subgraph Legend
direction TB
F["Rectangles: Frontend"]:::client
S["Rounded: Services"]:::aspire
D["Cylinders: Databases"]:::data
C["Cloud: External Services"]:::azure
end
%% Click Events
click WebClient "https://github.com/hackerspacemumbai/visage/blob/main/Visage.FrontEnd/Visage.FrontEnd.Web.Client"
click WebServer "https://github.com/hackerspacemumbai/visage/blob/main/Visage.FrontEnd/Visage.FrontEnd.Web"
click MAUI "https://github.com/hackerspacemumbai/visage/blob/main/Visage.FrontEnd/Visage.FrontEnd"
click SharedUI "https://github.com/hackerspacemumbai/visage/blob/main/Visage.FrontEnd/Visage.FrontEnd.Shared"
click AppHost "https://github.com/hackerspacemumbai/visage/blob/main/Visage.AppHost"
click Eventing "https://github.com/hackerspacemumbai/visage/blob/main/services/Visage.Services.Eventing"
click Registrations "https://github.com/hackerspacemumbai/visage/blob/main/services
Related Skills
node-connect
351.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
110.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
351.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
351.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
