Add implementation plan for env-var-controlled sign-up
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# 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, set `AllowSignup` on the `AuthHandler`.
|
||||
- Modify: `handler/auth.go` — replace count-based gating with the `AllowSignup` flag.
|
||||
- No changes to `store/store.go` (`UserCount` is left in place).
|
||||
- No changes to templates (the `HasUser` key drives the nav link already).
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add `AllowSignup` field and switch signup gating
|
||||
|
||||
**Files:**
|
||||
- Modify: `handler/auth.go`
|
||||
|
||||
- [ ] **Step 1: Add the `AllowSignup` field to `AuthHandler` and replace the count-based redirect**
|
||||
|
||||
Replace:
|
||||
|
||||
```go
|
||||
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:
|
||||
|
||||
```go
|
||||
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 an `allowSignup()` helper**
|
||||
|
||||
Replace:
|
||||
|
||||
```go
|
||||
func (h *AuthHandler) hasUsers() bool {
|
||||
count, err := h.Store.UserCount()
|
||||
return err == nil && count > 0
|
||||
}
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```go
|
||||
func (h *AuthHandler) allowSignup() bool {
|
||||
return h.AllowSignup
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update the three `HasUser` template renders to use `allowSignup()`**
|
||||
|
||||
Replace every occurrence of `"HasUser": h.hasUsers()` with `"HasUser": h.allowSignup()`. There are three (the initial GET render and the two error paths in the POST handler).
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
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 `strconv` to imports**
|
||||
|
||||
In `main.go`, add `"strconv"` to the import block (after `"os"`).
|
||||
|
||||
- [ ] **Step 2: Parse `PODSTALK_ALLOW_SIGNUP` and set it on the handler**
|
||||
|
||||
After the existing `baseURL` block, add:
|
||||
|
||||
```go
|
||||
allowSignup := false
|
||||
if v := os.Getenv("PODSTALK_ALLOW_SIGNUP"); v != "" {
|
||||
allowSignup = envBool(v)
|
||||
}
|
||||
```
|
||||
|
||||
Change the `authH` literal to include the flag:
|
||||
|
||||
```go
|
||||
authH := &handler.AuthHandler{Store: st, Sessions: sessions, Tpl: tpl, AllowSignup: allowSignup}
|
||||
```
|
||||
|
||||
At the bottom (near `envOrDefault`), add the `envBool` helper:
|
||||
|
||||
```go
|
||||
// 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**
|
||||
|
||||
```bash
|
||||
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**
|
||||
|
||||
```bash
|
||||
git status
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
**1. Spec coverage:**
|
||||
- Env var `PODSTALK_ALLOW_SIGNUP` parsed in `main.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 → `ParseBool` covers `1`/`true`, the switch covers `yes`/`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. ✓
|
||||
Reference in New Issue
Block a user