Deployment & Settings Changes - v1.60.0

Release: v1.60.0 Date: 2026-03-19


Summary

Impact Level: HIGH

Action Required: YES (self-hosted customers only)

Backward Compatible: NO (Docker container port changed from 80 to 8081 for frontend images)


Quick Decision Matrix

Component/Area Change Type Risk Level Action Required Impact
Environment Variables No changes NONE NO No new environment variables
Database Schema Migrations V90-V93 LOW NO Auto-applied by Flyway on startup
Kubernetes/Helm Security hardening, probes LOW NO Non-breaking chart updates
Docker Images Breaking HIGH YES Frontend container port changed: 80 -> 8081
Runtime Dependencies No changes NONE NO No dependency updates
Monitoring/Logging Actuator probes added LOW NO New health endpoints

Deployment Decision

Overall Risk: MEDIUM

Recommended Action: APPROVE with container port update

Downtime Required: NO - Zero-downtime supported (after port configuration update)

Rollback Risk: MEDIUM - Database migrations V90-V92 add columns and set data; V93 changes sequence increment. All are additive and do not remove data.

Special Considerations: Existing events are migrated to PUBLISHED status by V92. This is required for the booking API enforcement that rejects non-PUBLISHED events (HTTP 422).


Breaking Change: Nginx Unprivileged (Frontend Images)

What Changed

All frontend Docker images (editor-client, booking-client) have been migrated from nginx:1.27.4-alpine to nginxinc/nginx-unprivileged:1.27.4-alpine as part of security hardening to run all containers as non-root.

This changes the container listening port from 80 to 8081.

Image Before (1.59.x) After (1.60.x)
editor-client nginx:1.27.4-alpine, port 80 nginxinc/nginx-unprivileged:1.27.4-alpine, port 8081
booking-client nginx:1.27.4-alpine, port 80 nginxinc/nginx-unprivileged:1.27.4-alpine, port 8081

Who Is Affected

  • Self-hosted customers who manage their own Kubernetes manifests, Docker Compose files, or reverse proxy configurations. If you only changed the image tag from 1.59.x to 1.60.x without updating the container port, the frontend will not respond to HTTP requests.
  • SaaS / Helm-managed deployments are NOT affected – the Helm chart was updated alongside the image change.

Symptoms If Not Migrated

  • Frontend pods start successfully (nginx logs show “Configuration complete; ready for start up”)
  • But HTTP requests return connection refused, 502 Bad Gateway, or blank pages
  • Reverting to 1.59.x images restores functionality (confirms port mismatch)

Migration Steps

Kubernetes Deployment: Update containerPort in your pod spec:

# Before (1.59.x)
containers:
  - name: editor-client
    image: registry.gitlab.com/seatmap.pro/seatmap/editor-client:1.60.1
    ports:
      - containerPort: 80    # OLD

# After (1.60.x)
containers:
  - name: editor-client
    image: registry.gitlab.com/seatmap.pro/seatmap/editor-client:1.60.1
    ports:
      - containerPort: 8081  # NEW

Kubernetes Service: Update targetPort to match the new container port:

# Before
spec:
  ports:
    - port: 80
      targetPort: 80        # OLD

# After
spec:
  ports:
    - port: 80              # Service port can remain 80
      targetPort: 8081      # NEW - must match container port

Docker Compose: Update port mapping:

# Before
services:
  editor-client:
    image: registry.gitlab.com/seatmap.pro/seatmap/editor-client:1.60.1
    ports:
      - "80:80"             # OLD

# After
services:
  editor-client:
    image: registry.gitlab.com/seatmap.pro/seatmap/editor-client:1.60.1
    ports:
      - "80:8081"           # NEW

Direct Docker run:

# Before
docker run -p 80:80 registry.gitlab.com/seatmap.pro/seatmap/editor-client:1.60.1

# After
docker run -p 80:8081 registry.gitlab.com/seatmap.pro/seatmap/editor-client:1.60.1

Apply the same changes for booking-client.

Why This Change Was Made

Running nginx as root (PID 1, UID 0) inside containers is a security risk. The nginx-unprivileged image runs as non-root user (UID 101), which:

  • Complies with Kubernetes runAsNonRoot: true pod security policy
  • Reduces the blast radius if the container is compromised
  • Aligns with container security best practices (CIS Kubernetes Benchmark)

Non-root processes cannot bind to privileged ports (< 1024), hence the port change from 80 to 8081.


Configuration Changes

Environment Variables

No environment variable changes in this release.


Database Changes

Migrations

New Migrations: YES

Four Flyway migrations are included. All are applied automatically on service startup.

Migration Files

File Description Impact Rollback Safe
V90__enrich_event_model.sql Adds status, source, external_id, description, poster_url, tags, created_at, updated_at, published_at columns to event table. Creates indexes and CHECK constraints. LOW - additive columns with defaults Yes
V91__make_kill_after_nullable.sql Removes NOT NULL constraint and default value from kill_after column (deprecated field). LOW - relaxes constraint only Yes
V92__set_existing_events_published.sql Updates all existing DRAFT events to PUBLISHED and sets published_at timestamp. LOW - data migration, no schema change No - cannot determine original DRAFT events after migration
V93__fix_group_of_seats_sequence_increment.sql Changes group_of_seats_id_seq increment from 50 to 1, resolving duplicate key violations. LOW - sequence configuration only Yes

Schema Changes

Modified Tables

  • event:
    • Added columns: status (VARCHAR, default ‘DRAFT’), source (VARCHAR, default ‘MANUAL’), external_id (VARCHAR, nullable, unique), description (TEXT), poster_url (VARCHAR), tags (JSONB, default ‘[]’), created_at (TIMESTAMP), updated_at (TIMESTAMP), published_at (TIMESTAMP)
    • Modified columns: kill_after (now nullable, deprecated)
    • New indexes: idx_event_org_status, idx_event_schema_status, idx_event_external_id
    • CHECK constraints on status (DRAFT, PUBLISHED, ARCHIVED) and source (MANUAL, API)

Performance Impact

  • Expected Migration Time: Under 1 second for typical datasets
  • Downtime Required: NO
  • Table Locks: Brief lock on event table during ALTER (V90) and UPDATE (V92)

Kubernetes / Helm Changes

Helm Chart

Aligned with Kubernetes 1.30.14. Minimum Kubernetes version constraint added to all charts (>= 1.26.0-0).

Ingress Changes

  • Replaced deprecated kubernetes.io/ingress.class annotation with spec.ingressClassName: public across all ingresses
  • Added SSL/TLS enforcement: nginx.ingress.kubernetes.io/ssl-redirect: "true" and force-ssl-redirect: "true"
  • Added security response headers to all ingresses:
    • X-Content-Type-Options: nosniff
    • Strict-Transport-Security: max-age=31536000; includeSubDomains
    • Referrer-Policy: strict-origin-when-cross-origin
    • Permissions-Policy: camera=(), microphone=(), geolocation=()
  • Booking ingress additionally sets X-Frame-Options: SAMEORIGIN
  • Actuator endpoints blocked at ingress level (/actuator/ returns 404)

Gzip Compression

Added nginx compression to converter, knowledge-base, and landing-page ingresses (editor and booking already had it):

  • Compression level: 6
  • Minimum response size: 1000 bytes
  • Types: HTML, CSS, JS, JSON, XML, SVG, fonts, CSV

Security Contexts

Added pod and container security contexts to all deployments:

Pod level:

podSecurityContext:
  runAsNonRoot: true
  seccompProfile:
    type: RuntimeDefault

Container level:

securityContext:
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL

Chart Versioning

Chart version and image tags are now injected by CI at deploy time instead of being hardcoded in source.


Monitoring & Health Checks

Updated Health Checks

Both backend services now expose Spring Boot Actuator health groups:

  • Readiness: GET /actuator/health/readiness – returns 200 only when database and Redis are connected (includes readinessState, db, redis)
  • Liveness: GET /actuator/health/liveness – lightweight heartbeat (includes livenessState only)

Helm deployments use a three-probe strategy:

Probe Path Period Failure Threshold Purpose
startupProbe /actuator/health/liveness 5s 30 (150s budget) Absorbs JVM startup time
readinessProbe /actuator/health/readiness 10s 3 Routes traffic only when DB + Redis are up
livenessProbe /actuator/health/liveness 20s 3 Lightweight, avoids restart on transient DB issues

Action Required: NO – probes are configured in Helm values and applied automatically.


CI/CD Deployment

Automated Deployment via GitLab CI/CD

This release is deployed automatically through GitLab CI/CD pipelines. No manual deployment steps are required.

Deployment Flow:

  1. Merge to dev: Auto-deploys to seatmap.dev environment
  2. Merge to main: Manual trigger to deploy to seatmap.pro production

Zero-Downtime: Fully supported

Action Required: NONE


Rollback

Rollback Support: Automated via GitLab CI/CD

Database Rollback: Not supported for V92 (data migration is one-way). V90, V91, V93 are safe to roll back manually if needed, but Flyway does not support automatic down migrations.

Procedure: Redeploy the previous version via GitLab CI/CD. The application code is backward compatible with the new database columns (they are additive).


Release Notes Summary

What Changed

  1. Breaking - Docker Images: Frontend images (editor-client, booking-client) migrated to nginx-unprivileged. Container port changed from 80 to 8081. Self-hosted customers must update their manifests.
  2. Database: Event table enriched with lifecycle management fields (status, source, timestamps, tags). Existing events migrated to PUBLISHED.
  3. Kubernetes: Helm charts aligned with K8s 1.30, security contexts added, ingress security headers added, actuator probes configured.
  4. Health Checks: Dedicated readiness and liveness probe endpoints with three-probe deployment strategy.

What Didn’t Change

  • No new environment variables required
  • No changes to runtime dependencies
  • No changes to resource limits or requests
  • No changes to Redis configuration
  • No changes to authentication or session management
  • Backend service ports unchanged (editor: 8080, booking: 9090, converter: 8080)