{"id":50294719,"url":"https://github.com/chrisrobison/panic-backstage","last_synced_at":"2026-05-28T08:03:59.181Z","repository":{"id":355469888,"uuid":"1226148557","full_name":"chrisrobison/panic-backstage","owner":"chrisrobison","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-19T18:51:46.000Z","size":321,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-19T22:17:36.715Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chrisrobison.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-01T03:03:57.000Z","updated_at":"2026-05-19T18:51:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/chrisrobison/panic-backstage","commit_stats":null,"previous_names":["chrisrobison/panic-backstage"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chrisrobison/panic-backstage","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisrobison%2Fpanic-backstage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisrobison%2Fpanic-backstage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisrobison%2Fpanic-backstage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisrobison%2Fpanic-backstage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisrobison","download_url":"https://codeload.github.com/chrisrobison/panic-backstage/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisrobison%2Fpanic-backstage/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33599493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-28T08:03:58.134Z","updated_at":"2026-05-28T08:03:59.173Z","avatar_url":"https://github.com/chrisrobison.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Panic Backstage\n\nPanic Backstage helps venues track every show from hold to settlement, including lineup, schedule, artwork, ticketing, open items, and event readiness.\n\nThe app is intentionally boring to run:\n\n- PHP 8, served from `public/`\n- no Composer runtime dependencies\n- no npm, bundler, or frontend build step\n- MySQL with native PDO prepared statements\n- native PHP sessions, password hashing, CSRF tokens, and file uploads\n- static HTML/CSS/native Web Components that call JSON endpoints under `/api`\n- LARC/PAN loaded from a pinned CDN module for component coordination\n\n## Current Architecture\n\nPanic Backstage is API-first. PHP endpoint classes return JSON only; HTML pages are static and use browser-native Web Components, `fetch()`, and LARC/PAN topic events to load and mutate data.\n\nThe custom kernel in `src/Kernel.php` resolves constrained API paths to endpoint classes:\n\n```text\nGET    /api/dashboard                  -\u003e src/Dashboard.php\nGET    /api/events                     -\u003e src/Events.php\nPOST   /api/events                     -\u003e src/Events.php\nGET    /api/events/{id}                -\u003e src/Events.php\nPATCH  /api/events/{id}                -\u003e src/Events.php\n\nGET    /api/events/{id}/tasks          -\u003e src/Events/Tasks.php\nPOST   /api/events/{id}/tasks          -\u003e src/Events/Tasks.php\nPATCH  /api/events/{id}/tasks/{taskId} -\u003e src/Events/Tasks.php\nDELETE /api/events/{id}/tasks/{taskId} -\u003e src/Events/Tasks.php\n\nGET    /api/events/{id}/assets         -\u003e src/Events/Assets.php\nPOST   /api/events/{id}/assets         -\u003e src/Events/Assets.php\nPATCH  /api/events/{id}/assets/{id}    -\u003e src/Events/Assets.php\n\nGET    /api/public/events/{slug}       -\u003e src/PublicEvents.php\n```\n\nEach endpoint receives a `Request`, returns a `Response`, and uses shared services such as `Database` and `Auth`.\n\n## Project Layout\n\n```text\npublic/\n  index.html              Main staff UI\n  login.html              Login page\n  event.html              Public event page shell\n  invite.html             Invite acceptance shell\n  router.php              Local dev router for PHP built-in server\n  .htaccess               Apache rewrite for /api\n  api/index.php           API entrypoint\n  assets/app.css          Venue-ops UI styling\n  assets/app.js           Web Components client\n  uploads -\u003e ../storage/uploads\n\nsrc/\n  bootstrap.php           Autoloader and shared function include\n  Kernel.php              API path resolver and request dispatch\n  Request.php             HTTP request wrapper\n  Response.php            JSON response wrapper\n  Database.php            PDO wrapper\n  Auth.php                Native session auth and CSRF\n  Support.php             Small helper functions\n  Dashboard.php\n  Events.php\n  Templates.php\n  PublicEvents.php\n  Invites.php\n  Events/\n    Tasks.php\n    Blockers.php\n    Lineup.php\n    Schedule.php\n    Assets.php\n    Settlement.php\n    Invites.php\n\ndatabase/\n  schema.sql\n  seed.php\n\nstorage/\n  uploads/events/\n\nschema.sql                Root copy of database schema\n.env.example              Environment variable template\n```\n\n## Requirements\n\n- PHP 8.2 or newer\n- MySQL 8 or newer\n- PHP PDO MySQL extension\n\nNo Composer or Node install is required.\n\nThe frontend uses this pinned LARC module directly in the browser:\n\n```html\n\u003cscript type=\"module\" src=\"https://cdn.jsdelivr.net/npm/@larcjs/core@3.0.1/pan.mjs\"\u003e\u003c/script\u003e\n```\n\n## Local Setup\n\nCopy the example environment file:\n\n```bash\ncp .env.example .env\n```\n\nSet the database credentials in `.env`:\n\n```text\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_USER=panic_backstage\nDB_PASSWORD=your-local-password\nDB_NAME=panic_backstage\n```\n\nIf you need to create the local MySQL user manually:\n\n```sql\nCREATE DATABASE IF NOT EXISTS panic_backstage CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nCREATE USER IF NOT EXISTS 'panic_backstage'@'localhost' IDENTIFIED BY 'your-local-password';\nCREATE USER IF NOT EXISTS 'panic_backstage'@'127.0.0.1' IDENTIFIED BY 'your-local-password';\nGRANT ALL PRIVILEGES ON panic_backstage.* TO 'panic_backstage'@'localhost';\nGRANT ALL PRIVILEGES ON panic_backstage.* TO 'panic_backstage'@'127.0.0.1';\nFLUSH PRIVILEGES;\n```\n\nThen seed the database:\n\n```bash\nphp database/seed.php\n```\n\nSeed admin login:\n\n```text\nemail: admin@mabuhay.local\npassword: changeme\n```\n\n## Running Locally\n\nUse PHP's built-in server:\n\n```bash\nphp -S localhost:8000 -t public public/router.php\n```\n\nOpen:\n\n```text\nhttp://localhost:8000\n```\n\nThe built-in router serves static files normally and dispatches `/api/*` to `public/api/index.php`.\n\nTo smoke-test the app under a subdirectory path, set `APP_BASE_PATH`:\n\n```bash\nAPP_BASE_PATH=/backstage php -S localhost:8000 -t public public/router.php\n```\n\nThen open `http://localhost:8000/backstage/`. Static assets, API calls, invite links, and uploaded media are resolved relative to the app base path instead of the server document root.\n\n## Venue Demo Walkthrough\n\nThe seeded Mabuhay Gardens demo is designed for a venue operations walkthrough.\n\nReset and launch locally:\n\n```bash\nphp database/seed.php\nphp -S localhost:8000 -t public public/router.php\n```\n\nLogin:\n\n```text\nemail: admin@mabuhay.local\npassword: changeme\n```\n\nSuggested flow:\n\n1. Open the dashboard and call out the next show, open items, empty holds, flyer needs, and settlement signals.\n2. Open `Local Band Showcase`, edit event details, assign tasks, resolve the open flyer/ticketing items, approve the seeded flyer, and review the run sheet.\n3. Create an invite link from the event workspace and copy it for a collaborator.\n4. Use the public page button after publishing the event to show the guest-facing event page.\n5. Open Templates, create a new show from `Three-Band Local Show`, then show how tasks and schedule items come preloaded.\n6. Open `Legacy Benefit Night`, calculate venue net, and show the completed settlement fields.\n7. Open Calendar and Pipeline to show the same events by date and update operational status.\n\nExample public event URL after seeding:\n\n```text\nhttp://localhost:8000/event.html?slug=local-band-showcase\n```\n\nEndpoint smoke test against a running local or staging server:\n\n```bash\nphp scripts/endpoint-smoke.php http://localhost:8000\n```\n\nThe smoke script logs in as admin, loads dashboard data, creates an event from a template, updates an open item, creates and accepts a viewer invite, verifies collaborator event access, verifies unrelated event access and viewer mutation are blocked, saves settlement data, publishes the event, and verifies the public event API. It does not send email and does not exercise multipart asset upload.\n\n## Deployment Notes\n\nUse `public/` as the web root.\n\nFor Apache, the included `public/.htaccess` routes API requests to `public/api/index.php`.\n\nFor Nginx/PHP-FPM, route `/api/*` to `public/api/index.php` and serve static files from `public/`. If the app is mounted under a subdirectory such as `/backstage`, route that prefix to `public/` and set `APP_BASE_PATH=/backstage` if the server does not expose the prefix through `SCRIPT_NAME`. Uploads should resolve through the `public/uploads` symlink to `storage/uploads`.\n\nKeep `.env` outside version control. It is ignored by `.gitignore`.\n\nStaging checklist:\n\n- PHP 8.2+, PDO MySQL, and fileinfo enabled.\n- `.env` uses staging database credentials and `APP_BASE_PATH` when mounted below `/`.\n- `storage/uploads/events` is writable by the PHP process.\n- The server can reach `https://cdn.jsdelivr.net/npm/@larcjs/core@3.0.1/pan.mjs`, or LARC should be vendored in a future offline-demo pass.\n- Run `php database/seed.php` only when resetting demo data is acceptable.\n\n## Core Workflow\n\n- `/` shows the staff dashboard after login.\n- Venue admins can create events from templates and see all events.\n- Each event workspace manages overview, lineup, tasks, open items, run sheet, assets, settlement, and activity.\n- Public event pages are loaded by `public/event.html?slug=event-slug`.\n- Public event API responses only include events with `public_visibility` enabled.\n- Web Components publish PAN-compatible topics such as `app.route.changed`, `events.loaded`, `event.saved`, `event.assetUploaded`, `event.openItemResolved`, `event.publicationChanged`, `toast.show`, and `api.error`.\n\n## Roles And Collaborator Access\n\nServer-side authorization is enforced by global user role plus event ownership or `event_collaborators` rows. Venue admins retain full access to every event, template, invite, asset, settlement, and user list. Non-admin users only see events they own or events where they have a collaborator row.\n\nEvent collaborator roles:\n\n- `event_owner`: full access to assigned/collaborating events except global user or template administration.\n- `promoter`: read event data, edit lineup, tasks, schedule, and open items, and view/copy the public page. Settlement is hidden.\n- `band` / `artist`: read the collaborating event, upload assets, and view tasks assigned directly to them.\n- `designer`: read the collaborating event and upload/manage event assets. Settlement is hidden.\n- `staff`: read the collaborating event and edit tasks, schedule, and open items.\n- `viewer`: read-only access to the collaborating event.\n\nInvite links still only create copyable links in the UI. They do not send email.\n\n## Collaborator Demo Flow\n\nAfter logging in as the seeded admin:\n\n1. Open an event workspace and select the Invites tab.\n2. Create a viewer, staff, designer, promoter, artist, or band invite link.\n3. Copy the generated invite link and open it in a separate browser session or private window.\n4. Accept the invite with a name and password.\n5. Confirm the collaborator can open that event from the dashboard or direct event URL.\n6. Confirm unrelated events are not listed and direct access to unrelated event IDs is rejected.\n7. For a viewer invite, confirm event detail fields, settlement, invite creation, and destructive asset controls are unavailable.\n8. For a designer invite, manually verify asset upload/manage controls on that event. The smoke script does not exercise multipart uploads.\n\n## Verification\n\nUseful checks:\n\n```bash\nfind src public database scripts -name '*.php' -print -exec php -l {} \\;\nnode --check public/assets/app.js\nphp database/seed.php\nphp -S localhost:8000 -t public public/router.php\nphp scripts/endpoint-smoke.php http://localhost:8000\n```\n\n`node --check` is optional and only validates the plain JavaScript file. The app does not require Node to run.\n\n## MVP Limitations\n\n- Stripe is represented by ticket fields only.\n- Invite links create collaborator-scoped access but still do not send email.\n- Uploads use local disk storage under `storage/uploads/events/:eventId`.\n- The frontend is intentionally browser-native Web Components, optimized for hackability over framework features.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisrobison%2Fpanic-backstage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisrobison%2Fpanic-backstage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisrobison%2Fpanic-backstage/lists"}