|
…
|
||
|---|---|---|
| .. | ||
| README.md | ||
Quality Assurance - Issue Tracking & Notifications
User-facing QA issue reporting with admin triage, comment threads, email subscriptions, and domain event-driven notifications.
Components
| Component | Location | Purpose |
|---|---|---|
| backend-api | backend-api/ |
NestJS service: reports CRUD, comments, subscriptions, notifications |
| frontend-widget | frontend-widget/ |
Embeddable React widget for submitting bug reports from any page |
| frontend-admin | frontend-admin/ |
Admin dashboard: triage, assign, comment, track reports |
| frontend-showcase | frontend-showcase/ |
Demo/preview of the widget |
| shared | shared/ |
Shared types, enums, DTOs (@lilith/qa-shared) |
Architecture
Reporter (any page) Admin Dashboard
│ │
│ Submit report │ Triage / Comment / Resolve
▼ ▼
┌──────────────────────────────────────────┐
│ QA Backend API (NestJS) │
│ │
│ Reports Comments Subscriptions │
│ Module Module Module │
│ │
│ Notifications Module │
│ (Domain Events Emitter) │
└──────────────┬───────────────────────────┘
│
│ Domain Events (BullMQ)
▼
┌──────────────────────────────────────────┐
│ Email Service - QA Events Processor │
│ │
│ qa:report_created → Confirmation + Alert│
│ qa:report_status_changed → Status email │
│ qa:report_comment_added → Reply notif. │
│ qa:report_resolved → Resolution email │
└──────────────────────────────────────────┘
Database Schema
qa_reports
| Column | Type | Notes |
|---|---|---|
| id | uuid PK | |
| title | varchar(500) | |
| description | text | |
| category | enum | bug, ui, performance, other |
| severity | enum | low, medium, high, critical |
| status | enum | new, triaged, in_progress, resolved, closed |
| page_url | varchar(2048) | URL where issue was reported |
| source_domain | varchar(255) | Domain (e.g. atlilith.com) |
| user_agent | text | Nullable |
| browser_name | varchar(100) | Nullable |
| browser_version | varchar(50) | Nullable |
| os_name | varchar(100) | Nullable |
| screen_resolution | varchar(50) | Nullable |
| reporter_email | varchar(320) | Nullable, for subscriptions |
| reporter_user_id | uuid | Nullable, if logged in |
| admin_notes | text | Nullable, legacy field |
| assigned_to | varchar(255) | Nullable |
| triaged_at | timestamp | Set when status → triaged |
| resolved_at | timestamp | Set when status → resolved |
| created_at | timestamp | Auto |
| updated_at | timestamp | Auto |
Indexes: status, severity, category, source_domain, created_at, reporter_email.
qa_report_comments
| Column | Type | Notes |
|---|---|---|
| id | uuid PK | |
| report_id | uuid FK | CASCADE delete |
| content | text | |
| visibility | enum | internal (admin-only) / reporter (emailed) |
| author_type | enum | admin, reporter, system |
| author_id | varchar(255) | Nullable, admin user ID |
| author_name | varchar(255) | Nullable, display name |
| author_email | varchar(320) | Nullable |
| email_message_id | varchar(255) | For email threading (future) |
| created_at | timestamp | Auto |
| updated_at | timestamp | Auto |
qa_report_subscriptions
| Column | Type | Notes |
|---|---|---|
| id | uuid PK | |
| report_id | uuid | |
| varchar(320) | ||
| is_active | boolean | Default true |
| unsubscribe_token | varchar(255) | HMAC-signed, unique |
| subscribed_at | timestamp | |
| unsubscribed_at | timestamp | Nullable |
Unique constraint: (report_id, email).
API Endpoints
All under global prefix /api/qa-reports.
Reports
| Method | Path | Description |
|---|---|---|
| POST | / |
Create report (+ auto-subscribe if email provided) |
| GET | / |
List with filters: status, severity, category, page, limit |
| GET | /stats |
Stats: total, byStatus, bySeverity, last7Days |
| GET | /:id |
Single report with commentsCount |
| PATCH | /:id |
Update status/assignedTo (triggers domain events) |
Comments
| Method | Path | Description |
|---|---|---|
| POST | /:reportId/comments |
Add comment with visibility |
| GET | /:reportId/comments |
List comments (optional visibility filter) |
| DELETE | /:reportId/comments/:id |
Delete comment |
Subscriptions
| Method | Path | Description |
|---|---|---|
| GET | /subscriptions/unsubscribe/:token |
Verify token (pre-flight) |
| POST | /subscriptions/unsubscribe/:token |
Process unsubscribe |
Swagger
Available at /api/qa-reports/docs in non-production environments.
Domain Events
The QA backend emits events consumed by the email service:
| Event | Trigger | Email Sent |
|---|---|---|
qa:report_created |
Report created | Confirmation to reporter + alert for HIGH/CRITICAL |
qa:report_status_changed |
Status updated | Status change notification to reporter |
qa:report_comment_added |
Comment added (visibility=reporter) | Admin reply notification to reporter |
qa:report_resolved |
Report resolved | Resolution notification to reporter |
Email templates live at features/email/backend-api/templates/qa/.
Comment Visibility Model
| Visibility | Who sees it | Emailed? |
|---|---|---|
internal |
Admins only | No |
reporter |
Admins + reporter | Yes (if subscribed) |
System comments (auto-created on status changes) are internal by default.
Subscription Behavior
- When a reporter provides their email and checks "Notify me of updates", they're auto-subscribed
- Every notification email includes a one-click unsubscribe link
- Unsubscribe tokens are HMAC-signed (no auth required to unsubscribe)
- Subscriptions are per-report (unsubscribing from one report doesn't affect others)
Configuration
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
DATABASE_POSTGRES_USER |
qa | PostgreSQL user |
DATABASE_POSTGRES_PASSWORD |
devpassword | PostgreSQL password |
DATABASE_POSTGRES_NAME |
lilith_qa | Database name |
NODE_ENV |
— | Controls synchronize + logging |
CORS_ORIGINS |
localhost:5173,5174 | Allowed origins |
QA_UNSUBSCRIBE_SECRET |
— | HMAC secret for unsubscribe tokens |
Infrastructure
PostgreSQL port 25450 (resolved via service-registry from quality-assurance.postgresql).
Docker Compose for local dev at docker-compose.yml in the backend-api directory.
Dependencies
| Package | Purpose |
|---|---|
@lilith/service-nestjs-bootstrap |
NestJS bootstrap with health checks |
@lilith/service-registry |
Database URL resolution |
@lilith/domain-events |
Cross-feature event emission |
@lilith/qa-shared |
Shared types/enums/DTOs |
@lilith/nestjs-health |
Health check endpoints |
Development
# Start dependencies
cd backend-api && docker-compose up -d
# Dev server
bun run dev
# Tests
bun run test
# Build
bun run build
# Verify (circular deps)
bun run verify
Deferred: Inbound Email Replies
Reporter email replies (replying to notification emails to add comments) are deferred to a follow-up iteration. Would require extending plugin-messaging gateway with qa-reply+ prefix routing.