CardCore
Back to Blog

Building CardCore - March 30, 2026 - Square Terminal Goes Live, Tournament Check-In Ships, and Our First Team Meeting

March 30, 20267 min readBy Dan Vohasek
building-in-publicstar-wars-unlimitedpaymentssquare-terminaltournamentcheck-inteamconvention

We took our first credit card payment today

Not a test transaction. Not a sandbox simulation. A real credit card, tapped on a real Square Terminal, charging a real 65 cents for a real card order. The terminal lit up, the customer tapped, and the payment went through. Then CardCore's webhook picked it up and the order page updated automatically - card brand, last four digits, receipt link, everything.

Getting here was a journey. Setting up the Square Developer account, configuring sandbox credentials, encrypting OAuth tokens with AES-256-GCM, pairing the physical terminal - each step had its own set of surprises. The sandbox OAuth page rendered blank because you don't actually need the OAuth flow for sandbox testing (Square gives you a pre-authorized token). The terminal pairing created a device code but our app wasn't polling for completion. The "Send to Terminal" button was invisible because it was reading the enabled flag from the wrong database table.

One by one, each issue got solved. By the end of the day, the full flow works end to end: staff opens an order, clicks "Send to Terminal", selects the paired device, the physical terminal prompts the customer, they tap their card, Square sends a webhook, and CardCore updates the order automatically. Cash, card, Venmo, CashApp - we take it all now.

Card processing fees - fully transparent

Square charges 2.6% plus 10 cents per tap. Rather than absorb that cost or hide it in higher prices, we built a transparent fee surcharge system. When a staff member sends a payment to the terminal, the fee is calculated and shown as a separate line item before the charge goes through.

The customer sees it on the checkout page too. If they select "Pay in Person", a small note appears: "Card payments include a 2.6% + $0.10 processing fee charged by the payment processor." No surprises. No hidden markup. The fee is configurable in store settings - the owner can adjust it or turn it off entirely. And every penny is tracked in the audit trail and the Discord notification.

This is how payment transparency should work. The store isn't the bad guy - the card processor charges a fee, and we show it honestly.

Tournament check-in - built for April 12

Thirteen days until the TCF Gaming Arena Planetary Qualifier. We need a check-in system that handles 50+ players scanning QR codes, signing up, and paying entry fees - fast and without confusion. Today we built it.

Here's how it works: table tents at the venue have QR codes. A player scans one and lands on a premium check-in page at store.cardcore.gg/checkin/14. If they don't have a CardCore account, they sign in with Discord (takes 10 seconds - no account creation needed). Then they enter their first name, last name, and optionally their melee.gg username. Hit "Check Me In" and they get a check-in number.

Up at the counter, staff has a tablet running the dashboard. Every checked-in player appears in a live list with their Discord name, real name, melee handle, and a red "Unpaid" badge. Staff calls them up in order, takes payment (cash, card, Venmo, whatever), and marks them paid. The badge turns green. Simple.

The identity matching was the hardest design problem. A player's melee.gg name might be "DarthTrader" but their Discord is "vonmonkey". The tournament organizer needs to know who paid and match that to the melee.gg bracket. Our solution: three identity layers. Discord username (automatic from login), real first and last name (required), and melee.gg handle (optional but encouraged). The staff dashboard shows all three side by side. Yellow dot means the melee handle is missing. Green dot means everything's linked up. Staff can edit any field, flag a player for review, and add notes. The whole thing exports to CSV so the TO can reconcile against the melee bracket.

We also built a full audit trail - every check-in, every payment status change, every identity edit gets logged with who did it and when.

The visual polish pass

The first version of the check-in page worked, but it looked like an internal tool. Functional. Gray. Not the experience you want when a player is standing at your table deciding whether to trust this QR code.

So we did a visual overhaul. The page now has ambient amber glow, gradient text on the event name, a "CHECK-IN OPEN" badge with a pulse animation, structured event metadata cards, a three-step explainer, and premium dark styling that matches the CardCore brand. The success screen has a dramatic bloom effect behind the checkmark and a big, bold check-in number. It feels like an event, not a form.

Small detail that matters: the Discord sign-in button says "We only use Discord to verify your identity. No messages will be sent." and "First time? No account needed - just sign in and go." Trust copy. At a convention, players are hesitant to sign into things. These two lines lower the barrier.

We broke the site (and fixed it in 20 minutes)

Transparency moment. During the tournament check-in deploy, the site went completely down. All four PM2 instances entered a crash loop - 172 restarts.

The root cause: Next.js requires consistent dynamic route segment names at the same path level. The existing event API routes used [id] but the new check-in routes used [eventId]. Next.js refuses to start when it sees both. The build passed. TypeScript passed. The error only surfaces at runtime.

Fixed it by renaming the routes to match the existing convention. Wrote a postmortem. Added a health check to the deploy process so we always verify the site returns 200 after every reload. The system can never be down - lesson learned and documented.

First team meeting - 5 people

This is the one I'm most excited about. We held our first CardCore team meeting today. Five people in the room talking about the platform, the convention strategy, the April 12 PQ, and what's coming next.

CardCore started as a solo project - one developer, one idea, built in public from day one. Today it has a team. People who believe in what we're building and want to be part of it. That's a milestone that no amount of code can replicate.

What shipped today

Looking at the Plane board, here's everything that moved to testing today:

  • COREAPP-812: Square Terminal integration - sandbox, production pairing, webhook
  • COREAPP-813: Card processing fee surcharge system
  • COREAPP-814: Tournament check-in with identity reconciliation and payment tracking
  • COREAPP-815: Premium visual polish for check-in pages
  • COREAPP-816: Fix - Square Terminal button reading enabled flag from wrong table
  • COREAPP-817: Fix - Send to Terminal button restricted to pay-in-person only

Six tickets. Two migrations. Ten new files. Three new pages. One physical terminal paired. One real payment processed. One team assembled.

What's next

Twelve days until the PQ. The check-in system needs real-world testing with multiple concurrent users. The staff dashboard needs to be battle-tested on a tablet. The Square Terminal needs to handle a queue of 50 players paying one after another without dropping a beat. And the team needs to rehearse the event-day workflow.

The code is deployed. The terminal is paired. The QR codes are ready to print. Now we drill.


First real card payment. First tournament check-in system. First team meeting. March 30 was a day of firsts.