Skip to content

docs + ci: fix broken cross-links, stage/prod symmetric inline-refresh deploy, new documentation - #3370

Merged
aryanmehrotra merged 22 commits into
developmentfrom
fix/doc-broken-links
May 4, 2026
Merged

aryanmehrotra merged 22 commits into
developmentfrom
fix/doc-broken-links

Conversation

@aryanmehrotra

@aryanmehrotra aryanmehrotra commented May 1, 2026 •

Copy link
Copy Markdown
Member

Summary

Three commits, one shipping unit:

  1. Doc cross-links — 6 internal 4xx links flagged by an external SEO crawl, all caused by relative ../.. paths breaking under no-trailing-slash URLs + a couple of one-offs. Fixed at the source. Repo-wide sweep confirms no remaining instances.
  2. docs/Dockerfile parametrized with ARG WEBSITE_TAG=latest. Default works for any standalone docker build.
  3. Stage and prod CI now both inline-refresh — checkout gofr-dev/website main, run yarn refresh-data, build the source-bundle locally with fresh data, build docs, deploy. Same pattern in both, different namespaces and GCP keys.

Why inline refresh instead of a pre-published image

Previously prod pulled ghcr.io/gofr-dev/website:latest. If the website hadn't been re-tagged since data went stale, prod deployed with last-week's roadmap / contributors / changelog. Now every framework v*.*.* tag automatically:

  1. Checks out gofr-dev/website (full history).
  2. Runs yarn install + yarn refresh-data (with GITHUB_TOKEN).
  3. Builds the website source-bundle locally with the freshly-refreshed JSONs baked in.
  4. Builds the framework docs image on top.
  5. Pushes to GAR and rolls out via kubectl set image.

No PAT needed — uses the workflow's built-in GITHUB_TOKEN.

What changed since the first push of this PR

The earlier draft had cron-based daily refresh (04:00 UTC website + 05:00 UTC framework) and a separately-published :stage image. After feedback that cron was solving a non-problem (data freshness is naturally tied to deploys, not wall-clock time), removed both:

  • Stage flow now matches prod — single push to development or click of workflow_dispatch is enough.
  • Companion website PR (gofr-dev/website#211) drops its publish_stage job entirely.

Test plan

  • Repo sweep — zero remaining instances of any broken doc-link patterns.
  • Manual: re-run external SEO crawl on staging post-deploy → expect 4xx internal-link count = 0.
  • CI: confirm website-stage.yml succeeds on the next push to development — yarn refresh-data runs cleanly with GITHUB_TOKEN rate-limit, source-bundle build picks up the refreshed JSONs, kubectl rolls out with a unique image tag.
  • CI: confirm website-prod.yml succeeds on the next GoFr v*.*.* tag with the same flow against the prod namespace.

Companion PR

gofr-dev/website#211 — the website overhaul (content, SEO, JSON-LD, AI discoverability, team page composite scoring, etc.) plus the matching CI cleanup. Both PRs need to land for the new flow to work end-to-end.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 1, 2026 10:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes several broken internal documentation links identified by an SEO crawl, primarily by switching to more robust /docs/... absolute paths and correcting outdated slugs. The PR also updates the framework version constant used across GoFr telemetry/tracing.

Changes:

  • Replace fragile relative doc cross-links with absolute /docs/... paths in GoFr CLI and datasource docs.
  • Fix an incorrect RBAC related-doc link to point to the correct authentication page.
  • Update a CLI docs link to point to the GitHub example source instead of a non-existent site route.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/gofr/version/version.go Bumps the framework version constant from dev to v1.56.4.
docs/references/gofrcli/page.md Replaces relative ../../advanced-guide/... links with absolute /docs/advanced-guide/... links.
docs/datasources/cockroachdb/page.md Fixes missing /docs/ prefix in an advanced guide link.
docs/advanced-guide/rbac/page.md Corrects related-doc link from /http-authentication to /authentication.
docs/advanced-guide/building-cli-applications/page.md Repoints an invalid examples link to the GitHub repository example path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/gofr/version/version.go Resolved
@aryanmehrotra aryanmehrotra changed the title docs: fix broken cross-links surfaced by Sitebulb crawl docs + ci: fix broken cross-links, refresh data on every prod deploy May 1, 2026
aryanmehrotra added a commit to gofr-dev/website that referenced this pull request May 1, 2026
Two complementary publish jobs replace the single tag-only flow,
so the framework's stage deploy can track gofr-dev/website's main
branch via :stage while prod stays anchored to tagged releases.

publish_stage (new):
  - Fires on push to main, on a daily cron at 04:00 UTC, and via
    workflow_dispatch.
  - Runs `yarn refresh-data` so :stage bakes in fresh releases /
    roadmap / team / doc-mtimes on every publish.
  - Tags ghcr.io/gofr-dev/website:stage.
  - Cron exists so :stage picks up new GoFr releases / maintainer
    activity even between merges. workflow_dispatch is the manual
    button for ad-hoc refreshes.

release_package (existing behavior, body unchanged):
  - Fires on tag v* push.
  - Publishes ghcr.io/gofr-dev/website:<tag> + :latest with fresh
    data. Prod tracks tags.

The framework-side companion (gofr-dev/gofr#3370) parameterizes
docs/Dockerfile to accept WEBSITE_TAG, points website-stage.yml at
:stage, and adds inline refresh + local source-bundle build to
website-prod.yml so prod always ships with current data on every
GoFr `v*.*.*` tag.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra added a commit to gofr-dev/website that referenced this pull request May 1, 2026
Removed publish_stage job and the cron / push-to-main triggers.
Stage and prod in the framework repo now both check out this
website source, run yarn refresh-data, and build their source-bundle
in-runner — so neither needs a pre-published :stage on ghcr.

What this trims:
  - ~120 unnecessary CI runs/month (the daily cron)
  - Surprise 05:00 UTC stage rollouts
  - The two-layer cron/staleness coordination headache

Workflow now only fires on:
  - push tag v*  → release_package publishes :latest + :vX.Y.Z
                   (kept as the public artifact + rollback target)
  - PR to main/development → build job only (no publish)

Companion change in gofr-dev/gofr#3370 ports the inline-refresh
pattern from website-prod.yml to website-stage.yml.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aryanmehrotra aryanmehrotra changed the title docs + ci: fix broken cross-links, refresh data on every prod deploy docs + ci: fix broken cross-links, stage/prod symmetric inline-refresh deploy May 1, 2026
aryanmehrotra added a commit to gofr-dev/website that referenced this pull request May 1, 2026
These 18 files are framework-specific content — positioning, comparisons,
migration guides, the maintainer list, the AI-assistant rule sheet —
and they should evolve in lockstep with the framework. They now live
in gofr-dev/gofr/docs/ and overlay this tree at deploy time, exactly
how docs/quick-start, docs/advanced-guide, events.json, testimonials.json,
and navigation.js already work.

Companion: gofr-dev/gofr#3370 adds these files there + the 9 new
COPY directives in docs/Dockerfile.

Removed from this repo:
  src/app/why-gofr/page.md
  src/app/comparison/page.md + 4 sub-pages
  src/app/migrate/page.md + 5 sub-pages
  src/app/learn/page.md
  src/app/faq/page.md
  src/data/team.json
  src/app/showcase/companies.json
  src/app/examples/examples.json
  public/AGENTS.md

What stays in this repo (per the design/infrastructure principle):
  - All layouts and JSX components (rendering chrome) — the layout.jsx
    in why-gofr/, comparison/*, migrate/*, learn/, faq/, showcase/,
    examples/ remain so Next.js routing keeps working when the .md
    or .json gets dropped in by the framework's Dockerfile.
  - Build pipeline (utils/*.mjs, package.json, next.config.mjs,
    tailwind.config.js).
  - Build-time-generated JSON (releases, roadmap, team-enriched,
    doc-mtimes) — outputs of CI fetchers.
  - Site-discovery metadata: public/llms.txt, robots.txt, humans.txt,
    .well-known/security.txt — about the site as a whole.

Local dev caveat: routes that depend on the overlaid files will 404
locally until either (a) the framework's Dockerfile is exercised or
(b) someone clones gofr-dev/gofr and symlinks the content tree.
Same caveat already applies to /docs/* — handled identically.

Sequencing: gofr-dev/gofr#3370 must merge first so the framework
docs/ has the content; then this commit removes the local copies.
The deploy pipeline (gofr-dev/gofr's website-stage.yml and
website-prod.yml) checks out gofr-dev/website, builds source-bundle
locally, and overlays framework docs/ — so the deploy chain reads
content from gofr-dev/gofr regardless of whether this repo's local
copies exist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra and others added 6 commits May 1, 2026 18:44
Six 404 cross-links inside the docs flagged by an external SEO
crawl, all caused by the same two slip-ups:

1. Relative `../..` paths from /docs/references/gofrcli that
   resolved to /advanced-guide/* instead of /docs/advanced-guide/*
   because Next.js treats the URL as a file rather than a directory
   (no trailing slash). Replaced with absolute /docs/... links.

2. One absolute link in datasources/cockroachdb that omitted the
   /docs/ prefix entirely.

3. /advanced-guide/http-authentication referenced from rbac.md —
   the actual slug is /advanced-guide/authentication. Updated.

4. ../../../examples/sample-cmd from building-cli-applications —
   /examples/sample-cmd is not a website route. Replaced with the
   GitHub source URL (gofr-dev/gofr/tree/main/examples/sample-cmd)
   where the example actually lives.

Files touched:
  docs/references/gofrcli/page.md           (3 cross-links fixed)
  docs/datasources/cockroachdb/page.md      (1)
  docs/advanced-guide/rbac/page.md          (1)
  docs/advanced-guide/building-cli-applications/page.md (1)

Verified by sweep: no remaining `(../../advanced-guide` patterns,
no `](/advanced-guide` patterns missing /docs/ prefix, no other
`http-authentication` references, no other `../../../examples/`
relative paths in docs/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two related deploy-pipeline changes that together guarantee a GoFr
release ships with the new version present in the changelog and an
up-to-date roadmap / contributor list.

docs/Dockerfile
- New ARG WEBSITE_TAG=latest. The two CI flows pass it explicitly:
    website-stage.yml → WEBSITE_TAG=stage
    website-prod.yml  → WEBSITE_TAG=latest (default)
  Default keeps a hand-run `docker build -f docs/Dockerfile` working
  as a prod-flavored build with no extra arguments.

.github/workflows/website-stage.yml
- Pull ghcr.io/gofr-dev/website:stage instead of :latest. :stage is
  built from the website's main branch on every merge (gofr-dev/
  website's package.yml publish_stage job), so stage tracks the
  website's main automatically.
- Pass --build-arg WEBSITE_TAG=stage to the docs build.
- Add daily cron at 05:00 UTC and workflow_dispatch so stage redeploys
  even without a push to development — picks up new GoFr releases /
  roadmap / team changes that landed in :stage via its own 04:00 UTC
  cron.
- Append run_id to the image tag so kubectl actually rolls when
  rebuilding from the same SHA (otherwise scheduled rebuilds with
  identical SHAs are no-ops).

.github/workflows/website-prod.yml
- Replace "docker pull :latest" with an inline website refresh:
  checkout gofr-dev/website (full history), yarn install,
  yarn refresh-data (with GITHUB_TOKEN), then build the website
  source-bundle locally tagged ghcr.io/gofr-dev/website:latest.
- Switch to raw `docker build` for both the source-bundle and the
  framework docs image so the local-only :latest tag is visible to
  the docs build's FROM. No buildx setup needed.
- Net result: every GoFr `v*.*.*` tag triggers a full pipeline that
  refreshes data, rebuilds, and deploys — no manual coordination
  with the website's release cadence.

What stays unchanged:
- Prod is still tag-driven; no auto-deploy on schedule.
- :latest on ghcr is NOT pushed by the framework prod workflow —
  it's built locally inside the runner and used only for the docs
  FROM. The public :latest on ghcr stays managed by the website's
  release_package job (on website tag push). This keeps a single
  source of truth for the public artifact.
- Cluster, namespace, GAR registry, deployment commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stage now builds the website source-bundle in-runner with fresh
data, mirroring website-prod.yml. The previous design pulled a
pre-built ghcr :stage image and ran on a daily cron — replaced by a
single deterministic flow:

  - push to development      → checkout website main, refresh data,
                               build local source-bundle, build docs,
                               deploy to gofr-dev-stg namespace
  - workflow_dispatch button → same chain, manual trigger

Net effect:
  - Stage and prod are now symmetric — same pattern, same code path,
    just different namespaces and credentials.
  - No external :stage image dependency. The website repo no longer
    needs to publish :stage at all (companion PR removes that job).
  - Cron removed: data freshness is now tied to actual deploys, not
    a wall-clock schedule. workflow_dispatch covers ad-hoc refresh.
  - run_id appended to image tag so kubectl set image actually rolls
    on workflow_dispatch reruns of the same commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts the inline-refresh in stage and goes back to pulling the
:stage image published by gofr-dev/website's publish_stage job
(which runs on every merge to website main + workflow_dispatch).

Why pull instead of rebuild for stage:
  - Stage CI becomes a thin docs+kubectl wrapper — faster, fewer
    moving parts, no Node setup or yarn install needed in this
    workflow.
  - :stage on ghcr already has fresh data baked in (the website's
    publish_stage runs yarn refresh-data before tagging the image),
    so no freshness lost.
  - The website is the single authority for its source-bundle build.
    Stage CI just consumes the published artifact.

Prod stays on inline-rebuild (website-prod.yml unchanged) — that
guarantees prod ships with current data on every framework v*.*.*
tag regardless of when :stage was last refreshed. The asymmetry is
intentional: stage trades a small staleness window for a faster CI
loop; prod trades a slightly slower CI loop for hard freshness
guarantees on release.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stage was pulling :stage (data fetched in gofr-dev/website's
publish_stage job) while prod inline-rebuilt (data fetched in this
repo's website-prod.yml). Two different code paths with two
different freshness guarantees — surprising and harder to reason
about.

Aligning both:

  stage    → checkout website main, refresh-data, build local
              source-bundle, build docs, deploy gofr-dev-stg
  prod     → same checkout / refresh / build chain, deploy gofr-dev

Identical workflow body in both files, only the namespace and the
GCP service account secret differ. Same fresh-data guarantee on
every stage push as on every prod tag. The website's :stage image
keeps publishing on main merge as an internal artifact (per
gofr-dev/website's package.yml) but is no longer the source of
truth for the stage deploy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Moves framework-specific content out of gofr-dev/website and into
this repo, mirroring how docs/quick-start/, docs/advanced-guide/,
docs/datasources/, docs/references/, docs/events.json, and
docs/testimonials.json already work — content lives where the
framework lives, design lives in the website repo.

Marketing pages (14 .md files):
  docs/why-gofr/page.md
  docs/comparison/page.md + 4 sub-pages (gofr-vs-{gin,fiber,echo,chi})
  docs/migrate/page.md + 5 sub-pages (from-{gin,fiber,express,flask,spring-boot})
  docs/learn/page.md
  docs/faq/page.md

Framework-content data files (4):
  docs/team.json                     — maintainers list
  docs/showcase/companies.json       — companies using GoFr
  docs/examples/examples.json        — runnable examples index
  docs/AGENTS.md                     — curated rules for AI assistants

What this means for editing:
  - Update a comparison page or fix a typo in /faq → PR here, in this
    repo, alongside any related framework change. No cross-repo PR.
  - Add a maintainer or roll a contributor → edit team.json here.
  - Refine an AGENTS.md rule → edit here. /AGENTS.md served from
    this content via the website's overlay.

What stays in the website repo (gofr-dev/website):
  - All layouts and JSX components (the rendering chrome).
  - Build pipeline, fetcher scripts, design tokens.
  - Build-time-generated JSON (releases, roadmap, team-enriched,
    doc-mtimes) — output of CI fetchers, not source content.
  - Site-discovery metadata: public/llms.txt, robots.txt, humans.txt,
    .well-known/security.txt — about the site as a whole, not
    framework specifics.

docs/Dockerfile updated with 9 new COPY directives, all pointing at
the same destinations the website previously held the files at:

  COPY docs/why-gofr     /app/src/app/why-gofr
  COPY docs/comparison   /app/src/app/comparison
  COPY docs/migrate      /app/src/app/migrate
  COPY docs/learn        /app/src/app/learn
  COPY docs/faq          /app/src/app/faq
  COPY docs/team.json    /app/src/data/team.json
  COPY docs/showcase/companies.json  /app/src/app/showcase/companies.json
  COPY docs/examples/examples.json   /app/src/app/examples/examples.json
  COPY docs/AGENTS.md    /app/public/AGENTS.md

Companion change in gofr-dev/website#211 removes these 18 files
from that repo so there's exactly one source of truth.

Sequencing: this PR can land first — stage/prod keep working off
the website's current copies until the website removes them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aryanmehrotra
aryanmehrotra force-pushed the fix/doc-broken-links branch from 2a1f1ba to a39902a Compare May 1, 2026 13:14
aryanmehrotra added a commit to gofr-dev/website that referenced this pull request May 1, 2026
Five external audit reports converged on a small set of high-leverage
fixes. Landing them all at once.

Critical:
- Soft-404 on /docs fixed at the framework side (next commit on
  gofr-dev/gofr#3370): nextjs.metadata frontmatter added to
  docs/page.md so the route renders a real <title>.
- Broken hreflang alternates (/es, /zh — both routes 404) removed
  from src/app/page.jsx. Google flagged these in Search Console as
  page-level errors on every site URL.
- /pkg/** redirect stubs (23 routes, no SEO content, just
  PkgRedirect → /docs) now ship with `robots: noindex,nofollow` via
  src/app/pkg/layout.jsx and are excluded from sitemap.xml. Same
  for /cli/** and /releases. These were 27 of the orphan URLs the
  audit flagged.
- FAQPage JSON-LD now auto-emits on /faq. Previously FaqList only
  generated the schema when an explicit `items={[...]}` prop was
  passed; the Markdoc {% faq %}{% faq-item %} pattern doesn't pass
  one. Refactored FaqList to walk its React children, extract
  question + answer text, and emit FAQPage schema regardless of
  whether items was supplied. Single highest-leverage AEO fix —
  unlocks Google AI Overview citation eligibility for Q/A queries.
- <main id="main"> landmark + skip-to-main link added to
  src/components/Layout.jsx. WCAG 2.4.1 (Bypass Blocks) was failing
  on every page.
- DocStructuredData now reads doc-mtimes.json directly to populate
  schema.org dateModified instead of relying on the caller to pass
  lastUpdated. The caller (DocsLayout) wasn't passing it, so every
  TechArticle in the wild was missing dateModified — invisible
  freshness signal.

High:
- alt="Transistor" (from a stale tutorial template) repeated on 11
  marquee logos (DBlistComponent.jsx) and 9 trusted-companies logos
  (CompanyTrustedList.jsx) — both now use real names ("Redis",
  "Kafka", "American Express", etc.) sourced from the data array.
- prefers-reduced-motion: reduce honored in src/styles/prism.css —
  the 30s scrolling marquee freezes and lays items out statically
  for users who've requested reduced motion at OS level. WCAG 2.3.3.
- generate-doc-mtimes.mjs now walks /why-gofr, /comparison,
  /migrate, /learn, /faq in addition to /docs — so every overlay-
  content page gets a real "Last updated" byline + dateModified
  instead of only the docs tree.

What stays as snapshots (no change needed):
- src/data/doc-mtimes.json regenerates on next refresh-data run.
- Sitemap auto-rebuilds at next build.

What's NOT in this commit (followups):
- /docs/quick-start/introduction lead-with-Prerequisite issue —
  framework PR concern.
- Per-route OG/Twitter card overrides — bigger change, separate commit.
- Accordion <div onClick> → <button> — separate commit, isolated.
- /llms-full.txt generator — separate commit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra and others added 7 commits May 1, 2026 20:47
Two surgical content fixes flagged by the SEO + AEO audits:

docs/page.md
  - Added nextjs.metadata frontmatter (title + description). Without
    it, /docs renders as a soft-404 in the deployed website (HTTP 200
    + "404 page could not be found" body) because the website has no
    explicit /docs page.{md,jsx} — only this overlay file. The empty
    <title> was the most damaging single SEO issue in the audit.

docs/quick-start/introduction/page.md
  - Replaced opening "# Prerequisite" with "# Hello, GoFr" + a 1-2
    sentence GoFr definition + a 1-sentence promise. Then the
    Prerequisites moved under an h2. Princeton GEO research shows
    30-40% AI-citation lift for pages whose first 200 words contain
    the answer to the implied question. The previous page led with
    "Go 1.24 or above" — useful, but not the answer Perplexity /
    ChatGPT / Google AI Overviews would extract for "what is GoFr"
    or "Go framework with built-in observability".
  - Added nextjs.metadata frontmatter so SERPs show
    "Quick Start — Your First GoFr REST API in Go" instead of
    Next.js's default page-title fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per maintainer team decision. Srijan Rastogi remains in the
gofr-dev/gofr contributor history and will continue to appear in
the community contributor grid on /team (sourced live from the
GitHub contributors API at deploy time), just not in the core
maintainer cards row above it.

Companion change in gofr-dev/website#211 regenerates the website's
team-enriched.json snapshot to reflect the new 5-maintainer roster.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- why-gofr: standardising → standardizing (US spelling required by typos CI)
- faq: rewire dead "Who maintains GoFr?" link from /community (removed) to
  /team and the GitHub repo

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
v0.0.9 ships multi-arch (amd64 + arm64) so local builds on Apple
Silicon stop emitting the InvalidBaseImagePlatform warning. Verified
the docs overlay still serves /, /docs, /faq, /comparison, /team,
/why-gofr, /llms-full.txt with 200s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds an entirely new "Production Guides" section under /docs/guides/
covering deployment, observability, reliability, and security
recipes — these were missing and have been the most common
production-readiness questions.

New /docs/guides/ (18 pages):
  Deployment
    - dockerizing-gofr-services
    - deploying-to-kubernetes
    - helm-chart-starter
    - multi-environment-deployment
    - cloud-deployment (EKS / GKE / AKS)
    - cicd-recipes
    - db-migrations-in-cicd
  Observability
    - production-tracing
    - distributed-tracing
    - production-prometheus-kubernetes
    - production-logging
  Reliability & scale
    - graceful-shutdown
    - horizontal-pod-autoscaler
    - connection-pooling
    - load-testing
  Configuration & security
    - twelve-factor-config
    - auth-in-kubernetes
    - service-mesh-integration

New /migrate/ pages (8): from-fastapi, from-echo, from-nestjs,
from-aspnet-core, from-chi, from-django-rest, from-laravel,
from-rails. /migrate/page.md index regrouped by language family
(Go / Node-TS / Python / Java-NET / PHP-Ruby) and now links all 13
migration guides.

Cross-links from existing feature reference docs to the relevant
production guides:
  - custom-spans-in-tracing → production-tracing, distributed-tracing
  - publishing-custom-metrics → production-prometheus-kubernetes, hpa
  - monitoring-service-health → deploying-to-kubernetes
  - startup-hooks → graceful-shutdown
  - dealing-with-sql → connection-pooling
  - handling-data-migrations → db-migrations-in-cicd
  - authentication / rbac → auth-in-kubernetes
  - circuit-breaker → service-mesh-integration
  - http-communication → distributed-tracing
  - remote-log-level-change → production-logging
  - references/configs → twelve-factor-config

Dockerfile — overlay `docs/guides/` to /app/src/app/docs/guides on
container build so the new section is served alongside existing
sections.

navigation.js — adds the "Production Guides" section between
"Advanced Guide" and "Datasources", ordered by sub-cluster
(Deployment → Observability → Reliability → Configuration & Security).

All claims grounded in verified GoFr features; no fabricated metrics,
SLA, or support content. Specific source-code references in each
guide (env-var names, function symbols) cross-checked against
pkg/gofr/{otel.go, factory.go, default.go, run.go, shutdown.go,
config/, datasource/sql/, service/}.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- typos.toml: allowlist `AKS` (Azure Kubernetes Service) so the typos
  CI stops flagging it as a misspelled `ASK`. Same shape as existing
  IIT / mosquitto entries.
- docs/guides/twelve-factor-config: materialise → materialize (×2)
- docs/guides/connection-pooling: recognises → recognizes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validated all 18 production guides against a live minikube cluster +
sample GoFr v1.46 app. Surface-level edits only — the guide
structure stays. Each fix cross-checked against framework source.

P0 (broken-in-production guidance):

- dockerizing-gofr-services: ARG GO_VERSION=1.23 → 1.25 (gofr.dev's
  go.mod requires Go ≥ 1.25.0; 1.23 fails on `go mod download`).
  Replace `HEALTHCHECK CMD ["/app/app", "healthcheck"]` — there is
  no `healthcheck` subcommand. Distroless can't run a HEALTHCHECK
  anyway (no shell, no wget); document both: drop HEALTHCHECK and
  rely on K8s probes (recommended for prod), OR switch to alpine
  and use `wget /.well-known/alive`.
- db-migrations-in-cicd: there is no `/app/migrate` binary or
  `gofr migrate` subcommand. Migrations register via
  `app.Migrate(map[int64]migration.Migrate{...})` and execute
  synchronously inside that call (verified pkg/gofr/gofr.go:Migrate
  → migration.Run). Job pattern now uses the same image gated by
  `MIGRATE_ONLY=true` and exits before `app.Run()`.
- cicd-recipes: setup-go `go-version: '1.22'` → '1.25' to match
  the framework's go.mod minimum.

P1 (inaccurate but not show-stopping):

- twelve-factor-config + multi-environment-deployment: TRACER_URL
  was `http://otel-collector...:4318`. Wrong on both counts —
  GoFr's OTLP exporter speaks gRPC (otlptracegrpc.WithEndpoint at
  pkg/gofr/otel.go:166), so the value must be a bare host:port (no
  scheme), and the correct port is 4317 (OTLP gRPC), not 4318
  (OTLP HTTP).
- connection-pooling: drop the outdated "ConnectionPoolConfig must
  be the first option" warning. extractHTTPService now recursively
  unwraps wrappers, so option order is irrelevant.
- production-logging + distributed-tracing: clarify the trace_id
  story. trace_id is a top-level JSON field on logEntry
  (json:"trace_id,omitempty" in pkg/gofr/logging/logger.go), so
  it's present only when there's a trace context. For HTTP request
  logs the value of `message` is a RequestLog struct that ALSO
  carries a nested trace_id (pkg/gofr/http/middleware/logger.go) —
  drop the "every log line" claim and document both shapes.
- production-prometheus-kubernetes: HELP strings and label sets
  matched against pkg/gofr/container/container.go and the SQL
  gauge in pkg/gofr/datasource/sql/sql.go (e.g. the gauge is set
  with no extra labels via SetGauge, so the example exposition
  shouldn't show `{}` placeholder).

Things validation flagged that we deliberately did NOT change:

- auth-in-kubernetes: claim that /.well-known/health is auth-exempt
  by default is correct. Verified via
  pkg/gofr/http/middleware/validate.go (isWellKnown() returns true
  for any /.well-known/* prefix; auth middleware uses this to
  bypass). auth_test.go:23-24 confirms 200 OK without auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra and others added 6 commits May 2, 2026 19:15
…urce

Compile-tested every disputed API claim against gofr.dev v1.56.4
with `go build`; grepped source for every feature/protocol claim.
Several long-standing claims turned out to be wrong or fabricated.
Removing them rather than inventing framework features to back them.

Removed (claims that don't match shipped code):

- **SSE / Server-Sent Events**: AGENTS.md, why-gofr, comparison index,
  comparison/gofr-vs-fiber, faq all listed SSE as a built-in handler
  type. `gofr.SSE` does not compile (`undefined: gofr.SSE`); no SSE
  responder, no `text/event-stream` writer, no heartbeat token in
  `pkg/gofr/`. Removed every SSE mention. The gofr-vs-fiber gotcha
  block now states honestly that there is no built-in SSE responder
  and points to writing to the underlying ResponseWriter from
  middleware.

- **`MIGRATE_ONLY=true` env-var gate** (db-migrations-in-cicd Option B):
  the framework recognises no such variable. Rewritten to document the
  two real patterns: in-process startup migrations (default lifecycle),
  or a separate `cmd/migrate/main.go` binary the user writes that
  calls `app.Migrate(...)` and exits — application code organisation,
  not a framework knob.

Fixed (broken APIs, all `go build`-verified):

- `app.AddSQL(...)` and `app.AddRedis(...)` (from-fastapi, from-echo,
  from-chi, from-laravel, from-nestjs): undefined on `*gofr.App`. SQL
  / Redis auto-init from `DB_DIALECT` / `REDIS_HOST` etc.
- `app.GetPublisher().Publish(...)` (from-django-rest, from-laravel,
  from-rails): undefined on `*App`. Method is on `*gofr.Context`;
  payload is `[]byte`.
- `app.AddCronJob(spec, fn)` (from-laravel): 2-arg form fails
  compile. Real signature `(schedule, jobName string, job CronFunc)`.
- `c.Request.Header.Get(...)` and `c.Request` typed as `*http.Request`
  (from-echo, from-chi): `c.Request` is the `gofr.Request` interface
  exposing `Param`, `PathParam`, `Bind`, `HostName`, `Params`, `Context`.
- `app.GRPCRegisterService(...)` (gofr-vs-gin, gofr-vs-fiber):
  undefined; correct symbol is `app.RegisterService(*grpc.ServiceDesc,
  any)` per `pkg/gofr/grpc.go:201`.
- RabbitMQ (from-nestjs): not in shipped Pub/Sub list. Real list:
  kafka, nats, sqs, mqtt, google, eventhub.

Misc factual corrections (source-grepped):

- `graceful-shutdown` order corrected to HTTP → gRPC → container →
  metrics → logger close per `pkg/gofr/gofr.go:96-114`.
- `cloud-deployment`: deprecated `kubernetes.io/ingress.class`
  annotation → modern `spec.ingressClassName` field across EKS / GKE
  / AKS examples.
- `production-logging`: `time` field is RFC3339Nano (Go default
  `time.Time` JSON marshaling), not RFC3339, per
  `pkg/gofr/logging/logger.go:55`.
- `multi-environment-deployment`: `REMOTE_LOG_FETCH_INTERVAL` is
  integer seconds (default 15), not a Go duration string.
- `production-prometheus-kubernetes`: dropped unverified Grafana
  dashboard ID `6671`; replaced with a search-link prose pointer.
- `auth-in-kubernetes`: reconciled "three categories vs five methods"
  count; clarified `/.well-known/*` blanket auth-exemption per
  `pkg/gofr/http/middleware/validate.go:6` and `auth_test.go:23-24`.
- `why-gofr`: added KV-store backends (Badger, DynamoDB, NATS) to the
  datasources bullet — verified by `ls pkg/gofr/datasource/kv-store/`.

Out of scope here: SEO/title-length polish, marketing-page customer
verification, and any framework-side changes (those are framework PRs,
not docs PRs).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
A new-user copy-paste walkthrough of the docs hit five places where
the documentation didn't match reality. Each fix below is grounded
in a `go build` against gofr.dev v1.56.4 or a literal exec trace.

- quick-start/connecting-redis: `redis-cli SET greeting ...` failed
  with `NOAUTH Authentication required` because the docker container
  is started with `--requirepass password` but the documented
  redis-cli call omitted `-a password`. Add the auth flag.

- quick-start/add-rest-handlers: example imported
  `gofr.dev/examples/using-crud-from-struct/migrations`, a path that
  doesn't exist in the framework repo. The actual example lives at
  `using-add-rest-handlers/migrations` (also referenced correctly
  later on the same page).

- comparison/gofr-vs-gin: snippet called
  `app.Service("payments").Get(ctx, "/charge", params)`. `app.Service`
  is undefined on `*gofr.App` (verified via `go build`). The real
  pattern is `ctx.GetHTTPService("payments").Get(...)` from inside a
  handler. Restructured the block to show registration at startup
  plus lookup from a handler — verified it compiles.

- AGENTS.md: "Requires Go 1.24+" → "Requires Go 1.25+". Framework
  go.mod declares `go 1.25.0`.

- quick-start/introduction: same Go version correction in the
  Prerequisites bullet.

The walkthrough surfaced one further issue that we are NOT fixing in
docs because it is a framework concern: gofr.dev v1.56.4's internal
MockRedis does not implement go-redis v9.19.0's `ReplicaOf` method,
so `go get github.com/redis/go-redis/v9` (which now resolves to
v9.19.0) breaks the mock. Pinning the SDK in user-facing docs would
be a band-aid; the right fix is on the framework side.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Blind-user walkthrough caught that the introduction page mentioned
"port 8000" in passing but never told the user (a) what else is
listening, (b) that port 2121 is also opened automatically for
metrics, or (c) what env var to set when those ports collide on
their dev machine. The framework FATALs without context, so the
user has nowhere to land.

Add a "Default ports and endpoints" section right after the
"Starting the server" walkthrough, listing each listener (HTTP 8000,
Metrics 2121, gRPC 9000), its override env var, and the endpoints
exposed on it. Includes the full `/.well-known/*` set
(health / alive / swagger / graphql/ui), explicitly notes those are
auth-exempt by default, and links to references/configs for the
full env-var matrix.

All ports / paths / env-var names verified against:
- pkg/gofr/default.go (defaults 8000 / 9000 / 2121)
- pkg/gofr/factory.go (HTTP_PORT / GRPC_PORT / METRICS_PORT)
- pkg/gofr/gofr.go:149-159 (auto-registered well-known handlers)
- pkg/gofr/swagger.go:67 (/.well-known/swagger)
- pkg/gofr/http/middleware/validate.go (well-known auth exemption)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two pre-existing inaccuracies caught by the blind-user walkthrough:

- The page tells you to write `createTableEmployee` after running
  `gofr migrate create -name=create_employee_table`. But the CLI
  scaffolds a function named `createEmployeeTable` (snake_case
  `create_employee_table` → camelCase `createEmployeeTable`). A
  blind copy-paste leaves you with two functions, no error.
  Renamed every occurrence of `createTableEmployee` →
  `createEmployeeTable` for internal consistency with what the
  CLI actually generates (also flips `createTableEmployeeCassandra`
  in the Cassandra example for symmetry).

- Success log example was shown as `INFO [16:55:46] Migration ...`,
  i.e. the bracketed pretty-print format. GoFr's default logger
  emits structured JSON via `Infof` (see
  pkg/gofr/migration/datasource.go:60 → c.Infof goes through the
  JSON encoder in pkg/gofr/logging/logger.go). Replaced the example
  with the real JSON shape so users matching log output against
  Loki / CloudWatch / Stackdriver queries don't waste time looking
  for the bracket format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Four parallel blind-user agents walked every page (~70 in scope) and
copy-pasted/compiled every Go block. Every fix below is grounded in
either a `go build` failure on the doc's own snippet or a direct
source-code grep. Honors the no-invented-features memory rule: no
user-side env-var gates were added; one was removed.

P0 fixes (broken copy-paste flow):

quick-start/
 - introduction: response example whitespace fixed (Go default JSON
   has no spaces).
 - configuration: APP_ENV behaviour rewritten — `.env` loads first,
   `.<APP_ENV>.env` overlays on top (per godotenv.Load + Overload in
   pkg/gofr/config/godotenv.go:36-77). Old text claimed fallback.
 - connecting-redis / connecting-mysql: dropped `docker exec -it`
   (TTY) so the steps work in CI / scripts. Added a mysqladmin ping
   readiness loop before CREATE TABLE on the MySQL page so a clean
   machine doesn't race the bootstrap.
 - observability: lead with `TRACE_EXPORTER=otlp`, demote zipkin to
   "legacy" with the framework's own deprecation note (verified in
   pkg/gofr/otel.go:140-142). Bumped TRACER_RATIO=1.0 in dev
   examples so a single curl actually shows trace data.
 - add-rest-handlers: `if err != nil { return }` (silent swallow)
   replaced with `app.Logger().Fatal(err)` so a beginner sees the
   error instead of a no-op.

advanced-guide/
 - custom-spans-in-tracing: handler signature `c context.Context`
   → `c *gofr.Context`; `span.Close()` → `span.End()` (OTel API).
 - websocket: `app.Logger.Errorf` → `app.Logger().Errorf` (Logger
   is a method, not a field — go build verified).
 - using-publisher-subscriber: `gofr.dev/.../datasources/...` typo
   → `datasource` (singular) — the real package path.
 - authentication: clarified that the entire `/.well-known/*`
   prefix is auth-exempt (not just `/alive`), per
   pkg/gofr/http/middleware/validate.go's HasPrefix check.

datasources/
 - couchbase: undefined-`app` (had `a := gofr.New()` then
   `app.Config.Get(...)`) — renamed for consistency.
 - elasticsearch: `Addresses []string` was being assigned a single
   string from Config.Get; switched to `strings.Split(..., ",")`
   matching pkg/gofr/datasource/elasticsearch/elasticsearch.go:39.
 - influxdb: stray `)` syntax error; `CreateBucket`/`DeleteBucket`
   arity in interface block aligned with the real driver
   (pkg/gofr/datasource/influxdb/influxdb.go:158, 188).

guides/ (production deployment guides)
 - production-tracing: `GetWithHeaders(ctx, path, nil, nil, &resp)`
   was a 5-arg call that doesn't compile. Real signature returns
   `(*http.Response, error)` and takes 4 args (path,
   queryParams, headers). Rewrote the example to call it correctly
   and decode resp.Body. Verified at
   pkg/gofr/service/custom_header.go:29-30.
 - connection-pooling: replaced fabricated `redis_open_connections`
   metric with the real series (`app_sql_open_connections`,
   `app_sql_inUse_connections`, `app_sql_stats`, `app_redis_stats`)
   per pkg/gofr/container/container.go:251-261.
 - multi-environment-deployment: REMOVED the recommendation to
   branch on `app.Config.Get("APP_ENV") == "prod"` inside main.go.
   That's user-side env gating (memory rule). Doc now says: ship
   the same image, differentiate via env / ConfigMap.
 - distributed-tracing: clarified the trace_id field — top-level
   `trace_id` is `omitempty` and present whenever there's a trace
   context; HTTP request-log lines also carry a nested copy inside
   the `RequestLog` struct (one log path, not every line).

comparison/
 - gofr-vs-fiber: `@hourly` cron shorthand → `0 * * * *` (parser
   only takes 5/6-part specs).
 - gofr-vs-echo: removed false claim that route grouping is
   supported. Match migrate/from-echo wording (no `App.Group`).

migrate/
 - from-fiber: dropped `c.Set` / `c.Get` references — those methods
   don't exist on `*gofr.Context` (go build verified). Replacement:
   pass via closures, or use the embedded context.Context with
   WithValue / Value.
 - Fixed broken internal links across rails, aspnet-core, laravel,
   django-rest, fastapi, nestjs:
     /docs/advanced-guide/scaffolding-rest-server  → /docs/quick-start/add-rest-handlers
     /docs/advanced-guide/openapi-documentation     → /docs/advanced-guide/swagger-documentation
     /docs/advanced-guide/http-authentication       → /docs/advanced-guide/authentication
     /docs/advanced-guide/using-gofr-cli            → /docs/advanced-guide/building-cli-applications

references/
 - configs: `PUBSUB_BACKEND` value list trimmed to what the switch
   in pkg/gofr/container/container.go:145-154 actually handles
   (kafka / google / mqtt / redis); added a note that nats / sqs
   / eventhub are wired via `app.AddPubSub(...)`. Clarified that
   `NATS_SERVER` is a user-named convention, not a framework knob.
 - gofrcli: "Go 1.22 or above" → "Go 1.25" (matches gofr/go.mod:3).

why-gofr/
 - openapi.json belongs in `static/` (not `configs/`); served at
   `/.well-known/swagger` (not `/swagger`). Verified at
   pkg/gofr/swagger.go:67.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remaining low/medium-severity items the previous fix-batch deferred,
each verified against framework source:

Tier 1 (env-var coherence across quick-start flow):
- connecting-mysql + observability + configuration: HTTP_PORT=9000
  collided with the documented gRPC default (9000). Switched to
  HTTP_PORT=8000 (HTTP default) on the MySQL/observability pages
  and HTTP_PORT=8001 on the configuration page (the configuration
  page intentionally demos a non-default port, so 8001 keeps that
  contrast without colliding with the gRPC server).
- connecting-mysql + observability: REDIS_HOST/PORT example was
  inconsistent with the immediately-prior connecting-redis page —
  pasted as-is, it pointed to a non-existent localhost:6379 instead
  of the docker Redis on :2002 with password. Updated both .env
  examples to REDIS_PORT=2002 + REDIS_PASSWORD=password so 5→6→7
  copy-paste flow stays internally consistent.

Tier 2 (reference + datasource accuracy):
- references/configs: `DB_REPLICA_PASSWORDS_` typo (trailing
  underscore) → `DB_REPLICA_PASSWORDS`. Pattern matches the other
  replica vars (DB_REPLICA_HOSTS / DB_REPLICA_PORTS /
  DB_REPLICA_USERS) — verified by source pattern in
  pkg/gofr/datasource/dbresolver/factory.go.
- advanced-guide/building-cli-applications: prose said
  `app.NewCMD()`. The constructor is top-level: `gofr.NewCMD()`
  (verified pkg/gofr/factory.go:64-65). Code snippet in same page
  was already correct; only the prose was wrong (line 3 + line 45
  in the "Key GoFr CLI Methods" list).
- advanced-guide/graphql: curl examples used `localhost:9091`. The
  GraphQL endpoint is mounted on the same HTTP server (default
  port 8000); 9091 was a fabrication. Both examples updated.

Tier 3 (production-guide language polish):
- graceful-shutdown: the OnStart vs OnShutdown paragraph used
  `t.Cleanup` (a *testing.T method) as an analogy for production
  teardown — confusing in prod docs. Reworded to "context-cancel
  driven cleanup": derive a context from signal.NotifyContext,
  pass it into your goroutines, defer cleanup on cancellation.

Tier 4 (migration-page polish):
- from-django-rest, from-laravel, from-rails: every
  `app.AddRESTHandlers(&User{})` snippet now wraps the call in
  `if err := ...; err != nil { app.Logger().Fatal(err) }`.
  AddRESTHandlers returns error (verified `go build`) and silently
  ignoring it is poor hygiene to copy from a doc.

Things flagged but verified-CORRECT (left unchanged):
- WebSocket auto-reconnect in faq/page.md — verified at
  pkg/gofr/websocket.go:51-95 (AddWSService takes
  enableReconnection bool + handleReconnection goroutine).
- why-gofr customer claims (American Express / IBM / Walmart /
  Mydbops) — verified consistent with docs/showcase/companies.json,
  not fabricated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra and others added 2 commits May 3, 2026 03:10
Page-load sweep against the live overlay found 79/128 routes shipping
the default site title ("GoFr — An Opinionated Go Framework") and the
default meta description because those pages had never been given an
`nextjs.metadata` frontmatter block. Search engines saw a single mass
of identically-titled pages.

Backfilled per-page frontmatter on 53 pages (the remaining 26 stale
routes are website-side and handled in the website repo's commit):

- 28 pages under docs/advanced-guide/
- 16 pages under docs/datasources/ (and docs/datasources/migrations/)
- 5 pages under docs/quick-start/ (configuration / connecting-redis /
  connecting-mysql / observability / add-rest-handlers)
- 4 pages under docs/references/ (configs, context, gofrcli, testing)

Each page received:
- top-level `description` (140–160 chars, lead verb / topic)
- `nextjs.metadata.title` (≤ 65 chars, page-topic + GoFr)
- `nextjs.metadata.description` (mirrors the top-level)

Titles derived from each page's H1; descriptions from the first
substantive paragraph. No fabricated feature claims.

Also (small follow-ups from the same audit pass):

- docs/why-gofr/page.md, docs/faq/page.md,
  docs/comparison/gofr-vs-gin/page.md, docs/migrate/from-gin/page.md:
  trimmed descriptions over 160 chars to ≤160 (each was being
  truncated by Google).
- docs/quick-start/introduction/page.md and
  docs/advanced-guide/circuit-breaker/page.md: added an `{% answer %}`
  block at the top so AI engines (Perplexity, ChatGPT, Copilot) have
  a clean 2-3 sentence direct answer to quote.

The website-side counterpart commit:
- removes the duplicate <title> the docs layout was injecting from
  inside the React tree (single root cause for the doc pages losing
  their proper SEO title even after frontmatter was set)
- adds per-page `alternates.canonical` derivation to the Markdoc
  loader so every page emits a unique canonical URL
- adds CCBot + Bytespider stanzas to robots.txt
- backfills metadata on 23 /pkg/** redirect stubs and the cli/gofr
  page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- migrate pages: auto-initialised/initialises → auto-initialized/initializes
  (from-nestjs, from-echo, from-fastapi, from-chi, from-laravel)
- guides/db-migrations-in-cicd: organise → organize, organisation → organization

These slipped in with the previous metadata-backfill batch.
typos.toml uses en-us locale, so UK spellings break the gating CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aryanmehrotra aryanmehrotra reopened this May 3, 2026
@aryanmehrotra aryanmehrotra changed the title docs + ci: fix broken cross-links, stage/prod symmetric inline-refresh deploy docs + ci: fix broken cross-links, stage/prod symmetric inline-refresh deploy, new documentation May 3, 2026
@aryanmehrotra
aryanmehrotra requested a review from Umang01-hash May 3, 2026 18:11
The 18 production guides ship under /docs/guides/, but six of them
were still pointing readers at /docs/advanced-guide/<sibling> for
sibling guides (e.g. dockerizing-gofr-services, deploying-to-
kubernetes). Those URLs return 404 in production — silent dead-end
for a real reader, and lost link equity for SEO/AEO crawlers.

9 cross-links fixed across:
- deploying-to-kubernetes/page.md (3)
- cicd-recipes/page.md (1)
- dockerizing-gofr-services/page.md (1)
- multi-environment-deployment/page.md (1)
- production-prometheus-kubernetes/page.md (2)
- distributed-tracing/page.md (1)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aryanmehrotra
aryanmehrotra merged commit 6e0d51a into development May 4, 2026
20 checks passed
@aryanmehrotra
aryanmehrotra deleted the fix/doc-broken-links branch May 4, 2026 06:28
aryanmehrotra added a commit that referenced this pull request May 5, 2026
11 inline review comments on docs that already shipped via PR #3370 — each
verified against framework code before fixing. The remaining 2 Copilot
comments (CI workflow checkout strategy) are operational design points,
not content bugs, and are out of scope here.

Config loader filename pattern (3 docs)
- migrate/from-spring-boot, from-aspnet-core, from-django-rest:
  Pages claimed `configs/.env.production` (or `.env.staging`) as the
  override file. Verified in pkg/gofr/config/godotenv.go:60 — the
  loader reads `configs/.env` first then overlays
  `configs/.<APP_ENV>.env` (note the dot prefix and `.env` suffix
  on the override file). Reword each guide to match.

Error → status code (1 doc)
- migrate/from-flask: claimed `return nil, errSomething` is mapped to
  404 by GoFr. Verified in pkg/gofr/http/responder.go:135-138,211-214:
  only error types that implement `StatusCode() int` get a custom
  status; plain `error` returns 500. Update the bullet to point at
  `http.ErrorEntityNotFound` and the `StatusCode()` interface.

Response envelope (2 docs)
- migrate/from-express, from-gin: claimed "return a wrapper struct
  to control the envelope" preserves a raw JSON contract. Verified
  in pkg/gofr/http/responder.go:38-41 — only typed responses
  (`response.Raw`, `response.Response`) bypass or reshape the
  `{"data": ...}` wrapper; arbitrary structs are always wrapped.
  Recommend the typed responses explicitly.

Remote log-level (1 doc)
- faq: claimed log-level changes are exposed via "a built-in admin
  endpoint". Verified in pkg/gofr/logging/remotelogger/dynamic_level_logger.go:
  the logger polls `REMOTE_LOG_URL` and adjusts its level from the
  remote response — there is no admin endpoint on the GoFr service.
  Reword to say so.

pprof (1 doc)
- guides/load-testing: suggested adding `app.GET("/debug/pprof/profile",
  …)` on the HTTP server. Verified in pkg/gofr/metrics/handler.go:28-31:
  pprof handlers (Cmdline / Profile / Symbol / Trace) are already
  mounted on the metrics server. Tell readers to fetch from
  `:METRICS_PORT/debug/pprof/profile` instead.

Cron during shutdown (1 doc)
- guides/graceful-shutdown: claimed running cron tasks complete on
  shutdown. Verified in pkg/gofr/gofr.go's `App.Shutdown` — it drains
  HTTP/gRPC/metrics servers and closes datasources, but does not stop
  the cron scheduler. Cron jobs run with `context.Background()` and
  may be cut off at termination. Recommend separating long-running
  cron work into a Kubernetes `CronJob` if completion guarantees
  matter.

SQL pool metric names (1 doc)
- guides/connection-pooling: referenced active / idle gauges and
  suggested alerting on `idle == 0`. Verified in
  pkg/gofr/datasource/sql/sql.go: only `app_sql_open_connections`
  and `app_sql_inUse_connections` are exported. There is no idle
  gauge — idle is open − inUse if needed in PromQL. Reword to
  point at the real metric names.

TRACER_HOST deprecation (1 doc)
- comparison/gofr-vs-gin: docs mentioned `TRACER_HOST`. Verified in
  pkg/gofr/otel.go: the runtime logs a deprecation warning for
  `TRACER_HOST`/`TRACER_PORT` and instructs users to use
  `TRACER_URL`. Update the comparison snippet accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra added a commit that referenced this pull request May 5, 2026
11 inline review comments on docs that already shipped via PR #3370 — each
verified against framework code before fixing. The remaining 2 Copilot
comments (CI workflow checkout strategy) are operational design points,
not content bugs, and are out of scope here.

Config loader filename pattern (3 docs)
- migrate/from-spring-boot, from-aspnet-core, from-django-rest:
  Pages claimed `configs/.env.production` (or `.env.staging`) as the
  override file. Verified in pkg/gofr/config/godotenv.go:60 — the
  loader reads `configs/.env` first then overlays
  `configs/.<APP_ENV>.env` (note the dot prefix and `.env` suffix
  on the override file). Reword each guide to match.

Error → status code (1 doc)
- migrate/from-flask: claimed `return nil, errSomething` is mapped to
  404 by GoFr. Verified in pkg/gofr/http/responder.go:135-138,211-214:
  only error types that implement `StatusCode() int` get a custom
  status; plain `error` returns 500. Update the bullet to point at
  `http.ErrorEntityNotFound` and the `StatusCode()` interface.

Response envelope (2 docs)
- migrate/from-express, from-gin: claimed "return a wrapper struct
  to control the envelope" preserves a raw JSON contract. Verified
  in pkg/gofr/http/responder.go:38-41 — only typed responses
  (`response.Raw`, `response.Response`) bypass or reshape the
  `{"data": ...}` wrapper; arbitrary structs are always wrapped.
  Recommend the typed responses explicitly.

Remote log-level (1 doc)
- faq: claimed log-level changes are exposed via "a built-in admin
  endpoint". Verified in pkg/gofr/logging/remotelogger/dynamic_level_logger.go:
  the logger polls `REMOTE_LOG_URL` and adjusts its level from the
  remote response — there is no admin endpoint on the GoFr service.
  Reword to say so.

pprof (1 doc)
- guides/load-testing: suggested adding `app.GET("/debug/pprof/profile",
  …)` on the HTTP server. Verified in pkg/gofr/metrics/handler.go:28-31:
  pprof handlers (Cmdline / Profile / Symbol / Trace) are already
  mounted on the metrics server. Tell readers to fetch from
  `:METRICS_PORT/debug/pprof/profile` instead.

Cron during shutdown (1 doc)
- guides/graceful-shutdown: claimed running cron tasks complete on
  shutdown. Verified in pkg/gofr/gofr.go's `App.Shutdown` — it drains
  HTTP/gRPC/metrics servers and closes datasources, but does not stop
  the cron scheduler. Cron jobs run with `context.Background()` and
  may be cut off at termination. Recommend separating long-running
  cron work into a Kubernetes `CronJob` if completion guarantees
  matter.

SQL pool metric names (1 doc)
- guides/connection-pooling: referenced active / idle gauges and
  suggested alerting on `idle == 0`. Verified in
  pkg/gofr/datasource/sql/sql.go: only `app_sql_open_connections`
  and `app_sql_inUse_connections` are exported. There is no idle
  gauge — idle is open − inUse if needed in PromQL. Reword to
  point at the real metric names.

TRACER_HOST deprecation (1 doc)
- comparison/gofr-vs-gin: docs mentioned `TRACER_HOST`. Verified in
  pkg/gofr/otel.go: the runtime logs a deprecation warning for
  `TRACER_HOST`/`TRACER_PORT` and instructs users to use
  `TRACER_URL`. Update the comparison snippet accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aryanmehrotra added a commit that referenced this pull request May 5, 2026
11 inline review comments on docs that already shipped via PR #3370 — each
verified against framework code before fixing. The remaining 2 Copilot
comments (CI workflow checkout strategy) are operational design points,
not content bugs, and are out of scope here.

Config loader filename pattern (3 docs)
- migrate/from-spring-boot, from-aspnet-core, from-django-rest:
  Pages claimed `configs/.env.production` (or `.env.staging`) as the
  override file. Verified in pkg/gofr/config/godotenv.go:60 — the
  loader reads `configs/.env` first then overlays
  `configs/.<APP_ENV>.env` (note the dot prefix and `.env` suffix
  on the override file). Reword each guide to match.

Error → status code (1 doc)
- migrate/from-flask: claimed `return nil, errSomething` is mapped to
  404 by GoFr. Verified in pkg/gofr/http/responder.go:135-138,211-214:
  only error types that implement `StatusCode() int` get a custom
  status; plain `error` returns 500. Update the bullet to point at
  `http.ErrorEntityNotFound` and the `StatusCode()` interface.

Response envelope (2 docs)
- migrate/from-express, from-gin: claimed "return a wrapper struct
  to control the envelope" preserves a raw JSON contract. Verified
  in pkg/gofr/http/responder.go:38-41 — only typed responses
  (`response.Raw`, `response.Response`) bypass or reshape the
  `{"data": ...}` wrapper; arbitrary structs are always wrapped.
  Recommend the typed responses explicitly.

Remote log-level (1 doc)
- faq: claimed log-level changes are exposed via "a built-in admin
  endpoint". Verified in pkg/gofr/logging/remotelogger/dynamic_level_logger.go:
  the logger polls `REMOTE_LOG_URL` and adjusts its level from the
  remote response — there is no admin endpoint on the GoFr service.
  Reword to say so.

pprof (1 doc)
- guides/load-testing: suggested adding `app.GET("/debug/pprof/profile",
  …)` on the HTTP server. Verified in pkg/gofr/metrics/handler.go:28-31:
  pprof handlers (Cmdline / Profile / Symbol / Trace) are already
  mounted on the metrics server. Tell readers to fetch from
  `:METRICS_PORT/debug/pprof/profile` instead.

Cron during shutdown (1 doc)
- guides/graceful-shutdown: claimed running cron tasks complete on
  shutdown. Verified in pkg/gofr/gofr.go's `App.Shutdown` — it drains
  HTTP/gRPC/metrics servers and closes datasources, but does not stop
  the cron scheduler. Cron jobs run with `context.Background()` and
  may be cut off at termination. Recommend separating long-running
  cron work into a Kubernetes `CronJob` if completion guarantees
  matter.

SQL pool metric names (1 doc)
- guides/connection-pooling: referenced active / idle gauges and
  suggested alerting on `idle == 0`. Verified in
  pkg/gofr/datasource/sql/sql.go: only `app_sql_open_connections`
  and `app_sql_inUse_connections` are exported. There is no idle
  gauge — idle is open − inUse if needed in PromQL. Reword to
  point at the real metric names.

TRACER_HOST deprecation (1 doc)
- comparison/gofr-vs-gin: docs mentioned `TRACER_HOST`. Verified in
  pkg/gofr/otel.go: the runtime logs a deprecation warning for
  `TRACER_HOST`/`TRACER_PORT` and instructs users to use
  `TRACER_URL`. Update the comparison snippet accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
vikash pushed a commit that referenced this pull request Aug 11, 2026
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.

3 participants