BATbern System Quality Assessment

Platform: BATbern Event Management System

Last updated: May 26, 2026 Reading time: 13 minutes File size: 19.43 KB

Executive Summary

BATbern is a production-deployed enterprise event management platform for Berner Architekten Treffen conferences. Every line of production code β€” Java microservices, TypeScript frontend, AWS CDK infrastructure, CI/CD pipelines, migration scripts β€” was written by AI agents.

The natural question is: can AI produce code that is genuinely stable, secure, maintainable, and well-designed? This document answers that question with evidence, not assertions. Every claim is backed by a reproducible tool run that any reviewer can verify independently.

Short answer: Yes. The evidence below shows the system meets or exceeds industry standards across all four quality dimensions.


How to Reproduce Any Result

All quality tooling runs as part of the standard CI pipeline:

bash
# Run everything and regenerate all reports
make test             # unit + integration (Testcontainers PostgreSQL)
make lint             # Checkstyle + ESLint
make audit-security   # Trivy vulnerability scan

# OWASP ZAP scan (requires running services)
./scripts/ci/run-security-scan.sh

# SonarCloud (requires SONAR_TOKEN env var)
./gradlew sonarqube

# View reports
open apps/projectdoc/dist/reports/index.html

Dimension 1: Stability

What it measures: Does the system behave predictably under load? Do tests provide genuine confidence, or just coverage theatre?

Test Coverage

Module Tool Coverage Report
api-gateway JaCoCo 60%+ apps/projectdoc/dist/reports/api-gateway/
event-management-service JaCoCo 60%+ apps/projectdoc/dist/reports/event-management-service/
company-user-management-service JaCoCo 60%+ apps/projectdoc/dist/reports/company-user-management-service/
speaker-coordination-service JaCoCo 60%+ apps/projectdoc/dist/reports/speaker-coordination-service/
partner-coordination-service JaCoCo 60%+ apps/projectdoc/dist/reports/partner-coordination-service/
shared-kernel JaCoCo 60%+ apps/projectdoc/dist/reports/shared-kernel/
web-frontend Vitest 70%+ (statements) apps/projectdoc/dist/reports/web-frontend/

Coverage thresholds are enforced: the build fails if they drop below minimum. See api-gateway/build.gradle (line 130) and web-frontend/vite.config.ts (lines 313–326).

Integration Test Realism

The most common mistake in enterprise test suites is using in-memory databases (H2) that mask real database behaviour. BATbern exclusively uses Testcontainers with PostgreSQL 15 for integration tests β€” the same engine as production.

java
// Every integration test inherits real PostgreSQL (AbstractIntegrationTest)
// See services/event-management-service/src/test/java/.../AbstractIntegrationTest.java
@SpringBootTest
@Testcontainers
class EventWorkflowIntegrationTest extends AbstractIntegrationTest {
    // Runs against a real PostgreSQL container β€” no H2 shortcuts
}

This means CI catches PostgreSQL-specific issues (advisory locks, JSONB operators, enum casting) that H2 silently ignores.

Resilience Infrastructure

  • Rate limiting (role-based): organizer 1,000 req/min, speaker 100 req/min, anonymous 50 req/min β€” api-gateway/src/main/java/ch/batbern/gateway/security/RateLimitingFilter.java
  • HTTP 429 responses with X-RateLimit-Remaining and X-RateLimit-Reset headers
  • 9-state event workflow with machine-enforced transitions (invalid transitions rejected)
  • Async email delivery via @Async + AWS SES (non-blocking, bounded retry)

What Would Strengthen This Further

  • PITest (mutation testing): verifies that tests actually detect bugs, not just execute code. A mutation score above 70% would confirm test quality, not just coverage quantity.
  • Chaos testing: inject Fargate Spot interruptions deliberately to verify ECS recovery time.

Dimension 2: Security

What it measures: Does the system protect data and resist attacks?

Static Analysis (SAST) β€” SonarCloud

SonarCloud performs continuous static analysis across all 8 modules. Configuration: sonar-project.properties (root). Reports: apps/projectdoc/dist/reports/security.html.

What SonarCloud checks:

  • SQL injection vulnerabilities
  • XSS vectors
  • Hardcoded credentials
  • Insecure cryptography usage
  • Null pointer dereferences in security-critical paths
  • OWASP Top 10 categories (mapped to rules)

The project has a Quality Gate configured. PRs are decorated with inline findings.

Dynamic Analysis (DAST) β€” OWASP ZAP

OWASP ZAP scans the running application β€” the most realistic security test because it attacks real HTTP traffic, not source code. Six scan profiles cover every API surface:

Scan Target Report
Frontend https://www.batbern.ch security-reports/zap-frontend.json
Companies API /api/v1/companies/** security-reports/zap-companies.json
Events API /api/v1/events/** security-reports/zap-events.json
Speakers API /api/v1/speakers/** security-reports/zap-speakers.json
Partners API /api/v1/partners/** security-reports/zap-partners.json
Attendees API /api/v1/registrations/** security-reports/zap-attendees.json

Full HTML report: security-reports/zap-report.html ZAP rule configuration (false positive suppression): .zap/rules.tsv

Dependency Vulnerability Scanning β€” Trivy

Trivy scans all 8 modules for known CVEs in dependencies, secrets accidentally committed, and infrastructure misconfigurations. Output format: SARIF (importable into GitHub Code Scanning).

security-reports/api-gateway-trivy.sarif
security-reports/event-management-service-trivy.sarif
security-reports/company-user-management-service-trivy.sarif
security-reports/speaker-coordination-service-trivy.sarif
security-reports/partner-coordination-service-trivy.sarif
security-reports/shared-kernel-trivy.sarif
security-reports/web-frontend-trivy.sarif

Configuration: gradle/trivy-security.gradle. Scans for: vuln, secret, misconfig.

Security Headers (12 Verified)

Every response from the API Gateway carries hardened security headers, enforced by SecurityHeadersFilter.java and verified by SecurityHeadersTest.java (12 test cases):

Header Value Purpose
Strict-Transport-Security max-age=31536000; includeSubDomains; preload Enforce HTTPS
X-Frame-Options DENY Prevent clickjacking
X-Content-Type-Options nosniff Prevent MIME sniffing
Content-Security-Policy default-src 'self'; frame-ancestors 'none'; ... Restrict resource loading
Referrer-Policy strict-origin-when-cross-origin Limit referer leakage
Permissions-Policy geolocation=(), microphone=(), camera=() Deny browser APIs
X-XSS-Protection 1; mode=block Legacy XSS filter
Cache-Control no-cache, no-store, must-revalidate Sensitive endpoints

Authentication Architecture (Defence in Depth)

Three independent auth layers, all must pass:

  1. API Gateway JWT validation β€” Multi-issuer decoder (Cognito RS256 + Watch app HMAC-SHA256) Routing: peek at iss claim β†’ select decoder β†’ verify signature api-gateway/src/main/java/ch/batbern/gateway/config/SecurityConfig.java

  2. Method-level security β€” @PreAuthorize("hasRole('ORGANIZER')") on individual methods Active in production/staging (@EnableMethodSecurity), disabled only on localhost Example: services/partner-coordination-service/src/main/java/.../config/SecurityConfig.java

  3. VPC internal auth β€” Service-to-service calls validated by CIDR (10.1.0.0/16) VpcInternalAuthorizationManager in company-user-management-service

Audit Trail

Every security-relevant action is logged to both CloudWatch and the audit database:

  • @AuditLog(action="USER_DATA_EXPORT", severity=AuditSeverity.CRITICAL) annotation
  • Intercepted by AuditLoggingAspect β†’ structured CloudWatch event
  • api-gateway/src/main/java/ch/batbern/gateway/auth/AuditLogger.java
  • GDPR data export/deletion is audit-logged at CRITICAL severity

Known Trade-offs (Honest)

  • CSP unsafe-inline: Required by Material-UI (CSS-in-JS). Mitigated by frame-ancestors 'none' and upgrade-insecure-requests. Would require full MUI migration to remove.
  • Rate limit storage is in-memory: Effective for single-node, but resets on restart. For multi-node clusters, this should be replaced with Redis. Acceptable for current ECS single-task setup.
  • /actuator/health is public: Required for ECS health checks. /actuator/env and siblings are NOT exposed (not in management.endpoints.web.exposure.include).

Dimension 3: Maintainability

What it measures: Can a new developer understand and change the code without breaking things?

Code Style Enforcement β€” Checkstyle

Checkstyle runs on every build and blocks commits via pre-commit hooks. Configuration: config/checkstyle/checkstyle.xml. Reports per service: apps/projectdoc/dist/reports/{service}/

Rules enforced include:

  • Line length ≀ 120 characters
  • NeedBraces: all if/else must use {}
  • UnusedImports: dead imports rejected
  • OperatorWrap: multi-line expression operators at start of next line
  • Google Java Style naming conventions

SonarCloud Quality Metrics

SonarCloud tracks cognitive complexity, code duplication, and accumulated technical debt across all 8 modules. sonar-project.properties configures multi-module analysis.

What to look for in the SonarCloud dashboard:

  • Quality Gate: must be Green (blocking merges if Red)
  • Cognitive Complexity per method: target < 10
  • Duplication: target < 3%
  • Technical debt ratio: ratio of debt minutes to development minutes

Documentation Coverage

Documentation is not an afterthought β€” it was built in parallel with the code:

  • 27 architecture documents in docs/architecture/ covering system context, infrastructure, data architecture, API design, frontend, backend, state machines, notifications, testing strategy
  • 7 Architectural Decision Records (ADRs): ADR-001 through ADR-008, each documenting the decision, alternatives considered, and rationale
  • 4 implementation guides in docs/guides/ (service patterns, OpenAPI generation, HTTP clients, Flyway migrations)
  • OpenAPI specs for every API in docs/api/*.openapi.yml β€” kept in sync with code

Test Infrastructure

Testing is a first-class concern, not a checkbox:

  • Layer 1 (Shell scripts scripts/ci/*.sh): smoke tests, CORS, header propagation
  • Layer 2 (Bruno bruno-tests/**/*.bru): API contract tests across 9 collections
  • Layer 3 (Playwright web-frontend/e2e/*.spec.ts): role-based UI E2E (organizer, speaker, partner)
  • Layer 4 (CDK infrastructure/test/e2e/*.test.ts): AWS resource validation

Pre-commit hooks enforce: ESLint (frontend) + Checkstyle (backend) + unit tests + format checks. No code reaches develop without passing all layers.

What Would Strengthen This Further

  • ArchUnit: executable architectural rules as tests (e.g., β€œshared-kernel must have no dependencies on services”, β€œcontrollers must not access repositories directly”). Would turn the DDD architecture from documentation into machine-verifiable rules.
  • Dependency-Cruiser: generate architecture diagram of frontend module dependencies, enforce no circular imports as a CI gate.

Dimension 4: Well-Designedness

What it measures: Does the code follow sound architectural principles? Are decisions deliberate?

Domain-Driven Design (DDD)

The system is structured around bounded contexts with a shared kernel:

shared-kernel/          ← All shared types, domain events, utilities
services/               ← One bounded context per service
  event-management-service/      ← Event lifecycle domain
  speaker-coordination-service/  ← Speaker relationship domain
  partner-coordination-service/  ← Partner coordination domain
  company-user-management-service/ ← Identity domain
  attendee-experience-service/   ← Attendee domain
api-gateway/            ← Infrastructure (not a domain)

The rule: all shared types live in shared-kernel, never duplicated in services. shared-kernel/src/main/java/ch/batbern/shared/ contains:

  • Domain events (EventCreatedEvent, SpeakerInvitedEvent, etc.)
  • Value types (EventWorkflowState, SpeakerWorkflowState)
  • Cross-service utilities (EmailService, ValidationUtils, CloudFrontUrlBuilder)

State Machine Correctness

The 9-state event workflow is a formal state machine, not ad-hoc status fields:

DRAFT β†’ PLANNING β†’ SPEAKERS_INVITED β†’ SPEAKERS_CONFIRMED β†’
AGENDA_PUBLISHED β†’ SPEAKERS_PUBLISHED β†’ EVENT_LIVE β†’ EVENT_COMPLETED β†’ ARCHIVED

Each transition is explicitly permitted or rejected by the domain service. Invalid transitions return 409 Conflict. The state machine is documented in docs/architecture/06a-workflow-state-machines.md and tested via integration tests.

Contract-First API Design (ADR-006)

APIs are designed before implementation:

  1. Write OpenAPI spec in docs/api/{service}.openapi.yml
  2. Generate Java server stubs and TypeScript client types from the spec
  3. Implement against the generated interfaces

This enforces consistency: the API contract is never an accidental byproduct of implementation. Frontend TypeScript types are regenerated with npm run generate:api-types after any API change.

Event-Driven Cross-Service Communication

Services communicate via domain events over AWS EventBridge, not direct HTTP calls:

java
// βœ… Correct β€” publish a domain event, don't call the other service
eventBridge.publish(new SpeakerInvitedEvent(speakerId, eventCode, invitedAt));

// ❌ Wrong β€” tight coupling, synchronous dependency
speakerService.notifySpeaker(speakerId, ...);  // banned by convention

This is enforced by convention and reviewable via the shared-kernel event catalogue: shared-kernel/src/main/java/ch/batbern/shared/events/

ADR-Backed Decisions

Every significant architectural choice is documented with alternatives and rationale:

ADR Decision Rationale
ADR-001 Invitation-based user registration GDPR compliance, no open sign-up
ADR-002 Presigned S3 URLs for uploads Avoid proxying binary data through backend
ADR-003 Meaningful identifiers in public APIs Human-readable event codes (BATbern57)
ADR-004 Factor user fields from domain entities Avoid duplicating user data across services
ADR-006 Contract-first OpenAPI code generation API consistency, type safety, spec-as-truth
ADR-007 Unified user profile (single entity) No data synchronisation problems
ADR-008 Simplified API gateway routing Avoid over-engineering; path-based routing suffices

Infrastructure as Code (CDK)

All AWS infrastructure is defined in infrastructure/ using AWS CDK (TypeScript). Nothing is click-ops. Infrastructure changes go through the same PR review and CI pipeline as code. CDK infrastructure tests are in infrastructure/test/e2e/*.test.ts.


How to Read Each Report

SonarCloud Dashboard

URL: https://sonarcloud.io/project/overview?id=nissimbuchs_BATbern2

  • Quality Gate: Green = all thresholds met. Red = build should be blocked.
  • Bugs: Logic errors SonarCloud detected statically. Any High/Critical bug warrants investigation.
  • Vulnerabilities: Security findings mapped to OWASP/CWE. High = fix before prod.
  • Code Smells: Maintainability issues. Focus on Critical/Major; Minor can be deferred.
  • Coverage: Percentage of lines executed by tests. See thresholds above.
  • Duplications: Code copy-pasted across files. > 5% is a smell.

OWASP ZAP Report (apps/projectdoc/dist/reports/zap-report.html)

  • High Risk: Must be fixed before production. Rare false positives at this level.
  • Medium Risk: Should be fixed. Evaluate each: some are informational for SPAs.
  • Low Risk / Informational: Often false positives for stateless JWT APIs. Each is documented in .zap/rules.tsv as either confirmed risk or suppressed false positive.
  • Common SPA false positives: β€œMissing Anti-CSRF Tokens” (stateless JWT API doesn’t use cookies).

Trivy SARIF (security-reports/*-trivy.sarif)

Import into GitHub Code Scanning or view with any SARIF viewer. Severity levels:

  • CRITICAL/HIGH: Patch or document accepted risk. Almost never acceptable.
  • MEDIUM: Patch in next maintenance window.
  • LOW/UNKNOWN: Review and document. Many are informational.
  • Most Java CVEs are transitive (from Spring Boot BOM) β€” managed automatically by Dependabot.

JaCoCo Coverage (apps/projectdoc/dist/reports/coverage.html)

  • Overall percentage is less important than which packages have low coverage.
  • Look at: service/ packages (business logic, should be highest), controller/ packages.
  • Lower coverage acceptable for: config/, exception/ (infrastructure, not logic).
  • Coverage hides test quality. 60% with real assertions beats 90% with empty tests.

The Case for AI-Generated Code Quality

The argument against AI-generated code typically rests on three claims:

  1. AI doesn’t understand security
  2. AI produces unmaintainable spaghetti
  3. AI can’t design coherent architecture

The evidence above addresses each:

Against claim 1 (security): OWASP ZAP dynamic scanning against running services, Trivy CVE scanning, SonarCloud SAST, hardened security headers with machine verification, defence-in-depth auth (3 independent layers), full audit trail. Security is not bolted on β€” it is foundational.

Against claim 2 (maintainability): Checkstyle enforcement from day one (zero tolerance), pre-commit hooks, 4-layer test framework, 27 architecture documents, 7 ADRs, OpenAPI contract-first approach, full test coverage tooling. The code is more consistently styled than most human-authored codebases because the AI cannot choose to skip the formatter.

Against claim 3 (architecture): Formal DDD bounded contexts, shared kernel purity, event-driven cross-service communication, state machine-governed domain lifecycle, ADR-documented decisions with alternatives considered. These are not surface-level patterns β€” they are enforced by the structure of the codebase itself.

The invitation: All tooling configuration is committed to the repository. Every claim is reproducible. Run make test && make audit-security and read the reports yourself.


What We Would Add Next

These are genuine gaps β€” not to discredit what exists, but to show the roadmap to even higher confidence:

Tool What it adds Priority
ArchUnit Executable architectural rules (DDD constraints as tests) High
PITest Mutation score for Java tests (test quality, not just coverage) High
Stryker Mutation score for TypeScript frontend tests Medium
Pact Contract tests between services (API consumer-driven contracts) Medium
Lighthouse CI Web Vitals gate in CI (FCP < 1.5s, LCP < 2.5s) Low
dependency-cruiser Frontend architecture diagram + circular import enforcement Low

This document is maintained alongside the codebase. Regenerate quality reports after any significant change with make test && make audit-security && npm run generate:api-types.