Skip to content

Deacode#4

Merged
afa7789 merged 5 commits into
mainfrom
deacode
May 8, 2026
Merged

Deacode#4
afa7789 merged 5 commits into
mainfrom
deacode

Conversation

@afa7789
Copy link
Copy Markdown
Owner

@afa7789 afa7789 commented May 8, 2026

Summary by CodeRabbit

  • New Features

    • Added a generic admin upload endpoint; blog admin now includes a prefix when uploading covers.
  • Bug Fixes / Changes

    • Email verification endpoint removed; password-reset flows are placeholders (do not change passwords).
  • Documentation

    • Added an improvements doc listing deferred work: rebuild verification/reset flows, DB cleanup recommendation, and test-coverage notes.
  • Chores

    • Added dead-code detection targets and updated ignore rules for local tool directories.

afa7789 added 3 commits May 7, 2026 20:28
- Makefile: deadcode/deadcode-backend/deadcode-frontend targets.
  Backend uses golangci-lint (already wired) + x/tools/deadcode for
  reachability from ./cmd entrypoints. Frontend uses knip + depcheck
  via bunx.
- lint-backend now finds golangci-lint at $(go env GOPATH)/bin
  when not in PATH.
- .gitignore: replace .dagrobin/db with .dagrobin/ to also cover
  backend/ and frontend/ subdir DBs; add .rtk/ for local rtk filters.
Backend (deadcode/reachability from ./cmd):
- pkg/logger: drop unused Logger.Debug method.
- pkg/middleware: drop RequireAnyFeature handler and its orphan tests
  (no production caller; tests were the only references).
- pkg/middleware: drop unused KeyByUserID rate-limit key fn.

Frontend (knip + depcheck):
- src/db/index.ts: remove unused Dexie/IndexedDB layer (leftover from
  the RAG removal); drop dexie dependency.
- src/services/featureFlags.ts: drop unused invalidateFeatureFlags
  and getFlags exports.
- package.json: remove unused @vueuse/core and @vue/test-utils.

Verified: rtk go build/vet/test ./... and frontend vue-tsc + vitest
all pass; make deadcode is clean on backend (frontend has 2 known
false-positives: env.d.ts referenced via tsconfig, @types/qrcode is
the types peer for qrcode).
Layer-2 sweep (deadcode + endpoint-vs-frontend reachability + schema
audit). All decisions logged in .claude/IMPROVEMENTS.md.

Removed (dead in practice):
- internal/testutil: MockWaitlistRepo struct + 4 methods (zero usage).
- internal/handlers/auth.go: VerifyEmail handler and its route in
  cmd/server/main.go. The handler read a verify:<token> Redis key
  that nothing in the project ever wrote (no email-sender), and
  registration auto-verifies. Half-built feature with no path to
  completion until SMTP integration lands. email_verified column
  retained for when it's rebuilt.
- internal/handlers/blog.go: AdminUploadCover (cover-specific upload
  that required the post to already exist; never called).

Fixed (live bug surfaced by the sweep):
- AdminBlog.vue uploadCover() was POSTing to /api/v1/admin/upload,
  which had no handler — cover uploads 404'd silently. Replaced
  AdminUploadCover with a generic AdminHandler.Upload that accepts a
  prefix form field (allowlisted) and returns {url}, matching the
  upload-before-create pattern the frontend uses. Frontend now sends
  prefix=covers.

Documented (deferred):
- .claude/IMPROVEMENTS.md captures the email-verification rebuild
  path, the ForgotPassword/ResetPassword placeholders that pretend
  success, the orphan health_checks table (migration 008 with no Go
  reader/writer), and the handler test-coverage gaps.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 778b2f16-2305-4dc9-a3a7-540630ecabfc

📥 Commits

Reviewing files that changed from the base of the PR and between f8178dd and c82cd6c.

📒 Files selected for processing (1)
  • backend/internal/handlers/admin.go

📝 Walkthrough

Walkthrough

This PR consolidates upload endpoints and removes dead code identified by a dead-code sweep. The main change replaces a blog-specific cover upload handler with a generic admin upload endpoint accepting an allowlisted prefix form field. Related cleanup removes email verification handlers, unused middleware/service methods, orphaned test doubles, and obsolete frontend dependencies.

Changes

Dead Code Removal & Upload Endpoint Consolidation

Layer / File(s) Summary
Deferred Improvements Documentation
.claude/IMPROVEMENTS.md
Tracks email verification removal (Redis token path had no email integration), password reset handlers as non-functional placeholders, cover upload consolidation into generic POST /api/v1/admin/upload with allowlisted prefix, orphaned health_checks table, and test coverage gaps.
Build Tooling & Repository Config
Makefile, .gitignore
Makefile adds deadcode, deadcode-backend (Go deadcode tool), and deadcode-frontend (knip, depcheck) targets; lint-backend updated to find golangci-lint in PATH or $GOPATH/bin. .gitignore ignores .dagrobin/ and .rtk/.
API Routing
backend/cmd/server/main.go
New admin route POST /api/v1/admin/upload wired to adminHandler.Upload under admin-auth/admin-role group; admin handler constructed with storageBackend.
Handler Implementation
backend/internal/handlers/admin.go
AdminHandler.storage added, constructor updated to accept storage, and AdminHandler.Upload added to handle multipart uploads with optional allowlisted prefix, delegating to UploadFormFile(...) and returning { "url": ... } or mapped errors.
Removed Handlers & Mocks
backend/internal/handlers/auth.go, backend/internal/handlers/blog.go, backend/internal/testutil/mocks.go, backend/pkg/logger/logger.go
Removed AuthHandler.VerifyEmail, removed BlogHandler.AdminUploadCover, deleted MockWaitlistRepo mock; logger Debug method removed while Info/Warn/Error + write logic remain. ResetPassword contains snapshot artifact lines.
Middleware & Service Updates
backend/pkg/middleware/feature_flags.go, backend/pkg/middleware/ratelimit.go, frontend/src/services/featureFlags.ts
Removed RequireAnyFeature middleware (single-key RequireFeature remains); removed KeyByUserID rate-limit preset, keep KeyByIP and KeyByEmail; frontend adds isFeatureEnabled(key) lookup.
Frontend Integration & Dependencies
frontend/package.json, frontend/src/db/index.ts, frontend/src/views/Admin/AdminBlog.vue
Removes @vueuse/core, dexie, and @vue/test-utils from package.json; Dexie DB snapshot present; AdminBlog.vue appends prefix: 'covers' to upload FormData to match generic admin upload endpoint.
Tests / Mocks Cleanup
backend/pkg/middleware/middleware_test.go, backend/internal/testutil/mocks.go
Removes TestRequireAnyFeature_* test cases in middleware tests; deletes MockWaitlistRepo from testutil mocks.

Sequence Diagram(s)

sequenceDiagram
  participant AdminUI
  participant Router
  participant AdminHandler
  participant Storage

  AdminUI->>Router: POST /api/v1/admin/upload (multipart: file + prefix)
  Router->>AdminHandler: Upload(ctx)
  AdminHandler->>Storage: UploadFormFile(ctx, file, prefix)
  Storage-->>AdminHandler: url / error
  AdminHandler-->>AdminUI: { "url": url } or 4xx/5xx
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hopped through code, I found and cleared,

old endpoints gone, new upload shared,
Prefix in paw, storage in tow,
A neater path for files to go. ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Deacode' appears to be a misspelling or incomplete reference to 'deadcode' work described in the PR, but is too vague to clearly convey the changeset's main purpose to a teammate. Revise the title to clearly describe the primary change, such as 'Add deadcode detection tooling and remove unused code' or 'Implement deadcode analysis and clean up dead endpoints'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deacode

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/views/Admin/AdminBlog.vue (1)

235-244: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

uploadCover silently swallows server-side errors — check r.ok before parsing.

fetch only rejects on network failures; HTTP 4xx/5xx responses still resolve. Without an r.ok guard, a rejected upload (e.g. auth failure, oversized file, invalid prefix) returns {"error":"..."}, data.url is undefined, form.value.cover_image is set to undefined, and the user sees no error message.

🐛 Proposed fix
-  ).then(r => r.json()) as { url: string }
-  form.value.cover_image = data.url
+  )
+  if (!r.ok) {
+    const errBody = await r.json().catch(() => ({})) as { error?: string }
+    throw new Error(errBody.error || `Upload failed (${r.status})`)
+  }
+  const data = await r.json() as { url: string }
+  form.value.cover_image = data.url
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/views/Admin/AdminBlog.vue` around lines 235 - 244, The
uploadCover implementation currently parses the response without checking HTTP
status, which can set form.value.cover_image to undefined on 4xx/5xx; update the
upload logic in the uploadCover handler to check the fetch Response.ok before
using the body: await fetch(...) -> const r = await fetch(...); const data =
await r.json(); if (!r.ok) { formError.value = data.error || `Upload failed:
${r.status} ${r.statusText}`; return; } form.value.cover_image = data.url; keep
the existing catch to handle network errors. Ensure you reference the
uploadCover handler and the variables form, formError, and cover_image when
applying this change.
🧹 Nitpick comments (3)
backend/cmd/server/main.go (1)

354-354: 💤 Low value

Move the /upload route out of the "Blog — admin routes" block.

adminHandler.Upload is the generic multi-prefix upload endpoint, not blog-specific. Placing it inside the blog comment block will confuse readers. Consider putting it in a dedicated "Admin — generic" section or directly before the blog routes block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/cmd/server/main.go` at line 354, The route admin.Post("/upload",
adminHandler.Upload) is incorrectly placed in the "Blog — admin routes" block;
move this generic upload endpoint out of that blog-specific section and place it
in a dedicated "Admin — generic" section (or immediately before the blog routes)
so readers see adminHandler.Upload as a global admin endpoint rather than
blog-specific.
backend/internal/handlers/admin.go (1)

54-61: 💤 Low value

Move allowed to a package-level variable.

The map literal is reallocated on every request. Declaring it once as a var at package level is idiomatic Go and avoids repeated allocation.

♻️ Proposed refactor
+var allowedUploadPrefixes = map[string]bool{
+	"uploads":   true,
+	"covers":    true,
+	"banners":   true,
+	"linktree":  true,
+	"brand-kit": true,
+	"products":  true,
+}
+
 func (h *AdminHandler) Upload(c *fiber.Ctx) error {
 	file, err := c.FormFile("file")
 	if err != nil {
 		return fiber.NewError(fiber.StatusBadRequest, "file is required")
 	}

 	prefix := c.FormValue("prefix", "uploads")
-	allowed := map[string]bool{
-		"uploads":   true,
-		"covers":    true,
-		"banners":   true,
-		"linktree":  true,
-		"brand-kit": true,
-		"products":  true,
-	}
-	if !allowed[prefix] {
+	if !allowedUploadPrefixes[prefix] {
 		return fiber.NewError(fiber.StatusBadRequest, "invalid prefix")
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/admin.go` around lines 54 - 61, Move the local
"allowed" map literal to a package-level variable to avoid reallocating it on
every request: declare a package-scope var like `var allowed = map[string]bool{
"uploads": true, "covers": true, "banners": true, "linktree": true, "brand-kit":
true, "products": true }` at the top of the file, then remove the local `allowed
:= map[string]bool{...}` in the handler and use the package-level `allowed` map
directly (refer to the existing usage of `allowed` in the handler where it is
currently defined).
Makefile (1)

134-134: 💤 Low value

Pin deadcode to a specific version instead of @latest.

go run golang.org/x/tools/cmd/deadcode@latest re-downloads and potentially upgrades the tool on every invocation. Different team members or CI runs could see different results across versions. Pin to a known-good release (e.g. @v0.44.0, the current stable version).

♻️ Proposed fix
-	cd backend && go run golang.org/x/tools/cmd/deadcode@latest ./cmd/...
+	cd backend && go run golang.org/x/tools/cmd/deadcode@v0.44.0 ./cmd/...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 134, Replace the use of the floating `@latest` version for
the deadcode tool in the Makefile command `go run
golang.org/x/tools/cmd/deadcode@latest ./cmd/...` with a pinned release (for
example `@v0.44.0`) so the tool invocation is deterministic across developers
and CI; update the `go run golang.org/x/tools/cmd/deadcode@latest` reference to
use the chosen semantic version tag.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/IMPROVEMENTS.md:
- Around line 36-48: AuthHandler.ResetPassword in auth.go currently returns a
successful response without changing any password; change the handler to stop
returning 200-success and instead return a clear 501 Not Implemented (or
equivalent error) response and log a descriptive message so the UI does not
falsely report success. Locate the ResetPassword method (and similarly
ForgotPassword if it currently no-ops) and replace the silent success path with
a short-circuit that returns the 501 response and an explanatory log entry;
leave the routes in place so UI links don’t break and add a TODO comment
referencing the future work: email-sender prerequisite, token storage, and
actual password update flow.

---

Outside diff comments:
In `@frontend/src/views/Admin/AdminBlog.vue`:
- Around line 235-244: The uploadCover implementation currently parses the
response without checking HTTP status, which can set form.value.cover_image to
undefined on 4xx/5xx; update the upload logic in the uploadCover handler to
check the fetch Response.ok before using the body: await fetch(...) -> const r =
await fetch(...); const data = await r.json(); if (!r.ok) { formError.value =
data.error || `Upload failed: ${r.status} ${r.statusText}`; return; }
form.value.cover_image = data.url; keep the existing catch to handle network
errors. Ensure you reference the uploadCover handler and the variables form,
formError, and cover_image when applying this change.

---

Nitpick comments:
In `@backend/cmd/server/main.go`:
- Line 354: The route admin.Post("/upload", adminHandler.Upload) is incorrectly
placed in the "Blog — admin routes" block; move this generic upload endpoint out
of that blog-specific section and place it in a dedicated "Admin — generic"
section (or immediately before the blog routes) so readers see
adminHandler.Upload as a global admin endpoint rather than blog-specific.

In `@backend/internal/handlers/admin.go`:
- Around line 54-61: Move the local "allowed" map literal to a package-level
variable to avoid reallocating it on every request: declare a package-scope var
like `var allowed = map[string]bool{ "uploads": true, "covers": true, "banners":
true, "linktree": true, "brand-kit": true, "products": true }` at the top of the
file, then remove the local `allowed := map[string]bool{...}` in the handler and
use the package-level `allowed` map directly (refer to the existing usage of
`allowed` in the handler where it is currently defined).

In `@Makefile`:
- Line 134: Replace the use of the floating `@latest` version for the deadcode
tool in the Makefile command `go run golang.org/x/tools/cmd/deadcode@latest
./cmd/...` with a pinned release (for example `@v0.44.0`) so the tool invocation
is deterministic across developers and CI; update the `go run
golang.org/x/tools/cmd/deadcode@latest` reference to use the chosen semantic
version tag.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15b416c1-e262-444e-b4e3-ff55b383a308

📥 Commits

Reviewing files that changed from the base of the PR and between ff9ceea and d643d67.

⛔ Files ignored due to path filters (1)
  • frontend/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • .claude/IMPROVEMENTS.md
  • .gitignore
  • Makefile
  • backend/cmd/server/main.go
  • backend/internal/handlers/admin.go
  • backend/internal/handlers/auth.go
  • backend/internal/handlers/blog.go
  • backend/internal/testutil/mocks.go
  • backend/pkg/logger/logger.go
  • backend/pkg/middleware/feature_flags.go
  • backend/pkg/middleware/middleware_test.go
  • backend/pkg/middleware/ratelimit.go
  • frontend/package.json
  • frontend/src/db/index.ts
  • frontend/src/services/featureFlags.ts
  • frontend/src/views/Admin/AdminBlog.vue
💤 Files with no reviewable changes (10)
  • backend/internal/handlers/blog.go
  • backend/pkg/middleware/feature_flags.go
  • frontend/src/services/featureFlags.ts
  • frontend/src/db/index.ts
  • backend/internal/testutil/mocks.go
  • backend/pkg/logger/logger.go
  • backend/pkg/middleware/ratelimit.go
  • backend/internal/handlers/auth.go
  • frontend/package.json
  • backend/pkg/middleware/middleware_test.go

Comment thread .claude/IMPROVEMENTS.md
Comment on lines +36 to +48
## Password reset — placeholder, kept

`AuthHandler.ResetPassword` (auth.go) returns success **without actually
resetting any password**. It's a security smell: the UI thinks the reset
worked, but the password is unchanged. `ForgotPassword` is also a no-op (good
fail-silent UX, but no email is sent).

Not removed because the routes/UI exist and removing them would visibly break
the "forgot password" link. Keep until a real reset flow is built.

**To fix:** same email-sender prerequisite as email verification, plus token
storage and password update in the handler.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

ResetPassword silently succeeds without changing the password — prioritize fixing this.

Leaving a route registered that reports success to the client while performing a no-op password change is a significant security UX defect: users who think they've changed their password haven't, and may be locked out or falsely confident their account is secured. This is more urgent than most of the other deferred items and shouldn't wait for the full email-sender implementation — a simple 501 / "not yet implemented" error response is safer than a false 200.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/IMPROVEMENTS.md around lines 36 - 48, AuthHandler.ResetPassword in
auth.go currently returns a successful response without changing any password;
change the handler to stop returning 200-success and instead return a clear 501
Not Implemented (or equivalent error) response and log a descriptive message so
the UI does not falsely report success. Locate the ResetPassword method (and
similarly ForgotPassword if it currently no-ops) and replace the silent success
path with a short-circuit that returns the 501 response and an explanatory log
entry; leave the routes in place so UI links don’t break and add a TODO comment
referencing the future work: email-sender prerequisite, token storage, and
actual password update flow.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Cannot run autofix: This PR has merge conflicts.

Please resolve the conflicts with the base branch and try again.

Alternatively, use @coderabbitai resolve merge conflict to automatically resolve the conflicts.

@afa7789
Copy link
Copy Markdown
Owner Author

afa7789 commented May 8, 2026

@copilot resolve the merge conflicts in this pull request

Co-authored-by: afa7789 <26887703+afa7789@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 8, 2026

@copilot resolve the merge conflicts in this pull request

Resolved and pushed in commit f8178dd. I merged main into this branch, fixed the conflict in backend/internal/handlers/blog.go, and aligned admin upload wiring so the backend builds and tests pass.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 127.0.0.11
    • Triggering command: REDACTED, pid is -1 (packet block)
  • backend
    • Triggering command: /bin/prometheus /bin/prometheus --config.file=/etc/prometheus/prometheus.yml --web.external-url=/prometheus/ --web.route-prefix=/prometheus/ -j DNAT --to-destination 127.0.0.11:37141 -p github.com/munne--wait t pkg/mod/golang.ofilter -qui�� 5c2cdbbc:backendDOCKER-ISOLATION-STAGE-2 t pkg/mod/golang.obr-a53b5c442c21 . -imultiarch t pkg/mod/golang.o--prefix=/net/ipv6/conf/veth6f1cb42 (dns block)
  • grafana.com
    • Triggering command: /usr/share/grafana/bin/grafana grafana server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker cfg:default.log.mode=console cfg:default.paths.data=/var/lib/grafana cfg:default.paths.logs=/var/log/grafana cfg:default.paths.plugins=/var/lib/grafana/plugins cfg:default.paths.provisioning=/etc/grafana/provisioning t pkg/mod/golang.org/toolchain@v0.-trimpath -I 5c2cdbbc:backend/internal/infras-p t k/_temp/ghcca-node/node/bin/bash-lang=go1.25 --gdwarf-5 --64 t /home/REDACTED/go/pkg/mod/golang.o-trimpath (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of afa7789 May 8, 2026 00:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/internal/handlers/admin.go (1)

33-45: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard against nil storage dependency before serving uploads

h.storage is required for Upload, but NewAdminHandler accepts it without validation. A nil dependency here can cause runtime failure on the upload path. Please fail fast in constructor (or short-circuit in Upload) when storage is nil.

Suggested fix
 func NewAdminHandler(
@@
 	storage domain.Storage,
 	cfg *config.Config,
 ) *AdminHandler {
+	if storage == nil {
+		panic("handlers.NewAdminHandler: storage dependency is nil")
+	}
 	return &AdminHandler{
@@
 	}
 }

Also applies to: 71-72

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/internal/handlers/admin.go` around lines 33 - 45, NewAdminHandler
must fail fast when the storage dependency is nil to avoid runtime panics in
Upload: update NewAdminHandler to validate the storage parameter (and other
required deps) and return an error (change signature to (*AdminHandler, error))
or explicitly panic with a clear message if storage == nil; additionally add a
defensive nil-check at the start of AdminHandler.Upload (check h.storage) to
return a clear error rather than dereferencing nil. Target the NewAdminHandler
constructor and the Upload method (references: NewAdminHandler, AdminHandler,
Upload, h.storage) and ensure any call sites are updated to handle the
constructor's error return.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/internal/handlers/admin.go`:
- Line 76: The log statement in admin.Upload currently logs the
client-controlled file.Filename raw, which risks log-forging and sensitive data
leakage; update the admin.Upload logging to avoid raw filenames by replacing
file.Filename with a sanitized or quoted representation (e.g., use a
quoting/sanitization helper or format specifier like %q) and/or omit the
filename entirely; locate the log.Printf call referencing prefix and
file.Filename and change it to use the sanitized variable (create a small
sanitizeFilename function if needed) before logging.

---

Outside diff comments:
In `@backend/internal/handlers/admin.go`:
- Around line 33-45: NewAdminHandler must fail fast when the storage dependency
is nil to avoid runtime panics in Upload: update NewAdminHandler to validate the
storage parameter (and other required deps) and return an error (change
signature to (*AdminHandler, error)) or explicitly panic with a clear message if
storage == nil; additionally add a defensive nil-check at the start of
AdminHandler.Upload (check h.storage) to return a clear error rather than
dereferencing nil. Target the NewAdminHandler constructor and the Upload method
(references: NewAdminHandler, AdminHandler, Upload, h.storage) and ensure any
call sites are updated to handle the constructor's error return.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7dfe3dc7-5788-4062-aa09-c4b5862d529c

📥 Commits

Reviewing files that changed from the base of the PR and between d643d67 and f8178dd.

📒 Files selected for processing (3)
  • backend/cmd/server/main.go
  • backend/internal/handlers/admin.go
  • backend/internal/handlers/blog.go
💤 Files with no reviewable changes (1)
  • backend/internal/handlers/blog.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/cmd/server/main.go

Comment thread backend/internal/handlers/admin.go Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 1 file(s) based on 1 unresolved review comment.

Files modified:

  • backend/internal/handlers/admin.go

Commit: c82cd6ce39b1ab16c33a03ddd607b03c7643fcd3

The changes have been pushed to the deacode branch.

Time taken: 2m 29s

Fixed 1 file(s) based on 1 unresolved review comment.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@afa7789 afa7789 merged commit b31ee38 into main May 8, 2026
1 of 2 checks passed
@afa7789 afa7789 deleted the deacode branch May 8, 2026 01:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants