A dead-simple spot board for Instagram waffle drops. Built for collectors, by collectors.
Live Demo: [Coming Soon] | Latest Release: v0.1.11
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.16 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.
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.16 |
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.
|
Dani Boo Glass
|
Crysis Designs
|
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.
If this project helps you run smoother waffles, consider buying me a coffee:
MIT — do whatever you want, just don't blame me when your waffle fills up in 30 seconds.
Built with 🧇 and questionable sleep habits.







