Letting strangers loose on your software: building the Ticket Foundry sandbox
Ticket Foundry has a public sandbox at sandbox.ticketfoundry.net. Anyone can open it, click around, create tickets, drag cards on the kanban board, mess with settings. No login. No signup. Full product, fully interactive.
We spent two solid weeks building it. Here's why a "demo" took two weeks, and what we learned about letting the public touch your stuff.
Why a sandbox at all
You can read about ticketing software all day. You can watch demo videos. You can read screenshots. None of those tell you whether the kanban board feels right. Whether the new-ticket form is annoying. Whether you'd actually use this.
The fastest way to convey "this is the product, this is what it's like" is to let people use it. So we did.
The constraint: no account. We did not want to gate the demo behind a signup. The moment you make people give you an email to see your product, half of them bounce. The whole point of a public sandbox is that someone can be skeptical, click the link, poke around for 90 seconds, and form an honest opinion.
What "no login" actually requires
Here's where it gets fun. Ticket Foundry has four roles: Admin, Tech, Manager, End User. They see different things. They can do different things. Without a login, how do we let visitors experience all four?
We built a role switcher in the sidebar. It's a dropdown that lets you flip between roles in real time, no password, no session, no nothing. Pick "Admin" — you see settings and everything else. Pick "End User" — you see only the public submit form and your own tickets.
It's not how the real product works (in production, your role is set when your account is created and you can't change it). But it's the right thing for a demo: people can immediately see what their team would experience.
Things that have to be different from production
Once you have a no-login public app where strangers can do whatever they want, you have a list of new problems:
1. The database will get filled with garbage. People will create test tickets called "asdf." People will write profanity. People will submit a thousand-word lorem ipsum into the description field. This is fine — but you need a way to start fresh.
2. People will try to break it. Some on purpose, some by accident. Someone will try to upload a 50MB file. Someone will try to set the company name to a slur. Someone will try every URL parameter combination they can think of.
3. Email cannot be allowed to leave the building. If a stranger creates a ticket and we send a "new ticket assigned" notification, who does it go to? Us. We will get thousands of emails. So all email from the sandbox has to be disabled, but the UI needs to show what email features exist.
4. Settings have to be visible but not destructive. If a visitor goes into Settings and changes the timezone or the theme defaults or the SMTP config, the next visitor sees their changes. We need read-only settings UI that shows the config without persisting it.
Here's how we solved each one.
Reset every 7 days, automatically
A cron job wipes and re-seeds the sandbox database every Sunday at 3 AM. The reset script:
- Truncates every table
- Re-runs the seed SQL (sample tickets, sample users, sample projects)
- Resets file uploads (deletes the uploads directory)
- Resets the audit log
This gives the sandbox a known-good baseline every week. Visitors who showed up Wednesday and saw a board full of test tickets named "lol" will see clean seed data on next Sunday.
There's also a manual reset.php available behind a secret key. If something goes really wrong, I can SSH in and trigger an immediate reset. Once the reset is done, I delete the file so it can't be hit again.
A word filter for user input
Anything visitors type gets passed through a filter.php middleware before hitting the database. It catches the obvious stuff — slurs, severe profanity, common spam patterns. It's not bulletproof; nothing is. But it catches the lazy bad-faith attempts.
The filter is not present in the production product. Production Ticket Foundry users are your own employees. They're not adversaries. They don't need their tickets sanitized for content. The filter is a sandbox-only thing.
Email is disabled, visibly
The Email Settings tab is fully visible. You can see all six providers, all the config options, the template editor. But:
- The "Send Test" button shows a polite "Emails disabled for sandbox" toast instead of actually sending
- All notification triggers throughout the app are no-ops
- Report email scheduling shows the UI but doesn't actually send
This was important to us. The point of the sandbox is to see what you're getting, including the parts that don't work in the sandbox. Hiding the email tab entirely would have been worse — visitors might assume the product doesn't have email at all.
Settings: visible, non-persisting
This was the hardest one. People go into Settings expecting changes to save. If you let changes save in the sandbox, the next visitor sees them. If you silently throw the changes away, that's a confusing UX.
We landed on: settings appear to save, but every page load resets them from a fixed config. The company name is locked to "Ticket Foundry Sandbox." All 10 themes work and persist per-session (via localStorage). Other settings show a save toast but on next page load they're back to defaults.
It's not perfect. A picky visitor could test it and figure it out. But for the casual click-around-and-see-the-product user, it works fine.
Audit log: fake data
The audit log feature shows recent activity in the system — who did what, when. For a sandbox where the activity is random strangers messing around, displaying real audit entries would be (a) overwhelming and (b) a privacy risk for IPs and timestamps.
So the sandbox audit log displays pre-baked, realistic-looking fake entries. "Mike Honcho updated ticket TF-0042," "Sarah Chen archived project PRJ-08," etc. Demonstrates the feature without exposing real data or showing what other visitors are doing.
File uploads: UI only
The attachment drag-drop area is visible on every ticket. Visitors can see it exists, can hover, can drag a file onto it. But the upload endpoint returns a polite rejection. No files actually leave the visitor's machine.
This was a security decision. An open file upload endpoint to the public internet is an attack surface we didn't want. Production installs of Ticket Foundry have working uploads (with size and type limits); the sandbox shows the feature without opening the hole.
Security hardening: belt and suspenders
A bunch of small things that add up:
.htaccessblocks direct access to/includes,.sqlfiles, andreset.php- A
TF_SANDBOXconstant in every include file — any direct HTTP request to a.phpfile in/includesreturns 403 - All paths are relative for portability
- No real customer data in the database, ever (only seed data)
- Different MySQL credentials than the production site (it's its own DB called
tf_sandbox)
If someone finds a vulnerability in the sandbox, the blast radius is the sandbox itself. They can't pivot into production. The two systems share a domain but nothing else.
The thing nobody warned us about
Sandboxes get crawled. Aggressively.
Within hours of going live, search engine bots, SEO scrapers, and security scanners were all hammering the sandbox. The kanban board, the new ticket form, every URL. This was fine in principle — we wanted it indexed — but it inflated our analytics and made the "is anyone actually using this" question much harder to answer.
We added some basic bot detection (user agent matching mostly), and we filter known crawler traffic out of the audit log displays. Still seeing volume from random scanners but the human-vs-bot ratio is at least visible now.
What I'd do differently
Build the sandbox after the product, not in parallel. I had a couple of sandbox-specific UI changes that I had to backport to production later, and it'd have been faster to build the real product first and then strip features out for the sandbox.
Plan for the reset script earlier. I built the reset script after the sandbox had already accumulated a week of test data and was somewhat broken. It would have been easier to design the reset path from day one and have it always working.
Don't underestimate how much fake data you need. The seed data is what visitors see first. If it's boring, the sandbox is boring. We put real effort into making the seed tickets funny and realistic: "Printer has chosen violence again," "It worked yesterday," etc. People notice.
Try it
sandbox.ticketfoundry.net — no login, click around, see if it's the product you want. It resets every Sunday so feel free to mess things up.