5.4 KiB
Env-Var-Controlled Sign-Up Implementation Plan
Goal: Gate sign-up and the sign-in "Sign Up" link on the PODSTALK_ALLOW_SIGNUP environment variable instead of the number of existing users.
Architecture: Add an AllowSignup bool field to the AuthHandler. main.go reads PODSTALK_ALLOW_SIGNUP and sets it on the handler. The signup handler and the sign-in page link both consult this boolean. store.UserCount() stays as a general utility but is no longer used by authentication.
Tech Stack: Go (net/http), strconv.ParseBool for env parsing.
File Structure
- Modify:
main.go— read env var, setAllowSignupon theAuthHandler. - Modify:
handler/auth.go— replace count-based gating with theAllowSignupflag. - No changes to
store/store.go(UserCountis left in place). - Modify:
template/signin.html— render the "Sign Up" nav link with{{if .AllowSignup}}.
Task 1: Add AllowSignup field and switch signup gating
Files:
-
Modify:
handler/auth.go -
Step 1: Add the
AllowSignupfield toAuthHandlerand replace the count-based redirect
Replace:
type AuthHandler struct {
Store *store.Store
Sessions *SessionStore
Tpl *Templates
}
func (h *AuthHandler) ServeSignup(w http.ResponseWriter, r *http.Request) {
count, err := h.Store.UserCount()
if err == nil && count > 0 {
http.Redirect(w, r, "/signin", http.StatusSeeOther)
return
}
with:
type AuthHandler struct {
Store *store.Store
Sessions *SessionStore
Tpl *Templates
AllowSignup bool
}
func (h *AuthHandler) ServeSignup(w http.ResponseWriter, r *http.Request) {
if !h.AllowSignup {
http.Redirect(w, r, "/signin", http.StatusSeeOther)
return
}
- Step 2: Replace the
hasUsers()helper with anallowSignup()helper
Replace:
func (h *AuthHandler) hasUsers() bool {
count, err := h.Store.UserCount()
return err == nil && count > 0
}
with:
func (h *AuthHandler) allowSignup() bool {
return h.AllowSignup
}
- Step 3: Update the three
AllowSignuptemplate renders to useallowSignup()
Replace every occurrence of "AllowSignup": h.allowSignup() where it was passed as the HasUser key. In the three render calls in the sign-in handler, ensure the map key is AllowSignup:
map[string]any{"AllowSignup": h.allowSignup()}
map[string]any{"Error": "Invalid email or password.", "AllowSignup": h.allowSignup()}
map[string]any{"Error": "Invalid email or password.", "AllowSignup": h.allowSignup()}
- Step 3b: Update the sign-in template to use
AllowSignupwithout inversion
In template/signin.html, the nav-link conditional must render the link when sign-up is allowed. Replace {{if not .HasUser}} with {{if .AllowSignup}}. (Retain the {{end}}.)
- Step 4: Commit
git add handler/auth.go
git commit -m "Gate sign-up on AllowSignup field instead of user count"
Task 2: Read the env var in main.go and wire it up
Files:
-
Modify:
main.go -
Step 1: Add
strconvto imports
In main.go, add "strconv" to the import block (after "os").
- Step 2: Parse
PODSTALK_ALLOW_SIGNUPand set it on the handler
After the existing baseURL block, add:
allowSignup := false
if v := os.Getenv("PODSTALK_ALLOW_SIGNUP"); v != "" {
allowSignup = envBool(v)
}
Change the authH literal to include the flag:
authH := &handler.AuthHandler{Store: st, Sessions: sessions, Tpl: tpl, AllowSignup: allowSignup}
At the bottom (near envOrDefault), add the envBool helper:
// envBool interprets a string as a truthy boolean.
func envBool(v string) bool {
if b, err := strconv.ParseBool(v); err == nil {
return b
}
switch strings.ToLower(strings.TrimSpace(v)) {
case "yes", "on":
return true
}
return false
}
Add "strings" to the imports if not already present (it is not present in main.go; add it).
- Step 3: Commit
git add main.go
git commit -m "Read PODSTALK_ALLOW_SIGNUP env var to control sign-up"
Task 3: Verify
- Step 1: Run the build script per AGENTS.md
Run: ./scripts/build
Expected: PASS (gofmt, go vet, go build, docker build all succeed).
- Step 2: Manual sanity check (sandbox permitting)
Run: PODSTALK_ALLOW_SIGNUP=true go run . & then curl -s -o /dev/null -w "%{http_code}\n" -X GET localhost:8080/signup → expect a 200 render.
Run: PODSTALK_ALLOW_SIGNUP=false go run . & then curl -s -o /dev/null -w "%{http_code}\n" -X GET localhost:8080/signup → expect 303 redirect to /signin.
- Step 3: Final commit (if the build produced no fixes) and push
git status
git push
Self-Review
1. Spec coverage:
- Env var
PODSTALK_ALLOW_SIGNUPparsed inmain.go→ Task 2 Step 2. ✓ - Default (unset) = disabled → Task 2 Step 2 (
allowSignup := false, only overridden when set non-empty). ✓ - Truthy values (
true,1,yes,on) enabled →ParseBoolcovers1/true, the switch coversyes/on. ✓ - Signup handler redirects when disabled → Task 1 Step 1. ✓
- Sign-in "Sign Up" link driven by same flag → Task 1 Steps 2–3 (
HasUser). ✓ store.UserCount()unchanged → noted in File Structure. ✓
2. Placeholder scan: No TBD/TODO; every task has concrete code. ✓
3. Type consistency: AllowSignup field, allowSignup() method, and envBool helper are named consistently throughout. ✓