HTTP backend for a competition track rent reservation system with:
- Passwordless login (OTP + magic link via email sender)
- SMTP email delivery with embedded templates (no external template files needed at runtime)
- Configurable allowed email domains
- VIP users with earlier reservation window and per-item VIP hourly pricing (total fee = hourly price × duration_hours)
- Reservation model:
start_time(Unix timestamp seconds, must be full hour) +duration_hours(whole hours) - Team-based reservation: user selects
team_idon first reservation - Non-VIP users: max 2 reservation hours per team per day (summed)
- Configurable timezone and weekly availability window (e.g. Mon-Fri 09-21, Sat/Sun 10-20)
- QR-payment flow with user-submitted identification code
awaiting_paymentreservations auto-cancel after 5 minutes- Admin payment verification and admin-editable runtime config
- Configurable DB backend (
sqliteimplemented,d1stubbed) - All API time values use Unix timestamps (seconds)
- Go 1.26+
modernc.org/sqlite(pure Go SQLite)net/httpstandard library router
- API reference for frontend developers:
docs/FRONTEND_API.md
- Configure CORS via environment variables:
CORS_ALLOWED_ORIGINS(comma-separated origins, e.g.http://localhost:3000)CORS_ALLOWED_METHODS(comma-separated methods)CORS_ALLOWED_HEADERS(comma-separated request headers)CORS_ALLOW_CREDENTIALS(true/false)CORS_MAX_AGE_SECONDS(preflight cache duration)
- For local dev with Vite/React, set
CORS_ALLOWED_ORIGINSto your frontend URL.
- Magic-link emails can point to frontend routes instead of backend routes.
- Configure with:
FRONTEND_BASE_URL(for examplehttp://localhost:5173)MAGIC_LINK_FRONTEND_PATH(for example/verify-link)
- Backend verification endpoint remains
GET /auth/verify-linkand is typically called by frontend after reading the token from URL.
- Copy
.env.examplevalues to your environment.
- The server auto-loads
.envand.env.localat startup.
- Configure SMTP (
SMTP_HOST,SMTP_FROM_EMAIL, and optionally auth fields) to send real email.
- If SMTP is not configured, the service falls back to log sender (credentials are logged for dev/testing).
- Start server:
go run ./cmd/server- Health check:
curl http://localhost:8080/health- Request login credential:
curl -X POST http://localhost:8080/auth/request \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","method":"otp"}'or magic link:
curl -X POST http://localhost:8080/auth/request \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","method":"magic_link"}'- Verify OTP:
curl -X POST http://localhost:8080/auth/verify-otp \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","code":"123456"}'or verify magic link token:
curl "http://localhost:8080/auth/verify-link?token=<token>"-
Use
session_tokenas bearer token. -
Optional: set contact email (OTP/magic-link delivery target):
curl -X PUT http://localhost:8080/me/contact-email \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{"contact_email":"notify@example.org"}'Notes:
- If contact email is set, OTP/magic-link will be sent to contact email instead of account email.
Get teams for selection:
curl -X GET http://localhost:8080/teams \
-H "Authorization: Bearer <session_token>"Get rentable items:
curl -X GET http://localhost:8080/items \
-H "Authorization: Bearer <session_token>"Get occupied slots (active reservations):
curl -X GET http://localhost:8080/reservations/occupied \
-H "Authorization: Bearer <session_token>"Get configured weekly availability and timezone:
curl -X GET http://localhost:8080/reservations/availability \
-H "Authorization: Bearer <session_token>"Create reservation:
curl -X POST http://localhost:8080/reservations \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{"item_id":1,"start_time":1774058400,"duration_hours":2,"team_id":1}'Admin list items:
curl -X GET http://localhost:8080/admin/items \
-H "Authorization: Bearer <admin_session_token>"Admin create item:
curl -X POST http://localhost:8080/admin/items \
-H "Authorization: Bearer <admin_session_token>" \
-H "Content-Type: application/json" \
-d '{"name":"Camera A","image_url":"https://cdn.example.com/camera-a.jpg","normal_price_cents":15000,"vip_price_cents":12000,"slot_capacity":2,"is_active":true}'Admin update item:
curl -X PUT http://localhost:8080/admin/items/1 \
-H "Authorization: Bearer <admin_session_token>" \
-H "Content-Type: application/json" \
-d '{"name":"Camera A+","image_url":"https://cdn.example.com/camera-a-plus.jpg","normal_price_cents":16000,"vip_price_cents":13000,"slot_capacity":2,"is_active":true}'Admin delete item:
curl -X DELETE http://localhost:8080/admin/items/1 \
-H "Authorization: Bearer <admin_session_token>"Get payment info (QR + identification code):
curl -X GET http://localhost:8080/reservations/<reservation_id>/payment-info \
-H "Authorization: Bearer <session_token>"Mark payment done (moves to pending_verification):
curl -X POST http://localhost:8080/reservations/<reservation_id>/payment-done \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{"identification_code":"<generated_code>"}'List config:
curl -X GET http://localhost:8080/admin/config \
-H "Authorization: Bearer <admin_session_token>"Update config key:
curl -X PUT http://localhost:8080/admin/config/reservation.vip_lead_hours \
-H "Authorization: Bearer <admin_session_token>" \
-H "Content-Type: application/json" \
-d '{"value":"72"}'Set user VIP:
curl -X PUT http://localhost:8080/admin/users/2/vip \
-H "Authorization: Bearer <admin_session_token>" \
-H "Content-Type: application/json" \
-d '{"vip":true}'Verify payment:
curl -X POST http://localhost:8080/admin/reservations/res_xxx/verify \
-H "Authorization: Bearer <admin_session_token>" \
-H "Content-Type: application/json" \
-d '{"approved":true,"note":"Matched incoming transfer"}'- Table
teamsis created by migration. - Teams are currently edited manually by admin (DB-level operation, no edit API yet).
- Frontend can fetch active teams via
GET /teams.
auth.allowed_domains(comma-separated)reservation.normal_lead_hoursreservation.vip_lead_hoursreservation.timezonereservation.weekly_availability_json(JSON by weekday withstart_hourandend_hour)payment.qr_by_price_json(JSON map: price -> QR payload)auth.otp_ttl_minutesauth.magic_link_ttl_minutesauth.session_ttl_hours
- Templates are embedded at build time via Go
embedininternal/email/templates/*.tmpl. - Current templates:
- OTP subject/body
- Magic-link subject/body
- This means the built executable includes the templates and does not require template files deployed beside the binary.
DB_BACKEND=sqlite: fully implemented.DB_BACKEND=d1: interface-compatible stub currently returnsnot implementedfor storage operations.