A .NET / C# marketplace finance & pricing-automation platform for Iranian marketplaces (SnappShop, TapsiShop) — supplier price crawling, an automated pricing engine, inventory reconciliation, and multi-channel seller operations.
VWare automates the finance and pricing side of running a marketplace reselling business. It continuously crawls supplier prices, computes floor prices and margins through a pricing engine, reconciles marketplace listings and inventory against live supplier availability, and pushes updates across multiple sales channels — with an operations dashboard on top.
It is not a demo: VWare powered a live phone-reselling operation on SnappShop (a Snapp Group marketplace), where pricing and reconciliation were fully automated by the platform.
VWare is a layered .NET 9 solution of 37 projects built on a small in-house application framework — GiliX — rather than a third-party stack, so the CQRS/mediator pipeline, logging, and cross-cutting behavior are owned and testable end to end.
flowchart TB
subgraph CH["Marketplace channels"]
SS["SnappShop"]
TS["TapsiShop"]
end
subgraph ING["Price ingestion"]
CRAWL["Crawler Service<br/>supplier price crawling + retry/backoff"]
LINK["AI Link Filler<br/>Claude-assisted product matching"]
end
subgraph CORE["Pricing & reconciliation engine"]
CALC["Calculator / Viravin.Calculator<br/>floor-price + margin computation"]
RECON["Reconciliation<br/>smart inventory reset"]
end
subgraph OPS["Multi-channel operations"]
AUTO["SnappShop Automation<br/>price / stock / listing sync"]
TIC["TapsiShop ItemCreator"]
BOT["Telegram Bot / SMS Reader"]
end
subgraph FW["GiliX framework + domain (foundation)"]
MED["GiliX.Mediator — CQRS"]
DOM["Domains + Persistence — EF Core"]
DIAG["VWare.Diagnostics — secret-safe logging"]
end
DASH["VWare.Dashboard — operations UI"]
SS --> CRAWL
TS --> CRAWL
CRAWL --> CALC
LINK --> CALC
CALC --> RECON
RECON --> AUTO
RECON --> TIC
AUTO --> SS
TIC --> TS
CALC --> MED
AUTO --> MED
MED --> DOM
CALC --> DIAG
DASH --> DOM
Why this design
- Custom mediator (
GiliX.Mediator). Commands, queries, and events flow through one owned CQRS pipeline with aValidationBehaviorseam. Owning the mediator (instead of pulling in a third-party one) keeps the request pipeline small, dependency-free, and fully unit-testable at the boundary. - Domain layering.
Domainsholds the domain model;Persistenceisolates EF Core. Business services and channel clients depend on the domain, not on infrastructure — so a marketplace or storage change stays contained. - Reconciliation as a first-class flow. The pricing run does a smart inventory reset: the first pass resets all listings, and subsequent passes only reset products that lost a valid supplier price — so a product removed from the source, or one whose supplier price can't be found, is never left purchasable at a stale price. This is the core "don't lose money on stale listings" guarantee.
- Secret-safe logging.
VWare.Diagnostics.RedactionEnginescrubs tokens, passwords, and PII out of logs and diagnostic bundles before they are ever written.
| Layer | Projects | Responsibility |
|---|---|---|
| Framework (GiliX) | GiliX, GiliX.Common, GiliX.Logging, GiliX.Mediator |
CQRS/mediator pipeline, logging, shared primitives |
| Domain | Domains, Persistence |
Domain model + EF Core persistence |
| Services | Authentication, Calculator, Crawler, SnappShopAdmin |
Core business services |
| Channel clients | VWare.SnappShop.Service / .Client / .Automation, Viravin.TapsiShop.Service, TapsiShop.ItemCreator, VWare.Crawler.Service, VWare.Calculator.Service, VWare.TelegramBot, VWare.SmsReader |
Marketplace integrations & runnable services |
| Pricing | Viravin.Calculator |
Floor-price & margin engine |
| Operations UI | VWare.Dashboard |
Monitoring / operations surface |
| Shared | Shared/VWare.Diagnostics |
Secret-safe logging, health checks, diagnostics |
| AI | VWare.AI |
Claude (Anthropic) integration for product matching |
| Tests | *.Tests (Crawler, Calculator, SnappShop Automation, TapsiShop, Diagnostics) |
xUnit unit & integration suites |
- Compile-time "Time Policy".
BannedSymbols.txt+ RoslynBannedApiAnalyzersturnDateTime.Now,DateTime.Today, Persian-calendar output, and ambiguousDateTime.Parseinto build errors — forcing UTC /IAppClockeverywhere. Server-timezone drift is a real correctness hazard for pricing and reconciliation, and this makes it unrepresentable. Directory.Build.props— nullable reference types, implicit usings, .NET analyzers atlatest, and warnings-as-errors for banned APIs, applied solution-wide..editorconfig— consistent formatting and style across every project.- Secret-safe logging —
RedactionEngine(with its own test suite) keeps credentials and PII out of logs. - Dedicated test projects — xUnit suites covering the crawler, calculator, SnappShop automation, TapsiShop pricing, and diagnostics.
- GitHub Actions — automated code-review and release-publishing workflows.
VWare priced and reconciled a ~10,000-SKU catalog (5,000+ active at a time) across 15 suppliers for a live phone-reselling operation on SnappShop (a Snapp Group marketplace), cutting manual reconciliation/listing work by ~60% through transaction-level mapping and reusable pricing logic. In a documented ~2-week window, with pricing and reconciliation fully automated by VWare:
- ~673M Toman gross merchandise value (GMV)
- ~32.5M Toman net profit across 67 orders
- ~5% blended net margin after platform fees (which reach up to ~20% per SKU)
- sourcing from 15 suppliers
VWare was developed spec-driven and AI-agent-orchestrated (see AGENTS.md): the human owns the architecture, the domain model, and the trade-offs; agents execute against tightly-scoped specifications and a strict developer contract — a single runtime crawl pipeline, a single per-shop config source, and structured, correlation-id crawl logs. The emphasis is ownership and verifiability, not automation for its own sake.
Requires the .NET 9 SDK.
dotnet restore Viravin.sln
dotnet build Viravin.sln -c Release
dotnet test Viravin.slnReal appsettings*.json files and any credentials/ are gitignored and never committed. Copy the template and fill it from your own environment:
cp appsettings.example.json appsettings.jsonThen set: ConnectionStrings:DefaultConnection, Snappshop:Token, Telegram:BotToken, GoogleSheets:CredentialsPath, and OpenRouter:ApiKey.
Released under the MIT License. © 2026 Mahdi Aghakhani.