Image
Open Court

Drupal 11 + Vue.js 3 · Sports facility booking platform

12 custom modules · 22+ entities · 12 user roles · 20 sport types · 9 country profiles

🏢 Facility Management

Multi-tenant hierarchy Company → Venue → Court. Each court has configurable sport type, surface, and capacity. Operating hours use 6-layer cascading inheritance (System → Company → Venue → Court Type → Court → Exception). Supports dedicated-instance or multi-tenant SaaS deployment from a single codebase.


📅 Booking System

Vue.js interactive booking grid with pre-computed 15-min oc_slot entities for fast loading. Supports Single, Serial (recurring weekly), Walk-in, Fixed, and Membership Reservation booking types. Full order lifecycle: Hold → Confirmed → Completed (+ Cancelled/Expired/No-Show). 3-layer anti-overbooking protection with optimistic locking and DB transactions.


💳 Payment System

6 payment gateways: Cash, Bank Transfer, VNPay, PayPal, Stripe, MoMo — each as a decoupled Drupal plugin. Payment modes: Pay Now, Pay Later, Deposit (30%). Event-driven architecture: PAYMENT_COMPLETED triggers booking confirmation. Handles double-payment prevention, IPN idempotency, and amount mismatch logging.


💰 Pricing Engine

Dynamic pricing per venue, per day-type (Weekday/Weekend/Holiday), per demand level (Low/Normal/High/Peak). 2-layer inheritance (Company → Venue). Special date overrides and holiday pricing rules. Visual 3-tab pricing editor with inline editing.


🏅 Membership System

Tiered plans (Bronze/Silver/Gold) with monthly or annual billing. Members book slots for free within monthly + daily hour quotas. Uses same checkout/payment flow as bookings. Auto-completion for membership reservations (price=0, status=completed). Cron-based expiry lifecycle. Usage tracked via oc_membership_usage entity.


🤝 Open Slots & Community

Players create open slots from their bookings to find teammates. Participant management with auto-approve or manual approval. 10-tier skill level matching (Beginner → Pro). OTT contact integration (Zalo, Telegram, WhatsApp). Per-slot fee for cost sharing. Lifecycle sync: cancelling a booking auto-closes its open slots.


🔔 Notifications

Multi-channel: In-App, Email, SMS, Push, plus OTT (WhatsApp, Telegram, Zalo) and collaboration (Slack, Discord). Event-driven triggers for booking confirmations, payments, open slot joins, membership expiry, etc. Users configure per-channel, per-event preferences. Email queue processed via cron.


🎨 Theme & Skins

Standalone open_court_theme with 8000+ lines CSS. 12 built-in skins (Court Blue, Dark, Sunset, Forest, etc.) with live switching via CSS custom properties — no page reload needed. Glassmorphism design language, micro-animations, responsive mobile-first. WCAG ≥ 4.5:1 contrast compliance.


🌍 Internationalization

11 languages: EN, VI, JA, DE, FR, ZH, KO, TH, MS, ID, ES. Content + config translation with URL prefix routing. Frontend language switcher in header.


💱 Currency Management

160+ currencies (ISO 4217). All amounts stored as integers in smallest unit (Stripe-style). Dynamic formatting with CurrencyFormatter service. Frontend integration via Vue.js formatPrice() + Twig {{ currency_symbol }}.


⚙️ Content Generator

18-step automated data generation for demos/testing. 9 country profiles with localized names, currencies, venues. Sport-specific content (images, descriptions, pricing). CLI via drush oc:generate and admin UI at /app/content/generator.


📰 Content Management

Frontend-first editing at /app/content/* — no Drupal admin needed. News articles, static pages (About, Terms, Privacy), categorized FAQs. Configurable page texts per sport and country.


👥 Roles & Access

12 roles: Administrator, Business Manager/Staff, Company Owner, Venue Manager/Staff, Accountant, Organizer, Player, Guest, Content Editor, Authenticated. Venue-scoped data isolation. Admin user switching with audit trail.


🖥️ Architecture

Frontend-first: all business CRUD via /app/*. Admin backend via /admin/open-court/* (Claro theme). Vue.js SPA for booking grid. JSON API layer for clients. Per-venue caching with tag-based invalidation. Cron jobs for hold expiry, slot generation, membership management.