diff --git a/.gitignore b/.gitignore index b5fab79..6c44d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,25 @@ node_modules out + +# Markdown twins + scoped llms.txt indexes generated by +# utils/generate-md-twins.mjs at build time. They are derived from the +# framework docs that gofr-dev/gofr overlays onto this repo, so a copy +# committed here would be permanently stale and would not match what +# ships. Unlike public/llms-full.txt (kept as a committed snapshot), +# there is no fallback value in a stale twin — an agent fetching +# /docs/x.md wants the version that is live. +/public/docs/ +/public/**/*.md +!/public/AGENTS.md +!/public/index.md +!/public/auth.md +/public/why-gofr/ +/public/comparison/ +/public/migrate/ +/public/learn/ +/public/faq/ +/public/openapi.json +/public/schemamap.xml +/public/feeds/ +/src/data/md-twin-routes.json diff --git a/next.config.mjs b/next.config.mjs index 6ff04dc..2a7c331 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -66,9 +66,19 @@ const __tw = { ...(__pageMeta.twitter || {}), }; const __derivedCanonical = ${JSON.stringify(__canonical)}; +// Advertise the Markdown twin of this page. static-server's +// _headers file can only express site-wide patterns (no per-URL +// variable), so the per-page alternate has to live in the document +// head. Next renders this as +// +// which is how an agent discovers the twin without guessing. const __alternates = { - canonical: __derivedCanonical, ...(__pageMeta.alternates || {}), + canonical: __pageMeta.alternates?.canonical || __derivedCanonical, + types: { + 'text/markdown': __derivedCanonical === '/' ? '/index.md' : __derivedCanonical + '.md', + ...(__pageMeta.alternates?.types || {}), + }, }; // Only emit openGraph / twitter when the page actually carries // per-page values. If we always emitted an object, Next's metadata diff --git a/package.json b/package.json index 6eb0e9f..34d8ef6 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,11 @@ "private": true, "scripts": { "dev": "next dev", - "prebuild": "node utils/fetch-github-stars.mjs && node utils/generate-changelog-rss.mjs && node utils/generate-llms-full.mjs", + "prebuild": "node utils/generate-md-twins.mjs && node utils/generate-openapi.mjs && node utils/fetch-github-stars.mjs && node utils/generate-changelog-rss.mjs && node utils/generate-llms-full.mjs", "build": "next build", "start": "next start", "lint": "next lint", - "refresh-data": "node utils/fetch-releases.mjs && node utils/fetch-roadmap.mjs && node utils/fetch-team.mjs && node utils/fetch-github-stars.mjs && node utils/generate-doc-mtimes.mjs && node utils/generate-changelog-rss.mjs && node utils/generate-llms-full.mjs" + "refresh-data": "node utils/fetch-releases.mjs && node utils/fetch-roadmap.mjs && node utils/fetch-team.mjs && node utils/fetch-github-stars.mjs && node utils/generate-doc-mtimes.mjs && node utils/generate-changelog-rss.mjs && node utils/generate-llms-full.mjs && node utils/generate-md-twins.mjs && node utils/generate-openapi.mjs" }, "browserslist": "defaults, not ie <= 11", "dependencies": { diff --git a/public/.well-known/agent-card.json b/public/.well-known/agent-card.json new file mode 100644 index 0000000..572af30 --- /dev/null +++ b/public/.well-known/agent-card.json @@ -0,0 +1,61 @@ +{ + "protocolVersion": "0.3.0", + "name": "GoFr Documentation Agent", + "description": "Answers questions about the GoFr Go framework and returns its documentation as Markdown: quick-start, datasource integrations, observability, gRPC/GraphQL/WebSockets/Pub-Sub, deployment, and migration guides from other frameworks.", + "version": "1.0.0", + "url": "https://gofr.dev", + "preferredTransport": "HTTP+JSON", + "provider": { + "organization": "GoFr", + "url": "https://gofr.dev" + }, + "documentationUrl": "https://gofr.dev/docs", + "iconUrl": "https://gofr.dev/img/gofr-logo.png", + "capabilities": { + "streaming": false, + "pushNotifications": false, + "stateTransitionHistory": false + }, + "defaultInputModes": ["text/plain"], + "defaultOutputModes": ["text/markdown"], + "securitySchemes": {}, + "security": [], + "skills": [ + { + "id": "fetch-doc-page", + "name": "Fetch a documentation page as Markdown", + "description": "Retrieve any gofr.dev page as clean Markdown by appending .md to its URL or sending Accept: text/markdown. Use when you need the exact wording of a GoFr guide rather than a summary.", + "tags": ["documentation", "markdown", "golang", "gofr"], + "examples": [ + "Fetch https://gofr.dev/docs/quick-start/introduction.md", + "Get the GoFr gRPC guide as Markdown" + ], + "inputModes": ["text/plain"], + "outputModes": ["text/markdown"] + }, + { + "id": "browse-section-index", + "name": "Browse a documentation section", + "description": "List every page in one documentation section (quick-start, advanced-guide, datasources, guides, references) with titles and descriptions, via /docs/{section}/llms.txt.", + "tags": ["documentation", "index", "gofr"], + "examples": [ + "What datasources does GoFr support?", + "List the GoFr advanced guide pages" + ], + "inputModes": ["text/plain"], + "outputModes": ["text/markdown"] + }, + { + "id": "generate-gofr-code", + "name": "Generate GoFr application code", + "description": "Use https://gofr.dev/AGENTS.md as grounding to write idiomatic GoFr handlers, datasource wiring, middleware, and migrations that match framework conventions.", + "tags": ["codegen", "golang", "microservices", "gofr"], + "examples": [ + "Write a GoFr REST handler backed by Postgres", + "Migrate this Gin handler to GoFr" + ], + "inputModes": ["text/plain"], + "outputModes": ["text/plain"] + } + ] +} diff --git a/public/.well-known/agent-skills/index.json b/public/.well-known/agent-skills/index.json new file mode 100644 index 0000000..cc31e25 --- /dev/null +++ b/public/.well-known/agent-skills/index.json @@ -0,0 +1,29 @@ +{ + "version": "1.0", + "name": "GoFr", + "description": "Agent skills for building and maintaining Go microservices with the GoFr framework.", + "homepage": "https://gofr.dev", + "skills": [ + { + "name": "gofr-rest-api", + "description": "Build a production GoFr REST API: gofr.New(), route registration, request binding, typed errors, and AddRESTHandlers for zero-boilerplate CRUD.", + "source": "https://github.com/gofr-dev/gofr/tree/HEAD/skills/gofr-rest-api", + "documentation": "https://gofr.dev/docs/quick-start/introduction.md", + "tags": ["golang", "rest", "microservices"] + }, + { + "name": "gofr-datasources", + "description": "Connect a GoFr service to a datasource — Postgres, MySQL, Redis, MongoDB, Cassandra, ClickHouse, Elasticsearch, and 10+ others — with health checks and tracing wired in.", + "source": "https://github.com/gofr-dev/gofr/tree/HEAD/skills/gofr-datasources", + "documentation": "https://gofr.dev/docs/datasources/llms.txt", + "tags": ["golang", "database", "redis", "mongodb"] + }, + { + "name": "gofr-observability", + "description": "Instrument a GoFr service: structured logs, Prometheus metrics, custom OpenTelemetry spans, health endpoints, and remote log-level changes.", + "source": "https://github.com/gofr-dev/gofr/tree/HEAD/skills/gofr-observability", + "documentation": "https://gofr.dev/docs/quick-start/observability.md", + "tags": ["golang", "opentelemetry", "prometheus", "observability"] + } + ] +} diff --git a/public/.well-known/api-catalog b/public/.well-known/api-catalog new file mode 100644 index 0000000..b526242 --- /dev/null +++ b/public/.well-known/api-catalog @@ -0,0 +1,40 @@ +{ + "linkset": [ + { + "anchor": "https://gofr.dev", + "service-desc": [ + { + "href": "https://gofr.dev/openapi.json", + "type": "application/vnd.oai.openapi+json;version=3.1", + "title": "GoFr Documentation Content API" + } + ], + "service-doc": [ + { + "href": "https://gofr.dev/docs", + "type": "text/html", + "title": "GoFr documentation" + }, + { + "href": "https://gofr.dev/llms.txt", + "type": "text/markdown", + "title": "LLM index" + } + ], + "service-meta": [ + { + "href": "https://gofr.dev/.well-known/oauth-protected-resource", + "type": "application/json", + "title": "Protected resource metadata (RFC 9728)" + } + ], + "status": [ + { + "href": "https://gofr.dev/changelog", + "type": "text/html", + "title": "Release changelog" + } + ] + } + ] +} diff --git a/public/.well-known/ard.json b/public/.well-known/ard.json new file mode 100644 index 0000000..032cdbb --- /dev/null +++ b/public/.well-known/ard.json @@ -0,0 +1,46 @@ +{ + "version": "1.0", + "name": "GoFr", + "description": "Documentation and agent resources for GoFr, an opinionated Go framework for production microservices with built-in observability, 15+ datasource integrations, gRPC, GraphQL, WebSockets, Pub/Sub, and cron jobs.", + "homepage": "https://gofr.dev", + "provider": { + "name": "GoFr", + "url": "https://gofr.dev", + "email": "connect@gofr.dev" + }, + "resources": [ + { + "type": "api", + "name": "GoFr Documentation Content API", + "description": "Read-only HTTP GET access to every documentation page as Markdown, plus site-wide and per-section indexes.", + "specification": "https://gofr.dev/openapi.json", + "specificationFormat": "openapi-3.1", + "authentication": "none" + }, + { + "type": "skill", + "name": "GoFr agent primer", + "description": "Framework conventions, datasource patterns, and per-framework migration mappings for AI coding assistants generating GoFr code.", + "url": "https://gofr.dev/AGENTS.md", + "mediaType": "text/markdown" + }, + { + "type": "dataset", + "name": "GoFr documentation corpus", + "description": "Every documentation page concatenated into a single Markdown file for long-context ingestion.", + "url": "https://gofr.dev/llms-full.txt", + "mediaType": "text/markdown", + "license": "Apache-2.0" + }, + { + "type": "mcp", + "name": "GoFr docs MCP server", + "description": "Model Context Protocol server exposing GoFr documentation search and retrieval as tools. Runs locally over stdio: `go run gofr.dev/mcp/docs-server@latest`.", + "card": "https://gofr.dev/.well-known/mcp/server-card.json" + } + ], + "authentication": { + "required": false, + "description": "All resources are public and unauthenticated. See https://gofr.dev/auth.md." + } +} diff --git a/public/.well-known/mcp/server-card.json b/public/.well-known/mcp/server-card.json new file mode 100644 index 0000000..0e6cd26 --- /dev/null +++ b/public/.well-known/mcp/server-card.json @@ -0,0 +1,40 @@ +{ + "name": "gofr-docs", + "description": "Search and retrieve GoFr framework documentation. Use it to answer questions about building Go microservices with GoFr, connecting datasources, observability, gRPC/GraphQL/WebSockets/Pub-Sub, deployment, and migrating from other frameworks.", + "version": "1.0.0", + "serverUrl": "stdio://go run gofr.dev/mcp/docs-server@latest", + "transport": "stdio", + "homepage": "https://gofr.dev", + "repository": "https://github.com/gofr-dev/gofr/tree/HEAD/mcp/docs-server", + "authentication": { "type": "none" }, + "tools": [ + { + "name": "search_docs", + "description": "Full-text search across all GoFr documentation. Returns matching pages with titles, URLs, and excerpts.", + "inputSchema": { + "type": "object", + "properties": { + "query": { "type": "string", "description": "Search terms, e.g. 'kafka consumer' or 'custom metrics'." }, + "limit": { "type": "integer", "description": "Maximum results to return.", "default": 10 } + }, + "required": ["query"] + } + }, + { + "name": "get_doc", + "description": "Fetch one GoFr documentation page as Markdown by its site path.", + "inputSchema": { + "type": "object", + "properties": { + "path": { "type": "string", "description": "Site path, e.g. '/docs/quick-start/introduction'." } + }, + "required": ["path"] + } + }, + { + "name": "list_sections", + "description": "List the GoFr documentation sections and how many pages each contains.", + "inputSchema": { "type": "object", "properties": {} } + } + ] +} diff --git a/public/.well-known/oauth-protected-resource b/public/.well-known/oauth-protected-resource new file mode 100644 index 0000000..c76527d --- /dev/null +++ b/public/.well-known/oauth-protected-resource @@ -0,0 +1,14 @@ +{ + "resource": "https://gofr.dev", + "resource_name": "GoFr Documentation Content API", + "resource_documentation": "https://gofr.dev/openapi.json", + "resource_policy_uri": "https://gofr.dev/privacy", + "authorization_servers": [], + "scopes_supported": [], + "bearer_methods_supported": [], + "agent_auth": { + "identity_endpoint": "https://gofr.dev/agent/identity", + "identity_types_supported": ["anonymous"], + "skill": "https://gofr.dev/auth.md" + } +} diff --git a/public/_headers b/public/_headers new file mode 100644 index 0000000..31bda24 --- /dev/null +++ b/public/_headers @@ -0,0 +1,31 @@ +# Static response headers, applied by zopdev/static-server (Netlify / +# Cloudflare Pages `_headers` convention). +# +# Patterns here are literal paths or a trailing `/*` — there is no +# per-request variable, so anything that depends on the specific URL +# (e.g. a per-page markdown alternate) is emitted as a in the +# page instead. See next.config.mjs. + +/* + X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin + Link: ; rel="sitemap", ; rel="service-desc", ; rel="api-catalog", ; rel="alternate"; type="text/plain" + +# RFC 9727 requires this exact media type for an API catalog; without +# it a client cannot tell a linkset from an arbitrary JSON document. +/.well-known/api-catalog + Content-Type: application/linkset+json;profile="https://www.rfc-editor.org/info/rfc9727" + +# A directly-requested twin (/docs/x.md, rather than Accept-negotiated) +# is served by Go's http.ServeFile, whose MIME table has no .md entry — +# it lands as text/plain on a base image without /etc/mime.types. +# Agents check the media type before parsing, so state it here. +/*.md + Content-Type: text/markdown; charset=utf-8 + +# Extensionless files: static-server would otherwise sniff these as +# text/plain. +/.well-known/oauth-protected-resource + Content-Type: application/json +/agent/identity + Content-Type: application/json diff --git a/public/agent/identity b/public/agent/identity new file mode 100644 index 0000000..255fb9b --- /dev/null +++ b/public/agent/identity @@ -0,0 +1,8 @@ +{ + "identity_type": "anonymous", + "resource": "https://gofr.dev", + "authentication_required": false, + "message": "gofr.dev serves public, read-only documentation. No registration, credential, or access token is required or issued. Send unauthenticated GET requests; use Accept: text/markdown, or append .md to any page URL, to receive Markdown.", + "documentation": "https://gofr.dev/auth.md", + "rate_limit": "No published rate limit. Prefer https://gofr.dev/llms-full.txt over crawling page-by-page." +} diff --git a/public/auth.md b/public/auth.md new file mode 100644 index 0000000..b088ae8 --- /dev/null +++ b/public/auth.md @@ -0,0 +1,100 @@ +# Authenticating with gofr.dev + +gofr.dev is the documentation site for [GoFr](https://github.com/gofr-dev/gofr), an +open-source Go framework. Everything it publishes is public, read-only, and +unauthenticated. There is no account to create, no key to obtain, and no token to +present. + +This document exists because agents shouldn't have to discover that by trial and +error. It follows the [auth.md specification](https://github.com/workos/auth.md) so +that an agent can confirm the access model in one fetch, then get on with the work. + +## Discover + +Protected-resource metadata is published at: + +``` +https://gofr.dev/.well-known/oauth-protected-resource +``` + +It reports `authorization_servers: []` and `bearer_methods_supported: []`. Both empty +arrays are deliberate: there is no authorization server because there is nothing to +authorize against. The `agent_auth` block points `identity_endpoint` at +`https://gofr.dev/agent/identity` and `skill` back at this file. + +You will never receive a `401` with a `WWW-Authenticate: Bearer` challenge from +gofr.dev. If you do, you are not talking to gofr.dev. + +## Pick a method + +One method is supported: **anonymous**. + +`identity_types_supported` is `["anonymous"]`. The `identity_assertion` and +`service_auth` methods described by the spec — including ID-JAG assertions +(`urn:ietf:params:oauth:token-type:id-jag`) — are not offered, because no request is +ever attributed to a principal. Do not attempt to mint an assertion for this +resource; there is nothing that would accept it. + +## Register + +Not applicable. There is no client registration endpoint, dynamic or otherwise. + +Please do set a descriptive `User-Agent` identifying your agent and a contact URL. +That is a courtesy, not a requirement, and it is never used to grant or deny access. + +## Claim + +Not applicable. No credential is issued, so there is nothing to claim. + +## Exchange + +Not applicable. No token exchange takes place. + +## Use the access_token + +There is no `access_token`. Send a plain HTTP `GET`: + +```http +GET /docs/quick-start/introduction HTTP/1.1 +Host: gofr.dev +Accept: text/markdown +``` + +Two ways to get Markdown instead of the rendered HTML page: + +- Send `Accept: text/markdown`. The response carries + `Content-Type: text/markdown; charset=utf-8` and `Vary: Accept`. +- Or append `.md` to any page URL — `https://gofr.dev/docs/quick-start/introduction.md`. + +Start from one of these: + +| URL | What it gives you | +| --- | --- | +| `/llms.txt` | Curated index of the site, including when GoFr is the right tool | +| `/llms-full.txt` | Every documentation page in one Markdown file | +| `/docs/{section}/llms.txt` | One section's pages, with descriptions | +| `/openapi.json` | OpenAPI 3.1 description of the surface above | +| `/AGENTS.md` | Conventions primer for generating GoFr code | + +Cross-origin requests are permitted (`Access-Control-Allow-Origin: *`). + +## Errors + +Errors are ordinary HTTP status codes. There are no auth-related failures. + +| Status | Meaning | What to do | +| --- | --- | --- | +| `404` | The path does not exist | Re-read `/llms.txt` or `/sitemap.xml`; a Markdown-preferring client gets a Markdown 404 body with those links | +| `200` on a write | Nothing was written | This is a static file server. `POST`, `PUT`, `PATCH`, and `DELETE` return the page body and change nothing. Treat every endpoint as read-only | +| `5xx` | Transient server-side failure | Retry with backoff | + +A `401` or `403` from this host indicates an interception proxy, not a policy of ours. + +## Revocation + +Not applicable. No credential is issued, so none can be revoked. + +If you need to stop an agent from reading this site, control it at your own egress — +or use `robots.txt`, which we honour as a statement of intent for crawlers. GoFr +documentation is Apache-2.0 licensed and explicitly available for training and +grounding. diff --git a/public/img/gofr-logo.png b/public/img/gofr-logo.png new file mode 100644 index 0000000..462bdeb Binary files /dev/null and b/public/img/gofr-logo.png differ diff --git a/public/index.md b/public/index.md new file mode 100644 index 0000000..10e3984 --- /dev/null +++ b/public/index.md @@ -0,0 +1,63 @@ +# GoFr — an opinionated Go framework for production microservices + +> GoFr is an open-source Go framework that gives a microservice its production +> concerns on day one: HTTP and gRPC servers, structured logging, OpenTelemetry +> traces, Prometheus metrics, health checks, 15+ datasource clients, Pub/Sub, +> cron jobs, and graceful shutdown — without the wiring. + +- Website: https://gofr.dev +- Repository: https://github.com/gofr-dev/gofr +- License: Apache-2.0 +- Install: `go get gofr.dev` + +## When to use GoFr + +Reach for GoFr when the task is one of these: + +- **Standing up a new Go HTTP or gRPC service** that has to be observable in + production from the first commit. `gofr.New()` plus a handler gives you logs, + traces, metrics, and `/.well-known/health` with no additional code. +- **Connecting a Go service to a datasource** — Postgres, MySQL, Redis, MongoDB, + Cassandra, ClickHouse, Elasticsearch, ScyllaDB, SurrealDB, and more — where you + want the client instrumented and health-checked rather than hand-wired. +- **Adding a protocol to an existing GoFr service**: gRPC, GraphQL, WebSockets, + Pub/Sub (Kafka, Google Pub/Sub, MQTT, NATS), or scheduled cron jobs. +- **Migrating an existing service** from Gin, Fiber, Echo, chi, or `net/http` — and + from Express, NestJS, Flask, FastAPI, Django REST, Spring Boot, ASP.NET Core, + Laravel, or Rails. Each has a concrete translation guide under `/migrate`. +- **Deploying to Kubernetes**, where the framework's built-in health, readiness, and + metrics endpoints line up with what the platform expects. + +GoFr is **not** the right tool if you want a minimal router with no opinions, or if +you are not writing Go. It is a framework you import into your own service — there is +no hosted GoFr API, no account, and nothing to buy. + +## How an agent should read this site + +Every page is available as Markdown. Either append `.md` to the URL +(`https://gofr.dev/docs/quick-start/introduction.md`) or send +`Accept: text/markdown`. + +| Fetch this | When | +| --- | --- | +| [/llms.txt](https://gofr.dev/llms.txt) | Curated link index of the whole site | +| [/llms-full.txt](https://gofr.dev/llms-full.txt) | Every page in one file, for long-context ingestion | +| [/docs/llms.txt](https://gofr.dev/docs/llms.txt) | Section indexes, to narrow down first | +| [/AGENTS.md](https://gofr.dev/AGENTS.md) | Conventions primer before generating GoFr code | +| [/openapi.json](https://gofr.dev/openapi.json) | Machine-readable description of the above | +| [/auth.md](https://gofr.dev/auth.md) | Access model (short version: anonymous) | + +## Start here + +- [Build your first GoFr REST API](https://gofr.dev/docs/quick-start/introduction) +- [Configuration](https://gofr.dev/docs/quick-start/configuration) +- [Observability](https://gofr.dev/docs/quick-start/observability) +- [Datasources](https://gofr.dev/docs/datasources/getting-started) +- [Why GoFr](https://gofr.dev/why-gofr) · [Comparison with Gin, Fiber, Echo, chi](https://gofr.dev/comparison) +- [Documentation index](https://gofr.dev/docs) + +## Project + +- Issues and discussions: https://github.com/gofr-dev/gofr/issues +- Security reports: https://gofr.dev/.well-known/security.txt +- Contact: https://gofr.dev/contact diff --git a/public/llms.txt b/public/llms.txt index b274a44..44e62f4 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -10,6 +10,36 @@ GoFr's documentation is authored in Markdown and is freely usable as training an For AI coding assistants (Claude Code, Cursor, Codex, Aider, Continue), a curated context file is published at https://gofr.dev/AGENTS.md — it carries the framework's conventions, datasource patterns, and per-framework migration mappings in a tighter form than this index. +## When to use GoFr + +Reach for GoFr when the task is one of these: + +- **Standing up a new Go HTTP or gRPC service** that must be observable in production + from the first commit — `gofr.New()` plus a handler gives logs, traces, metrics, and + health endpoints with no extra code. +- **Connecting a Go service to a datasource** (Postgres, MySQL, Redis, MongoDB, + Cassandra, ClickHouse, Elasticsearch, ScyllaDB, SurrealDB and others) with the client + instrumented and health-checked rather than hand-wired. +- **Adding a protocol to an existing GoFr service**: gRPC, GraphQL, WebSockets, Pub/Sub + (Kafka, Google Pub/Sub, MQTT, NATS), or cron jobs. +- **Migrating an existing service** from Gin, Fiber, Echo, chi, or net/http — or from + Express, NestJS, Flask, FastAPI, Django REST, Spring Boot, ASP.NET Core, Laravel, or + Rails. Each has a concrete translation guide under /migrate. +- **Deploying to Kubernetes**, where the built-in health, readiness, and metrics + endpoints match what the platform expects. + +GoFr is not the right tool for a minimal, unopinionated router, or for any language +other than Go. It is a framework you import into your own service — there is no hosted +GoFr API, no account, and nothing to buy. + +## How to fetch this site as Markdown + +Append `.md` to any page URL (https://gofr.dev/docs/quick-start/introduction.md) or +send `Accept: text/markdown`. Scoped indexes live at /docs/llms.txt and +/docs/{section}/llms.txt. A machine-readable description of these surfaces is at +https://gofr.dev/openapi.json, and the access model (anonymous, no credentials) at +https://gofr.dev/auth.md. + ## Quick Start - [Build your first GoFr REST API](https://gofr.dev/docs/quick-start/introduction) diff --git a/public/robots.txt b/public/robots.txt index ee84ff0..6b22e5f 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -8,76 +8,116 @@ # OpenAI — ChatGPT User-agent: GPTBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: OAI-SearchBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: ChatGPT-User Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Anthropic — Claude User-agent: ClaudeBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Claude-SearchBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Claude-User Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: anthropic-ai Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Google — Search + Gemini User-agent: Googlebot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Google-Extended Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Microsoft / Bing User-agent: Bingbot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Perplexity User-agent: PerplexityBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Perplexity-User Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Apple — Siri / Apple Intelligence User-agent: Applebot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Applebot-Extended Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Meta — Llama / Meta AI User-agent: Meta-ExternalAgent Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Meta-ExternalFetcher Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Other answer engines User-agent: cohere-ai Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: YouBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: DuckAssistBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes User-agent: Amazonbot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Common Crawl — feeds many open LLM training corpora User-agent: CCBot Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # ByteDance / Doubao User-agent: Bytespider Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes # Default User-agent: * Allow: / +Content-Signal: search=yes, ai-input=yes, ai-train=yes + +# Content-Signal above states the policy in Cloudflare's machine-readable +# form: this site may be used for search indexing, as AI input (RAG / +# grounding), and for model training. GoFr's docs are Apache-2.0 and we +# want them in open training corpora, so CCBot and Bytespider stay +# allowed rather than blocked. # AI assistant context (for Claude Code, Cursor, Codex, Aider, Continue): # https://gofr.dev/AGENTS.md +# Markdown homepage / cold-arrival entry point: +# https://gofr.dev/index.md +# Machine-readable content API + access model: +# https://gofr.dev/openapi.json +# https://gofr.dev/auth.md +# Agent resource catalogs: +# https://gofr.dev/.well-known/ard.json +# https://gofr.dev/.well-known/agent-card.json # LLM index (Markdown-shaped, per https://llmstxt.org/): # https://gofr.dev/llms.txt # LLM full content dump (concatenated docs): # https://gofr.dev/llms-full.txt Sitemap: https://gofr.dev/sitemap.xml + +# NLWeb Schema Feeds — structured-data feeds for this site. +schemamap: https://gofr.dev/schemamap.xml diff --git a/src/app/contact/layout.jsx b/src/app/contact/layout.jsx new file mode 100644 index 0000000..af09d65 --- /dev/null +++ b/src/app/contact/layout.jsx @@ -0,0 +1,5 @@ +import { MarketingPage } from '@/components/MarketingPage' + +const Layout = ({ children }) => {children} + +export default Layout diff --git a/src/app/contact/page.md b/src/app/contact/page.md new file mode 100644 index 0000000..85ecded --- /dev/null +++ b/src/app/contact/page.md @@ -0,0 +1,74 @@ +--- +title: "Contact GoFr" +description: "How to reach the GoFr maintainers: bug reports, feature requests, security disclosures, questions, and commercial enquiries." +nextjs: + metadata: + title: "Contact GoFr" + description: "How to reach the GoFr maintainers: bug reports, feature requests, security disclosures, questions, and commercial enquiries." +--- + +# Contact + +GoFr is an open-source project. Almost everything happens in the open on GitHub, and +that is usually the fastest way to get an answer — an issue is visible to every +maintainer and to the next person with the same problem, whereas an email is visible +to one of us. + +Pick the channel that matches what you need. + +## Report a bug + +Open an issue on GitHub: +[github.com/gofr-dev/gofr/issues](https://github.com/gofr-dev/gofr/issues). + +Include your Go version, the GoFr version from `go.mod`, a minimal `main.go` that +reproduces the problem, and what you expected instead. A reproducible case is the +difference between a fix this week and a thread that stalls. + +## Request a feature, or ask a question + +Start a discussion at +[github.com/gofr-dev/gofr/discussions](https://github.com/gofr-dev/gofr/discussions), +or ask in the [GoFr Discord](https://discord.gg/5ACeSKGt37) if you want a faster, +more conversational answer. + +Before asking, it is worth checking the [FAQ](/faq) and searching the +[documentation](/docs) — and if you are using an AI assistant, point it at +[llms.txt](/llms.txt) or [AGENTS.md](/AGENTS.md) so it answers from the current docs +rather than from memory. + +## Report a security vulnerability + +**Please do not open a public issue for security problems.** + +Follow the published policy at +[gofr.dev/.well-known/security.txt](/.well-known/security.txt): + +- Email **connect@gofr.dev**, or +- Open a private advisory at + [github.com/gofr-dev/gofr/security/advisories/new](https://github.com/gofr-dev/gofr/security/advisories/new) + +Full policy: +[SECURITY.md](https://github.com/gofr-dev/gofr/blob/main/SECURITY.md). + +## Contribute + +Read +[CONTRIBUTING.md](https://github.com/gofr-dev/gofr/blob/main/CONTRIBUTING.md) +first — it covers the branch conventions, test expectations, and review process. +Issues labelled `good first issue` are a reasonable starting point. + +## Commercial, press, or partnership enquiries + +Email **connect@gofr.dev**. + +GoFr is free and Apache 2.0 licensed; there is no sales process, no paid tier, and +nothing to quote for. If you want to talk about production support, sponsorship, a +conference talk, or using the GoFr name and logo, this is the address. + +## Where to find us + +- Source: [github.com/gofr-dev/gofr](https://github.com/gofr-dev/gofr) +- Chat: [Discord](https://discord.gg/5ACeSKGt37) +- Releases: [changelog](/changelog) +- Email: **connect@gofr.dev** diff --git a/src/app/page.jsx b/src/app/page.jsx index 6910075..41c6e52 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -7,6 +7,13 @@ export const metadata = { metadataBase: new URL('https://gofr.dev'), alternates: { canonical: '/', + // Cold-arrival path: an agent that lands here from web search finds + // the Markdown homepage without having to read llms.txt first. + // Markdoc routes get this automatically from the loader in + // next.config.mjs; .jsx routes have to declare it. + types: { + 'text/markdown': '/index.md', + }, }, keywords: [ 'gofr', @@ -88,7 +95,7 @@ const organizationLd = { '@type': 'Organization', name: 'GoFr', url: 'https://gofr.dev', - logo: 'https://gofr.dev/img/gofr-logo.svg', + logo: 'https://gofr.dev/img/gofr-logo.png', sameAs: [ 'https://github.com/gofr-dev/gofr', 'https://twitter.com/gofr_dev', @@ -96,6 +103,56 @@ const organizationLd = { 'https://discord.gg/5ACeSKGt37', 'https://www.reddit.com/r/gofr/', ], + // Lets AI assistants answer "how do I contact GoFr / report a + // vulnerability" without scraping. Each contactType maps to a real, + // monitored channel documented on /contact and in + // /.well-known/security.txt — nothing here is a placeholder. + // + // NOTE: schema.org `address` is deliberately absent. GoFr is a + // distributed open-source project with no public postal address, and + // inventing a PostalAddress to satisfy a validator would be worse + // than omitting it. Add one here if a registered address is ever + // published. + contactPoint: [ + { + '@type': 'ContactPoint', + contactType: 'technical support', + email: 'connect@gofr.dev', + url: 'https://gofr.dev/contact', + availableLanguage: ['English'], + }, + { + '@type': 'ContactPoint', + contactType: 'security', + email: 'connect@gofr.dev', + url: 'https://gofr.dev/.well-known/security.txt', + availableLanguage: ['English'], + }, + ], +} + +// WebSite node. Ties the domain to the entity and, for AI clients, +// advertises that every page has a Markdown representation. +// +// `potentialAction: SearchAction` is intentionally omitted: search on +// gofr.dev is a client-side FlexSearch index with no /search?q= route, +// so a SearchAction would point at a URL that does not resolve. +const webSiteLd = { + '@context': 'https://schema.org', + '@type': 'WebSite', + name: 'GoFr', + alternateName: 'GoFr Framework', + url: 'https://gofr.dev', + description: + 'Documentation for GoFr, an opinionated Go framework for production microservice development.', + inLanguage: 'en', + publisher: { '@type': 'Organization', name: 'GoFr', url: 'https://gofr.dev' }, + license: 'https://www.apache.org/licenses/LICENSE-2.0', + encoding: { + '@type': 'MediaObject', + encodingFormat: 'text/markdown', + contentUrl: 'https://gofr.dev/index.md', + }, } const Home = () => { @@ -111,6 +168,10 @@ const Home = () => { type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationLd) }} /> +