# QA Engineer — Audit Report: GoodGo POS System
**Date**: 2026-03-20
**Auditor**: QA Engineer (TechBi / GoodGo Platform)
**Scope**: Test coverage, test quality, CI/CD test pipelines, missing test scenarios
**Working Directory**: `/Users/velikho/Desktop/WORKING/pos-system`
---
## Executive Summary
The GoodGo POS System has a well-structured testing foundation for backend .NET microservices — all 26 services follow Clean Architecture test patterns with xUnit + Moq + FluentAssertions, and the IAM service demonstrates a gold-standard test suite. However, **only 1 of 26 services has a CI test pipeline**, there is **zero coverage for the MCP server** (a critical AI operations component with 12 tools), **no contract testing** between microservices, and **no performance testing** anywhere in the stack. Coverlet is installed in all test projects but never generates reports or enforces thresholds. Frontend testing is surface-level smoke tests only beyond 8 Playwright E2E specs.
---
## Critical Issues
### C1 — Only 1 of 26 Services Has CI Test Pipeline
**Severity**: Critical (P0)
**File**: `.github/workflows/ci-iam-service.yml`
Only `iam-service-net` has a dedicated CI workflow that runs unit tests and functional tests on pull requests. The remaining 25 services (merchant, order, fnb-engine, booking, catalog, inventory, wallet, promotion, membership, chat, social, storage, mining, mission, ads-manager, ads-serving, ads-billing, ads-tracking, ads-analytics, mkt-facebook, mkt-whatsapp, mkt-x, mkt-zalo, and both template services) have **no automated test execution on PRs or merges**.
This means regressions in 25 services are not caught until staging deployment or manual testing.
**Impact**: A broken handler, validator, or domain entity in any of the 25 uncovered services can be deployed to staging undetected.
**Evidence**:
- `.github/workflows/ci-iam-service.yml` — only service CI that runs tests
- No `ci-merchant-service.yml`, `ci-order-service.yml`, etc.
- `deploy-staging.yml` runs EF Core migrations but NOT test suites before deployment
---
### C2 — MCP Server Has Zero Tests (12 Production Tools)
**Severity**: Critical (P0)
**File**: `services/goodgo-mcp-server/package.json`, `services/goodgo-mcp-server/src/`
The `goodgo-mcp-server` is a TypeScript MCP server providing 12 tools for AI-assisted F&B operations:
- **Catalog tools** (`src/tools/catalog-tools.ts`): list/create/update/delete products, menu items
- **Inventory tools** (`src/tools/inventory-tools.ts`): check stock, record intake (nhập kho), record usage (xuất kho), low-stock alerts
- **Recipe tools** (`src/tools/recipe-tools.ts`): list/create recipes with ingredients
- **Analytics tools** (`src/tools/analytics-tools.ts`): popular items, cost analysis
The `package.json` has no `test` script, no test framework (Jest, Vitest, Mocha) installed, and no test files exist in the project directory.
**Impact**: Any bug in the MCP tool definitions, input validation via `zod`, API client error handling (`src/services/error-handler.ts`), or tool logic will silently surface as incorrect AI-generated operations on merchant data.
---
### C3 — No Coverage Thresholds or Reports Enforced
**Severity**: Critical (P0)
**File**: All `*.UnitTests.csproj` files (e.g., `services/order-service-net/tests/OrderService.UnitTests/OrderService.UnitTests.csproj`)
All test projects include `coverlet.collector` v6.0.2, but:
- No `.runsettings` or `coverlet.runsettings` file defines coverage thresholds
- No CI step collects or uploads coverage reports
- No quality gate exists to fail a build below a coverage percentage
- Minimum 80% coverage standard (per project requirements) is stated but not enforced
**Evidence**:
```xml
runtime; build; native; contentfiles; analyzers; buildtransitive
all
```
No `--collect:"XPlat Code Coverage"` flag in any CI `dotnet test` command outside `ci-iam-service.yml`, and even there, no coverage threshold or report upload step exists.
---
### C4 — No Contract Testing Between Microservices
**Severity**: Critical (P0)
The system has 26 microservices communicating via REST API and RabbitMQ events. There is **no contract testing** (Pact.io or similar) anywhere in the codebase. Service contracts are verified only by:
- Shared TypeScript types in `packages/types/` (but packages have no tests either)
- Integration test patterns that use InMemoryDatabase (no real cross-service calls)
In a microservice architecture, breaking changes to API contracts — even minor ones like renaming a field from `merchantId` to `merchant_id` — can silently break consumers. Currently, such breaks would only surface after both services are deployed.
**Evidence**: Search across entire codebase found no Pact files, no `pactum` package, no consumer/provider test annotations.
---
## Warnings
### W1 — Shared Packages Have No Tests
**Severity**: High (P1)
**Files**: `packages/` directory (6 packages)
All 6 shared Node.js packages have zero test coverage:
- `packages/types/` — `@goodgo/types` (shared TypeScript types used across frontend + MCP server)
- `packages/http-client/` — `@goodgo/http-client` (axios wrapper used by all frontends)
- `packages/auth-sdk/` — `@goodgo/auth-sdk` (JWT utilities for auth flows)
- `packages/logger/` — `@goodgo/logger`
- `packages/tracing/` — `@goodgo/tracing`
- `packages/config/` — `@goodgo/config`
A breaking change in `@goodgo/http-client` or `@goodgo/auth-sdk` can cascade through all frontend applications (3 apps), the MCP server, and any consumer service.
---
### W2 — E2E Tests Require Live Backend (No Mocking)
**Severity**: High (P1)
**File**: `apps/web-client-tpos-net/tests/WebClientTpos.E2ETests/playwright.config.ts`
The Playwright config targets `http://localhost:5092` with no mock server or fixture setup. The E2E tests depend on a fully running backend stack (IAM service, Merchant service, etc.) to function. In CI (`ci-web.yml`), these tests run against hardcoded test credentials (`admin@goodgo.vn / Admin@123`) with no evidence of a test database being seeded.
This means:
- E2E tests are brittle — they fail if the backend is not pre-seeded
- Tests cannot run in isolation for frontend-only changes
- Test data hardcoded in `helpers/test-data.ts` uses magic UUIDs (`TEST_SHOP_ID = 00000000-0000-0000-0000-000000000001`) that must exist in a live DB
**Evidence**:
```typescript
// helpers/test-data.ts
export const TEST_SHOP_ID = '00000000-0000-0000-0000-000000000001';
export const ADMIN_USER = { email: 'admin@goodgo.vn', password: 'Admin@123' };
```
---
### W3 — Playwright Tests Do Not Cover Mutation Scenarios
**Severity**: High (P1)
**Files**: `apps/web-client-tpos-net/tests/WebClientTpos.E2ETests/tests/*.spec.ts`
All 8 Playwright E2E specs are **read-only / navigation-only** tests. They verify that pages load and elements are visible, but do not test:
- Creating an order (POST to order-service)
- Adding items to a POS order session
- Processing a payment (wallet-service integration)
- Creating a booking (booking-service)
- Staff login with RBAC restrictions
- Merchant onboarding wizard submission
- CRM campaign creation
- Promotions applied to orders
- Inventory decrement after order
The E2E layer only validates that pages render, not that they function end-to-end.
---
### W4 — No Performance / Load Testing
**Severity**: Medium (P2)
No k6, Artillery, Gatling, or any load testing framework exists in the repository. Critical paths with known performance sensitivity have no benchmarks:
- `POST /api/v1/orders` — Order creation under concurrent load
- `GET /api/v1/catalog/products` — Catalog listing (expected high read volume)
- `POST /api/v1/ads-tracking/events` — Ad event ingestion (bursty, high-throughput)
- SignalR connections in `chat-service-net` — WebSocket scalability
- `goodgo-mcp-server` — LLM tool calls during peak restaurant hours
Without baselines, there is no way to detect performance regressions introduced by refactors.
---
### W5 — Frontend Has No Component-Level Tests
**Severity**: Medium (P2)
**Files**: `apps/web-client-tpos-net/`, `apps/web-client-base-net/`
The Blazor WASM apps have only:
- 2 unit tests in `WebClientTpos.SmokeTests/ApiResponseTests.cs` (tests `ApiResponse` DTO, not Razor components)
- 8 Playwright E2E specs for the POS app
There are no component-level tests for:
- `AuthButton` (5 variants: orange, blue, green, outline, ghost)
- `OtpInput` — complex state management, timer countdown
- `PosDataService` — 4-format deserialization logic (critical business logic in frontend service)
- `AuthStateService` — singleton JWT token state management
- MudBlazor form validation in onboarding wizard
- Shop sidebar vertical-specific menus (`ShopSidebarConfig`)
**Note**: `PosDataService` with 4-format deserialization (`plain array`, `paged {items}`, `wrapped {data:{items}}`, `direct {data:[]}`) is exactly the kind of complex branching logic that should have unit tests. A regression here silently breaks API data display for all merchants.
---
### W6 — MAUI and Swift Apps Have Minimal Testing
**Severity**: Medium (P2)
**Files**: `apps/app-client-base-net/tests/`, `apps/app-client-base-swift/`
- **MAUI** (`app-client-base-net`): 1 unit test file (`AppClientBase.UnitTests`) — content not analyzed but project is described as "Template phase"
- **Swift iOS** (`app-client-base-swift`): 1 smoke test referenced in `ci-mobile.yml` — no Xcode test plans found
Mobile apps in "template phase" with near-zero tests will carry this debt forward into feature development.
---
### W7 — Test Parallelism Disabled in Playwright
**Severity**: Low (P3)
**File**: `apps/web-client-tpos-net/tests/WebClientTpos.E2ETests/playwright.config.ts`
```typescript
fullyParallel: false,
workers: process.env.CI ? 1 : undefined,
```
With 8 spec files and no parallelism, E2E runs are unnecessarily slow. Parallel execution is safe when tests are properly isolated (each test navigates independently). Disabling parallelism suggests tests may be sharing state or there are concerns about race conditions on the backend — both are red flags.
---
## Improvements
### I1 — Add CI Pipelines for All 25 Missing Services
Use `ci-iam-service.yml` as the template. Each service pipeline should:
1. Trigger on changes to `services/{service-name}/**`
2. Spin up PostgreSQL 16-alpine service container
3. Run `dotnet test` with `--collect:"XPlat Code Coverage"` flag
4. Upload coverage to Codecov or similar
5. Fail the build if coverage drops below 80%
**Reference**: `.github/workflows/ci-iam-service.yml`
**Effort**: Low (copy-paste + variable substitution for 25 services)
---
### I2 — Add Tests for goodgo-mcp-server
Add Vitest (preferred for TypeScript ESM) with the following coverage targets:
```
services/goodgo-mcp-server/
src/
tools/
catalog-tools.test.ts ← mock axios, test zod validation, tool schema
inventory-tools.test.ts ← test stock calculation, low-stock alerts
recipe-tools.test.ts ← test recipe ingredient validation
analytics-tools.test.ts ← test aggregation logic
services/
error-handler.test.ts ← test all error code paths
api-client.test.ts ← test interceptors, auth headers
```
**Effort**: Medium (3-5 days)
---
### I3 — Enforce Coverage Thresholds in CI
Add a `.runsettings` file at repo root:
```xml
cobertura
80
Line
Minimum
```
And update CI test commands:
```bash
dotnet test --settings ../../.runsettings --collect:"XPlat Code Coverage"
```
---
### I4 — Add Contract Tests for Critical Service Boundaries
Priority contracts to establish (consumer → provider):
1. `order-service` → `catalog-service` (product price, availability)
2. `order-service` → `wallet-service` (payment processing)
3. `order-service` → `inventory-service` (stock decrement)
4. `merchant-service` → `iam-service` (user/RBAC validation)
5. `promotion-service` → `order-service` (discount application)
Use Pact.io with .NET consumer SDK (`PactNet`) and add contract verification to each service's CI pipeline.
---
### I5 — Add Mutation E2E Tests for Critical Workflows
Extend Playwright specs to cover actual business transactions:
- Complete order creation: table selection → add items → submit → verify order in KDS
- Payment flow: order total → wallet/VNPay mock → confirm receipt
- Booking creation: select date/time → confirm → verify in calendar
- Inventory: place order → verify stock decremented
**File to extend**: `apps/web-client-tpos-net/tests/WebClientTpos.E2ETests/tests/pos-restaurant.spec.ts`
---
### I6 — Unit Test PosDataService (Frontend)
`PosDataService` deserializes 4 different API response formats. Add unit tests in `WebClientTpos.SmokeTests/` or a new `WebClientTpos.UnitTests/` project:
```csharp
// PosDataServiceTests.cs
[Fact]
public async Task Deserialize_PlainArray_ShouldReturnItems();
[Fact]
public async Task Deserialize_PagedResponse_ShouldReturnItemsWithCount();
[Fact]
public async Task Deserialize_WrappedDataResponse_ShouldUnwrapCorrectly();
[Fact]
public async Task Deserialize_DirectDataArray_ShouldReturnItems();
```
---
### I7 — Add k6 Performance Tests for Critical Paths
Create `tests/performance/` at repo root:
```
tests/performance/
k6/
order-creation.js ← VUs: 100, ramp to 500
catalog-listing.js ← VUs: 200, sustained load
ads-event-ingestion.js ← VUs: 1000 burst
auth-token-refresh.js ← VUs: 50
```
Add a weekly `performance-test.yml` GitHub Actions workflow that runs k6 against staging.
---
## Action Items (Prioritized)
| # | Priority | Action | Effort | Owner |
|---|----------|--------|--------|-------|
| A1 | P0 — Critical | Generate CI pipelines for 25 missing services (copy `ci-iam-service.yml` template) | 1 day | DevOps |
| A2 | P0 — Critical | Add Vitest + test suite to `goodgo-mcp-server` (12 tools, error handler, api-client) | 3-5 days | Backend Dev |
| A3 | P0 — Critical | Add `.runsettings` coverage threshold (80% minimum) and upload in all CI pipelines | 0.5 days | DevOps |
| A4 | P0 — Critical | Add Pact.io contract tests for top 5 service boundaries | 5-7 days | Backend Dev |
| A5 | P1 — High | Add unit tests for all 6 shared packages in `packages/` | 3-4 days | Frontend Dev |
| A6 | P1 — High | Fix E2E backend dependency: add DB seeding/reset step in `ci-web.yml` | 2 days | DevOps |
| A7 | P1 — High | Extend Playwright specs with mutation tests (order creation, payment, booking) | 3-4 days | QA |
| A8 | P2 — Medium | Add `PosDataService` unit tests (4-format deserialization) | 1 day | Frontend Dev |
| A9 | P2 — Medium | Enable Playwright `fullyParallel: true` with proper test isolation | 0.5 days | QA |
| A10 | P2 — Medium | Add k6 performance baseline tests for 4 critical paths | 3 days | QA |
| A11 | P3 — Low | Expand MAUI unit test coverage beyond template placeholder | 2-3 days | Mobile Dev |
| A12 | P3 — Low | Add Xcode test plan for Swift iOS app | 2-3 days | Mobile Dev |
---
## Appendix: Current Test Inventory
### Backend (.NET)
| Layer | Count | Framework |
|-------|-------|-----------|
| Unit Tests (all services) | ~100+ files | xUnit + Moq + FluentAssertions |
| Functional Tests (all services) | ~50+ files | xUnit + WebApplicationFactory + InMemory DB |
| Smoke Tests (Blazor) | 4 projects | xUnit |
| MAUI Unit Tests | 1 project | xUnit |
### Frontend (TypeScript)
| Layer | Count | Framework |
|-------|-------|-----------|
| E2E Specs (Playwright) | 8 files | Playwright/test (Chromium only) |
| Smoke DTO Tests | 2 tests | xUnit via .NET project |
| Shared package tests | **0** | — |
| MCP server tests | **0** | — |
### CI Coverage
| Service | Has CI Tests? |
|---------|--------------|
| iam-service-net | ✅ Yes (`ci-iam-service.yml`) |
| 25 other services | ❌ No |
| web-client-tpos-net | ⚠️ Partial (E2E in `ci-web.yml`) |
| goodgo-mcp-server | ❌ No |
| packages/* (6) | ❌ No |
### Key Test Files Referenced
- IAM unit test: `services/iam-service-net/tests/IamService.UnitTests/Application/Commands/RegisterUserCommandHandlerTests.cs`
- IAM functional test: `services/iam-service-net/tests/IamService.FunctionalTests/Controllers/AuthControllerTests.cs`
- Template unit test: `services/_template_dot_net/tests/MyService.UnitTests/Application/CreateSampleCommandHandlerTests.cs`
- Playwright config: `apps/web-client-tpos-net/tests/WebClientTpos.E2ETests/playwright.config.ts`
- Playwright helpers: `apps/web-client-tpos-net/tests/WebClientTpos.E2ETests/helpers/test-data.ts`
- Smoke test: `apps/web-client-tpos-net/tests/WebClientTpos.SmokeTests/ApiResponseTests.cs`