go
Technical notes on web development, DevOps, and AI integration.
9 articles
- 05:05backend
Bidang RBAC Enforcement: The Middleware Gate and IN Filters
Enforcing the bidang scope in Go: middleware at the gate, IN filters in repositories, and subtests that read like the security policy.
TL;DR: Middleware at the gate verifies the JWT and injects the bidang scope so handlers stay clean. Repositories then filter by allowed modules using sqlx In, while announcements handle NULL as global, and global routes require ALL access. Leaving the repository fail-open keeps public calls simple, and subtests ensure scoped admins only see their own data.
#go#mysql#security - 04:57backend
Two-Axis RBAC: Roles for Actions, Bidang for Data
Roles decide actions, bidang decides data. Notes from building a fail-closed scope resolver in Go: ModulesFor, ResolveBidang, and the NULL trap.
TL;DR: Roles handle actions while a bidang column scopes data by agency, avoiding a huge permission matrix. A helper maps bidang to modules, returns nil for unknowns to fail closed, and copies the ALL slice to prevent Go append bugs. Announcements use NULL for global posts with an IS NULL filter, and empty bidang maps to ALL for legacy JWT compatibility.
#go#mysql#security - 04:23backend
XLSX Export from Go, and the Binary Guess That Missed
openapi-fetch does have parseAs blob. The friction is binary-format typing and the DOM download flow.
TL;DR: I assumed openapi-fetch couldn't handle binary downloads, but checking the source showed it supports blobs just fine. The real hurdles were typing that masks blobs as strings and the manual DOM work to trigger downloads. On the backend, the Go export validates module filters and always returns a valid file via excelize, even when empty.
#go#excelize#openapi-fetch - 04:18testing
Unit Testing Whose Contents Are Not Just Unit Tests
One script per test tier: vet, integration against real MySQL, a smoke gate, up to Playwright E2E.
TL;DR: Scattered manual tests were often skipped, so they were consolidated into four strict scripts for backend, frontend, E2E and smoke. Backend handles Docker and runs integration tests serially on real MySQL, while smoke validates deployment endpoints and E2E wraps Playwright with retries. README now defines what to run when, so a passing backend script signals the shared team contract.
#testing#bash#go - 03:34backend
Move One Category, Watch the Tree Loop
A validation that only rejects self-parenting looks sufficient until a re-parent to your own descendant quietly forms a cycle in the category tree.
TL;DR: Moving A under B seemed fine but created a loop because B was already A's child. The old validation only blocked self-parenting, so the fix now walks up ancestors until it hits a root, a missing parent, or the original category. It uses the standard wrapped-error check and limits the walk to ten levels to handle legacy cycles safely.
#golang#mysql#backend - 03:24testing
The Category CRUD Was Done. The Tests Did Not Exist
Shipping nested categories with zero tests worked until the QA checklist asked for proof: the boot env is a contract, and constraint edges need a real MySQL.
TL;DR: Nested categories were live with no test coverage, and even the health check was broken since it missed required env vars. I patched the env setup and added three MySQL-backed integration tests for tricky deletes that mocks would hide. They run with the integration tag and -p 1 to avoid collisions on the shared test database.
#golang#testing#mysql - 12:57devops
40 Mbps in the Config, 5 Mbps on the Screen
A half-remembered Mbps-to-bytes formula left the 3proxy bandlim cap at 5 Mbps instead of 40. The manual said bits all along.
TL;DR: A 3proxy bandwidth cap configured at 40 Mbps actually limited traffic to 5 Mbps because bandlim expects bits per second, not bytes, so the fix was changing 5000000 to 40000000. The same commit trimmed a GoAccess dashboard to three panels, surfacing the URL table immediately. Lesson: verify unit conversions against the manpage.
#3proxy#bandwidth#networking - 12:39devops
I Deleted My Dashboard, Then Called It Back
I tore out my self-built GoAccess stack for 3proxy's built-in admin counters, then realized counters can't answer which URLs eat the bandwidth.
TL;DR: The author deleted a self-built GoAccess dashboard for 3proxy, replacing it with the built-in admin directive and secure-mode counters. That answered how much traffic, but not which URLs or hosts consumed it. GoAccess returned properly: stripped fractional timestamps, filtered ADMIN lines, and nginx proxying WebSocket with explicit upgrade headers and longer read timeouts.
#3proxy#goaccess#nginx - 03:04seo
9,200 Articles in the Sitemap, Google Only Indexes the Homepage
An audit of a news site with 9,200 articles in its sitemap and almost nothing indexed: crawl demand, internal linking, and the fixes that actually matter.
TL;DR: An audit of a news site with 9,200 articles in its sitemap found only about 44 that ever earned a Google impression, dropping to zero for the most recent publish months. Every technical check came back clean, so the problem is crawl demand: publishing volume far outpacing authority signals, plus an archive cut off from internal links. The fixes are editorial: lower the volume, build contextual links into old content, trim the news sitemap, and earn external validation.
#seo#google-search-console#crawl-budget