diff --git a/.gitignore b/.gitignore index e47157d4db..6e290fb25f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ npm-debug.log* yarn-debug.log* yarn-error.log* /.claude +.vs diff --git a/docs/authors.json b/docs/authors.json index ac9f094f0d..b3fb1967ae 100644 --- a/docs/authors.json +++ b/docs/authors.json @@ -1,14 +1,14 @@ { "Paweł Lachowski": { "name": "Paweł Lachowski", - "title": "Technical Writer @ RavenDB", + "job_title": "Technical Writer", "url": null, "image_url": "https://ravendb.net/wp-content/uploads/2024/11/Default-author-thumbnail-150x150.png", "socials": {} }, "Omer Ratsaby": { "name": "Omer Ratsaby", - "title": "DevOps Engineer @ RavenDB", + "job_title": "DevOps Engineer", "url": null, "image_url": "https://ravendb.net/wp-content/uploads/2024/11/Default-author-thumbnail-150x150.png", "socials": {} diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 70b785905e..6676ccfb63 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -108,6 +108,16 @@ const config: Config = { showLastUpdateTime: true, }, ], + [ + "@docusaurus/plugin-ideal-image", + { + max: 1200, + min: 640, + steps: 3, + quality: 85, + disableInDev: false, + }, + ], require.resolve("./src/plugins/recent-guides-plugin"), ], themeConfig: { @@ -122,6 +132,21 @@ const config: Config = { }, image: "img/social-card.jpg", headTags: [ + { + tagName: "link", + attributes: { + rel: "preconnect", + href: "https://GYTCYX561T-dsn.algolia.net", + crossorigin: "anonymous", + }, + }, + { + tagName: "link", + attributes: { + rel: "preconnect", + href: "https://www.googletagmanager.com", + }, + }, { tagName: "link", attributes: { @@ -225,6 +250,10 @@ const config: Config = { property: "og:image:height", content: "630", }, + { + property: "og:image:alt", + content: "RavenDB Documentation", + }, ], colorMode: { defaultMode: "dark", diff --git a/guides/ai-image-search-with-ravendb.mdx b/guides/ai-image-search-with-ravendb.mdx index 6cc7fe97ef..59ff6571b3 100644 --- a/guides/ai-image-search-with-ravendb.mdx +++ b/guides/ai-image-search-with-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about AI Image Search with RavenDB on the RavenDB.net news se externalUrl: "https://ravendb.net/articles/ai-image-search-with-ravendb" publishedAt: 2025-09-09 icon: "ai" +proficiencyLevel: "Expert" --- diff --git a/guides/begin-analysis-with-olap-etl.mdx b/guides/begin-analysis-with-olap-etl.mdx index 6cff8ecfb9..328e74d7b4 100644 --- a/guides/begin-analysis-with-olap-etl.mdx +++ b/guides/begin-analysis-with-olap-etl.mdx @@ -5,5 +5,6 @@ description: "Read about Begin Analysis with OLAP ETL on the RavenDB.net news se externalUrl: "https://ravendb.net/articles/begin-analysis-with-olap-etl" publishedAt: 2025-12-22 image: "https://ravendb.net/wp-content/uploads/2025/12/OLAP-article-image.svg" +proficiencyLevel: "Expert" --- diff --git a/guides/building-a-beer-vending-machine-program-with-ravendb-embedded-server.mdx b/guides/building-a-beer-vending-machine-program-with-ravendb-embedded-server.mdx index 28ffef2854..01d2dfd14a 100644 --- a/guides/building-a-beer-vending-machine-program-with-ravendb-embedded-server.mdx +++ b/guides/building-a-beer-vending-machine-program-with-ravendb-embedded-server.mdx @@ -5,5 +5,6 @@ description: "Read about Building a Beer Vending Machine with RavenDB Embedded o externalUrl: "https://ravendb.net/articles/building-a-beer-vending-machine-program-with-ravendb-embedded-server" publishedAt: 2025-12-23 image: "https://ravendb.net/wp-content/uploads/2024/11/article-beer-2.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/connecting-c-application-to-ravendb-cloud.mdx b/guides/connecting-c-application-to-ravendb-cloud.mdx index a86422016f..7b4e88c0a2 100644 --- a/guides/connecting-c-application-to-ravendb-cloud.mdx +++ b/guides/connecting-c-application-to-ravendb-cloud.mdx @@ -5,4 +5,5 @@ description: "Read about Connecting C# application to RavenDB Cloud on the Raven externalUrl: "https://ravendb.net/articles/connecting-c-application-to-ravendb-cloud" publishedAt: 2025-02-25 image: "https://ravendb.net/wp-content/uploads/2025/01/connecting-c-application-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/connecting-node-js-application-to-ravendb-cloud.mdx b/guides/connecting-node-js-application-to-ravendb-cloud.mdx index 4f223f94a4..57e044d41d 100644 --- a/guides/connecting-node-js-application-to-ravendb-cloud.mdx +++ b/guides/connecting-node-js-application-to-ravendb-cloud.mdx @@ -5,4 +5,5 @@ description: "Read about Connecting Node.js application to RavenDB Cloud on the externalUrl: "https://ravendb.net/articles/connecting-node-js-application-to-ravendb-cloud" publishedAt: 2025-02-25 image: "https://ravendb.net/wp-content/uploads/2025/01/connecting-nodejs-to-ravendb-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/connecting-node-js-web-application-to-ravendb.mdx b/guides/connecting-node-js-web-application-to-ravendb.mdx index 5ee4004426..8cb195a14e 100644 --- a/guides/connecting-node-js-web-application-to-ravendb.mdx +++ b/guides/connecting-node-js-web-application-to-ravendb.mdx @@ -5,4 +5,5 @@ description: "Read about Connecting Node.JS web application to RavenDB on the Ra externalUrl: "https://ravendb.net/articles/connecting-node-js-web-application-to-ravendb" publishedAt: 2025-02-25 image: "https://ravendb.net/wp-content/uploads/2024/12/NodeJS-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/deploying-ravendb-with-helm-chart.mdx b/guides/deploying-ravendb-with-helm-chart.mdx index 2356d2f254..70cd92656a 100644 --- a/guides/deploying-ravendb-with-helm-chart.mdx +++ b/guides/deploying-ravendb-with-helm-chart.mdx @@ -5,4 +5,5 @@ description: "Read about Deploying RavenDB with Helm Chart on the RavenDB.net ne externalUrl: "https://ravendb.net/articles/deploying-ravendb-with-helm-chart" publishedAt: 2025-11-18 image: "https://ravendb.net/wp-content/uploads/2025/05/helm-chart-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/diacritic-sensitive-search-in-ravendb.mdx b/guides/diacritic-sensitive-search-in-ravendb.mdx index b8b81844cf..4d8bcbeb00 100644 --- a/guides/diacritic-sensitive-search-in-ravendb.mdx +++ b/guides/diacritic-sensitive-search-in-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about Diacritic-Sensitive Search in RavenDB on the RavenDB.ne externalUrl: "https://ravendb.net/articles/diacritic-sensitive-search-in-ravendb" publishedAt: 2025-05-09 image: "https://ravendb.net/wp-content/uploads/2025/05/diacritic-sensitive-article.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/dynamic-fields.mdx b/guides/dynamic-fields.mdx index 7ceb16e9cb..93ab001595 100644 --- a/guides/dynamic-fields.mdx +++ b/guides/dynamic-fields.mdx @@ -5,5 +5,6 @@ description: "Read about Dynamic Fields in RavenDB on the RavenDB.net news secti externalUrl: "https://ravendb.net/articles/dynamic-fields" publishedAt: 2024-10-28 image: "https://ravendb.net/wp-content/uploads/2024/10/dynamic-fields-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/embeddings-generation-with-ravendb.mdx b/guides/embeddings-generation-with-ravendb.mdx index 746332bcf7..f66cecc699 100644 --- a/guides/embeddings-generation-with-ravendb.mdx +++ b/guides/embeddings-generation-with-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about Embeddings Generation with RavenDB on the RavenDB.net n externalUrl: "https://ravendb.net/articles/embeddings-generation-with-ravendb" publishedAt: 2025-03-31 image: "https://ravendb.net/wp-content/uploads/2025/03/ai-search-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/employing-data-archival-guide.mdx b/guides/employing-data-archival-guide.mdx index f4e26e6891..0966ceda22 100644 --- a/guides/employing-data-archival-guide.mdx +++ b/guides/employing-data-archival-guide.mdx @@ -6,6 +6,7 @@ image: "https://ravendb.net/wp-content/uploads/2025/10/employing-data-archival-a publishedAt: 2025-11-17 description: "How to set up and use data archival in RavenDB" author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; @@ -14,6 +15,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; Let’s say you’re building an invoice processing system. When you first set up your database during development, everything feels great. Routines start storing invoices as documents, and indexes work flawlessly, allowing queries to be processed quickly. The entire system feels smooth and responsive. @@ -37,9 +39,8 @@ from index "InvoicesByIssueDate" where issue_date >= "2025-06-25T10:21:56.1500Z" A query (not so complex) alone took over 1200ms. Exploring the data by the user takes a lot of time, reducing the quality of service and making interacting with your application frustrating. -![](./assets/archival1.png) -![](./assets/archival2.png) - + + Not mentioning overhead of the rest of the system. Forget about instant filtering \- you’re indexing all of the data, even though your users don’t care about the old stuff. This creates a huge problem as all those files from seven years ago are still being viewed and filtered during the query. @@ -62,8 +63,7 @@ To trigger this feature, you can take one of two approaches: from code or the st **If you’re using RavenDB Cloud,** make sure to enable Data Archival in the Product Features section before continuing. -![](./assets/archival3.png) - + To enable and trigger data archival from your application, we need to define which collection should be archived and set up the archival configuration. That’s how we do that: ```csharp showLineNumbers @@ -101,8 +101,7 @@ Or we can trigger it from the studio easily, we just need to: 4. Optionally, toggle to customize the maximum number of documents the archiving task will process in a single run. 5. Click Save to apply your settings. -![](./assets/archival4.png) - + But this is only the beginning. We have only triggered our archival, but now we need to tell RavenDB which files we want to archive. ## Sorting Through the Piles: Choosing What to Archive @@ -125,8 +124,7 @@ update { This code calculates our gap 90 days from the `issue_date` of each file. Then it converts it to an ISO string, allowing us to use and archive it using this calculated value. RavenDB will process all documents in the Invoices collection. -![](./assets/archival5.png) - + Alternatively, we can do it with patchByQuery from code: ```csharp showLineNumbers @@ -181,16 +179,13 @@ using (var session = store.OpenSession()) How does archival affect this problem? After setting up the archival, documents only 90 days old or newer will be made available by default for all indexes. Because indexes are interconnected with other parts of the system, this affects your whole system. After archiving our files, changes are made to the metadata. -![](./assets/archival6.png) - + And the index becomes smaller, containing fewer files. -![](./assets/archival7.png) - + This will affect queries by reducing the time they need to search through data. After all, a big part of the documents isn’t in the indexes. -![](./assets/archival8.png) - + Query performance improved, but the data is still in the database. Perfect of two worlds. ## Archive behaviour @@ -201,12 +196,10 @@ When you have archival enabled during index creation, you can choose the behavio In indexes, you do that at the bottom of the index in the configuration. -![](./assets/archival9.png) - + Or if you are using subscriptions, you can change this setting directly under subscription RQL. -![](./assets/archival10.png) - + More information about behaviour can be found in our documentation under this [link](https://docs.ravendb.net/7.1/data-archival/archived-documents-and-other-features). ## Taking documents out @@ -242,6 +235,6 @@ Note: Don’t try to just remove `@archived: true` manually in the document. Thi ## Summary -Data archival gives you more control over your database. By excluding unnecessary documents from queries, it makes them run smoother. But there’s so much more to RavenDB, like GenAI support, which you can read about [here](https://ravendb.net/articles/survive-the-ai-tidal-wave-with-ravendb-genai) and so many other features. +Data archival gives you more control over your database. By excluding unnecessary documents from queries, it makes them run smoother. If you’re also looking to reduce storage costs for binary data, check out our guide on [using remote attachments to cut storage costs](https://docs.ravendb.net/guides/using-remote-attachments-to-cut-storage-costs). But there’s so much more to RavenDB, like GenAI support, which you can read about [here](https://ravendb.net/articles/survive-the-ai-tidal-wave-with-ravendb-genai) and so many other features. Interested in testing this feature before taking a production licence? Grab the developer license dedicated to testing under this link [here](https://ravendb.net/dev). Any questions about this feature or just want to hang out and talk with the RavenDB team? Join our Discord Community Server \- invitation link is [here](https://discord.com/invite/ravendb). diff --git a/guides/employing-schema-validation-to-standardize-your-data.mdx b/guides/employing-schema-validation-to-standardize-your-data.mdx index 07ae72e2b6..11e6bb4289 100644 --- a/guides/employing-schema-validation-to-standardize-your-data.mdx +++ b/guides/employing-schema-validation-to-standardize-your-data.mdx @@ -5,6 +5,7 @@ icon: "document-schema" description: "Learn more about configuring schema validation in RavenDB to incrase trust in your data across teams." publishedAt: 2026-02-01 author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; @@ -13,6 +14,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; When working with any type of data, things usually go smoothly when a single team owns the entire system. When an organisation adds new teams that work on the same data, it can quickly become a mess without proper governance. You may find yourself being frustrated that the other team is saving as a string what breaks your system from time to time. Data must be tracked, and dataset version changes must be enforced precisely. You need to keep the same data model between all documents. Thankfully, we now have a tool to handle those situation and you don’t need to prepare for the worst by preparing boundaries. This tool is a schema validation. @@ -56,21 +58,18 @@ About the modes we mentioned, we can divide the audit operation into two modes. If the schema is triggered, it will block the document from being stored and return an error. If you want to input only a few documents or use schema validation as a one-time scan, you can disable schema validation while leaving global schema validation enabled. You can also trigger a collection-wide scan to test all documents, not just new ones. We will use a basic schema to scan if all our Orders have the Company and Employee fields. Click on the testing button and then on the bottom-right corner, press run test. It will return all errors in the table. -![](./assets/Validation1.png) -![](./assets/Validation2.png) - + + As you can see, one of our orders is missing the Employee field. ### Index Once your schema is ready, we can also create an index to store all documents that do not fit the schema in one place. With index, prepared you can just query your documents: -![](./assets/Validation3.png) - + And after clicking eye icon in preview you can learn more information about this document. -![](./assets/Validation4.png) - + ## How to use it with code? ### Audit Operation @@ -101,8 +100,7 @@ foreach (var error in result.Errors) ``` After that, we get a response like this. -![](./assets/Validation5.png) - + ### Index Of course, querying from code is an option too; you just need to prepare the required index beforehand. To query such an index, you can usea script like this one: @@ -141,8 +139,7 @@ How do you create such index? Can we make it from code? Let’s get into configu To configure schema validation in Studio, first enter the database you want to set it for, then navigate to Settings \> Document Schema. Add a new schema. This gives us two fields. One to select the collection and another to write our schema in. -![](./assets/Validation6.png) - + After you selected collection, you can proceed to write your schema. Schemas are built using [JSON Schema](https://json-schema.org/), a popular vocabulary for JSON files. Basic schema on orders collection can look like this: ```json @@ -257,8 +254,7 @@ select new We need to add Errors to stored values. We can easily do that in the fields section. -![](./assets/Validation7.png) - + If you want to make this index to only gather errors from one collection, change the first line to: ``` @@ -267,16 +263,14 @@ from doc in docs.ChosenCollection //change ChosenCollection to your collection We can save the index, and if we have any documents not matching the schema in database, we can notice they are added to the index. -![](./assets/Validation8.png) - + ### Dedicated index schema Because our schema is enabled, writes will be blocked. But we can create an index that does not require enabling the schema. We switch to a different section on the same bar where we were selecting Fields to add the Errors field, and switch to Schema Definitions. There, we can write a definition dedicated to this index. In there, we select our desired collection and input our schema. -![](./assets/Validation9.png) - + After saving it if you didn’t do it before, you can delete or disable the schema in the **database** setting. Now let’s do this from code. ## Configure it from code diff --git a/guides/enable-ai-search-in-your-web-app-in-5-minutes.mdx b/guides/enable-ai-search-in-your-web-app-in-5-minutes.mdx index 6e18b06d22..37d5defbe1 100644 --- a/guides/enable-ai-search-in-your-web-app-in-5-minutes.mdx +++ b/guides/enable-ai-search-in-your-web-app-in-5-minutes.mdx @@ -5,5 +5,6 @@ description: "Read about Enable AI Search in Your Web App in 5 Minutes on the Ra externalUrl: "https://ravendb.net/articles/enable-ai-search-in-your-web-app-in-5-minutes" publishedAt: 2025-04-28 image: "https://ravendb.net/wp-content/uploads/2025/04/enable-ai-search-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/feed-elasticsearch-from-your-ravendb.mdx b/guides/feed-elasticsearch-from-your-ravendb.mdx index bfe4b014e0..753d79a70e 100644 --- a/guides/feed-elasticsearch-from-your-ravendb.mdx +++ b/guides/feed-elasticsearch-from-your-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about Feed Elasticsearch from Your RavenDB on the RavenDB.net externalUrl: "https://ravendb.net/articles/feed-elasticsearch-from-your-ravendb" publishedAt: 2025-12-14 image: "https://ravendb.net/wp-content/uploads/2025/12/elastic-search-article-image.png" +proficiencyLevel: "Expert" --- diff --git a/guides/from-zero-to-a-fully-secured-cluster.mdx b/guides/from-zero-to-a-fully-secured-cluster.mdx index f20dacd513..ffad3a587c 100644 --- a/guides/from-zero-to-a-fully-secured-cluster.mdx +++ b/guides/from-zero-to-a-fully-secured-cluster.mdx @@ -5,6 +5,7 @@ icon: "toggle-on" publishedAt: 2026-02-23 description: "How to set up a fully secured cluster with RavenDB Kubernetes Operator." author: "Omer Ratsaby" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; @@ -13,6 +14,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; ## Prologue @@ -93,8 +95,7 @@ The operator oversees that entire lifecycle. And before we dive into the details, here’s the architecture we’ll gradually build throughout the series. We won’t start with everything at once \- we’ll assemble it piece by piece, explain each component as it enters the picture, and by the end, you’ll understand exactly how the full system fits together: -![](./assets/fromzero1.png) - + ## Part 1: Setup & Operator Installation This series begins by establishing the full baseline **before** we even think about CRDs. We’re building the foundation the rest of the series depends on. @@ -280,8 +281,7 @@ If all three workers nodes show different zones \- AZ distribution is correct. This is how our architecture looks like after successful setup: -![](./assets/fromzero2.png) - + Now, let’s deploy dependencies and RavenDB Operator itself.

Cert-manager

@@ -423,8 +423,7 @@ Whatever installation path you choose, the end result is identical: Nothing cluster-specific happens yet \- no Secrets, no RavenDB nodes. This is just the operator itself, waiting for a `RavenDBCluster` definition. -![](./assets/fromzero3.png) - + With the operator installed and the baseline environment ready, you can now continue to **Part 2**, where we introduce the `RavenDBCluster` CRD \- the contract that defines what the Operator builds, validates, and enforces, and the foundation we’ll extend step by step throughout the rest of the series. ## Part 2: RavenDBCluster CRD @@ -1000,8 +999,7 @@ kube-system aws-load-balancer-controller-76874bd966-qp8wc Allocate 3 EIPs up front. These will become the static public IPs for nodes `a`, `b`, and `c`. You can do that by navigating to: [**Elastic IPs**](https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#Addresses:) **EC2** console -![](./assets/fromzero4.png) - + [eips.png](https://drive.google.com/open?id=12KMnVZMxU8x5O-wEHJWqQcwYBomaqKSK) These will be pre-assigned to NLBs for node-level external access: @@ -1090,8 +1088,7 @@ The Operator is designed to work *with* this model, not around it. Allocate 3 EIPs up front. These will become the static public IPs for nodes `a`, `b`, and `c`. You can do that by navigating to: Network foundation | Public IP addresses view -![](./assets/fromzero5.png) - + [pips.png](https://drive.google.com/open?id=11PA7wN4uy6zE7H5LsYSGeI_XLxPtTUJs) These will be pre-assigned to NLBs for node-level external access: @@ -1113,8 +1110,7 @@ In this setup: There is no need to manually assign subnets or availability zones. Azure handles traffic distribution and zone resiliency automatically -![](./assets/fromzero6.png) - + The external access contract is intentionally simple. You only map RavenDB node tags to public IPs: ```bash showLineNumbers @@ -1135,9 +1131,7 @@ spec: -![](./assets/fromzero7.png) - - + With external access now clearly defined, the networking layer is no longer a black box. Ingress controllers, cloud load balancers, and MetalLB all serve the same purpose here: they give the Operator a concrete, stable entry point it can reason about. At this stage, nothing is secured yet and that’s intentional. @@ -1502,8 +1496,7 @@ The `mode`, `domain`, and `email` fields tell the Operator how TLS is managed (i At this stage, these fields are **declarative only**. They describe what certificates the cluster expects and how they are mapped to nodes, but no Secrets are required yet. In later chapters, just before we apply the final CR, we’ll create the actual Secrets from the setup package. Once those Secrets exist, the Operator will pick them up automatically and wire TLS into the cluster during provisioning. -![](./assets/fromzero8.png) - +

Self-signed certificates

Self-signed TLS is supported, but it comes with more responsibility. @@ -1588,8 +1581,7 @@ $ kubectl -n kube-system rollout restart deployment coredns This ensures that both RavenDB nodes and in-cluster clients can resolve the node URLs consistently. -![](./assets/fromzero9.png) - +

Certificate Renewal and Rotation

TLS does not end once the cluster is up. Certificates expire, security requirements change, and rotations must happen without downtime. RavenDB is designed for this from day one, and the Operator builds on those guarantees rather than reinventing them. @@ -1888,8 +1880,7 @@ This is typically used for restore or migration workflows. The PVC might contain With storage fully defined, the cluster now has a place to persist its identity and state. Data, logs, and auxiliary files are no longer tied to ephemeral Pods, but to durable volumes managed explicitly by Kubernetes and enforced by the Operator. -![](./assets/fromzero10.png) - + In **Part 6**, we finally bring everything together. We’ll create the remaining Secrets, apply the completed `RavenDBCluster` resource, and watch the Operator reconcile intent into reality \- provisioning nodes, attaching storage, wiring networking, and forming a live RavenDB cluster. ## Part 6: Bringing the Cluster to Life @@ -1979,8 +1970,7 @@ ravendb-license Opaque 1 26s At this point we’re ready to apply the *real* `RavenDBCluster` manifest, because we’ve already put the identity material in place. -![](./assets/fromzero11.png) - +

The full RavenDBCluster YAML

This is the moment where all the snippets collapse into a single manifest. You’ve seen every part of this YAML before \- just not all at once: @@ -2083,8 +2073,7 @@ From this point on, the reconciliation loop kicks in: StatefulSets, Services, In There’s no setup wizard to click through and no manual cluster formation step. The moment the manifest is accepted, Kubernetes and the operator take over and the cluster starts assembling itself. -![](./assets/fromzero12.png) - + You can watch the full layout by listing all resources under the ravendb namespace: ```bash showLineNumbers @@ -2150,8 +2139,7 @@ $ kubectl logs job/ravendb-cluster-init -n ravendb The logs are intentionally explicit. You’ll see DNS resolution, connectivity checks, and node additions logged step by step. When this job completes successfully, the cluster is fully formed \- no manual setup, no UI-driven registration, no follow-up actions required. -![](./assets/fromzero13.png) - +

Accessing RavenDB Studio from your browser

At this point, the cluster is up, the bootstrap job has completed, and RavenDB is fully operational. Let’s access the RavenDB Studio. @@ -2194,12 +2182,10 @@ Now open your browser and navigate to your URL. The browser will prompt you to select a client certificate. Choose the imported RavenDB client certificate. If everything is wired correctly, RavenDB Studio loads immediately \- secured, clustered, and fully initialized. -![](./assets/fromzero14.png) - + With the cluster now running, certificates in place, and the bootstrap process completed, RavenDB has fully transitioned from a declarative specification into a living system. -![](./assets/fromzero15.png) - + At this point, the most important question is no longer *how* the cluster was created, but *how it tells you what’s happening*. In **Part 7**, we’ll shift focus to **events and logging** \- how the operator communicates progress, surfaces problems, and explains its decisions through Kubernetes Events, structured logs, and status conditions. This is where observability replaces guesswork, and operating the cluster becomes predictable instead of reactive. ## Part 7: Events and Logging @@ -2385,8 +2371,7 @@ $ kubectl get events.events.k8s.io -A -o json | jq -r ' ] | @tsv' ``` -![](./assets/fromzero16.png) - + You’re not looking at noise. You’re looking at a timeline of state changes. This is especially powerful during rollouts, because you can literally watch readiness move from one requirement to the next: @@ -2509,8 +2494,7 @@ Next, we establish a clear “before” snapshot of the running RavenDB version. Open RavenDB Studio in your browser and navigate to the **About** tab. This shows the exact server version currently running on the cluster. -![](./assets/fromzero17.png) - + With the baseline confirmed, we trigger the upgrade itself. In this demo, we change only one thing: the container image version. Nothing else in the manifest is touched: ```bash showLineNumbers @@ -2533,8 +2517,7 @@ Once all pods have been updated and stabilized, the operator converges back to a To close the loop, return to RavenDB Studio and revisit the **About** tab. You should now see the new RavenDB version reported. This final check confirms that the upgrade completed successfully across all nodes and that the running system matches the desired state you declared: -![](./assets/fromzero19.png) - + As the upgrade progresses, Pods alone only tell part of the story. They show *what* is restarting, but not *why* the operator decided it was safe to do so. For that, Kubernetes Events are the real source of truth. While the rolling upgrade is in progress \- or immediately after it completes \- open a second terminal and watch the events emitted by the operator: @@ -2618,12 +2601,10 @@ From RavenDB’s point of view, this leaves the cluster in a fragile state: ther Before Sabotage: -![](./assets/fromzero20.png) - + After Sabotage: -![](./assets/fromzero21.png) - + Now let’s trigger an upgrade and see what happens: ```bash showLineNumbers diff --git a/guides/full-lifecycle-automation-of-ravendb-with-ansible.mdx b/guides/full-lifecycle-automation-of-ravendb-with-ansible.mdx index 29cfbd8270..d3b4195c14 100644 --- a/guides/full-lifecycle-automation-of-ravendb-with-ansible.mdx +++ b/guides/full-lifecycle-automation-of-ravendb-with-ansible.mdx @@ -5,5 +5,6 @@ description: "Read about Full Lifecycle Automation of RavenDB with Ansible on th externalUrl: "https://ravendb.net/articles/full-lifecycle-automation-of-ravendb-with-ansible" publishedAt: 2025-06-16 image: "https://ravendb.net/wp-content/uploads/2025/06/Ansible-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/genai-how-we-make-you-work-less.mdx b/guides/genai-how-we-make-you-work-less.mdx index dc8e654570..b5f577cd83 100644 --- a/guides/genai-how-we-make-you-work-less.mdx +++ b/guides/genai-how-we-make-you-work-less.mdx @@ -5,5 +5,6 @@ description: "Read about GenAI: How We Make You Work Less on the RavenDB.net new externalUrl: "https://ravendb.net/articles/genai-how-we-make-you-work-less" publishedAt: 2025-08-11 image: "https://ravendb.net/wp-content/uploads/2025/05/GenAI-how-we-make-you-work-less.png" +proficiencyLevel: "Expert" --- diff --git a/guides/getting-started-with-graphql-and-ravendb.mdx b/guides/getting-started-with-graphql-and-ravendb.mdx index 960a1fc4f1..596349f097 100644 --- a/guides/getting-started-with-graphql-and-ravendb.mdx +++ b/guides/getting-started-with-graphql-and-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about Getting Started with GraphQL and RavenDB on the RavenDB externalUrl: "https://ravendb.net/articles/getting-started-with-graphql-and-ravendb" publishedAt: 2024-06-27 image: "https://ravendb.net/wp-content/uploads/2024/06/graphql.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/grafana-cloud-configuration-with-opentelemetry.mdx b/guides/grafana-cloud-configuration-with-opentelemetry.mdx index d6c0ba34c7..f8773df57b 100644 --- a/guides/grafana-cloud-configuration-with-opentelemetry.mdx +++ b/guides/grafana-cloud-configuration-with-opentelemetry.mdx @@ -5,5 +5,6 @@ description: "Read about Grafana Cloud Configuration with OpenTelemetry on the R externalUrl: "https://ravendb.net/articles/grafana-cloud-configuration-with-opentelemetry" publishedAt: 2025-04-25 image: "https://ravendb.net/wp-content/uploads/2025/03/open-telemetry-grafana-integration.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/home.mdx b/guides/home.mdx index 9a07691322..f7c0941f64 100644 --- a/guides/home.mdx +++ b/guides/home.mdx @@ -18,7 +18,7 @@ import TagsGrid from "@site/src/components/Guides/TagsGrid";
diff --git a/guides/how-to-query-using-ravendb-and-asp-net-core-9.mdx b/guides/how-to-query-using-ravendb-and-asp-net-core-9.mdx index 70bf1adc63..bbb7d05cdf 100644 --- a/guides/how-to-query-using-ravendb-and-asp-net-core-9.mdx +++ b/guides/how-to-query-using-ravendb-and-asp-net-core-9.mdx @@ -5,4 +5,5 @@ description: "Read about How to query using RavenDB and ASP.NET Core 9 on the Ra externalUrl: "https://ravendb.net/articles/how-to-query-using-ravendb-and-asp-net-core-9" publishedAt: 2025-09-21 image: "https://ravendb.net/wp-content/uploads/2024/12/asp_net_core8_article_cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/how-to-setup-ravendb-with-asp-net-core-8-application.mdx b/guides/how-to-setup-ravendb-with-asp-net-core-8-application.mdx index a400888db2..3f85589aae 100644 --- a/guides/how-to-setup-ravendb-with-asp-net-core-8-application.mdx +++ b/guides/how-to-setup-ravendb-with-asp-net-core-8-application.mdx @@ -5,4 +5,5 @@ description: "Read about How to setup RavenDB with ASP.NET Core 8 application on externalUrl: "https://ravendb.net/articles/how-to-setup-ravendb-with-asp-net-core-8-application" publishedAt: 2025-02-25 image: "https://ravendb.net/wp-content/uploads/2024/12/asp_net_core8_article_cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/how-to-troubleshoot-ravendbs-high-cpu-usage.mdx b/guides/how-to-troubleshoot-ravendbs-high-cpu-usage.mdx index 4cfb373f7d..e74ce4ba56 100644 --- a/guides/how-to-troubleshoot-ravendbs-high-cpu-usage.mdx +++ b/guides/how-to-troubleshoot-ravendbs-high-cpu-usage.mdx @@ -5,5 +5,6 @@ description: "Read about How to Troubleshoot High CPU Usage on the RavenDB.net n externalUrl: "https://ravendb.net/articles/how-to-troubleshoot-ravendbs-high-cpu-usage" publishedAt: 2025-02-23 image: "https://ravendb.net/wp-content/uploads/2025/02/troubleshoot-cpu-usage-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/incorporating-machine-learning-into-ravendb-indexing.mdx b/guides/incorporating-machine-learning-into-ravendb-indexing.mdx index a463a992cd..0693eebe64 100644 --- a/guides/incorporating-machine-learning-into-ravendb-indexing.mdx +++ b/guides/incorporating-machine-learning-into-ravendb-indexing.mdx @@ -5,5 +5,6 @@ description: "Read about Machine Learning Inside RavenDB Indexing on the RavenDB externalUrl: "https://ravendb.net/articles/incorporating-machine-learning-into-ravendb-indexing" publishedAt: 2024-12-02 image: "https://ravendb.net/wp-content/uploads/2024/12/machine-learning-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/integrate-ravendb-into-sveltekit-app.mdx b/guides/integrate-ravendb-into-sveltekit-app.mdx index 53fff7490d..16ca837c80 100644 --- a/guides/integrate-ravendb-into-sveltekit-app.mdx +++ b/guides/integrate-ravendb-into-sveltekit-app.mdx @@ -5,4 +5,5 @@ description: "Read about Integrate RavenDB into SvelteKit app on the RavenDB.net externalUrl: "https://ravendb.net/articles/integrate-ravendb-into-sveltekit-app" publishedAt: 2025-01-27 image: "https://ravendb.net/wp-content/uploads/2025/01/svelte-cover-article.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/integrating-ravendb-into-next-js-app.mdx b/guides/integrating-ravendb-into-next-js-app.mdx index 70f1836963..1e849efcae 100644 --- a/guides/integrating-ravendb-into-next-js-app.mdx +++ b/guides/integrating-ravendb-into-next-js-app.mdx @@ -5,4 +5,5 @@ description: "Read about Integrating RavenDB into Next.js app on the RavenDB.net externalUrl: "https://ravendb.net/articles/integrating-ravendb-into-next-js-app" publishedAt: 2024-08-26 image: "https://ravendb.net/wp-content/uploads/2024/08/next-js-logo.png" +proficiencyLevel: "Beginner" --- diff --git a/guides/integrating-ravendb-with-net-aspire-project-for-enhanced-development.mdx b/guides/integrating-ravendb-with-net-aspire-project-for-enhanced-development.mdx index b605cbc880..75d2e715c1 100644 --- a/guides/integrating-ravendb-with-net-aspire-project-for-enhanced-development.mdx +++ b/guides/integrating-ravendb-with-net-aspire-project-for-enhanced-development.mdx @@ -5,5 +5,6 @@ description: "Read about Integrating RavenDB with .NET Aspire on the RavenDB.net externalUrl: "https://ravendb.net/articles/integrating-ravendb-with-net-aspire-project-for-enhanced-development" publishedAt: 2025-03-25 image: "https://ravendb.net/wp-content/uploads/2025/03/net-aspire-integration-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/leverage-ravendb-observability-with-datadog.mdx b/guides/leverage-ravendb-observability-with-datadog.mdx index 058c2d560e..7fb31262e5 100644 --- a/guides/leverage-ravendb-observability-with-datadog.mdx +++ b/guides/leverage-ravendb-observability-with-datadog.mdx @@ -5,5 +5,6 @@ description: "Read about Leverage RavenDB Observability with Datadog on the Rave externalUrl: "https://ravendb.net/articles/leverage-ravendb-observability-with-datadog" publishedAt: 2025-06-10 image: "https://ravendb.net/wp-content/uploads/2025/06/datadog-article.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/master-ravendb-indexing-staleness.mdx b/guides/master-ravendb-indexing-staleness.mdx index 6cbecb8c28..de5412fc1f 100644 --- a/guides/master-ravendb-indexing-staleness.mdx +++ b/guides/master-ravendb-indexing-staleness.mdx @@ -5,5 +5,6 @@ description: "Read about Indexing Staleness Explained on the RavenDB.net news se externalUrl: "https://ravendb.net/articles/master-ravendb-indexing-staleness" publishedAt: 2025-11-25 image: "https://ravendb.net/wp-content/uploads/2025/11/acid-base-article-cover.svg" +proficiencyLevel: "Expert" --- diff --git a/guides/master-ravendb-projections-performance.mdx b/guides/master-ravendb-projections-performance.mdx index 1e1cf8711b..e45d591e08 100644 --- a/guides/master-ravendb-projections-performance.mdx +++ b/guides/master-ravendb-projections-performance.mdx @@ -5,5 +5,6 @@ description: "Read about Master RavenDB Projections Performance on the RavenDB.n externalUrl: "https://ravendb.net/articles/master-ravendb-projections-performance" publishedAt: 2025-07-30 image: "https://ravendb.net/wp-content/uploads/2025/07/master-ravendb-article-cover.png" +proficiencyLevel: "Expert" --- diff --git a/guides/master-ravendb-spotting-red-flags-in-index-definitions-guide.mdx b/guides/master-ravendb-spotting-red-flags-in-index-definitions-guide.mdx index 79392ba8ff..ef48d05daf 100644 --- a/guides/master-ravendb-spotting-red-flags-in-index-definitions-guide.mdx +++ b/guides/master-ravendb-spotting-red-flags-in-index-definitions-guide.mdx @@ -6,6 +6,7 @@ description: "Learn about index definitions and thier optimization." publishedAt: 2025-09-17 image: "https://ravendb.net/wp-content/uploads/2025/09/spotting-red-flags-article-image.png" author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; @@ -14,6 +15,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; Every database has a way of making data easier & faster to find. This role is often fulfilled by [indexes](https://docs.ravendb.net/studio/database/indexes/indexes-overview/#indexes---the-general-concept). Without them, every request would be like searching through a stack of papers one by one, hoping to stumble on the right page. With them, your queries can quickly jump over to the relevant results, going through compacted entries with only the data that the query cares about. @@ -165,8 +167,7 @@ And this one would return a negative response, as it should. But if we’d have order that matches this query, it works properly: -![](./assets/indexdef1.png) - + ## Map Reduce With Unique Values Sometimes you want to aggregate your data \- e.g. all profit generated from each customer, but you hold each purchase in separate documents. That is where [Map-Reduce](https://docs.ravendb.net/6.0/studio/database/indexes/create-map-reduce-index/) can help you. It aggregates all the data you want from your query under one key and combines them. diff --git a/guides/master-ravendb-troubleshoot-fix-high-memory-usage.mdx b/guides/master-ravendb-troubleshoot-fix-high-memory-usage.mdx index 5866b1a66f..3fe949d494 100644 --- a/guides/master-ravendb-troubleshoot-fix-high-memory-usage.mdx +++ b/guides/master-ravendb-troubleshoot-fix-high-memory-usage.mdx @@ -5,5 +5,6 @@ description: "Read about Fix High Memory Usage in RavenDB on the RavenDB.net new externalUrl: "https://ravendb.net/articles/master-ravendb-troubleshoot-fix-high-memory-usage" publishedAt: 2025-04-09 image: "https://ravendb.net/wp-content/uploads/2025/04/high-memory-usage-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/migrate-your-databases-in-ravendb.mdx b/guides/migrate-your-databases-in-ravendb.mdx index c99143d138..fdd8757ca0 100644 --- a/guides/migrate-your-databases-in-ravendb.mdx +++ b/guides/migrate-your-databases-in-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about Migrate Your Databases in RavenDB on the RavenDB.net ne externalUrl: "https://ravendb.net/articles/migrate-your-databases-in-ravendb" publishedAt: 2025-05-14 image: "https://ravendb.net/wp-content/uploads/2025/04/migrate-to-ravendb-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/new-in-7-0-ravendb-and-amazon-sqs-etl.mdx b/guides/new-in-7-0-ravendb-and-amazon-sqs-etl.mdx index 4da11ab16f..6211a9361f 100644 --- a/guides/new-in-7-0-ravendb-and-amazon-sqs-etl.mdx +++ b/guides/new-in-7-0-ravendb-and-amazon-sqs-etl.mdx @@ -5,5 +5,6 @@ description: "Read about New in 7.0: RavenDB and Amazon SQS ETL on the RavenDB.n externalUrl: "https://ravendb.net/articles/new-in-7-0-ravendb-and-amazon-sqs-etl" publishedAt: 2025-02-25 image: "https://ravendb.net/wp-content/uploads/2025/02/amazon-sqs-etl-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/new-in-7-0-ravendb-to-snowflake.mdx b/guides/new-in-7-0-ravendb-to-snowflake.mdx index 7a04ddea85..2b96f67d17 100644 --- a/guides/new-in-7-0-ravendb-to-snowflake.mdx +++ b/guides/new-in-7-0-ravendb-to-snowflake.mdx @@ -5,5 +5,6 @@ description: "Read about New in 7.0: RavenDB to Snowflake on the RavenDB.net new externalUrl: "https://ravendb.net/articles/new-in-7-0-ravendb-to-snowflake" publishedAt: 2025-03-12 image: "https://ravendb.net/wp-content/uploads/2025/02/snowflake-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/new-in-7-0-ravendbs-vector-search.mdx b/guides/new-in-7-0-ravendbs-vector-search.mdx index e20e827126..d12b5125ef 100644 --- a/guides/new-in-7-0-ravendbs-vector-search.mdx +++ b/guides/new-in-7-0-ravendbs-vector-search.mdx @@ -5,5 +5,6 @@ description: "Read about New in 7.0: RavenDB Vector Search on the RavenDB.net ne externalUrl: "https://ravendb.net/articles/new-in-7-0-ravendbs-vector-search" publishedAt: 2025-10-27 image: "https://ravendb.net/wp-content/uploads/2025/02/vector-search-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/practical-look-at-ai-agents-with-ravendb.mdx b/guides/practical-look-at-ai-agents-with-ravendb.mdx index 0a3b160f02..7a7948168d 100644 --- a/guides/practical-look-at-ai-agents-with-ravendb.mdx +++ b/guides/practical-look-at-ai-agents-with-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about A Practical Look at AI Agents with RavenDB on the Raven externalUrl: "https://ravendb.net/articles/practical-look-at-ai-agents-with-ravendb" publishedAt: 2025-12-24 image: "https://ravendb.net/wp-content/uploads/2025/09/practical-look-ai-agents-article-image.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/processing-invoices-using-data-subscriptions-in-ravendb.mdx b/guides/processing-invoices-using-data-subscriptions-in-ravendb.mdx index 83f28baa26..69621264fe 100644 --- a/guides/processing-invoices-using-data-subscriptions-in-ravendb.mdx +++ b/guides/processing-invoices-using-data-subscriptions-in-ravendb.mdx @@ -5,5 +5,6 @@ description: "Read about Processing Invoices Using Data Subscriptions on the Rav externalUrl: "https://ravendb.net/articles/processing-invoices-using-data-subscriptions-in-ravendb" publishedAt: 2024-12-08 image: "https://ravendb.net/wp-content/uploads/2024/12/processing-invoices-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/programmatic-backup-and-restore-operations-in-ravendb-with-node-js.mdx b/guides/programmatic-backup-and-restore-operations-in-ravendb-with-node-js.mdx index 16f5ebde29..009f5ffefb 100644 --- a/guides/programmatic-backup-and-restore-operations-in-ravendb-with-node-js.mdx +++ b/guides/programmatic-backup-and-restore-operations-in-ravendb-with-node-js.mdx @@ -5,5 +5,6 @@ description: "Read about Programmatic Backup and Restore with Node.js on the Rav externalUrl: "https://ravendb.net/articles/programmatic-backup-and-restore-operations-in-ravendb-with-node-js" publishedAt: 2024-07-29 icon: "backup" +proficiencyLevel: "Beginner" --- diff --git a/guides/ravendb-client-certificates.mdx b/guides/ravendb-client-certificates.mdx index 04223ce5ce..bd43f301c0 100644 --- a/guides/ravendb-client-certificates.mdx +++ b/guides/ravendb-client-certificates.mdx @@ -5,6 +5,7 @@ icon: "guides" description: "RavenDB client certificates that renew automatically without re-registration using vault-backed key reuse patterns." publishedAt: 2026-02-12 author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; @@ -13,6 +14,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; ## Overview @@ -174,8 +176,7 @@ In the upload dialog, fill in the following fields: - **Expiration (optional)** \- If you want RavenDB to treat the certificate as expired earlier than its actual validity period. -![](./assets/cert1.png) - +

**Alternatively, register the certificate via the CLI**

For automation or scripted deployments, you can perform the same registration using the admin REST API: @@ -245,8 +246,7 @@ You can also inspect the registered certificates- and verify that both versions Navigate to: **Manage Server → Certificates → Manage Certificates** -![](./assets/cert2.png) - + **Alternatively, view certificate entries via CLI** ```bash showLineNumbers @@ -401,8 +401,7 @@ In the upload dialog, fill in the following fields: - **Expiration (optional)** \- If you want RavenDB to treat the certificate as expired earlier than its actual validity period. -![](./assets/cert1.png) - +

Alternatively, register the certificate via the CLI

```bash showLineNumbers @@ -467,8 +466,7 @@ You can also inspect the registered certificates- and verify that both versions Navigate to: **Manage Server → Certificates → Manage Certificates** -![](./assets/cert2.png) - + **Alternatively, view certificate entries via CLI** ```bash showLineNumbers @@ -619,8 +617,7 @@ In the upload dialog, fill in the following fields: - **Expiration (optional)** \- If you want RavenDB to treat the certificate as expired earlier than its actual validity period. -![](./assets/cert1.png) - +

Alternatively, register the certificate via the CLI

For automation or scripted deployments, you can perform the same registration using the admin REST API: @@ -708,8 +705,7 @@ You can also inspect the registered certificates- and verify that both versions Navigate to: **Manage Server → Certificates → Manage Certificates** -![](./assets/cert2.png) - + **Alternatively, view certificate entries via CLI** ```bash showLineNumbers diff --git a/guides/ravendb-data-visualization-with-power-bi.mdx b/guides/ravendb-data-visualization-with-power-bi.mdx index 90ec99b9e2..e03c727d9d 100644 --- a/guides/ravendb-data-visualization-with-power-bi.mdx +++ b/guides/ravendb-data-visualization-with-power-bi.mdx @@ -5,5 +5,6 @@ description: "Read about RavenDB Data Visualization with Power BI on the RavenDB externalUrl: "https://ravendb.net/articles/ravendb-data-visualization-with-power-bi" publishedAt: 2025-03-25 image: "https://ravendb.net/wp-content/uploads/2025/03/power-BI-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/ravendb-deployment-guide-docker-compose-cluster.mdx b/guides/ravendb-deployment-guide-docker-compose-cluster.mdx index b6ae796f71..984beaf13f 100644 --- a/guides/ravendb-deployment-guide-docker-compose-cluster.mdx +++ b/guides/ravendb-deployment-guide-docker-compose-cluster.mdx @@ -5,4 +5,5 @@ description: "Read about RavenDB Deployment Guide – Docker Compose Cluster on externalUrl: "https://ravendb.net/articles/ravendb-deployment-guide-docker-compose-cluster" publishedAt: 2025-03-10 image: "https://ravendb.net/wp-content/uploads/2025/03/docker-ravendb-integration-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/semantic-search-with-ravendb-python-and-fastapi.mdx b/guides/semantic-search-with-ravendb-python-and-fastapi.mdx index 48f4b7e853..61e87022c0 100644 --- a/guides/semantic-search-with-ravendb-python-and-fastapi.mdx +++ b/guides/semantic-search-with-ravendb-python-and-fastapi.mdx @@ -5,6 +5,7 @@ description: "Read about Semantic Search with RavenDB and Python" publishedAt: 2025-07-22 image: "https://ravendb.net/wp-content/uploads/2025/07/Semantic-Search-cover.png" author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; @@ -13,6 +14,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; ## Introduction @@ -32,9 +34,8 @@ Using FastAPI, we can quickly build a web AI search endpoint to demonstrate how See, we query for “Cheese” and we get all kinds of cheese products from our database: -![](./assets/semsearch1.png) -![](./assets/semsearch2.png) - + + Under the hood, the application translates our query term “Cheese” to an embedding (vector) on the fly and compares other vectors within the database, finding the closest “meanings”. Let’s show how to build that. Without the query implementation, our application looks like this: @@ -202,7 +203,7 @@ Adding automatic embeddings generation starts in the AI Hub. We will automate th ### AI Connection String Create a new [AI connection string](https://ravendb.net/docs/ai-integration/connection-strings/connection-strings-overview) in RavenDB Studio: -![](./assets/semsearch3.png) + Define your custom name and identifier and pick the service you want to use; we chose OpenAI. Then, in the new fields, select the endpoint & model, and paste your API key. Other fields are optional and not currently relevant to us. You can test the connection to ensure everything works properly. @@ -211,7 +212,7 @@ You can test the connection to ensure everything works properly. We can connect to the OpenAI model, but we need to create a task that generates embeddings. Go back to the AI Hub and choose ‘AI Tasks’. Create a new embeddings generation task and fill in its name and identifier. Select our new connection string. We select the ‘Products’ collection and type ‘Name’ for a path just beneath the collection. Just save it, and it’s ready. -![](./assets/semsearch4.png) + Look how easy and short it is. Using RavenDB, we don’t need to worry about adding new fields; query logic is already thinner, and all connections to AI are already handled without the need for additional stuff. ### Application code @@ -273,12 +274,10 @@ This way we get: Works perfectly: -![](./assets/semsearch5.png) -![](./assets/semsearch6.png) - + + In the studio, RavenDB created a separate collection for embeddings and cached terms: -![](./assets/semsearch7.png) - + Everything’s working on its own, and our semantic search can be delivered much quicker. ## Summary diff --git a/guides/sending-your-ravendb-7-0-logs-to-grafana-cloud.mdx b/guides/sending-your-ravendb-7-0-logs-to-grafana-cloud.mdx index 3607e1dfbd..d9ee574423 100644 --- a/guides/sending-your-ravendb-7-0-logs-to-grafana-cloud.mdx +++ b/guides/sending-your-ravendb-7-0-logs-to-grafana-cloud.mdx @@ -5,5 +5,6 @@ description: "Read about Sending Your RavenDB 7.0 Logs to Grafana Cloud on the R externalUrl: "https://ravendb.net/articles/sending-your-ravendb-7-0-logs-to-grafana-cloud" publishedAt: 2025-02-25 image: "https://ravendb.net/wp-content/uploads/2025/02/grafana-cloud-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/set-up-ravendb-server-using-aws-marketplace.mdx b/guides/set-up-ravendb-server-using-aws-marketplace.mdx index 415dfde2f5..1a717ac6f8 100644 --- a/guides/set-up-ravendb-server-using-aws-marketplace.mdx +++ b/guides/set-up-ravendb-server-using-aws-marketplace.mdx @@ -5,4 +5,5 @@ description: "Read about Set up RavenDB Server using AWS Marketplace on the Rave externalUrl: "https://ravendb.net/articles/set-up-ravendb-server-using-aws-marketplace" publishedAt: 2025-11-13 image: "https://ravendb.net/wp-content/uploads/2025/11/aws-ravendb-article.png" +proficiencyLevel: "Beginner" --- diff --git a/guides/setting-up-ravendb-cluster-on-aws-eks.mdx b/guides/setting-up-ravendb-cluster-on-aws-eks.mdx index 06bc77c5f3..81e538c45c 100644 --- a/guides/setting-up-ravendb-cluster-on-aws-eks.mdx +++ b/guides/setting-up-ravendb-cluster-on-aws-eks.mdx @@ -5,4 +5,5 @@ description: "Read about Setting Up RavenDB Cluster on AWS EKS on the RavenDB.ne externalUrl: "https://ravendb.net/articles/setting-up-ravendb-cluster-on-aws-eks" publishedAt: 2025-03-09 image: "https://ravendb.net/wp-content/uploads/2025/03/kubernetes-aws-ravendb-article-cover.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/setting-up-ravendb-with-docker-and-https.mdx b/guides/setting-up-ravendb-with-docker-and-https.mdx index 3cd9469d98..a0ff5d4768 100644 --- a/guides/setting-up-ravendb-with-docker-and-https.mdx +++ b/guides/setting-up-ravendb-with-docker-and-https.mdx @@ -5,4 +5,5 @@ description: "Read about Setting up RavenDB with Docker and HTTPS on the RavenDB externalUrl: "https://ravendb.net/articles/setting-up-ravendb-with-docker-and-https" publishedAt: 2024-12-06 icon: "docker" +proficiencyLevel: "Beginner" --- diff --git a/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx b/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx index 7f97d7e4b4..31439c4604 100644 --- a/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx +++ b/guides/simple-crud-operations-with-ravendb-and-asp-net-core-8-application.mdx @@ -5,4 +5,5 @@ description: "Read about Simple CRUD operations with RavenDB and ASP.NET Core 8 externalUrl: "https://ravendb.net/articles/simple-crud-operations-with-ravendb-and-asp-net-core-8-application" publishedAt: 2025-03-31 image: "https://ravendb.net/wp-content/uploads/2025/03/crud-operations-asp_net-article-cover.jpg" +proficiencyLevel: "Beginner" --- diff --git a/guides/spatial-search-in-ravendb.mdx b/guides/spatial-search-in-ravendb.mdx index 2412bb6131..9e61850df6 100644 --- a/guides/spatial-search-in-ravendb.mdx +++ b/guides/spatial-search-in-ravendb.mdx @@ -1,10 +1,25 @@ --- -title: "Points & Polygons: On Spatial Search in RavenDB" -tags: [python, demo, querying, indexes] +title: "Spatial Search in RavenDB: Radius, Polygon, and Reverse Queries" +tags: [python, demo, querying, indexes, spatial, fastapi] icon: "spatial-map-view" -description: "Explore Flat Finder demo with us and learn how to use spatial search in RavenDB." +description: "Learn how to implement spatial search in RavenDB with Python. Covers radius queries, custom polygon shapes, WKT syntax, and reverse point-in-polygon lookup using the Flat Finder demo." author: "Paweł Lachowski" publishedAt: 2026-03-11 +proficiencyLevel: "Expert" +keywords: ["spatial search", "geospatial query", "radius search", "polygon search", "WKT", "BoundingBox", "QuadPrefixTree", "GeoHashPrefixTree", "RavenDB Python"] +see_also: + - title: "Indexing Spatial Data" + link: "indexes/indexing-spatial-data" + source: "docs" + path: "Indexes" + - title: "Spatial Queries" + link: "indexes/querying/spatial" + source: "docs" + path: "Indexes > Querying" + - title: "How to Make a Spatial Query" + link: "client-api/session/querying/how-to-make-a-spatial-query" + source: "docs" + path: "Client API > Session > Querying" --- import Admonition from '@theme/Admonition'; @@ -13,6 +28,11 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; + + +RavenDB offers native spatial search without external plugins. Store point coordinates or polygon shapes in your documents and query by radius, custom shapes, or reverse point-in-polygon lookup — using the same indexing workflow you use for all other fields. This guide walks through all three query types with a working Python demo. + Spatial data tends to create an impression that you need to learn a dedicated tool from scratch before you can do anything useful with it. The technical concepts like storing coordinates and polygons may look simple at first, but once you dig a little deeper, they can become surprisingly hard to navigate through. Geospatial tools often do not help newcomers get started smoothly due to convoluted technical documentation. @@ -40,7 +60,7 @@ Respectively, as we allow indexing points and WKT shapes, you can achieve anythi All those usages depend on how you use your indexes and queries, and there is, of course, more you can do. -#### Dynamic vs Static index +### Dynamic vs Static index Queries over spatial data behave the same as regular RavenDB queries, so we can either let RavenDB generate an auto-index (dynamic) or create a predefined index (static) manually. Dynamic indexes are good if you are satisfied with the default search options, and you are fine with the first query being slower (while the index is being created). @@ -107,11 +127,11 @@ Once your geometry is stored, you can run spatial queries on it. You can check i ## Demo \- How we use Spatial Search -Now that we have covered the theory, let’s look at the demo and see how to build it with RavenDB. The demo is coded in Python and is available to clone via this [link](https://github.com/poissoncorp/samples.flats). +Now that we have covered the theory, let’s look at the demo and see how to build it with RavenDB. The examples below use **RavenDB 7.2** and the **RavenDB Python client** with **FastAPI**. The demo is coded in Python and is available to clone via this [link](https://github.com/poissoncorp/samples.flats). Let’s start from the beginning. We `git clone` the repository and `uv sync` for dependencies, and then start it with `uv run python main.py`. What we get is this view. -![](./assets/spatialsearch1.png) +Flat Finder demo application initial view after startup Now let's dive into the app and see what it's capable of. We will go through three demos: @@ -125,11 +145,11 @@ Let’s start with the first function, searching by radius. This option is selected by default on the top left. All you need to do is click anywhere and select a radius if the default search radius does not suit you. This gives us points within the radius; in this demo, those are flats in Paris. -![](./assets/spatialsearch2.png) +Radius search result showing two flats within the selected distance in Paris As you can see, a search by radius excludes any other flats outside the radius, leaving us with only two results. We also get information about the flats themselves and the distance to them from our point. This is how flat data looks inside. -![](./assets/spatialsearch3.png) +Flat document detail showing coordinates and distance metadata But how do we map those flats on a map? @@ -173,7 +193,7 @@ async def search_by_radius(request: SearchByRadiusRequest): First, we define the endpoint and open a session in order to communicate with RavenDB. Then we have this part of code that is querying using index we prepared that looks like this: -![](./assets/spatialsearch4.png) +Flats_SpatialIndex definition in RavenDB Studio ```py query = session.query_index_type(Flats_SpatialIndex, Flat) @@ -222,7 +242,7 @@ The second option in our demo allows us to search not by distance from a point, Instead of saying “show me flats within 3 km of this point”, we now say “show me flats inside this exact area.” -![](./assets/spatialsearch5.png) +Custom polygon drawn on the Paris map for shape-based flat search This is useful when the area you care about is not a perfect circle. Maybe you want to select only a specific neighborhood or exclude a specific zone. A polygon gives you full control. @@ -324,7 +344,7 @@ Just like in Part 1, RavenDB stores spatial calculation results in metadata. We We can also use similar logic and search all points inside the area. -![](./assets/spatialsearch6.png) +Paris district overlays shown on the map for selecting arrondissement boundaries As you can see, those are districts that we had ready underneath it all. We can select them and see all flats in a specific area. How do we do this? Of course, we start with the endpoint and the opening session. @@ -355,15 +375,15 @@ Then we can just connect search by shape type of code, and we can search all fla You might have noticed that if we click on any flat, the district (4th Arrondissement - Hôtel-de-Ville on the image) it is in is shown. -![](./assets/spatialsearch7.png) +Flat detail showing reverse search result identifying the 4th Arrondissement This is a reverse search. We select a point, and RavenDB returns the area it is in. Data of our districts look like this: -![](./assets/spatialsearch8.png) +District document structure showing name, population, and boundary_wkt fields All those districts were indexed in RavenDB, and a field was created to hold interpreted spatial data. Static index that holds it looks like this: -![](./assets/spatialsearch9.png) +Districts_SpatialIndex definition with boundary field for spatial indexing The only thing that distinguishes this index from a non-spatial one is a single field: boundary. This is the field that contains our prepared spatial data. @@ -454,6 +474,6 @@ raise HTTPException( ## Summary -As you can see, RavenDB lets you query spatial data and use spatial search capabilities without becoming an expert in a completely new technology. Want to easily add more advanced capabilities to your application? You may consider combining semantic search with your spatial search to query by the best-matching description. You can find more about semantic search in RavenDB in [this](https://docs.ravendb.net/guides/semantic-search-with-ravendb-python-and-fastapi/) article. +As you can see, RavenDB lets you query spatial data and use spatial search capabilities without becoming an expert in a completely new technology. Want to easily add more advanced capabilities to your application? You may consider combining semantic search with your spatial search to query by the best-matching description. You can find more about [semantic search in RavenDB with Python and FastAPI](/guides/semantic-search-with-ravendb-python-and-fastapi/) in the companion guide. -Interested in RavenDB? Grab the developer license dedicated for testing under this link [here](https://ravendb.net/dev?_gl=1*x014vj*_gcl_au*NTAyODIzOTk4LjE3NzAwMTY5NTcuMzYwMzg1MDIwLjE3NzMwNDQ3NjcuMTc3MzA0NDc2Nw..), or get a free cloud database [here](https://ravendb.net/cloud?_gl=1*s4ciyf*_gcl_au*NTAyODIzOTk4LjE3NzAwMTY5NTcuMzYwMzg1MDIwLjE3NzMwNDQ3NjcuMTc3MzA0NDc2Nw..). If you have questions about this feature, or want to hang out and talk with the RavenDB team, join our Discord Community Server \- invitation link is [here](https://discord.com/invite/ravendb). +Interested in RavenDB? Grab the [free developer license](https://ravendb.net/dev) for testing, or get a [free cloud database](https://ravendb.net/cloud). If you have questions about this feature, or want to hang out and talk with the RavenDB team, join our Discord Community Server \- invitation link is [here](https://discord.com/invite/ravendb). diff --git a/guides/survive-the-ai-tidal-wave-with-ravendb-genai.mdx b/guides/survive-the-ai-tidal-wave-with-ravendb-genai.mdx index b1bcafb931..ee91b7f374 100644 --- a/guides/survive-the-ai-tidal-wave-with-ravendb-genai.mdx +++ b/guides/survive-the-ai-tidal-wave-with-ravendb-genai.mdx @@ -5,5 +5,6 @@ description: "Read about Survive the AI Tidal Wave with RavenDB GenAI on the Rav externalUrl: "https://ravendb.net/articles/survive-the-ai-tidal-wave-with-ravendb-genai" publishedAt: 2025-07-07 image: "https://ravendb.net/wp-content/uploads/2025/06/article-cover-genai.png" +proficiencyLevel: "Expert" --- diff --git a/guides/tags.yml b/guides/tags.yml index 0fc782ebc8..57e64a5c54 100644 --- a/guides/tags.yml +++ b/guides/tags.yml @@ -90,6 +90,10 @@ fastapi: label: "FastAPI" permalink: "/fastapi" description: "Content related to FastAPI." +spatial: + label: "Spatial" + permalink: "/spatial" + description: "Content related to Spatial search and geospatial queries." nextjs: label: "Next.js" permalink: "/nextjs" diff --git a/guides/transactional-outbox.mdx b/guides/transactional-outbox.mdx index 1512097f3e..102e246cda 100644 --- a/guides/transactional-outbox.mdx +++ b/guides/transactional-outbox.mdx @@ -1,5 +1,5 @@ --- -title: "Transactional Outbox Pattern with RavenDB Queue ETL" +title: "Transactional Outbox with RavenDB Queue ETL" tags: [ongoing-tasks, architecture, csharp, integration] icon: "etl" description: "Learn to implement the transactional outbox pattern in C# using RavenDB data subscriptions or Queue ETL, with RabbitMQ and Kafka code examples." @@ -19,64 +19,16 @@ see_also: source: "docs" path: "Client API > Data Subscriptions" author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- - - - - import Admonition from '@theme/Admonition'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; ## Distributed systems and their quirks @@ -94,7 +46,7 @@ When it happens, we can end up with situations where the invoice exists, but no At the same time, we can have the opposite situation: the queue receives our event, but the database doesn’t create an invoice. That’s how minor problems can change into real legal difficulties. We can’t have partial failure at all; it is worse than complete failure. Then how is it possible we have so many online services that work? -### Solution +### How the transactional outbox pattern works The reason systems like this can work at all is that they stop treating event sending or document creation separately. The moment an invoice is created is also the exact moment an event must be captured. There is no acceptable state in which only one of those happens. @@ -114,7 +66,7 @@ await session.SaveChangesAsync(); // single atomic commit But in RavenDB particularly, there’s another way of achieving the same goal, using our Queue ETL feature. In the guide below, we’ll show how to achieve a transactional outbox pattern in RavenDB with ease, and then, we’ll show you how a transactional outbox pattern can be easily swapped with Queue ETL. Let’s dive into it\! -## Setup +## Implementing the outbox with data subscriptions We want to connect and save our documents to both collections as a single atomic transaction. To achieve that, we want to use the saveChanges() after storing both documents, to wrap both changes into a single transaction, as described in this [article](/7.2/client-api/faq/transaction-support#acid-for-document-operations). @@ -383,21 +335,19 @@ With our app running, we can enter our queue’s interface or console. Both Kafka and RabbitMQ are receiving data. Kafka can be checked using a shell script: -![Kafka terminal output showing invoice-created messages after the RavenDB subscription worker ran](./assets/outbox1.png) - +Kafka terminal output showing invoice-created messages after the RavenDB subscription worker ran And RabbitMQ can be checked in the GUI. -![RabbitMQ management GUI showing the invoice-created queue with queued messages](./assets/outbox2.png) - +RabbitMQ management GUI showing the invoice-created queue with queued messages So this works perfectly, we’ve used various features of RavenDB, like ACID for document operations, or data subscriptions, to implement transactional outbox in no time. But RavenDB offers another way to help you achieve your goal. Instead of the Transactional Outbox pattern, we’ll use another durable ongoing task \- RavenDB Queue ETL\! -## ETL Outbox +## Simplifying the outbox with RavenDB Queue ETL We can simplify this further by using RavenDB Queue ETLs, making it trivial. RavenDB can put different messages inside your queue each time an Invoice document is created, or updated. -Instead of saving events in a collection, we can use ETL to queues like RabbitMQ or Apache Kafka as our outbox. It’s a durable, highly available task with decent observability. It eliminates the need for transactional outbox \- the ETL task state will be our transactional outbox now. +Instead of saving events in a collection, we can use ETL to queues like RabbitMQ or Apache Kafka as our outbox. It’s a durable, highly available task with decent observability. The ETL task acts as the outbox infrastructure, removing the need to implement the pattern manually in application code. RavenDB monitors database changes, and the transformation script creates events based on them. RavenDB’s ETL takes care of everything else, like retries and journaling, for data that has already been processed. @@ -407,14 +357,12 @@ Most importantly, we can do it without writing any application-level code\! Let’s show how to connect and configure this task: -![RavenDB Studio Ongoing Tasks panel showing available ETL task types including RabbitMQ and Kafka](./assets/outbox3.png) - +RavenDB Studio Ongoing Tasks panel showing available ETL task types including RabbitMQ and Kafka ### Connecting RabbitMQ ETL Let’s connect to RabbitMQ. We enter the ongoing tasks creation menu and select RabbitMQ ETL. First, we need to create a connection string, which we can do easily: -![RavenDB Studio RabbitMQ ETL connection string configuration form](./assets/outbox4.png) - +RavenDB Studio RabbitMQ ETL connection string configuration form Select a name for the task, then proceed and select a name for the new connection string. Then you need to add the actual connection string that connects RavenDB to RabbitMQ. Use this format: ``` @@ -425,8 +373,7 @@ amqp://user:password@host:10000/ You can also do the same using Kafka ETL. We open the ongoing tasks menu in your database, then select Kafka ETL. Then you select your ETL name and name for your connection string. Enter your bootstrap server address (we’re running Kafka locally on port 9092): -![RavenDB Studio Kafka ETL connection string form with bootstrap server address field](./assets/outbox5.png) - +RavenDB Studio Kafka ETL connection string form with bootstrap server address field After that, we can move to the transformation script. ### Transformation Script \- “T” in the ETL @@ -454,16 +401,13 @@ loadToInvoiceCreated({ Then you just select your collection from the list, in this example, collection Invoices, and it’s ready to be saved. Nothing more is needed for the connection between RavenDB and those queues. -![RavenDB Studio ETL transformation script editor showing the loadToInvoiceCreated function with Invoices collection selected](./assets/outbox6.png) - +RavenDB Studio ETL transformation script editor showing the loadToInvoiceCreated function with Invoices collection selected Let’s check if the data is stored properly. Kafka: -![Kafka terminal output confirming invoice-created events published via RavenDB Queue ETL](./assets/outbox7.png) - +Kafka terminal output confirming invoice-created events published via RavenDB Queue ETL And for RabbitMQ we can just look into the GUI. -![RabbitMQ management GUI showing messages published via RavenDB Queue ETL](./assets/outbox8.png) - +RabbitMQ management GUI showing messages published via RavenDB Queue ETL This way, with RavenDB, you can address the actual need of publishing an event after invoice creation in **minutes**. RavenDB ETLs can be used in many different ways. If you are interested in ETL to AWS SQS, [read about RavenDB Amazon SQS ETL](https://ravendb.net/articles/new-in-7-0-ravendb-and-amazon-sqs-etl). You might also be interested in [The Library of Ravens sample repository](https://github.com/ravendb/samples-library), which uses ETL to handle timeouts. diff --git a/guides/troubleshooting-which-index-ate-my-disk.mdx b/guides/troubleshooting-which-index-ate-my-disk.mdx index 61bd1da84e..f61bbf060e 100644 --- a/guides/troubleshooting-which-index-ate-my-disk.mdx +++ b/guides/troubleshooting-which-index-ate-my-disk.mdx @@ -5,5 +5,6 @@ description: "Read about Which Index Ate My Disk? on the RavenDB.net news sectio externalUrl: "https://ravendb.net/articles/troubleshooting-which-index-ate-my-disk" publishedAt: 2025-08-26 image: "https://ravendb.net/wp-content/uploads/2024/09/Designer.png" +proficiencyLevel: "Expert" --- diff --git a/guides/unlock-ravendb-genai-potential-with-attachments.mdx b/guides/unlock-ravendb-genai-potential-with-attachments.mdx index b5fd909caa..e0f1df8be0 100644 --- a/guides/unlock-ravendb-genai-potential-with-attachments.mdx +++ b/guides/unlock-ravendb-genai-potential-with-attachments.mdx @@ -5,5 +5,6 @@ description: "Read about Unlock RavenDB GenAI Potential with Attachments on the externalUrl: "https://ravendb.net/articles/unlock-ravendb-genai-potential-with-attachments" publishedAt: 2025-10-08 image: "https://ravendb.net/wp-content/uploads/2025/10/unlock-genai-potential-article-image.svg" +proficiencyLevel: "Expert" --- diff --git a/guides/unlocking-the-benefits-of-on-demand-production-database-replication.mdx b/guides/unlocking-the-benefits-of-on-demand-production-database-replication.mdx index 6b68455565..d38d43d0cb 100644 --- a/guides/unlocking-the-benefits-of-on-demand-production-database-replication.mdx +++ b/guides/unlocking-the-benefits-of-on-demand-production-database-replication.mdx @@ -5,5 +5,6 @@ description: "Read about On-Demand Production Database Replication on the RavenD externalUrl: "https://ravendb.net/articles/unlocking-the-benefits-of-on-demand-production-database-replication" publishedAt: 2025-02-23 image: "https://ravendb.net/wp-content/uploads/2025/02/unlocking-the-benefits.jpg" +proficiencyLevel: "Expert" --- diff --git a/guides/using-azure-queue-storage-etl-to-process-ravendb-documents-in-a-serverless-manner.mdx b/guides/using-azure-queue-storage-etl-to-process-ravendb-documents-in-a-serverless-manner.mdx index 8b811e6933..36241640e4 100644 --- a/guides/using-azure-queue-storage-etl-to-process-ravendb-documents-in-a-serverless-manner.mdx +++ b/guides/using-azure-queue-storage-etl-to-process-ravendb-documents-in-a-serverless-manner.mdx @@ -5,5 +5,6 @@ description: "Read about Using Azure Queue Storage ETL for Serverless Processing externalUrl: "https://ravendb.net/articles/using-azure-queue-storage-etl-to-process-ravendb-documents-in-a-serverless-manner" publishedAt: 2025-10-22 image: "https://ravendb.net/wp-content/uploads/2024/09/azure_queue_storage.png" +proficiencyLevel: "Expert" --- diff --git a/guides/using-ravendb-persistence-in-an-akka-net-application.mdx b/guides/using-ravendb-persistence-in-an-akka-net-application.mdx index 9deeaf9084..2560e6b9e0 100644 --- a/guides/using-ravendb-persistence-in-an-akka-net-application.mdx +++ b/guides/using-ravendb-persistence-in-an-akka-net-application.mdx @@ -5,5 +5,6 @@ description: "Read about Using RavenDB Persistence in an Akka.NET Application on externalUrl: "https://ravendb.net/articles/using-ravendb-persistence-in-an-akka-net-application" publishedAt: 2025-08-26 image: "https://ravendb.net/wp-content/uploads/2024/08/akka.png" +proficiencyLevel: "Expert" --- diff --git a/guides/using-ravendb-with-phpfastcache.mdx b/guides/using-ravendb-with-phpfastcache.mdx index ffe150f93f..a7fd4d8e5f 100644 --- a/guides/using-ravendb-with-phpfastcache.mdx +++ b/guides/using-ravendb-with-phpfastcache.mdx @@ -5,5 +5,6 @@ description: "Read about Using RavenDB with PHPFastCache on the RavenDB.net news externalUrl: "https://ravendb.net/articles/using-ravendb-with-phpfastcache" publishedAt: 2024-08-05 image: "https://ravendb.net/wp-content/uploads/2024/08/phpfastcache.png" +proficiencyLevel: "Beginner" --- diff --git a/guides/using-remote-attachments-to-cut-storage-costs.mdx b/guides/using-remote-attachments-to-cut-storage-costs.mdx index 9f9310ae44..546ade2595 100644 --- a/guides/using-remote-attachments-to-cut-storage-costs.mdx +++ b/guides/using-remote-attachments-to-cut-storage-costs.mdx @@ -2,90 +2,98 @@ title: "Using Remote Attachments to cut storage costs" tags: [document-extensions, attachments, data-governance, architecture, csharp] icon: "remote-attachment" -description: "Learn more about offloading RavenDB attachments to remote storage buckets to slash your storage costs." +description: "Store RavenDB attachments in Amazon S3 or Azure Blob Storage to reduce database storage costs. Step-by-step setup for Studio and C# code, including bulk migration of existing local attachments." publishedAt: 2026-02-01 author: "Paweł Lachowski" +proficiencyLevel: "Expert" --- import Admonition from '@theme/Admonition'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; -import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; -import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; -RavenDB's document [attachments](https://docs.ravendb.net/7.2/document-extensions/attachments/overview/) let you store any file with the corresponding document. No matter if it's a PDF, a video, an image, or something completely different, you can still keep it with the rest of the document, stored as bytes. The only problem is that some attachments can be large and numerous, while your storage space may be limited. +RavenDB's document [attachments](https://docs.ravendb.net/7.2/document-extensions/attachments/overview/) let you store any file with the corresponding document. No matter if it's a PDF, a video, an image, or something completely different, you can still keep it with the rest of the document, stored as bytes. The only problem is that some attachments can be large and numerous, while your storage space may be limited. -There’s a simple solution \- you might want to store binary files at some cloud object storage, but transporting your data with custom scripts creates operational risk and adds another point of failure, not to mention implementation and maintenance costs. - -That's why remote attachments exist: an easy way to add and store attachments in the cloud storage service. In this guide, we will discuss how to add and utilize remote attachments. Let’s dive into the topic and learn how to utilize them with maximum efficiency. +There's a simple solution \- you might want to store binary files at some cloud object storage, but transporting your data with custom scripts creates operational risk and adds another point of failure, not to mention implementation and maintenance costs. -## Attachments overall +That's why remote attachments exist: an easy way to add and store attachments in the cloud storage service. In this guide, we will discuss how to add and utilize remote attachments. Let's dive into the topic and learn how to utilize them with maximum efficiency. -Let’s start with Voron \- RavenDB’s storage engine. Locally, when you store your attachment, Voron turns it into a single binary stream \- we only know where the file starts and how long it is. This allows the database to store any attachment, regardless of data type. This concept may seem basic, but that's what makes it work. What makes it awesome is the optimization part of the Voron itself, but the concept is easy to grasp, and it follows RavenDB’s attachment design principle: they are meant to be easy to understand and easy to use. +## How does RavenDB store attachments locally? -## Why use remote attachments +RavenDB uses Voron, its own storage engine, to manage attachment data. When you store an attachment locally, Voron writes it as a single binary stream — the engine tracks only where the file starts and how long it is. This allows the database to store any attachment regardless of data type, with Voron's internal optimizations handling compression and I/O efficiency transparently. -Remote attachments let you store large attachment data in external cloud storage instead of inside the database. This keeps your database small and fast, even when working with heavy files. Attachments are stored in your **own** cloud account (Azure Blob Storage, Amazon S3, or S3-compatible storage). +## Why should you use remote attachments instead of local storage? -From the application’s perspective, nothing changes. Attachments are accessed exactly the same way as before. The only difference is that the binary data lives outside the database. Existing attachments can be moved to remote storage without schema changes or application rewrites. +Remote attachments let you store large attachment data in external cloud storage instead of inside the database. This keeps your database small and fast, even when working with heavy files. Attachments are stored in your **own** cloud account (Azure Blob Storage, Amazon S3, or S3-compatible storage such as MinIO, Wasabi, or Backblaze B2). -RavenDB handles the entire process for you: uploads, retries, consistency, and monitoring. There are no custom scripts, no fragile migrations, and no application changes required. Let’s discover various destinations and describe how we can leverage them. +From the application's perspective, nothing changes. Attachments are accessed exactly the same way as before. The only difference is that the binary data lives outside the database. Existing attachments can be moved to remote storage without schema changes or application rewrites. -#### Cold storage +RavenDB handles the entire process for you: uploads, retries, consistency, and monitoring. There are no custom scripts, no fragile migrations, and no application changes required. Let's discover various destinations and describe how we can leverage them. -When data that is rarely accessed, but must be kept for long periods of time, e.g. invoices, medical documentation, or legal documents, you typically don’t need to access them immediately, as fast as possible. For those documents, we want to use cost-effective storage options, such as Glacier Instant or Glacier Deep Archive for AWS S3. What’s the difference between those classes? - - -S3 storage class can be configured in Studio, but if you want to configure Azure Blob storage behaviour you will need to do it yourself in Azure settings. + +Remote attachments are not supported on sharded databases. If you are using [sharding](https://docs.ravendb.net/7.2/sharding/overview), attachments must remain local. -Main differences between types of storage that we need to take into account are costs and retrieval time. Glacier Deep Archive can take time to retrieve an attachment, while Instant will bring it in a moment. So is Instant better? The difference is in price, as Deep Archive is cheaper per GB of data we retrieve. But are remote attachments only good for cold storage? - -#### Latency-sensitive Data +### When should you use cold storage classes like Glacier? -Not at all. If you select another class, like Standard or Intelligent-Tiering, you can easily store and retrieve data in a much more rapid manner. If you have a situation that needs fast retrievals, like product images or PDFs used repeatedly, you may prefer to select S3 Standard class. +Cold storage classes are the right choice for remote attachments that are written once and rarely read — such as invoices, medical documentation, or legal documents. For those cases, you typically don't need immediate access. Cost-effective storage options such as Glacier Instant Retrieval or Glacier Deep Archive for AWS S3 are ideal. Deep Archive can cost roughly 90% less per GB than Standard storage, but retrieval takes minutes to hours instead of milliseconds. - -Currently for this feature (RavenDB 7.2.0) Azure Blob, Amazon S3, and any S3-compatible services are supported. In this guide, we assume you already have your S3 or Blob. + +S3 storage class can be configured in Studio, but if you want to configure Azure Blob storage behaviour you will need to do it yourself in Azure settings. -### Setup in studio +### Which S3 storage class is best for frequently accessed attachments? -To pick a destination for your attachments, we first need to prepare a connection string. Open your database, open the Settings tab, and then the Remote Attachments settings. +If your attachments need fast retrieval — such as product images or PDFs used repeatedly — choose S3 Standard or Intelligent-Tiering. Standard provides millisecond-level access with higher per-GB costs. Intelligent-Tiering automatically moves objects between access tiers based on usage patterns, optimizing cost without sacrificing retrieval speed. -![](./assets/Remote1.png) + +Currently (RavenDB 7.2), Azure Blob, Amazon S3, and any S3-compatible services (MinIO, Wasabi, Backblaze B2) are supported. In this guide, we assume you already have your S3 or Blob storage configured. + -#### Amazon S3 +### How do you set up remote attachments in Studio? -Configuration is straightforward. Pick the provider and enter a Destination identifier (your new Destination's unique name). Then we can go to AWS S3 and grab the needed information for the connection. First, enter the bucket you selected when creating S3, then select the remote folder (if needed) and the region that you can check on top right. Then go into IAM and create/enter your role with access key and secret key. +To pick a destination for your attachments, first prepare a connection string. Open your database, open the Settings tab, and then the Remote Attachments settings. -If you want to learn more about role creation in AWS’s IAM please refer to [documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html). +RavenDB Studio Settings tab showing the Remote Attachments configuration panel +#### Amazon S3 -Next we need to choose S3 Storage class. Those classes affect how your S3 will behave and how storage services will be priced, as we spoke before. Depending on your needs, you might choose from different classes, which can be divided into four basic ones and then further subdivided. Those four are: +Configuration is straightforward: -* For frequent access, e.g. S3 Standard -* For occasional access, e.g. S3 Standard-IA -* For rare access, e.g. S3 Glacier Instant Retrieval -* Unpredictable/auto e.g. S3 Intelligent-Tiering +1. Pick the provider and enter a Destination identifier (your new Destination's unique name). +2. Enter the bucket name you selected when creating S3, then select the remote folder (if needed) and the region. +3. Go to IAM and create or retrieve your role with access key and secret key. If you want to learn more about role creation in AWS's IAM please refer to [the AWS IAM documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html). +4. Choose an S3 Storage Class. Those classes affect how your S3 will behave and how storage services will be priced. Depending on your needs, you can choose from: -If you want to learn more about them, you should look [here](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html). After choosing a class, you can Test credentials and then Apply Configuration. Then you switch on Remote Attachements and you are ready to add documents. +* For frequent access, e.g. S3 Standard +* For occasional access, e.g. S3 Standard-IA +* For rare access, e.g. S3 Glacier Instant Retrieval +* Unpredictable/auto e.g. S3 Intelligent-Tiering -![](./assets/Remote2.png) +If you want to learn more about S3 storage classes, see the [AWS storage class documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html). After choosing a class, you can Test credentials and then Apply Configuration. Then switch on Remote Attachments and you are ready to add documents. +Amazon S3 remote attachments connection string configuration in RavenDB Studio #### Azure Blob -Azure Blob Storage doesn’t have a class, so the setup is even simpler. You can just configure object storage itself on Azure’s page; from our perspective, you just connect and go. +Azure Blob Storage doesn't have a storage class selector in Studio, so the setup is simpler. You configure storage tiers (Hot, Cool, Archive) directly in the Azure portal; from RavenDB's side, you just connect and go. -![](./assets/Remote3.png) +Azure Blob Storage remote attachments configuration form in RavenDB Studio +To connect: -To connect your Azure you need to go into your Security settings and into Access key. There you can copy both the Account name (Storage account name) and Account key. Then you just go to your Containers tab and create a new container. Copy the Account name, account key, and fill in the storage container name. Then just select name for the destination and save. After enabling Remote Attachements we are ready to add attachments. +1. In Azure, go to your Storage Account's Security settings and then Access keys. Copy both the Account name and Account key. +2. Go to your Containers tab and create a new container (or use an existing one). +3. In RavenDB Studio, enter the Account name, Account key, and storage container name. Then select a name for the destination and save. +4. After enabling Remote Attachments, you are ready to add attachments. -![Nazwa](./assets/Remote4.png) +Azure Blob connection string details entered in RavenDB Studio configuration panel +### How do you configure remote attachments from C# code? -### Setup from code + +Sending `ConfigureRemoteAttachmentsOperation` replaces the **entire** existing configuration. If you already have a destination configured and want to add a second one, first retrieve the current configuration, add your new destination to it, then send the updated configuration. Otherwise, the existing destination will be silently removed. + -If you prefer to configure your destination using code, you can do that easily. You can do that like this. +You can configure an Amazon S3 destination like this: ```csharp var s3Settings = new RemoteAttachmentsS3Settings @@ -123,7 +131,7 @@ await store.Maintenance.SendAsync( ``` -Or alternatively, for Azure, you can do this like this. +Or alternatively, for Azure Blob Storage: ```csharp var azureSettings = new RemoteAttachmentsAzureSettings @@ -159,19 +167,19 @@ await store.Maintenance.SendAsync( ); ``` -### Add remote attachment \- Studio - -Once we are configured up let’s add a new remote attachment to a document. Enter your document you want to add attachment to and then select the attachments tab under the properties window. There, you want to click the arrow on the right to reveal ‘Add attachment to remote storage’ +For more details on all configuration options, see the [remote attachments reference documentation](https://docs.ravendb.net/7.2/document-extensions/attachments/configure-remote-attachments). -![](./assets/Remote5.png) +### How do you add a remote attachment in Studio? -Just add the file, select the destination you want to use, and set the time it is supposed to be moved to the destination. After saving, your attachment is added locally and will be transported to your remote storage when the scheduled time comes. +Once configured, you can add a new remote attachment to a document. Enter your document and select the attachments tab under the properties window. Click the arrow on the right to reveal 'Add attachment to remote storage'. -![](./assets/Remote6.png) +Document attachments tab in RavenDB Studio with the expanded dropdown showing the Add attachment to remote storage option +Add the file, select the destination you want to use, and set the time it is supposed to be moved to the destination. After saving, your attachment is added locally and will be transported to your remote storage when the scheduled time comes. -### Add remote attachment \- Code +Remote attachment upload dialog showing destination selection and scheduled transfer time +### How do you add a remote attachment from C# code? -Adding remote attachments from code is nearly as easy as adding regular attachments. You can use such code: +Adding remote attachments from code is nearly as easy as adding regular attachments: ```csharp using (var asyncSession = store.OpenAsyncSession()) @@ -204,14 +212,14 @@ using (var asyncSession = store.OpenAsyncSession()) ContentType = "image/png" }; - asyncSession.Advanced.Attachments.Store("products/999", storeParameters); + asyncSession.Advanced.Attachments.Store("products/1999", storeParameters); await asyncSession.SaveChangesAsync(); } } ``` -Or alternatively you can do it using an `PutAttachmentOperation` operation like this: +Or alternatively you can do it using a `PutAttachmentOperation` operation: ```csharp var attachmentPath = @"C:\temp\image1.png"; @@ -240,11 +248,10 @@ await using (var stream = new FileStream( Then after one minute that has been requested with `DateTime.UtcNow.AddMinutes(1)`, we can see the attachments were automatically offloaded to our S3 bucket: -![](./assets/Remote7.png) +RavenDB Studio showing an attachment that has been offloaded to Amazon S3 remote storage with a remote storage indicator +### How do you migrate existing local attachments to remote storage? -### Moving all Local Attachments to Remote - -When moving to remote storage, you would probably also want to move old attachments. To do that we can use [patch operation](https://docs.ravendb.net/7.2/client-api/operations/patching/set-based#updating-all-documents): +When moving to remote storage, you would probably also want to move old attachments. To do that we can use a [set-based patch operation](https://docs.ravendb.net/7.2/client-api/operations/patching/set-based#updating-all-documents): ```csharp from @all_docs @@ -270,4 +277,16 @@ update After this script is executed, all attachments will be scheduled to be offloaded into the target destination. +## Summary + +Remote attachments in RavenDB let you offload binary data to Amazon S3, Azure Blob Storage, or any S3-compatible service while keeping the same API access patterns. Key takeaways: + +- **Cold storage** (Glacier, Archive tiers) is ideal for rarely accessed compliance or archival data, reducing storage costs by up to 90%. +- **Standard or Intelligent-Tiering** is best for frequently accessed attachments like product images. +- Configuration is available through both Studio and C# code. The upload process is asynchronous — attachments are stored locally first, then transferred at the scheduled time. +- Existing local attachments can be bulk-migrated using a set-based patch operation. +- Remote attachments are **not supported on sharded databases**. + +For the full API reference, see the [remote attachments configuration documentation](https://docs.ravendb.net/document-extensions/attachments/configure-remote-attachments). To learn about storing remote attachments programmatically, see [store remote attachments](https://docs.ravendb.net/document-extensions/attachments/store-attachments/store-attachments-remote). For how remote attachments interact with replication, backups, and subscriptions, see [attachments and other features](https://docs.ravendb.net/document-extensions/attachments/attachments-and-other-features). + Interested in RavenDB? Grab the developer license dedicated for testing under this link [here](https://ravendb.net/dev), or get a free cloud database [here](https://ravendb.net/cloud). If you have questions about this feature, or want to hang out and talk with the RavenDB team, join our Discord Community Server \- invitation link is [here](https://discord.com/invite/ravendb). diff --git a/guides/vibe-coding-with-ravendb-and-context7.mdx b/guides/vibe-coding-with-ravendb-and-context7.mdx index 3bb900d915..28bb2bdf58 100644 --- a/guides/vibe-coding-with-ravendb-and-context7.mdx +++ b/guides/vibe-coding-with-ravendb-and-context7.mdx @@ -1,8 +1,8 @@ --- title: "Vibe Coding with RavenDB and Context7" -tags: [getting-started, ai] +tags: [getting-started, ai, integration] icon: "ai" -description: "Learn how to set up Context7 MCP with OpenAI Codex in VS Code to give your AI assistant direct access to RavenDB documentation — faster, context-rich vibe coding with fewer interruptions." +description: "Set up Context7 MCP with OpenAI Codex in VS Code to give your AI direct access to RavenDB docs — faster, context-rich vibe coding with fewer interruptions." keywords: [vibe coding, Context7, MCP, model context protocol, RavenDB, AI coding assistant, OpenAI Codex, VS Code, NoSQL prototype] publishedAt: 2026-03-09 see_also: @@ -15,42 +15,16 @@ see_also: source: "docs" path: "AI Integration > Generating Embeddings" author: "Paweł Lachowski" +proficiencyLevel: "Beginner" --- - - - - import Admonition from '@theme/Admonition'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; As AI tools become more capable, so-called “vibe coding” becomes a practical option in certain situations. It can be especially useful for fast PoC development and prototyping. When treated as just another tool in our toolbox, it fits naturally into a modern workflow. One of its strongest advantages is lowering the barrier to entry for technologies you are not yet comfortable with. With AI assistance, you can quickly prototype an idea and evaluate whether a chosen technology is appropriate before committing more time to it. @@ -84,8 +58,7 @@ Before starting, make sure you have the following in place: First, we install the Codex extension in Visual Studio Code and log in to our Codex. Next, we open the Codex settings menu (the cog icon) and select MCP settings → Open config.toml. -![OpenAI Codex settings menu showing the cog icon and MCP settings option in VS Code](./assets/context1.png) - +OpenAI Codex settings menu showing the cog icon and MCP settings option in VS Code Inside this file, we need to establish a connection with our MCP server. Using the [Context7 MCP setup guide for Codex](https://context7.com/docs/resources/all-clients#openai-codex), we copy and paste the configuration code. For Codex, it is: ```json @@ -100,8 +73,7 @@ command = "npx" Then replace the `YOUR_API_KEY` argument with your Context7 API key. -![config.toml file open in VS Code with the Context7 MCP server entry and API key field filled in](./assets/context2.png) - +config.toml file open in VS Code with the Context7 MCP server entry and API key field filled in After saving the config and restarting the IDE, you should be able to tell your AI assistant to use Context7. Now what is left is to go and check if it works. ## Building an E-Commerce Prototype with RavenDB @@ -120,20 +92,16 @@ Using Context7, write the backend and frontend of an e-commerce website connecti Now we can check whether the assistant will provide the requested code and use Context7 for it. We easily check by just looking at the generated content, and we can also click on the AI tool call to see it used Context7: -![AI assistant tool call panel showing Context7 was invoked to retrieve RavenDB library documentation](./assets/context3.png) - +AI assistant tool call panel showing Context7 was invoked to retrieve RavenDB library documentation As you can see, Context7 was called first to retrieve information about libraries. It gathered context from `ravendb/docs`. Of course, we don't need to call Context7 explicitly; the AI can use it on its own. We run a few more prompts to fix potential errors. While doing so, Codex fetches from Context7 on its own. -![Codex autonomously calling Context7 to resolve a RavenDB client API error without being asked](./assets/context4.png) - +Codex autonomously calling Context7 to resolve a RavenDB client API error without being asked As you can see, we asked the AI to help with an error we received, and Codex called Context7 itself. After those fixes we have ready-to-run prototype code: -![Generated e-commerce backend code using the RavenDB client API, connected to the live test server](./assets/context5.png) - +Generated e-commerce backend code using the RavenDB client API, connected to the live test server We can run the prepared code and verify it works and looks as expected. -![Running e-commerce prototype web application showing a product listing page connected to RavenDB](./assets/context6.png) - +Running e-commerce prototype web application showing a product listing page connected to RavenDB Fast and easy to build a working prototype without much prior knowledge of RavenDB. But we want more features. ### Expanding the Prototype with a Sales Dashboard @@ -146,12 +114,10 @@ Create a dashboard that analyzes orders and provides basic sales insights. Inclu After that, we have to wait a bit and let the AI work. We check and approve changes from time to time and issue additional prompts to fix errors and iterate on functionality (e.g., design or sorting logic) until we have working code. -![Dashboard source code showing RavenDB queries for order aggregation and sales statistics](./assets/context7.png) - +Dashboard source code showing RavenDB queries for order aggregation and sales statistics We can of course restart the program to pick up the changes and see how it looks. -![Sales analytics dashboard showing top products, best-selling days, top companies, revenue totals, and order counts](./assets/context8.png) - +Sales analytics dashboard showing top products, best-selling days, top companies, revenue totals, and order counts What AI created gives us information about top products, which day sells best, and which company is doing best, while also counting revenue, items sold, and orders. It is satisfactory at this point. ### Automated Email Support @@ -164,12 +130,10 @@ Add email sending. When a customer completes the order form, an email with the o The assistant then generates the code with the ready logic and informs us we only need to change the required lines in the config file. -![Generated email configuration file showing SMTP settings and order confirmation template](./assets/context9.png) - +Generated email configuration file showing SMTP settings and order confirmation template We enable email sending in the config and test it using a local SMTP server. We can see the message is generated and delivered. -![Local SMTP server log showing an order confirmation email successfully received at the test address](./assets/context10.png) - +Local SMTP server log showing an order confirmation email successfully received at the test address ## Summary and Next Steps With an AI assistant at our side, we built a working RavenDB e-commerce prototype — complete with a product listing page, a sales analytics dashboard, and automated order email notifications — in a single session. Context7 kept the AI grounded in accurate RavenDB documentation throughout, reducing the need to search for context and keeping the workflow uninterrupted. diff --git a/guides/what-requests-hit-my-cloud-cluster.mdx b/guides/what-requests-hit-my-cloud-cluster.mdx index 5134bea796..26b37958a7 100644 --- a/guides/what-requests-hit-my-cloud-cluster.mdx +++ b/guides/what-requests-hit-my-cloud-cluster.mdx @@ -5,5 +5,6 @@ description: "Read about What Requests Hit My Cloud Cluster? on the RavenDB.net externalUrl: "https://ravendb.net/articles/what-requests-hit-my-cloud-cluster" publishedAt: 2025-10-23 image: "https://ravendb.net/wp-content/uploads/2025/07/troublshooting-cluster-cover.png" +proficiencyLevel: "Expert" --- diff --git a/guides/writing-unit-tests-with-ravendb-java-test-driver.mdx b/guides/writing-unit-tests-with-ravendb-java-test-driver.mdx index 49077a5905..0b753d5998 100644 --- a/guides/writing-unit-tests-with-ravendb-java-test-driver.mdx +++ b/guides/writing-unit-tests-with-ravendb-java-test-driver.mdx @@ -5,4 +5,5 @@ description: "Read about Writing unit tests with RavenDB Java Test Driver on the externalUrl: "https://ravendb.net/articles/writing-unit-tests-with-ravendb-java-test-driver" publishedAt: 2024-09-05 icon: "java" +proficiencyLevel: "Beginner" --- diff --git a/guides/writing-unit-tests-with-ravendb-net-test-driver.mdx b/guides/writing-unit-tests-with-ravendb-net-test-driver.mdx index d136e50d78..aad46a79c4 100644 --- a/guides/writing-unit-tests-with-ravendb-net-test-driver.mdx +++ b/guides/writing-unit-tests-with-ravendb-net-test-driver.mdx @@ -5,4 +5,5 @@ description: "Read about Writing unit tests with RavenDB .NET Test Driver on the externalUrl: "https://ravendb.net/articles/writing-unit-tests-with-ravendb-net-test-driver" publishedAt: 2024-08-28 image: "https://ravendb.net/wp-content/uploads/2024/08/csharp-in-mem.png" +proficiencyLevel: "Beginner" --- diff --git a/guides/writing-unit-tests-with-ravendb-python-test-driver.mdx b/guides/writing-unit-tests-with-ravendb-python-test-driver.mdx index 8a75ddb11c..83158125e7 100644 --- a/guides/writing-unit-tests-with-ravendb-python-test-driver.mdx +++ b/guides/writing-unit-tests-with-ravendb-python-test-driver.mdx @@ -5,4 +5,5 @@ description: "Read about Writing unit tests with RavenDB Python Test Driver on t externalUrl: "https://ravendb.net/articles/writing-unit-tests-with-ravendb-python-test-driver" publishedAt: 2024-08-24 image: "https://ravendb.net/wp-content/uploads/2024/09/in-mem-python2-2.png" +proficiencyLevel: "Beginner" --- diff --git a/guides/zabbix-setup-guide.mdx b/guides/zabbix-setup-guide.mdx index 39df08a4aa..0d08e4b244 100644 --- a/guides/zabbix-setup-guide.mdx +++ b/guides/zabbix-setup-guide.mdx @@ -6,6 +6,7 @@ description: "How to set up your Zabbix to monitor your RavenDB Cloud" publishedAt: 2025-11-16 image: "https://ravendb.net/wp-content/uploads/2025/11/zabbix-article-image.svg" author: "Paweł Lachowski" +proficiencyLevel: "Beginner" --- import Admonition from '@theme/Admonition'; @@ -14,6 +15,7 @@ import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; import LanguageSwitcher from "@site/src/components/LanguageSwitcher"; import LanguageContent from "@site/src/components/LanguageContent"; +import Image from "@theme/IdealImage"; After setting up RavenDB and watching data flow smoothly between your app and a database, you realize that storing information is only half the story. The other half is keeping it nice and safe. That curiosity leads to monitoring. Tools designed to keep an eye on systems, servers, and networks in real time. @@ -105,12 +107,10 @@ Those four containers are the whole Zabbix environment. Now we need to connect i Let’s first log in to Zabbix with default credentials. You can enter webUI clicking at port next to the web container or by searching [`http://localhost:80`](http://localhost:80). -![](./assets/zabbix1.png) - + You should be greeted with sight like that: -![](./assets/zabbix2.png) - + There, you want to input default login credentials: Username: Admin @@ -118,30 +118,24 @@ Password: zabbix Once we log in, it’s worth changing the default credentials to something more secure. Let’s select User Settings on the left, then the profile tab and change your password. -![](./assets/zabbix3.png) - + Let’s add a RavenDB template we will use later. Templates can be downloaded from [Zabbix community github](https://github.com/zabbix/community-templates/blob/main/Databases/RavenDB/template_ravendb_server/6.0/template_ravendb_server.yaml). With the file downloaded, enter Data Collection and Templates. On the top right corner click import and select our file. -![](./assets/zabbix4.png) - + ## Connecting to RavenDB Now that we have the base for what we want to do let’s connect your RavenDB Cloud. First we need to turn on the monitoring product feature. You can do it in the Manage page of your chosen RavenDB Cloud instance. -![](./assets/zabbix5.png) - + In the product features, find the Monitoring option and enable it. We need SNMP credentials to connect with Zabbix. Just follow the configuration menu that you can open by pressing the button that will appear under where the enable button was. -![](./assets/zabbix6.png) - + Inside, you want to copy three things: authentication username, authentication password and privacy password. RavenDB is designed to be safe, so to ensure that we use SNMPv3, we use two passwords. Also, add IP you will be connecting to on top. -![](./assets/zabbix7.png) - + Now we go back to Zabbix and click on monitoring on the left bar and hosts. Then on the top right corner of the screen, hit create host. -![](./assets/zabbix8.png) - + What you need to do here is (In brackets, you have RavenDB Cloud configuration names): 1. Add Host Name @@ -156,14 +150,12 @@ What you need to do here is (In brackets, you have RavenDB Cloud configuration n 10. Select AES128 and add your Privacy passphrase (Privacy password) 11. Save -![](./assets/zabbix9.png) - + That’s it. If done correctly, you should be able to go into the latest data, select everything, and at the bottom of the page, click execute now. After a few seconds and a refresh, you should have data in your Zabbix. You can check all monitored metrics at this page. Let’s go to data collection and hosts. There are click triggers at your new host. You can see that we already have some triggers inside from the template. If they satisfy your needs, you are done; if not, let’s add a new one. On the top right corner of the screen, press Create Trigger. -![](./assets/zabbix10.png) - + We can add an expression in two ways. Either use the editor by pressing add or just typing it. We want to create information that will inform us that our database has been down for the last 30 minutes. Our expression will look like this. ``` showLineNumbers diff --git a/package-lock.json b/package-lock.json index 62481ea22c..f6ac53f011 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@docusaurus/core": "^3.9.2", "@docusaurus/faster": "^3.9.2", "@docusaurus/plugin-client-redirects": "^3.9.2", + "@docusaurus/plugin-ideal-image": "^3.9.2", "@docusaurus/preset-classic": "^3.9.2", "@mdx-js/react": "^3.0.0", "autoprefixer": "^10.4.21", @@ -247,6 +248,7 @@ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.41.0.tgz", "integrity": "sha512-G9I2atg1ShtFp0t7zwleP6aPS4DcZvsV4uoQOripp16aR6VJzbEnKFPLW4OFXzX7avgZSpYeBAS+Zx4FOgmpPw==", "license": "MIT", + "peer": true, "dependencies": { "@algolia/client-common": "5.41.0", "@algolia/requester-browser-xhr": "5.41.0", @@ -397,6 +399,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2184,6 +2187,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -2206,6 +2210,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2315,6 +2320,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2736,6 +2742,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3493,6 +3500,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/faster/-/faster-3.9.2.tgz", "integrity": "sha512-DEVIwhbrZZ4ir31X+qQNEQqDWkgCJUV6kiPPAd2MGTY8n5/n0c4B8qA5k1ipF2izwH00JEf0h6Daaut71zzkyw==", "license": "MIT", + "peer": true, "dependencies": { "@docusaurus/types": "3.9.2", "@rspack/core": "^1.5.0", @@ -3524,6 +3532,22 @@ "node": ">=20.0" } }, + "node_modules/@docusaurus/lqip-loader": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/lqip-loader/-/lqip-loader-3.9.2.tgz", + "integrity": "sha512-Q9QO0E+HLKhcpKVOIXRVBdJ1bbxxpfSwBll5NsmGxcx1fArH0fFi68cpEztqBg7WwbFRb976MTlqlBuGrMLpuw==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.9.2", + "file-loader": "^6.2.0", + "lodash": "^4.17.21", + "sharp": "^0.32.3", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, "node_modules/@docusaurus/mdx-loader": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.9.2.tgz", @@ -3645,6 +3669,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz", "integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==", "license": "MIT", + "peer": true, "dependencies": { "@docusaurus/core": "3.9.2", "@docusaurus/logger": "3.9.2", @@ -3791,6 +3816,36 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/plugin-ideal-image": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-ideal-image/-/plugin-ideal-image-3.9.2.tgz", + "integrity": "sha512-YYYbmC2wSYFd7o4//5rPXt9+DkZwfwjCUmyGi5OIVqEbwELK80o3COXs2Xd0BtVIpuRvG7pKCYrMQwVo32Y9qw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/lqip-loader": "3.9.2", + "@docusaurus/responsive-loader": "^1.7.0", + "@docusaurus/theme-translations": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "sharp": "^0.32.3", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "jimp": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "jimp": { + "optional": true + } + } + }, "node_modules/@docusaurus/plugin-sitemap": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.9.2.tgz", @@ -3868,6 +3923,30 @@ "react-dom": "^18.0.0 || ^19.0.0" } }, + "node_modules/@docusaurus/responsive-loader": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@docusaurus/responsive-loader/-/responsive-loader-1.7.1.tgz", + "integrity": "sha512-jAebZ43f8GVpZSrijLGHVVp7Y0OMIPRaL+HhiIWQ+f/b72lTsKLkSkOVHEzvd2psNJ9lsoiM3gt6akpak6508w==", + "license": "BSD-3-Clause", + "dependencies": { + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "jimp": "*", + "sharp": "*" + }, + "peerDependenciesMeta": { + "jimp": { + "optional": true + }, + "sharp": { + "optional": true + } + } + }, "node_modules/@docusaurus/theme-classic": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.9.2.tgz", @@ -4595,6 +4674,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -5149,6 +5229,7 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -5253,6 +5334,7 @@ "integrity": "sha512-oExhY90bes5pDTVrei0xlMVosTxwd/NMafIpqsC4dMbRYZ5KB981l/CX8tMnGsagTplj/RcG9BeRYmV6/J5m3w==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.25" @@ -6236,6 +6318,7 @@ "version": "19.1.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -6405,6 +6488,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.0.tgz", "integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", @@ -6823,6 +6907,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6903,6 +6988,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -6946,6 +7032,7 @@ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.41.0.tgz", "integrity": "sha512-9E4b3rJmYbBkn7e3aAPt1as+VVnRhsR4qwRRgOzpeyz4PAOuwKh0HI4AN6mTrqK0S0M9fCCSTOUnuJ8gPY/tvA==", "license": "MIT", + "peer": true, "dependencies": { "@algolia/abtesting": "1.7.0", "@algolia/client-abtesting": "5.41.0", @@ -7304,6 +7391,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "node_modules/babel-loader": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", @@ -7393,6 +7494,113 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.5.tgz", + "integrity": "sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz", + "integrity": "sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.1.tgz", + "integrity": "sha512-bSeR8RfvbRwDpD7HWZvn8M3uYNDrk7m9DQjYOFkENZlXW8Ju/MPaqUPQq5LqJ3kyjEm07siTaAQ7wBKCU59oHg==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.21.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", + "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/baseline-browser-mapping": { "version": "2.9.19", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", @@ -7429,6 +7637,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -7552,6 +7771,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7566,6 +7786,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -7991,6 +8235,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -8007,6 +8264,16 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -8500,6 +8767,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9296,6 +9564,15 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.19.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", @@ -9574,6 +9851,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -10133,6 +10411,15 @@ "node": ">=0.8.x" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/eventsource-parser": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", @@ -10164,6 +10451,15 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/express": { "version": "4.22.1", "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", @@ -10290,6 +10586,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -10437,6 +10739,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -10665,6 +10968,12 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, "node_modules/fs-extra": { "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", @@ -10807,6 +11116,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, "node_modules/github-slugger": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", @@ -11635,6 +11950,26 @@ "postcss": "^8.1.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -15430,6 +15765,12 @@ "node": ">= 18" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -15473,6 +15814,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -15502,6 +15849,24 @@ "tslib": "^2.0.3" } }, + "node_modules/node-abi": { + "version": "3.88.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.88.0.tgz", + "integrity": "sha512-At6b4UqIEVudaqPsXjmUO1r/N5BUr4yhDGs5PkBE8/oG5+TfLPhFechiskFsnT6Ql0VfUXbalUUCbfXxtj7K+w==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "license": "MIT" + }, "node_modules/node-emoji": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", @@ -15613,6 +15978,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -15781,6 +16147,15 @@ "node": ">= 0.8" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -16203,6 +16578,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -17106,6 +17482,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -17642,6 +18019,67 @@ "postcss": "^8.4.31" } }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -17769,6 +18207,16 @@ "node": ">= 0.10" } }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -17907,6 +18355,7 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -17915,6 +18364,7 @@ "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "peer": true, "dependencies": { "scheduler": "^0.26.0" }, @@ -17966,6 +18416,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "peer": true, "dependencies": { "@types/react": "*" }, @@ -17992,6 +18443,7 @@ "version": "5.3.4", "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -19098,6 +19550,29 @@ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -19202,6 +19677,66 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, "node_modules/sirv": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", @@ -19416,6 +19951,17 @@ "node": ">= 0.4" } }, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -19784,6 +20330,32 @@ "node": ">=18" } }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/tar/node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -19793,6 +20365,15 @@ "node": ">=18" } }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, "node_modules/terser": { "version": "5.43.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", @@ -19876,6 +20457,15 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/thingies": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", @@ -20007,7 +20597,20 @@ "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "peer": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } }, "node_modules/type-check": { "version": "0.4.0", @@ -20153,6 +20756,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "devOptional": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -20504,6 +21108,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -20709,6 +21314,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -21272,6 +21878,12 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", @@ -21401,6 +22013,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 36bd030ef0..ff83ca24c3 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@docusaurus/core": "^3.9.2", "@docusaurus/faster": "^3.9.2", "@docusaurus/plugin-client-redirects": "^3.9.2", + "@docusaurus/plugin-ideal-image": "^3.9.2", "@docusaurus/preset-classic": "^3.9.2", "@mdx-js/react": "^3.0.0", "autoprefixer": "^10.4.21", diff --git a/src/components/Common/LazyImage.tsx b/src/components/Common/LazyImage.tsx index 07b385c1c1..e083d5d20d 100644 --- a/src/components/Common/LazyImage.tsx +++ b/src/components/Common/LazyImage.tsx @@ -7,6 +7,18 @@ export interface LazyImageProps extends React.ImgHTMLAttributes; + if (typeof src === "string") return src; + if (src && typeof src === "object") return (src as Record).src as string; + return undefined; +} + export default function LazyImage({ imgSrc, src, @@ -53,17 +65,16 @@ export default function LazyImage({ function getSources({ imgSrc, src }: Pick): ThemedImageProps["sources"] { if (src) { - return { - light: src, - dark: src, - }; + return { light: src, dark: src }; + } + + if (imgSrc && typeof imgSrc === "object" && "light" in imgSrc && "dark" in imgSrc) { + return imgSrc; } - if (typeof imgSrc === "string") { - return { - light: imgSrc, - dark: imgSrc, - }; + const resolved = toUrl(imgSrc); + if (resolved) { + return { light: resolved, dark: resolved }; } return imgSrc; diff --git a/src/theme/DocItem/Authors/index.tsx b/src/theme/DocItem/Authors/index.tsx index 944fceb3a9..257bdfce35 100644 --- a/src/theme/DocItem/Authors/index.tsx +++ b/src/theme/DocItem/Authors/index.tsx @@ -2,14 +2,14 @@ import React from "react"; import { useDoc } from "@docusaurus/plugin-content-docs/client"; import authorsData from "@site/docs/authors.json"; import { Icon } from "@site/src/components/Common/Icon"; -import LazyImage from "@site/src/components/Common/LazyImage"; import { IconName } from "@site/src/typescript/iconName"; +import LazyImage from "@site/src/components/Common/LazyImage"; type Platform = "x" | "github" | "linkedin" | "email"; type Author = { name: string; - title: string | null; + jobTitle: string | null; url: string | null; imageURL: string; socials: Record; @@ -24,7 +24,7 @@ function getAuthorData(authorKey: string): Author | null { } return { name: authorInfo.name, - title: authorInfo.title, + jobTitle: authorInfo.job_title, url: authorInfo.url, imageURL: authorInfo.image_url, socials: authorInfo.socials, @@ -84,7 +84,7 @@ export default function DocItemAuthors() { src={author.imageURL} alt={author.name} className="docAuthorImg" - minContentHeight={32} + minContentHeight={40} /> )}
@@ -97,7 +97,7 @@ export default function DocItemAuthors() { author.name )}
- {author.title &&
{author.title}
} + {author.jobTitle &&
{author.jobTitle}
} {author.socials && (
{Object.entries(author.socials).map(([platform, handleOrUrl]) => { diff --git a/src/theme/DocItem/Metadata/GuideMetadata.tsx b/src/theme/DocItem/Metadata/GuideMetadata.tsx new file mode 100644 index 0000000000..ce48e84917 --- /dev/null +++ b/src/theme/DocItem/Metadata/GuideMetadata.tsx @@ -0,0 +1,100 @@ +import React, { type ReactNode } from "react"; +import Head from "@docusaurus/Head"; +import authorsData from "@site/docs/authors.json"; + +/** Pre-validated guide frontmatter — all required fields are non-optional. */ +export interface GuideMetadataProps { + title: string; + description: string; + proficiencyLevel: string; + canonicalUrl: string; + ogImageUrl: string; + authorKey?: string; + publishedAt?: string; + keywords?: string[]; + lastUpdatedAt?: number; +} + +export default function GuideMetadata({ + title, + description, + proficiencyLevel, + canonicalUrl, + ogImageUrl, + authorKey, + publishedAt, + keywords, + lastUpdatedAt, +}: GuideMetadataProps): ReactNode { + const authorInfo = authorKey ? authorsData[authorKey as keyof typeof authorsData] : null; + + const techArticleJsonLd = JSON.stringify({ + "@context": "https://schema.org", + "@type": "TechArticle", + headline: title, + description, + url: canonicalUrl, + mainEntityOfPage: { "@type": "WebPage", "@id": canonicalUrl }, + image: { "@type": "ImageObject", url: ogImageUrl, width: 1200, height: 630 }, + ...(publishedAt ? { datePublished: publishedAt } : {}), + ...(lastUpdatedAt + ? { dateModified: new Date(lastUpdatedAt * 1000).toISOString().split("T")[0] } + : publishedAt + ? { dateModified: publishedAt } + : {}), + inLanguage: "en", + ...(keywords?.length ? { keywords } : {}), + ...(authorInfo + ? { + author: { + "@type": "Person", + name: authorInfo.name, + ...(authorInfo.url ? { url: authorInfo.url } : {}), + ...(authorInfo.job_title + ? { + jobTitle: authorInfo.job_title, + worksFor: { + "@type": "Organization", + name: "RavenDB", + url: "https://ravendb.net", + }, + } + : {}), + }, + } + : {}), + publisher: { + "@type": "Organization", + name: "RavenDB", + url: "https://ravendb.net", + logo: { "@type": "ImageObject", url: ogImageUrl }, + }, + proficiencyLevel, + }); + + const breadcrumbJsonLd = JSON.stringify({ + "@context": "https://schema.org", + "@type": "BreadcrumbList", + itemListElement: [ + { + "@type": "ListItem", + position: 1, + name: "Guides", + item: `${canonicalUrl.split("/guides/")[0]}/guides/`, + }, + { + "@type": "ListItem", + position: 2, + name: title, + item: canonicalUrl, + }, + ], + }); + + return ( + + + + + ); +} diff --git a/src/theme/DocItem/Metadata/index.tsx b/src/theme/DocItem/Metadata/index.tsx index 9f54da7a0d..53d5f8ce10 100644 --- a/src/theme/DocItem/Metadata/index.tsx +++ b/src/theme/DocItem/Metadata/index.tsx @@ -5,31 +5,113 @@ import type { WrapperProps } from "@docusaurus/types"; import { useDoc } from "@docusaurus/plugin-content-docs/client"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Head from "@docusaurus/Head"; +import GuideMetadata from "./GuideMetadata"; type Props = WrapperProps; export default function MetadataWrapper(props: Props): ReactNode { const { siteConfig } = useDocusaurusContext(); - const { metadata } = useDoc(); + const { metadata, frontMatter } = useDoc(); const permalink = metadata.permalink; + const source = (metadata as Record).source as string | undefined; + + // Use file path (source) for page type detection — more reliable than permalink + // which may vary depending on Docusaurus trailingSlash configuration. + const isGuide = source?.startsWith("@site/guides/") || source?.startsWith("guides/") || false; + const isCloud = source?.startsWith("@site/cloud/") || source?.startsWith("cloud/") || false; + const isTemplate = source?.startsWith("@site/templates/") || source?.startsWith("templates/") || false; + const isVersionedDoc = !isGuide && !isCloud && !isTemplate; + + // Exclude landing pages (e.g. guides/home.mdx) from guide-specific metadata + const fileName = source?.split("/").pop(); + const isGuidePage = isGuide && fileName !== "home.mdx"; + // Strip trailing slash from base URL to avoid double slashes const baseUrl = (siteConfig.url as string).replace(/\/$/, ""); - const isVersionedDoc = - !permalink.startsWith("/guides/") && !permalink.startsWith("/cloud/") && !permalink.startsWith("/templates/"); let canonicalUrl = isVersionedDoc ? `${baseUrl}/${siteConfig.customFields.latestVersion}${metadata.slug}` : `${baseUrl}${permalink}`; - if (canonicalUrl.endsWith("/") == false) { + if (!canonicalUrl.endsWith("/")) { canonicalUrl = canonicalUrl.concat("/"); } + const description = metadata.description || frontMatter.description || ""; + const title = metadata.title || ""; + const ogImageUrl = `${baseUrl}/img/social-card.jpg`; + return ( <> + {description && } + {title && } + + + + + + + {title && } + {description && } + + + {isGuidePage && ( + + )} ); } + +/** + * Validates required guide frontmatter fields at build time and passes + * pre-validated data to GuideMetadata so it doesn't deal with optional types. + */ +function ValidatedGuideMetadata({ + title, + description, + lastUpdatedAt, + frontMatter, + canonicalUrl, + ogImageUrl, + permalink, +}: { + title: string; + description: string; + lastUpdatedAt?: number; + frontMatter: ReturnType["frontMatter"]; + canonicalUrl: string; + ogImageUrl: string; + permalink: string; +}): ReactNode { + if (!title) { + throw new Error(`Guide "${permalink}" is missing a required "title" in frontmatter.`); + } + if (!frontMatter.proficiencyLevel) { + throw new Error(`Guide "${permalink}" is missing a required "proficiencyLevel" in frontmatter.`); + } + + return ( + + ); +} diff --git a/src/typescript/docMetadata.d.ts b/src/typescript/docMetadata.d.ts index 5add65f441..d40e3f782d 100644 --- a/src/typescript/docMetadata.d.ts +++ b/src/typescript/docMetadata.d.ts @@ -10,6 +10,8 @@ export interface CustomDocFrontMatter extends DocFrontMatter { icon?: IconName; image?: string | { light: string; dark: string }; publishedAt?: string; + proficiencyLevel?: string; + keywords?: string[]; } type CustomDocContextValue = Omit & { diff --git a/static/llms.txt b/static/llms.txt index 0836d1df32..36429e0ba2 100644 --- a/static/llms.txt +++ b/static/llms.txt @@ -1,6 +1,6 @@ -## RavenDB Documentation +# RavenDB -Everything you need to know about our product, from getting started to advanced features. +> RavenDB is a NoSQL document database designed for building high-performance, distributed applications. This is the official documentation site covering all product versions, cloud services, and community guides. ## General Information @@ -16,6 +16,8 @@ Everything you need to know about our product, from getting started to advanced ## Version Information +- [7.2 (Current)](https://docs.ravendb.net/): Documentation for the current version 7.2 of RavenDB. + - [7.1](https://docs.ravendb.net/7.1): Documentation for version 7.1 of RavenDB. - [7.0](https://docs.ravendb.net/7.0): Documentation for version 7.0 of RavenDB. @@ -168,6 +170,50 @@ Everything you need to know about our product, from getting started to advanced - [Akka.NET](https://docs.ravendb.net/integrations/akka.net-persistence/integrating-with-akka-persistence): Use RavenDB as storage for Akka.Persistence. +## Guides + +- [Guides Home](https://docs.ravendb.net/guides/home): Browse all community guides for RavenDB. + +- [Using Remote Attachments to Cut Storage Costs](https://docs.ravendb.net/guides/using-remote-attachments-to-cut-storage-costs): Store attachments in Amazon S3 or Azure Blob Storage to reduce database storage costs. + +- [Employing Data Archival](https://docs.ravendb.net/guides/employing-data-archival-guide): Set up and use data archival in RavenDB to improve query performance. + +- [AI Image Search with RavenDB](https://docs.ravendb.net/guides/ai-image-search-with-ravendb): Build AI-powered image search using vector search and embeddings. + +- [Embeddings Generation with RavenDB](https://docs.ravendb.net/guides/embeddings-generation-with-ravendb): Automatically generate vector embeddings from document data. + +- [Vector Search in RavenDB](https://docs.ravendb.net/guides/new-in-7-0-ravendbs-vector-search): Use vector search capabilities for semantic similarity queries. + +- [Practical Look at AI Agents with RavenDB](https://docs.ravendb.net/guides/practical-look-at-ai-agents-with-ravendb): Build database-native AI agents. + +- [GenAI: How We Make You Work Less](https://docs.ravendb.net/guides/genai-how-we-make-you-work-less): Leverage RavenDB's generative AI integration features. + +- [Setting Up RavenDB with ASP.NET Core 8](https://docs.ravendb.net/guides/how-to-setup-ravendb-with-asp-net-core-8-application): Connect and configure RavenDB in an ASP.NET Core 8 project. + +- [Querying with RavenDB and ASP.NET Core 9](https://docs.ravendb.net/guides/how-to-query-using-ravendb-and-asp-net-core-9): Query data using RavenDB in ASP.NET Core 9 applications. + +- [Integrating RavenDB into Next.js](https://docs.ravendb.net/guides/integrating-ravendb-into-next-js-app): Use RavenDB as the database for a Next.js web application. + +- [Integrate RavenDB into SvelteKit](https://docs.ravendb.net/guides/integrate-ravendb-into-sveltekit-app): Connect RavenDB to a SvelteKit application. + +- [Semantic Search with Python and FastAPI](https://docs.ravendb.net/guides/semantic-search-with-ravendb-python-and-fastapi): Build semantic search using RavenDB with Python and FastAPI. + +- [Spatial Search in RavenDB](https://docs.ravendb.net/guides/spatial-search-in-ravendb): Build radius, polygon, and reverse spatial search applications in Python using RavenDB's native geospatial indexing. + +- [Deploying RavenDB with Docker Compose](https://docs.ravendb.net/guides/ravendb-deployment-guide-docker-compose-cluster): Deploy a RavenDB cluster using Docker Compose. + +- [Setting Up RavenDB on AWS EKS](https://docs.ravendb.net/guides/setting-up-ravendb-cluster-on-aws-eks): Deploy RavenDB on Amazon Elastic Kubernetes Service. + +- [Deploying RavenDB with Helm Chart](https://docs.ravendb.net/guides/deploying-ravendb-with-helm-chart): Use Helm charts for Kubernetes deployment. + +- [Grafana Cloud with OpenTelemetry](https://docs.ravendb.net/guides/grafana-cloud-configuration-with-opentelemetry): Monitor RavenDB with Grafana Cloud via OpenTelemetry. + +- [Leverage RavenDB Observability with Datadog](https://docs.ravendb.net/guides/leverage-ravendb-observability-with-datadog): Integrate RavenDB monitoring with Datadog. + +- [Writing Unit Tests with .NET Test Driver](https://docs.ravendb.net/guides/writing-unit-tests-with-ravendb-net-test-driver): Test RavenDB applications using the .NET test driver. + +- [From Zero to a Fully Secured Cluster](https://docs.ravendb.net/guides/from-zero-to-a-fully-secured-cluster): Step-by-step guide to securing a RavenDB cluster. + ## Support and Resources - [Contact support](https://ravendb.net/support): Reach out for assistance with RavenDB. @@ -179,4 +225,3 @@ Everything you need to know about our product, from getting started to advanced - [About us](https://ravendb.net/about): Learn more about the RavenDB team and mission. - [Legal](https://ravendb.net/legal): Access legal information related to RavenDB usage. - diff --git a/static/robots_prod.txt b/static/robots_prod.txt index a80f891fbc..f714ca10f4 100644 --- a/static/robots_prod.txt +++ b/static/robots_prod.txt @@ -15,5 +15,70 @@ Disallow: /2.0/ Disallow: /1.0/ Allow: / +# AI Search Crawlers +User-agent: GPTBot +Disallow: /5.4/ +Disallow: /5.3/ +Disallow: /5.2/ +Disallow: /5.1/ +Disallow: /5.0/ +Disallow: /4.2/ +Disallow: /4.1/ +Disallow: /4.0/ +Disallow: /3.5/ +Disallow: /3.0/ +Disallow: /2.5/ +Disallow: /2.0/ +Disallow: /1.0/ +Allow: / + +User-agent: OAI-SearchBot +Disallow: /5.4/ +Disallow: /5.3/ +Disallow: /5.2/ +Disallow: /5.1/ +Disallow: /5.0/ +Disallow: /4.2/ +Disallow: /4.1/ +Disallow: /4.0/ +Disallow: /3.5/ +Disallow: /3.0/ +Disallow: /2.5/ +Disallow: /2.0/ +Disallow: /1.0/ +Allow: / + +User-agent: ClaudeBot +Disallow: /5.4/ +Disallow: /5.3/ +Disallow: /5.2/ +Disallow: /5.1/ +Disallow: /5.0/ +Disallow: /4.2/ +Disallow: /4.1/ +Disallow: /4.0/ +Disallow: /3.5/ +Disallow: /3.0/ +Disallow: /2.5/ +Disallow: /2.0/ +Disallow: /1.0/ +Allow: / + +User-agent: PerplexityBot +Disallow: /5.4/ +Disallow: /5.3/ +Disallow: /5.2/ +Disallow: /5.1/ +Disallow: /5.0/ +Disallow: /4.2/ +Disallow: /4.1/ +Disallow: /4.0/ +Disallow: /3.5/ +Disallow: /3.0/ +Disallow: /2.5/ +Disallow: /2.0/ +Disallow: /1.0/ +Allow: / + # Sitemaps Sitemap: https://docs.ravendb.net/sitemap.xml