schema / migration / 019-court-showcase-content

019 - Court showcase content (description, gallery, specs, perks)

  • Tanggal: 2026-08-11
  • DB: mpcdb (shared Postgres — mpc-be / mpc-be-pos / mpc-admin)
  • Ringkas: Kolom konten showcase di courts untuk halaman Court Detail (deskripsi, galeri foto, spesifikasi material, perks) + seed konten 3 court aktif.

ALTER (jalankan di DB server)

-- Idempotent; safe to re-run.
ALTER TABLE courts
  ADD COLUMN IF NOT EXISTS description text,
  ADD COLUMN IF NOT EXISTS gallery jsonb NOT NULL DEFAULT '[]',   -- array of image URLs
  ADD COLUMN IF NOT EXISTS specs jsonb NOT NULL DEFAULT '[]',     -- array of {"label","value"}
  ADD COLUMN IF NOT EXISTS perks jsonb NOT NULL DEFAULT '[]';     -- array of strings

Seed konten 3 court aktif (idempotent)

UPDATE courts SET
  description = 'Our signature indoor panoramic court. Full-glass back walls, tournament-grade turf, and calibrated LED lighting deliver consistent play from the first rally to the last point.',
  gallery = jsonb_build_array(
    COALESCE(NULLIF(image_url, ''), 'https://images.pexels.com/photos/38155778/pexels-photo-38155778/free-photo-of-indoor-padel-tennis-courts-with-blue-surface.jpeg?auto=compress&cs=tinysrgb&w=1200'),
    'https://images.pexels.com/photos/31012869/pexels-photo-31012869/free-photo-of-padel-racket-and-ball-on-blue-court-surface.jpeg?auto=compress&cs=tinysrgb&w=1200',
    'https://images.pexels.com/photos/37978215/pexels-photo-37978215/free-photo-of-padel-rackets-on-blue-court-with-tennis-ball.jpeg?auto=compress&cs=tinysrgb&w=1200'
  ),
  specs = '[
    {"label": "Surface", "value": "Premium monofilament turf"},
    {"label": "Walls", "value": "12mm tempered glass"},
    {"label": "Lighting", "value": "500 lux LED, anti-glare"},
    {"label": "Dimensions", "value": "20m x 10m (WPT standard)"}
  ]'::jsonb,
  perks = '["Complimentary locker", "Towel service", "Drinking water station", "Court-side seating"]'::jsonb,
  updated_at = now()
WHERE code = 'CRT-01';

UPDATE courts SET
  description = 'A bright, airy indoor court tuned for social play and training sessions. Even bounce, generous run-off space, and clear sightlines for spectators.',
  gallery = jsonb_build_array(
    COALESCE(NULLIF(image_url, ''), 'https://images.pexels.com/photos/32474981/pexels-photo-32474981/free-photo-of-indoor-padel-court-with-blue-surface.jpeg?auto=compress&cs=tinysrgb&w=1200'),
    'https://images.pexels.com/photos/37978215/pexels-photo-37978215/free-photo-of-padel-rackets-on-blue-court-with-tennis-ball.jpeg?auto=compress&cs=tinysrgb&w=1200',
    'https://images.pexels.com/photos/31012869/pexels-photo-31012869/free-photo-of-padel-racket-and-ball-on-blue-court-surface.jpeg?auto=compress&cs=tinysrgb&w=1200'
  ),
  specs = '[
    {"label": "Surface", "value": "Premium monofilament turf"},
    {"label": "Walls", "value": "12mm tempered glass"},
    {"label": "Lighting", "value": "500 lux LED, anti-glare"},
    {"label": "Dimensions", "value": "20m x 10m (WPT standard)"}
  ]'::jsonb,
  perks = '["Complimentary locker", "Drinking water station", "Court-side seating"]'::jsonb,
  updated_at = now()
WHERE code = 'CRT-02';

UPDATE courts SET
  description = 'The VIP experience. Private lounge access, climate-controlled hall, and a center-court feel with premium turf and broadcast-quality lighting — built for guests who expect the best.',
  gallery = jsonb_build_array(
    COALESCE(NULLIF(image_url, ''), 'https://images.pexels.com/photos/10926534/pexels-photo-10926534.jpeg?auto=compress&cs=tinysrgb&w=1200'),
    'https://images.pexels.com/photos/32897040/pexels-photo-32897040/free-photo-of-vibrant-indoor-padel-court-with-racket-and-balls.jpeg?auto=compress&cs=tinysrgb&w=1200',
    'https://images.pexels.com/photos/31012869/pexels-photo-31012869/free-photo-of-padel-racket-and-ball-on-blue-court-surface.jpeg?auto=compress&cs=tinysrgb&w=1200'
  ),
  specs = '[
    {"label": "Surface", "value": "Tournament-grade turf"},
    {"label": "Walls", "value": "12mm tempered glass, panoramic"},
    {"label": "Lighting", "value": "750 lux LED, broadcast quality"},
    {"label": "Climate", "value": "Air-conditioned hall"},
    {"label": "Dimensions", "value": "20m x 10m (WPT standard)"}
  ]'::jsonb,
  perks = '["VIP lounge access", "Complimentary locker & towel", "Priority parking", "Dedicated court attendant", "Welcome refreshments"]'::jsonb,
  updated_at = now()
WHERE code = 'CRT-03';

Rollback

ALTER TABLE courts
  DROP COLUMN IF EXISTS description,
  DROP COLUMN IF EXISTS gallery,
  DROP COLUMN IF EXISTS specs,
  DROP COLUMN IF EXISTS perks;

Catatan

  • mpc-be: GET /courts & GET /courts/:id mengembalikan field baru (backward compatible — field tambahan saja).
  • mpc-admin: form Court mengelola description/gallery/specs/perks (+ image_url yang sebelumnya drift dari Prisma).
  • mpc-be-pos / mpc-pos: tidak terdampak (POS tidak menampilkan konten marketing court).