Repository navigation
docs + ci: fix broken cross-links, stage/prod symmetric inline-refresh deploy, new documentation - #3370
Merged
Conversation
There was a problem hiding this comment.
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.
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
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>
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
force-pushed
the
fix/doc-broken-links
branch
from
May 1, 2026 13:14
2a1f1ba to
a39902a
Compare
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>
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>
…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>
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>
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>
Umang01-hash
approved these changes
May 4, 2026
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
…h deploy, new documentation (#3370)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three commits, one shipping unit:
../..paths breaking under no-trailing-slash URLs + a couple of one-offs. Fixed at the source. Repo-wide sweep confirms no remaining instances.docs/Dockerfileparametrized withARG WEBSITE_TAG=latest. Default works for any standalonedocker build.gofr-dev/websitemain, runyarn 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 frameworkv*.*.*tag automatically:gofr-dev/website(full history).yarn install+yarn refresh-data(withGITHUB_TOKEN).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
:stageimage. After feedback that cron was solving a non-problem (data freshness is naturally tied to deploys, not wall-clock time), removed both:developmentor click ofworkflow_dispatchis enough.publish_stagejob entirely.Test plan
website-stage.ymlsucceeds on the next push todevelopment—yarn refresh-dataruns cleanly withGITHUB_TOKENrate-limit, source-bundle build picks up the refreshed JSONs, kubectl rolls out with a unique image tag.website-prod.ymlsucceeds on the next GoFrv*.*.*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