A dead-simple spot board for Instagram waffle drops. Built for collectors, by collectors.
Live Demo: [Coming Soon] | Latest Release: v0.1.20
Project Syrup is a mobile-first live spot management system for Instagram waffle sellers. No timers. No randomizers. No payment processing. Just a clean, real-time board where buyers claim spots and admins track payments.
Built to work inside Instagram's in-app browser because that's where your buyers already are.
- Admin creates a waffle — sets title, price per spot, total spots, links to Instagram posts showing what's being waffled
- Buyers claim spots — tap available spots, enter Instagram handle, done (< 10 seconds)
- Admin marks paid — as payments come in via DM/CashApp/Venmo
- Winner drawn — admin enters winning spot number after external drawing
- Everyone sees results — instant WebSocket broadcast to all connected clients
| Screenshot | Screenshot |
|---|---|
Public Home![]() |
Admin Login![]() |
Admin Dashboard![]() |
Waffle Management![]() |
Admin Management![]() |
Reports![]() |
About Page![]() |
- Multi-admin auth — Role-based access control with
super_admin,admin, andwaffle_managerroles - Admin management — Create admins, change roles, deactivate accounts, and reset another admin's password (super_admin only)
- waffle_manager role — Create and manage waffles + view reports, without archive/delete/user-management access
- Timezone settings — Per-admin timezone preference with IANA timezone dropdown in settings page
- Password reset — Self-service reset tokens plus authenticated password changes
- Instagram media links — Link to posts showing what's being waffled (supports multiple items)
- Archive + delete controls — Hide completed waffles by default, or type
DELETEfor permanent removal - Real-time spot grid — WebSocket-powered claim, payment, release, and winner updates
- Mobile-first public flow — Built for fast spot claims inside Instagram's in-app browser
- Installable app shell — Web App Manifest, app icons, and standalone display metadata are wired in
- Admin dashboard — Create waffles, manage spots, track payments, enter winners
- Admin reports — Drought list, power buyers, monthly activity, and spot velocity reports
- Buyer stats — Track win/loss history per Instagram handle
- Activity history — Record claim, payment, release, and winner events per waffle
- CSV exports — Download a waffle's spot list for external reconciliation
- Transactional safety — No double-claims, ever
- Light/dark mode — Manual theme toggle with persisted preference
- Dual clock footer — Server UTC time + local browser time with waffle counter
- Winner management — Admin-only clear/change winner with buyer stats recalculation
- Login history — Audit trail with async WHOIS IP enrichment (org, country, city, ASN)
- Settings dropdown — Consolidated admin menu under username (Settings, History, About, Theme, Logout)
- About page — Public about page with admin-only system extras
- Configurable WHOIS — Super_admin can configure WHOIS server for IP lookups
- Admin audit log — Admin and super_admin users can review audited state changes with filters and pagination
- Security hardening — Structured logging, health/readiness probes, secure cookies, login lockout, password policy, and destructive action password confirmation
Prerequisites: Docker and Docker Compose.
# Clone the repo
git clone https://github.com/notfixingit3/waffle.git
cd waffle
# Start everything
docker compose up --buildDocker Compose starts both the Go app and PostgreSQL, runs database migrations, and injects safe local-development defaults for the database connection, JWT secret, and admin credentials. You do not need to create a .env file to run the app locally.
After startup, open the app and admin tools here:
| Service | URL |
|---|---|
| Application | http://localhost:8383 |
| Admin Login | http://localhost:8383/admin/login |
| PostgreSQL | localhost:5432 |
Default local admin credentials are admin / syrup. Change them before any real deployment.
Prerequisites: Docker and Docker Compose v2+.
- Copy
docker-compose.prod.ymlto your server - Create a
.envfile (see.env.examplefor reference):WAFFLE_VERSION=v0.1.20 DATABASE_URL=postgres://user:password@postgres:5432/syrup?sslmode=disable JWT_SECRET=your-secure-random-secret-here ADMIN_PASSWORD=your-secure-admin-password - Start the services:
docker compose -f docker-compose.prod.yml up -d
- Open
/admin/loginand change the default admin password immediately
Pre-built images are available at ghcr.io/notfixingit3/waffle for linux/amd64 and linux/arm64.
Beginning in v0.1.19, database migrations are embedded directly in the Go application binary.
If you are upgrading an existing deployment from a version prior to v0.1.19:
- Update
docker-compose.prod.yml: The volume mount for migrations (- ./backend/migrations:/app/migrations:ro) has been removed and is no longer needed. You can safely delete it from your local compose file. - Clean up files (Optional): You no longer need to copy the
backend/migrations/directory to your server. Any existingmigrations/directory on your server can be safely deleted. - Pull and redeploy:
docker compose -f docker-compose.prod.yml pull docker compose -f docker-compose.prod.yml up -d
The following channels are available for the Docker image:
| Channel | Tag | Description |
|---|---|---|
| Stable | latest |
Tracks the latest stable release from the main branch. Recommended for production. |
| Dev | dev |
Tracks the latest build from the dev branch. For testing and staging only. May be unstable. |
| Pinned | v0.1.20 |
A specific stable version. Recommended for reproducible deployments. |
The stable channel is currently in production testing. Pin to specific versions for critical deployments.
| Layer | Technology |
|---|---|
| Frontend | Go server-side templates + Tailwind CSS + DaisyUI |
| Backend | Go (Gin), WebSocket hub |
| Database | PostgreSQL with migrations |
| DevOps | Docker Compose, multi-stage builds |
| PWA | Web App Manifest, app icons, standalone display metadata |
| Phase | Status | Description |
|---|---|---|
| 1 | ✅ Complete | Docker Compose + Postgres + Go health check + server-rendered UI |
| 2 | ✅ Complete | Waffle schema + create endpoint + public page + spot grid + Instagram media links |
| 3 | ✅ Complete | Spot claims + pending status + admin dashboard + mark paid/release + archive + delete |
| 4 | ✅ Complete | WebSocket live updates + activity feed + buyer stats + admin reporting |
| 5 | ✅ Complete | Manual winner entry + winner/loser marking + buyer stats + history |
| 6 | ✅ Complete | Mobile polish + production Dockerfiles + deployment docs |
| 7 | ✅ Complete | Multi-admin auth + role-based access + password reset + admin management + archive/delete |
| 8 | ✅ Complete | Offline/service worker support with installable app shell, offline page caching, and update notifications |
| 9 | ✅ Complete | DaisyUI migration (Halloween/syrup theme + amber primary) |
| 10 | ✅ Complete | Production hardening (structured logging, health probes, graceful shutdown, rate limiting, Docker hardening) |
| 11 | ✅ Complete | Admin audit/security polish (audit log, password policy, lockout, destructive confirmations) |
| 12 | ✅ Complete | Bugfix/polish release (archived filters, buyer stats recalculation, password reset response, accessibility polish) |
┌──────────────────┐ ┌─────────────┐
│ Go (Gin) │────▶│ PostgreSQL │
│ Server Templates │◄────│ (pgx) │
│ + WebSocket Hub │ └─────────────┘
└──────────────────┘
│
▼
Tailwind CSS
(server-rendered)
Design principles:
- Keep it simple and boring
- No microservices
- WebSocket server stays inside Go backend
- Avoid premature abstractions
- Readable names over clever ones
Public Endpoints
GET /api/waffles— List public wafflesGET /api/waffles/:slug— Get waffle detailsGET /api/waffles/:slug/spots— Get spot gridGET /api/waffles/:slug/export— Export spots as CSVPOST /api/claims— Claim spotsGET /api/buyers/:handle/stats— Buyer win/loss statsGET /api/buyers/:handle/history— Buyer claim history
Public Pages
GET /— Home pageGET /waffles— Waffle listGET /waffle/:slug— Waffle detail + live spot gridGET /buyer/:handle— Buyer stats page
Admin Auth Endpoints
POST /api/admin/login— Username/password loginPOST /api/admin/forgot-password— Request password resetPOST /api/admin/reset-password— Reset password with token
Admin Endpoints (auth required)
GET /api/admin/me— Get current admin infoPATCH /api/admin/me/timezone— Update timezone preferencePOST /api/admin/change-password— Change passwordGET /api/admin/waffles?archived=true|false— List wafflesPOST /api/admin/waffles— Create wafflePATCH /api/admin/waffles/:id— Update wafflePOST /api/admin/waffles/:id/archive— Archive wafflePOST /api/admin/waffles/:id/unarchive— Unarchive waffleDELETE /api/admin/waffles/:id— Permanently delete wafflePOST /api/admin/spots/:id/pay— Mark spot paidPOST /api/admin/spots/:id/release— Release pending spotPOST /api/admin/waffles/:id/winner— Enter winnerGET /api/admin/admins— List all admins (super_admin only)POST /api/admin/admins— Create new admin (super_admin only)PATCH /api/admin/admins/:id— Update admin role (super_admin only)PATCH /api/admin/admins/:id/password— Reset another admin's password (super_admin only)DELETE /api/admin/admins/:id— Deactivate admin (super_admin only)GET /api/admin/reports/drought— Drought list reportGET /api/admin/reports/power-buyers— Power buyers reportGET /api/admin/reports/monthly-activity— Monthly activity reportGET /api/admin/reports/spot-velocity— Spot velocity report
This is a personal project, but issues and PRs are welcome. The codebase prioritizes:
- Correctness — Server-side validation for every state change
- Performance — Sub-10-second claim flow on mobile
- Simplicity — No over-engineering, clear service boundaries
Project Syrup exists because two glass artists kept running great waffles the hard way.
|
|
Special shout out to Dani Boo Glass and Crysis Designs for creating the original Waffle and for driving me nuts watching them copy/paste spot lists over and over again in chat.
Project Syrup is built out of passion for the glass art community. If this app helps you run smoother waffles or more exciting races, here is how you can support the project:
|
Sponsor Tom's next Wubble, Jelli, or Pocket Monstor. |
Help cover hosting costs and directly support the development of this application. |
Project Syrup utilizes several excellent open-source third-party libraries:
- Gin — MIT License
- Gin CORS middleware — MIT License
- Golang JWT — MIT License
- Golang Migrate — MIT License
- Google UUID — BSD 3-Clause License
- Gorilla WebSocket — BSD 2-Clause License
- pgx (PostgreSQL Driver) — MIT License
- Go Crypto Subrepository — BSD 3-Clause License
- Go Rate Limit Subrepository — BSD 3-Clause License
- Tailwind CSS — MIT License
- DaisyUI — MIT License
- Inter Font — SIL Open Font License 1.1
MIT — do whatever you want, just don't blame me when your waffle fills up in 30 seconds.
Built with 🧇 and questionable sleep habits.







