From cbf699251d75b0879e3041caf06d34dec535bd09 Mon Sep 17 00:00:00 2001 From: Yanislav Igonin Date: Thu, 16 Jul 2026 15:36:02 +0400 Subject: [PATCH] docs: design Fiber v3 migration --- ...-07-16-wave-2-fiber-v3-migration-design.md | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-16-wave-2-fiber-v3-migration-design.md diff --git a/docs/superpowers/specs/2026-07-16-wave-2-fiber-v3-migration-design.md b/docs/superpowers/specs/2026-07-16-wave-2-fiber-v3-migration-design.md new file mode 100644 index 0000000..9daaded --- /dev/null +++ b/docs/superpowers/specs/2026-07-16-wave-2-fiber-v3-migration-design.md @@ -0,0 +1,335 @@ +# Wave 2 Fiber v3 Migration Design + +Date: 2026-07-16 + +## Goal + +Migrate micrach from Fiber v2 to the current stable Fiber v3 and refresh the +compatible dependency baseline without changing application behavior, +architecture, routes, templates, persistence, uploads, or browser flow. + +## Entry Baseline + +Wave 1 is merged and green. The starting baseline is: + +- Go `1.26.0` with toolchain `go1.26.5`; +- Fiber `v2.52.14`; +- Fiber HTML template engine `v2.1.3`; +- pgx `v5.10.0`; +- passing `go test ./...`, `go vet ./...`, and `go build ./...`; +- local PostgreSQL through Docker Compose and host-run application workflow. + +At design time, the current stable migration targets are Fiber `v3.4.0` and +Fiber HTML `v3.0.6`. Fiber v3 requires Go 1.25 or later, so Go remains on 1.26. +These are a dated snapshot, not permanent pins. Implementation must recheck +Context7, official release notes, and `go list -m` before changing dependencies. + +## Scope + +Wave 2 is one focused pull request containing: + +- Fiber v2 to Fiber v3 migration; +- Fiber v3-compatible HTML template engine migration; +- required handler, context, middleware, static, redirect, and test API changes; +- DB-free unit characterization for migration-sensitive behavior; +- compatible patch and minor dependency refresh after Fiber migration; +- documentation updates and a confirmed modernization follow-up list; +- automated verification and manual application smoke testing. + +## Constraints + +- Preserve all existing routes, methods, status codes, templates, view data, + form field names, static URLs, upload paths, response flow, and minimal-JS UI. +- Preserve current package boundaries and server-rendered architecture. +- Do not redesign handlers or repositories, add dependency injection, introduce + an application factory, or add generalized compatibility wrappers. +- Do not add database migrations, schema changes, new routes, features, or UI + changes. +- Do not fix pre-existing bugs unless Fiber v3 causes a demonstrated regression. +- Do not add tests that require PostgreSQL, Docker, network services, or other + external infrastructure. +- Do not add an integration or end-to-end test harness. +- Do not combine other major dependency upgrades with Fiber v3. +- Never commit `.env`, uploads, binaries, credentials, or generated artifacts. + +## Chosen Migration Strategy + +Use a manual, narrow migration. Do not run `fiber migrate` in the working tree. +The migration CLI may be run against a disposable copy for comparison only; +its output is not authoritative and must not be copied without review. + +Implementation order: + +1. Add or refine DB-free characterization tests for migration-sensitive APIs. +2. Change Fiber and template dependencies and adapt compile-time API changes. +3. Make only the smallest changes needed to preserve runtime behavior. +4. Refresh compatible dependencies and normalize the module graph. +5. Update documentation and record confirmed follow-ups. +6. Run the full automated gate and manual smoke matrix. + +This approach is preferred over CLI-driven rewriting because the Fiber surface +is small and status/static behavior requires deliberate review. Compatibility +wrappers are rejected because they would add lasting structure for a one-time +migration. + +## Dependency Selection + +### Go and Fiber + +Keep the module, CI, and Docker builder on Go 1.26 because Fiber v3's current +minimum is Go 1.25. Upgrade them only if the rechecked stable Fiber release has +a higher requirement. + +Replace `github.com/gofiber/fiber/v2` with the current stable +`github.com/gofiber/fiber/v3`. At implementation start, verify that the selected +release is stable, not a beta or release candidate. + +### Template Engine + +The primary target is the current stable +`github.com/gofiber/template/html/v3`. Before committing the dependency graph, +compile the application and load/render the real templates through Fiber v3. + +If HTML v3 has a demonstrated incompatibility with the selected Fiber v3, +retain the documented Fiber v3-compatible `html/v2` engine as a controlled +fallback. Record the exact incompatibility and repeat the complete verification +gate. Documentation inconsistency alone is not enough to trigger fallback. + +### Other Dependencies + +After Fiber v3 is working: + +- run `go list -u -m` and review direct dependencies individually; +- accept only compatible patch or minor releases; +- do not add unrelated direct dependencies; +- do not take another major upgrade; +- run `go mod tidy`, inspect `go.mod`, `go.sum`, and `go mod graph`; +- remove obsolete direct Fiber v2 and HTML v2 requirements when HTML v3 is used; +- tolerate a lower-major transitive module only when the selected upstream + package legitimately requires it. + +At design time, the non-Fiber direct dependencies have no available updates. +Implementation must still recheck them rather than assuming that remains true. + +## Fiber API Migration + +### Handler Contexts + +Change all handlers and middleware callbacks from: + +```go +func(c *fiber.Ctx) error +``` + +to: + +```go +func(c fiber.Ctx) error +``` + +Fiber v3 `fiber.Ctx` implements `context.Context`. Remove `c.UserContext()` and +pass `c` directly to repository and pgx methods that accept `context.Context`. +Do not retain a second request context variable unless a specific API requires +one. + +### Route Parameters + +Fiber v3 removes `ParamsInt`. Do not replace it with +`fiber.Params[int](c, "threadID", 0)`, because an invalid parameter would become +zero and reach the repository instead of returning the current early 404. + +Parse with `strconv.Atoi(c.Params("threadID"))` and preserve the existing 404 +rendering on conversion failure. Catalog query parsing already uses +`strconv.Atoi` and remains unchanged. + +### Redirects + +Fiber v3 changes the default redirect from 302 to 303 and replaces the old +redirect call with a builder. Both successful write flows must set 302 +explicitly: + +```go +return c.Redirect().Status(fiber.StatusFound).To(path) +``` + +Thread creation continues redirecting to `/:threadID`. Reply creation continues +redirecting to `/:threadID#`. + +### Static Files + +Fiber v3 removes `app.Static`. Register the existing public prefixes through +`github.com/gofiber/fiber/v3/middleware/static`: + +- `/static/*` serves `./static`; +- `/uploads/*` serves `./uploads`. + +Preserve prefix stripping, file bodies, status behavior, dynamic route +precedence, and directory-browsing defaults. Unit tests must validate the exact +route form selected during implementation before the old registrations are +removed. + +### Middleware + +Move recover, limiter, and compress imports to Fiber v3 while preserving their +registration order: + +1. recover; +2. optional limiter; +3. compress; +4. static and application routes as currently ordered. + +Change limiter `Next` to `func(c fiber.Ctx) bool`. Preserve: + +- `Max: 50`; +- local-request bypass; +- `/static`, `/uploads`, and `/captcha` bypass; +- current default expiration, keying, headers, and limit response. + +Small unexported helpers are allowed for exact DB-free testing of static route +registration and the limiter skip predicate. Do not turn these helpers into a +new application-construction layer. + +### Multipart Forms and Uploads + +Keep `c.MultipartForm()` and `c.SaveFile()`; both remain available in Fiber v3. +Do not migrate forms to the Binder API without a compile-time requirement. + +Fiber v3 changed multipart body-limit enforcement. Compare observed v2 and v3 +behavior during manual smoke testing. Do not change the configured/effective +limit unless a migration regression is demonstrated. If needed, add the +smallest explicit `BodyLimit` setting that preserves the verified v2 contract, +and document the evidence. + +### Templates and Tests + +Keep template root, extension, helper names, template names, bindings, and +render calls unchanged. Update only engine imports or signatures required by +the selected template release. + +`app.Test(req)` remains valid without an explicit test configuration. Do not add +an empty `fiber.TestConfig`, because its semantics differ from Fiber's omitted +default configuration. + +## DB-Free Unit Test Safety Net + +All routine tests must run with no PostgreSQL, Docker, network service, or +external process. + +Update existing controller and gateway tests for Fiber v3 and cover: + +- invalid catalog page still renders 404; +- invalid thread ID still renders 404 before repository access; +- invalid multipart thread input returns 400 before repository access; +- gateway ping authentication and status behavior remain unchanged. + +Add focused tests where practical: + +- load the real templates with the configured helper functions; +- serve files for `/static/*` and `/uploads/*` from temporary directories; +- prove static prefixes map to the intended filesystem paths; +- prove a missing static file does not mask application routes; +- prove the limiter reaches 429 for ordinary remote requests; +- prove local, static, uploads, and CAPTCHA requests bypass the limiter. + +Tests may use `fiber.App`, `httptest`, `t.TempDir`, and in-memory middleware +state. Do not mock repositories or build an integration test seam merely to +automate successful database-backed flows. + +## Error and Regression Handling + +- Preserve existing 400, 404, 429, and 500 behavior and error templates. +- Treat compilation failures, changed statuses, changed route precedence, + broken template rendering, static mapping changes, and changed browser flow + as migration regressions. +- Reproduce a suspected regression with a focused unit check or manual request + before changing behavior. +- Apply the smallest Fiber-compatibility fix and rerun the full gate. +- Record unrelated defects and deferred redesigns as follow-ups. +- If the stable Fiber v3 migration cannot pass the acceptance gate, revert the + isolated migration rather than weakening the Wave 1 baseline. + +## Documentation and Follow-Ups + +Update README and AGENTS guidance to state Go 1.26 and Fiber v3, while keeping +local development, CI, Docker, and PostgreSQL instructions aligned with the +actual implementation. + +Create `docs/superpowers/modernization-followups.md`. Include only candidates +confirmed after the final module, vulnerability, and API audit. Each entry must +name the package or API, current and candidate state, why it is deferred, and +the evidence source. Do not add speculative cleanup ideas. + +The pull request must report selected versions, compatibility decisions, +dependency/fallback results, commands actually run, manual smoke results, and +any remaining follow-ups. + +## Automated Acceptance Gate + +Run fresh commands after the final dependency graph is settled: + +```sh +go fmt ./... +test -z "$(gofmt -l .)" +go mod tidy +git diff --exit-code -- go.mod go.sum +go test ./... +go vet ./... +go build ./... +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /tmp/micrach-linux-amd64 . +go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./... +git diff --check +docker build --tag micrach:wave2 . +``` + +Requirements: + +- every command exits zero; +- `go mod tidy` leaves no unexplained diff; +- no reachable vulnerability remains unhandled; +- the Docker build uses the selected Go line and succeeds; +- no forbidden generated or local artifact is tracked. + +No command in `go test ./...` may require PostgreSQL or another external +service. + +## Manual Smoke Matrix + +Use the disposable local Compose PostgreSQL and run the application on the +host. This is an operational acceptance pass, not an automated test suite. + +Verify: + +- catalog renders, including empty and populated states; +- `/?page=0` and out-of-range pages render 404; +- thread page and missing/invalid thread IDs behave unchanged; +- valid thread creation returns 302 and its exact location; +- valid reply returns 302 with the post fragment; +- CAPTCHA image is PNG and valid/invalid answers retain their behavior; +- JPEG and PNG uploads honor verified limits; +- multiple uploads, originals, and thumbnails use unchanged paths; +- pagination links and page boundaries work; +- limiter returns 429 and still bypasses local/static/uploads/CAPTCHA requests; +- `sage` does not bump the thread; +- normal reply bump, bump limit, and archival behavior remain unchanged; +- `/static` and `/uploads` assets render correctly; +- catalog and thread pages have no narrow or wide viewport regression. + +Record actual results in the pull request. Do not replace failures with an +integration harness inside this wave. + +## Non-Goals + +- Handler or repository architecture cleanup. +- Repository mocks, service interfaces, application factories, or DI. +- Automated PostgreSQL, upload-flow, or browser E2E tests. +- New features, routes, templates, CSS, JavaScript, or UI redesign. +- Database schema or migration changes. +- Deployment, publishing, proxy, cache, queue, or observability changes. +- Unrelated dependency major upgrades. + +## References + +- [Fiber v3 migration guide](https://docs.gofiber.io/next/whats_new/) +- [Fiber v3.4.0 release](https://github.com/gofiber/fiber/releases/tag/v3.4.0) +- [Fiber static middleware](https://docs.gofiber.io/next/middleware/static/) +- [Fiber HTML v3.0.6 release](https://github.com/gofiber/template/releases/tag/html%2Fv3.0.6)