Open-source event management and ticket selling platform — perfect for concerts, conferences, and everything in between 🎟️ If you find this project helpful, please consider giving us a star ⭐️
Organizers need a self‑hosted ticketing system that can be branded, integrated with Stripe, and run on their own infrastructure. Commercial SaaS solutions lock data and charge per‑ticket fees, forcing teams to trade control for convenience.
What This Does
Events delivers a full‑stack ticketing platform. The backend (Laravel + Express) lives under backend/ and implements the domain model, REST API, and Stripe integration. The frontend (React + Vite) in frontend/ provides a SPA for event creation, checkout, and admin dashboards. Docker orchestration (Dockerfile.all-in-one, docker/all-in-one/docker-compose.yml) lets you spin up the whole stack with a single command. Key entry files are:
backend/resources/js/app.js – compiles the admin UI assets.
frontend/src/App.tsx – root React component.
frontend/server.js – development server wrapper.
Configuration defaults are in backend/.env.example and docker/all-in-one/.env.example.
How It Is Wired
Startup – docker compose -f docker/all-in-one/docker-compose.yml up builds the all‑in‑one image (Dockerfile.all-in-one). The image runs both PHP‑FPM (Laravel) and Node (Vite) processes.
Request flow – An HTTP request hits the Nginx proxy (inside the image) and is routed to Laravel (backend/public/index.php). Laravel’s app/Http/Controllers resolve to service classes under app/Services/Domain. Business logic creates/updates domain objects such as OrderDomainObject.php or EventDomainObject.php.
API layer – Laravel routes expose JSON endpoints consumed by the React SPA. The SPA’s data layer uses frontend/src/api/client.ts (the most‑connected module, imported by 19 other files) to call endpoints like /api/events.
State handling – Responses are cached in Redux stores; UI components such as frontend/src/components/common/Modal/index.tsx (imported by 18 modules) render dialogs. Notification handling centralises through frontend/src/utilites/notifications.tsx (imported by 25 modules).
External side‑effects – Stripe calls are wrapped in backend/app/DomainObjects/Enums/PaymentProviders.php and invoked from service classes. Webhooks are processed by Laravel listeners that push updates back to the SPA via Laravel Echo.
The import graph shows no circular dependencies and a clear hub in frontend/src/utilites/notifications.tsx, indicating that changes there have a wide blast radius. Deep nesting and duplicated code blocks (see measured findings) are concentrated in a few hook files (useFormErrorResponseHandler.tsx) and backend DTOs.
How To Use It
# 1. Clone
git clone https://github.com/moses-y/Events
cd Events
# 2. Prepare env files
cp backend/.env.example backend/.env
cp docker/all-in-one/.env.example docker/all-in-one/.env
# 3. Build and run (Docker)
docker compose -f docker/all-in-one/docker-compose.yml up -d
# 4. Install frontend deps (optional, for local dev)
cd frontend
yarn install
yarn dev # runs Vite dev server on localhost:5173
Required variables are defined in the .env.example files (e.g., APP_KEY, DB_CONNECTION, STRIPE_SECRET). After the containers are healthy, the API is reachable at http://localhost/api and the UI at http://localhost.
Real‑World Use
A midsize conference organizer can deploy the stack on a private VPS, point APP_URL to their domain, configure Stripe Connect keys, and immediately gain a branded checkout page, QR‑code check‑in, and exportable attendee lists—all without third‑party fees. The REST API (/api/v1/events/{id}/tickets) can be called from a mobile app to display live inventory.
Code Health & Issues
Critical – Committed credentials in docker/development/.env; rotate and remove from Git.
Critical – Personal access token in .github/workflows/cla.yml; move to a workflow_run job or protected environment.
High – GitHub Actions use mutable tags; pin each action to a commit SHA.
High – Duplicate logic across multiple DTOs (EditOrderResultDTO.php, EditAttendeeResultDTO.php, etc.); extract shared helpers.
Medium – Deep nesting (max depth 7) in several hooks/components; refactor with early returns.
Medium – Base Docker images not pinned by digest; use @sha256 to lock CVE surface.
Additional observations: tests exist (76 files) and CI runs via GitHub Actions, but no dependency‑vulnerability scan is configured. A pre‑commit secret‑scan hook is absent despite the .env leak.
The Bottom Line
Events provides a complete, self‑hostable ticketing stack with a solid Laravel + React foundation and ready‑to‑run Docker image. The codebase is functional but suffers from secret leakage, unpinned CI actions, and some maintainability hotspots (deep nesting, duplicated DTOs). Teams comfortable managing Docker and Laravel can adopt it quickly; however, they should address the critical security findings before production deployment.
What the analyser found
Deployment readiness
6/7
✓Container image
✓CI pipeline
✓Lockfile committed
✓Test suite
✓README
✓License
✗No committed secrets
Composition
2,347 files
PHP1436
TSX317
TypeScript245
SCSS139
Markdown32
JavaScript23
ReactExpressLaravelDocker
Module dependencies
The 10 most depended-upon modules of 400, from static import analysis. Red outline marks a module in an import cycle.
Ranked by severity × confidence × production reach. Reach is the honest discriminator across a collection that is mostly other people's code: the same finding matters more in something that ships.
critical2
high2
medium7
low2
Rotate the credentials in the committed environment filecritical
docker/development/.env
APP_KEY hold generated values
These values are loaded by the application at boot, so a generated value here is a working credential for something that runs.
Fix: Rotate each named credential, remove the file from the index, and replace it with a keys-only example.
Keep secrets out of workflows a fork can triggercritical
.github/workflows/cla.yml
PERSONAL_ACCESS_TOKEN (publish or cloud scope)
Contributor-controlled input reaches a job holding a publish token or cloud credential, so a pull request becomes credential exfiltration.
Fix: Move secret-using steps into a workflow_run job that never checks out pull request code, or gate on an environment with required reviewers.
Pin third-party GitHub Actions to a commit SHAhigh6 occurrences
A tag can be moved, so the action running with your token and secrets is whatever its owner last pushed; this is how tj-actions/changed-files leaked secrets from thousands of repos.
Fix: Replace each @vN with the 40-character commit SHA, keep # vN as a comment, and let Dependabot bump the SHAs.
Remove the committed .env and rotate what it holdshigh
docker/development/.env
docker/development/.env
A tracked .env is the most common route for a working key to reach a public clone, and it is the file the app actually loads, so the value is usually live.
Fix: git rm --cached the file, add it to .gitignore, rotate every credential it names, commit a .env.example with empty values.
Declare least-privilege permissions for GITHUB_TOKENmedium3 occurrences
.github/workflows/deploy.yml
3 workflow(s) declare no permissions, 2 of them reference secrets
With no declaration the token inherits the repository default, so any injected step can push commits or mint releases from inside your own CI.
Fix: Add permissions: contents: read at the top of the workflow and widen per job only where needed.
Pin the container base image by digestmedium2 occurrences
An untagged or mutable base means today's build and last month's contain different libc and a different CVE set, with no record of which shipped.
Fix: Use image:tag@sha256:<digest> and enable Dependabot's docker ecosystem.
Gate pull requests on a dependency vulnerability scanmedium
.github/workflows
no dependency scan in CI
This is the one gate that would catch a known-vulnerable package before it reaches a build, and no repository in the sample had it.
Fix: Add dependency-review-action on pull_request, or osv-scanner on push and a schedule.
Add a pre-commit secret gatemedium
a secret-shaped file is tracked and no repo-level gate is visible
Without a gate the same class of leak recurs on the next commit, so a leak finding is the symptom and this is the cause.
Fix: Add a pre-commit hook scanning staged content, and enable push protection.
Set persist-credentials: false on checkoutmedium
.github/workflows/deploy.yml
checkout keeps the token, then dependencies are installed
The token stays in .git/config for every later step, so a malicious postinstall script reads a pushable credential without one ever being passed to it.
Fix: Add with: persist-credentials: false, and pass an explicit token only to the step that pushes.
Add a non-root USER to the imagemedium
Dockerfile.all-in-one
CMD or ENTRYPOINT with no USER directive
A process running as root in the container is root against every mounted volume, and it turns any container escape or writable-mount mistake from a contained problem into a host one.
Fix: Create an unprivileged user, chown what it needs, and end the Dockerfile with USER.
Expand the test suite; it cannot cover this codebasemedium65 occurrences
65 test files against 2007 source files (ratio 0.032)
A reviewer reads "has tests" and assumes a safety net that covers two files out of eighty-five, which is how untested paths ship behind a green badge.
Fix: Add tests for the highest fan-in modules first.
Set timeout-minutes on the workflow jobslow4 occurrences
.github/workflows/cla.yml
4 workflow(s) declare no job timeout
A wedged step runs to the six-hour platform default, which on a two-hourly schedule means three runs overlap behind it.
Fix: Add timeout-minutes with a realistic bound to each job.
1 further finding(s) are listed in the full report.
Checked deterministically against the repository tree and a bounded set of its files: committed credentials, unpinned actions and base images, missing lockfiles and update bots, workflows that discard failures, published advisories against the declared dependencies, runtime configuration, licensing and notebook reproducibility. No language model is involved in this section.