Turning tickets into programmable assets
This project is how I learned that blockchain can solve real problems, but only when its benefits are worth the added cost. It began as an assignment for a blockchain course, and my teammate and I chose event ticketing because counterfeiting and scalping remain common problems in Indonesia.
We represented every ticket as an NFT, giving it a verifiable identity and allowing purchasing rules to live inside the smart contract. Even if someone bypassed the website, the contract could still reject a resale above the permitted price.
I had worked with the Internet Computer Protocol before, but I had never built with Solidity or the Ethereum ecosystem. I volunteered to own the smart-contract layer because I wanted to try something unfamiliar.
I am proudest of the anti-scalping rule and the signed tax oracle. The oracle showed me how carefully off-chain information must be verified before a contract can trust it.
The bug hiding outside the code
One of the hardest parts was simply running and testing the blockchain locally. At one point, the contracts stopped behaving as expected. I spent hours reading the code before discovering that local chain state or cached artifacts needed to be reset.
It taught me that a contract can be correct while its deployment state or surrounding environment is out of sync. Debugging requires understanding the environment, not only the code inside it.
Storing everything on-chain would have been unnecessarily expensive and slow. We kept ticket ownership, capacity, pricing rules, and financial state on the blockchain. Descriptions, images, categories, and analytics stayed in PostgreSQL.
The blockchain handled the state that needed to be trusted, while the database handled information that needed to be flexible and affordable.
From curiosity to skepticism
Our main goal was to make the system work, so we did not explore blockchain security as deeply as a production platform would require. A real event would demand threat modelling, careful key management, and a much deeper review of contract vulnerabilities.
Making the happy path work is only the beginning. A production contract must remain safe when someone deliberately tries to break it.
I started this project because Solidity was new and interesting. I finished it with a more critical view of blockchain.
Blockchain offers transparent and enforceable ownership rules, but it also introduces cost, slower operations, complicated infrastructure, and additional security risk. The project taught me that blockchain must justify its cost through a problem that genuinely requires trust, verifiability, or decentralized ownership.
What stayed with me
- Blockchain has to earn its cost.
- Rules enforced by a contract are stronger than rules enforced by a button.
- Not everything valuable belongs on-chain.
Run it locally
Clone the source repository or download the project ZIP, then run these commands from the project folder.
Explore the complete project
Download the source, assets, and included documentation as a ZIP archive.
Environment
$ cp backend/.env.example backend/.env
$ cp frontend/.env.example frontend/.env
$ cp smart-contract/.env.example smart-contract/.env
Services
$ make up
$ make migrate
$ make seed
$ cd backend && bun run seed:users-events && cd ..
Frontend
$ cd frontend
$ bun install
$ bun run dev
# open http://localhost:3000
Seeing the seeded events
# Seeded events start as DRAFT and the public list only shows ACTIVE ones,
# so browse them without a wallet by publishing them directly:
$ docker compose exec postgres psql -U postgres -d ticketing_db -c "UPDATE events SET status='ACTIVE';"




