felt/internal/blind/templates.go
Mikkel Georgsen dd2f9bbfd9 feat(01-03): implement PIN auth routes, JWT HS256 enforcement, and auth tests
- Add auth HTTP handlers (login, me, logout) with proper JSON responses
- Enforce HS256 via jwt.WithValidMethods to prevent algorithm confusion attacks
- Add context helpers for extracting operator ID and role from JWT claims
- Add comprehensive auth test suite (11 unit tests + 6 integration tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 03:59:05 +01:00

101 lines
8.9 KiB
Go

package blind
// BuiltinStructures returns the built-in blind structures that ship with the app.
// These are used by the seed migration to populate the database on first boot.
// TurboLevels returns the Turbo blind structure (~2hr for 20 players, 15-min levels).
func TurboLevels() []BlindLevel {
return []BlindLevel{
{Position: 0, LevelType: "round", GameType: "nlhe", SmallBlind: 25, BigBlind: 50, DurationSeconds: 900},
{Position: 1, LevelType: "round", GameType: "nlhe", SmallBlind: 50, BigBlind: 100, DurationSeconds: 900},
{Position: 2, LevelType: "round", GameType: "nlhe", SmallBlind: 75, BigBlind: 150, DurationSeconds: 900},
{Position: 3, LevelType: "round", GameType: "nlhe", SmallBlind: 100, BigBlind: 200, DurationSeconds: 900},
{Position: 4, LevelType: "break", GameType: "nlhe", DurationSeconds: 600},
{Position: 5, LevelType: "round", GameType: "nlhe", SmallBlind: 150, BigBlind: 300, Ante: 300, DurationSeconds: 900},
{Position: 6, LevelType: "round", GameType: "nlhe", SmallBlind: 200, BigBlind: 400, Ante: 400, DurationSeconds: 900},
{Position: 7, LevelType: "round", GameType: "nlhe", SmallBlind: 300, BigBlind: 600, Ante: 600, DurationSeconds: 900},
{Position: 8, LevelType: "round", GameType: "nlhe", SmallBlind: 400, BigBlind: 800, Ante: 800, DurationSeconds: 900},
{Position: 9, LevelType: "break", GameType: "nlhe", DurationSeconds: 600},
{Position: 10, LevelType: "round", GameType: "nlhe", SmallBlind: 600, BigBlind: 1200, Ante: 1200, DurationSeconds: 900},
{Position: 11, LevelType: "round", GameType: "nlhe", SmallBlind: 800, BigBlind: 1600, Ante: 1600, DurationSeconds: 900},
{Position: 12, LevelType: "round", GameType: "nlhe", SmallBlind: 1000, BigBlind: 2000, Ante: 2000, DurationSeconds: 900},
{Position: 13, LevelType: "round", GameType: "nlhe", SmallBlind: 1500, BigBlind: 3000, Ante: 3000, DurationSeconds: 900},
{Position: 14, LevelType: "round", GameType: "nlhe", SmallBlind: 2000, BigBlind: 4000, Ante: 4000, DurationSeconds: 900},
}
}
// StandardLevels returns the Standard blind structure (~3-4hr for 20 players, 20-min levels).
func StandardLevels() []BlindLevel {
return []BlindLevel{
{Position: 0, LevelType: "round", GameType: "nlhe", SmallBlind: 25, BigBlind: 50, DurationSeconds: 1200},
{Position: 1, LevelType: "round", GameType: "nlhe", SmallBlind: 50, BigBlind: 100, DurationSeconds: 1200},
{Position: 2, LevelType: "round", GameType: "nlhe", SmallBlind: 75, BigBlind: 150, DurationSeconds: 1200},
{Position: 3, LevelType: "round", GameType: "nlhe", SmallBlind: 100, BigBlind: 200, DurationSeconds: 1200},
{Position: 4, LevelType: "round", GameType: "nlhe", SmallBlind: 150, BigBlind: 300, DurationSeconds: 1200},
{Position: 5, LevelType: "break", GameType: "nlhe", DurationSeconds: 600},
{Position: 6, LevelType: "round", GameType: "nlhe", SmallBlind: 200, BigBlind: 400, Ante: 400, DurationSeconds: 1200},
{Position: 7, LevelType: "round", GameType: "nlhe", SmallBlind: 300, BigBlind: 600, Ante: 600, DurationSeconds: 1200},
{Position: 8, LevelType: "round", GameType: "nlhe", SmallBlind: 400, BigBlind: 800, Ante: 800, DurationSeconds: 1200},
{Position: 9, LevelType: "round", GameType: "nlhe", SmallBlind: 500, BigBlind: 1000, Ante: 1000, DurationSeconds: 1200},
{Position: 10, LevelType: "break", GameType: "nlhe", DurationSeconds: 600},
{Position: 11, LevelType: "round", GameType: "nlhe", SmallBlind: 600, BigBlind: 1200, Ante: 1200, DurationSeconds: 1200},
{Position: 12, LevelType: "round", GameType: "nlhe", SmallBlind: 800, BigBlind: 1600, Ante: 1600, DurationSeconds: 1200},
{Position: 13, LevelType: "round", GameType: "nlhe", SmallBlind: 1000, BigBlind: 2000, Ante: 2000, DurationSeconds: 1200},
{Position: 14, LevelType: "round", GameType: "nlhe", SmallBlind: 1500, BigBlind: 3000, Ante: 3000, DurationSeconds: 1200},
{Position: 15, LevelType: "round", GameType: "nlhe", SmallBlind: 2000, BigBlind: 4000, Ante: 4000, DurationSeconds: 1200},
{Position: 16, LevelType: "round", GameType: "nlhe", SmallBlind: 3000, BigBlind: 6000, Ante: 6000, DurationSeconds: 1200},
}
}
// DeepStackLevels returns the Deep Stack blind structure (~5-6hr for 20 players, 30-min levels).
func DeepStackLevels() []BlindLevel {
return []BlindLevel{
{Position: 0, LevelType: "round", GameType: "nlhe", SmallBlind: 25, BigBlind: 50, DurationSeconds: 1800},
{Position: 1, LevelType: "round", GameType: "nlhe", SmallBlind: 50, BigBlind: 100, DurationSeconds: 1800},
{Position: 2, LevelType: "round", GameType: "nlhe", SmallBlind: 75, BigBlind: 150, DurationSeconds: 1800},
{Position: 3, LevelType: "round", GameType: "nlhe", SmallBlind: 100, BigBlind: 200, DurationSeconds: 1800},
{Position: 4, LevelType: "round", GameType: "nlhe", SmallBlind: 150, BigBlind: 300, DurationSeconds: 1800},
{Position: 5, LevelType: "break", GameType: "nlhe", DurationSeconds: 900},
{Position: 6, LevelType: "round", GameType: "nlhe", SmallBlind: 200, BigBlind: 400, DurationSeconds: 1800},
{Position: 7, LevelType: "round", GameType: "nlhe", SmallBlind: 250, BigBlind: 500, Ante: 500, DurationSeconds: 1800},
{Position: 8, LevelType: "round", GameType: "nlhe", SmallBlind: 300, BigBlind: 600, Ante: 600, DurationSeconds: 1800},
{Position: 9, LevelType: "round", GameType: "nlhe", SmallBlind: 400, BigBlind: 800, Ante: 800, DurationSeconds: 1800},
{Position: 10, LevelType: "break", GameType: "nlhe", DurationSeconds: 900},
{Position: 11, LevelType: "round", GameType: "nlhe", SmallBlind: 500, BigBlind: 1000, Ante: 1000, DurationSeconds: 1800},
{Position: 12, LevelType: "round", GameType: "nlhe", SmallBlind: 600, BigBlind: 1200, Ante: 1200, DurationSeconds: 1800},
{Position: 13, LevelType: "round", GameType: "nlhe", SmallBlind: 800, BigBlind: 1600, Ante: 1600, DurationSeconds: 1800},
{Position: 14, LevelType: "round", GameType: "nlhe", SmallBlind: 1000, BigBlind: 2000, Ante: 2000, DurationSeconds: 1800},
{Position: 15, LevelType: "break", GameType: "nlhe", DurationSeconds: 900},
{Position: 16, LevelType: "round", GameType: "nlhe", SmallBlind: 1500, BigBlind: 3000, Ante: 3000, DurationSeconds: 1800},
{Position: 17, LevelType: "round", GameType: "nlhe", SmallBlind: 2000, BigBlind: 4000, Ante: 4000, DurationSeconds: 1800},
{Position: 18, LevelType: "round", GameType: "nlhe", SmallBlind: 3000, BigBlind: 6000, Ante: 6000, DurationSeconds: 1800},
{Position: 19, LevelType: "round", GameType: "nlhe", SmallBlind: 4000, BigBlind: 8000, Ante: 8000, DurationSeconds: 1800},
{Position: 20, LevelType: "round", GameType: "nlhe", SmallBlind: 5000, BigBlind: 10000, Ante: 10000, DurationSeconds: 1800},
}
}
// WSOPStyleLevels returns the WSOP-style blind structure (60-min levels, with antes from level 4, BB ante option).
func WSOPStyleLevels() []BlindLevel {
return []BlindLevel{
{Position: 0, LevelType: "round", GameType: "nlhe", SmallBlind: 25, BigBlind: 50, DurationSeconds: 3600},
{Position: 1, LevelType: "round", GameType: "nlhe", SmallBlind: 50, BigBlind: 100, DurationSeconds: 3600},
{Position: 2, LevelType: "round", GameType: "nlhe", SmallBlind: 75, BigBlind: 150, DurationSeconds: 3600},
{Position: 3, LevelType: "round", GameType: "nlhe", SmallBlind: 100, BigBlind: 200, BBAnte: 200, DurationSeconds: 3600},
{Position: 4, LevelType: "break", GameType: "nlhe", DurationSeconds: 1200},
{Position: 5, LevelType: "round", GameType: "nlhe", SmallBlind: 150, BigBlind: 300, BBAnte: 300, DurationSeconds: 3600},
{Position: 6, LevelType: "round", GameType: "nlhe", SmallBlind: 200, BigBlind: 400, BBAnte: 400, DurationSeconds: 3600},
{Position: 7, LevelType: "round", GameType: "nlhe", SmallBlind: 250, BigBlind: 500, BBAnte: 500, DurationSeconds: 3600},
{Position: 8, LevelType: "round", GameType: "nlhe", SmallBlind: 300, BigBlind: 600, BBAnte: 600, DurationSeconds: 3600},
{Position: 9, LevelType: "break", GameType: "nlhe", DurationSeconds: 1200},
{Position: 10, LevelType: "round", GameType: "nlhe", SmallBlind: 400, BigBlind: 800, BBAnte: 800, DurationSeconds: 3600},
{Position: 11, LevelType: "round", GameType: "nlhe", SmallBlind: 500, BigBlind: 1000, BBAnte: 1000, DurationSeconds: 3600},
{Position: 12, LevelType: "round", GameType: "nlhe", SmallBlind: 600, BigBlind: 1200, BBAnte: 1200, DurationSeconds: 3600},
{Position: 13, LevelType: "round", GameType: "nlhe", SmallBlind: 800, BigBlind: 1600, BBAnte: 1600, DurationSeconds: 3600},
{Position: 14, LevelType: "break", GameType: "nlhe", DurationSeconds: 1200},
{Position: 15, LevelType: "round", GameType: "nlhe", SmallBlind: 1000, BigBlind: 2000, BBAnte: 2000, DurationSeconds: 3600},
{Position: 16, LevelType: "round", GameType: "nlhe", SmallBlind: 1500, BigBlind: 3000, BBAnte: 3000, DurationSeconds: 3600},
{Position: 17, LevelType: "round", GameType: "nlhe", SmallBlind: 2000, BigBlind: 4000, BBAnte: 4000, DurationSeconds: 3600},
{Position: 18, LevelType: "round", GameType: "nlhe", SmallBlind: 2500, BigBlind: 5000, BBAnte: 5000, DurationSeconds: 3600},
{Position: 19, LevelType: "round", GameType: "nlhe", SmallBlind: 3000, BigBlind: 6000, BBAnte: 6000, DurationSeconds: 3600},
}
}