Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions app/authzed/guides/picking-a-product/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,36 @@ This document is designed to give a high-level overview of the features supporte

## Feature Matrix

| Feature | [Open Source] | [Cloud] | [Dedicated] | [Enterprise] |
| ---------------------------- | :-----------: | :-----: | :---------: | :----------: |
| Self-Hosted | <Yes /> | <No /> | <No /> | <Yes /> |
| No-commit pricing | <Yes /> | <Yes /> | <No /> | <No /> |
| [Materialize (Early Access)] | <No /> | <No /> | <Yes /> | <No /> |
| [Management Dashboard] | <No /> | <Yes /> | <Yes /> | <No /> |
| [Private Networking] | DIY | <No /> | <Yes /> | DIY |
| [Workload Isolation] | DIY | <Yes /> | <Yes /> | DIY |
| [Automated Updates] | DIY | <Yes /> | <Yes /> | DIY |
| [SOC2 Compliance] | DIY | <Yes /> | <Yes /> | DIY |
| [Audit Logging] | <No /> | <Yes /> | <Yes /> | <Yes /> |
| [Rate Limiting] | <No /> | <Yes /> | <Yes /> | <Yes /> |
| [Multi-Region Deployments] | DIY | <No /> | <Yes /> | DIY |
| [Security Embargo] | <No /> | <Yes /> | <Yes /> | <Yes /> |
| [Restricted API Access] | DIY | <Yes /> | <Yes /> | <Yes /> |
| [Expedited Support] | <No /> | <Yes /> | <Yes /> | <Yes /> |
<FeatureMatrix>

| Feature | [Open Source] | [Cloud] | [Dedicated] | [Enterprise] |
| -------------------------------- | :-----------: | :--------: | :---------: | :----------: |
| Self-Hosted | <Yes /> | <Absent /> | <Absent /> | <Yes /> |
| No-commit pricing | <Yes /> | <Yes /> | <Absent /> | <Absent /> |
| **[Materialize]** | | | | |
| ↳ [Accelerated Queries] | <Absent /> | <Absent /> | <Yes /> | <Absent /> |
| ↳ [Event Streams (Early Access)] | <Absent /> | <Absent /> | <Yes /> | <Absent /> |
| [Management Dashboard] | <Absent /> | <Yes /> | <Yes /> | <Absent /> |
| [Private Networking] | DIY | <Absent /> | <Yes /> | DIY |
| [Workload Isolation] | DIY | <Yes /> | <Yes /> | DIY |
| [Automated Updates] | DIY | <Yes /> | <Yes /> | DIY |
| [SOC2 Compliance] | DIY | <Yes /> | <Yes /> | DIY |
| [Audit Logging] | <Absent /> | <Yes /> | <Yes /> | <Yes /> |
| [Rate Limiting] | <Absent /> | <Yes /> | <Yes /> | <Yes /> |
| [Multi-Region Deployments] | DIY | <Absent /> | <Yes /> | DIY |
| [Security Embargo] | <Absent /> | <Yes /> | <Yes /> | <Yes /> |
| [Restricted API Access] | DIY | <Yes /> | <Yes /> | <Yes /> |
| [Expedited Support] | <Absent /> | <Yes /> | <Yes /> | <Yes /> |

</FeatureMatrix>

[Cloud]: #cloud
[Dedicated]: #dedicated
[Enterprise]: #enterprise
[Open Source]: #open-source
[Materialize (Early Access)]: /materialize/getting-started/overview
[Materialize]: /materialize/getting-started/overview
[Accelerated Queries]: /materialize/getting-started/overview#accelerated-queries
[Event Streams (Early Access)]: /materialize/getting-started/overview#event-streams
[Audit Logging]: ../concepts/audit-logging
[Automated Updates]: ../concepts/update-channels
[Management Dashboard]: ../concepts/management-dashboard
Expand Down
7 changes: 3 additions & 4 deletions app/materialize/getting-started/overview/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ AuthZed Materialize takes inspiration from the Leopard index component described
Much like the concept of a materialized view in relational databases, AuthZed Materialize is a service that you configure with a list of permissions that you want it to precompute, and it will calculate how those permissions change after relationships
are written (specifically, when those relationships affect a subject's membership in a permission set or a set's permission on a specific resource), or when a new schema is written.

Materialize puts that precomputed data to work in two ways: **Accelerated Queries** and **Event Streams**, both currently in early access. Every other piece of Materialize content belongs to one of these two features. Look for badges at the top of the page, which link back to the feature it belongs to.
Materialize puts that precomputed data to work in two ways: **Accelerated Queries**, generally available to AuthZed [Dedicated] users, and **Event Streams**, currently in early access. Every other piece of Materialize content belongs to one of these two features. Look for badges at the top of the page, which link back to the feature it belongs to.

<MaterializeArchitecture
role="img"
Expand All @@ -23,9 +23,8 @@ Materialize puts that precomputed data to work in two ways: **Accelerated Querie
## Accelerated Queries

<Callout type="info">
Accelerated Queries is available to users of AuthZed [Dedicated] as part of an early access
program. Don't hesitate to get in touch with your AuthZed account team if you would like to
participate.
Accelerated Queries is generally available to users of AuthZed [Dedicated]. Get in touch with your
AuthZed account team to get started.
</Callout>

Accelerated Queries use Materialize's precomputed permissions cache to answer the SpiceDB queries your application already makes, without changing how you call SpiceDB:
Expand Down
4 changes: 2 additions & 2 deletions app/spicedb/getting-started/faq/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ There are three approaches for filtering resources based on whether users have a

2. **CheckBulkPermissions** - Use when accessible resources are too large for LookupResources. Fetch a page of candidate results from your database, then call `CheckBulkPermissions` to determine which ones the user can access. Keep iterating until you have a full page of permitted results. This works well with cursor-based pagination and search interfaces.

3. **Materialize** (Early Access) - For maximum scalability with large datasets or high traffic. Materialize watches permission changes in SpiceDB and maintains a local denormalized view of user permissions, allowing you to use simple database JOINs for filtering.
3. **Materialize's Event Streams** (Early Access) - For maximum scalability with large datasets or high traffic. Materialize watches permission changes in SpiceDB and maintains a local denormalized view of user permissions, allowing you to use simple database JOINs for filtering.

Choose based on your scale: start with LookupResources, move to CheckBulkPermissions when needed, and consider Materialize for the highest performance requirements. [Learn more]
Choose based on your scale: start with LookupResources, move to CheckBulkPermissions when needed, and consider Materialize's Event Streams for the highest performance requirements. [Learn more]

[Learn more]: ../modeling/protecting-a-list-endpoint

Expand Down
6 changes: 4 additions & 2 deletions app/spicedb/modeling/protecting-a-list-endpoint/page.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ to the point where checking them via bulk check is relatively easy.
## Using Materialize

<Callout type="info">
Materialize is currently in Early Access. Additional documentation and product information will be
coming soon. In the meantime, if you're interested, [schedule a call!][Schedule Call]
This pattern uses Materialize's Event Streams feature, currently in early access for AuthZed
Dedicated users. See the [Materialize overview] to learn more, or [schedule a call!][Schedule
Call]
</Callout>

[Authzed Materialize] is Authzed's version of the [Leopard cache] referenced in the Zanzibar paper, which provides a denormalized view
Expand All @@ -113,6 +114,7 @@ under the above two approaches, we recommend giving Authzed Materialize a try.

[Schedule Call]: https://authzed.com/call
[Leopard cache]: https://authzed.com/zanzibar/2IoYDUFMAE:0:T
[Materialize overview]: /materialize/getting-started/overview#event-streams

## Other Considerations

Expand Down
20 changes: 20 additions & 0 deletions components/feature-icon.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,23 @@ html.dark .feature-yes svg {
.feature-no svg {
stroke: hsl(351 55% 53%);
}

/* Absent — muted dash, no disc. Reads as "nothing here" rather than "no". */
.feature-absent {
color: hsl(280 4% 62%);
font-size: 1.125rem;
line-height: 1;
}
html.dark .feature-absent {
color: hsl(279 9% 40%);
}

.feature-sr {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
17 changes: 16 additions & 1 deletion components/feature-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import "./feature-icon.css";

/* Feature-matrix marks for docs tables — Lucide check / x glyphs in Sandworm
colors, matching the marketing pricing comparison. Theme-aware styling lives
in feature-icon.css. Used in MDX as <Yes /> / <No /> (mdx-components.ts). */
in feature-icon.css. Used in MDX as <Yes /> / <No /> / <Absent />
(mdx-components.ts).

<No /> is a red cross: a real negative (a permission check that denied).
<Absent /> is a muted dash: a tier that simply doesn't carry a line. In a
product matrix an absence is not a failure, so it should not read as one.
Same rule as the marketing pricing/support comparison (SupportComparison). */

export function Yes() {
return (
Expand Down Expand Up @@ -41,3 +47,12 @@ export function No() {
</span>
);
}

export function Absent() {
return (
<span className="feature-mark feature-absent">
<span aria-hidden="true">&ndash;</span>
<span className="feature-sr">Not included</span>
</span>
);
}
130 changes: 130 additions & 0 deletions components/feature-matrix.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* Feature matrix — the docs twin of authzed.com's pricing/Support comparison
tables (web: pricing/TableGroup.tsx + SupportComparison.tsx). Unlayered so
it wins over Nextra's `x:` table utilities without !important. */

.feature-matrix {
--fm-rule: hsl(280 5% 84%);
--fm-hover: hsl(300 8% 96%);
--fm-label: hsl(280 6% 22%);
--fm-head: hsl(280 10% 12%);
--fm-muted: hsl(280 4% 48%);
--fm-link-rule: hsl(280 5% 72%);
--fm-link: hsl(var(--sand-300));
margin-top: 1.5rem;
overflow-x: auto;
}
html.dark .feature-matrix {
--fm-rule: hsl(279 9% 22%);
--fm-hover: hsl(279 12% 11%);
--fm-label: hsl(280 6% 82%);
--fm-head: hsl(300 6% 95%);
--fm-muted: hsl(280 4% 55%);
--fm-link-rule: hsl(279 8% 36%);
--fm-link: hsl(var(--sand-300));
}

.feature-matrix table {
display: table;
width: 100%;
margin: 0;
padding: 0;
border-collapse: collapse;
overflow: visible;
}

.feature-matrix tr {
margin: 0;
padding: 0;
border: 0;
border-top: 1px solid var(--fm-rule);
border-bottom: 1px solid var(--fm-rule);
background: transparent;
}
.feature-matrix thead tr {
border-top: 0;
}
.feature-matrix tbody tr:hover {
background: var(--fm-hover);
}

.feature-matrix th,
.feature-matrix td {
margin: 0;
padding: 1rem 0.5rem;
border: 0;
vertical-align: middle;
}

/* Column headers: plain text, not link-orange. The link still works. */
.feature-matrix thead th {
padding-top: 0.75rem;
padding-bottom: 1rem;
font-family: inherit;
font-size: 1.125rem;
font-weight: 400;
color: var(--fm-head);
text-align: center;
}
.feature-matrix thead th:first-child {
padding-left: 1.5rem;
text-align: left;
}
.feature-matrix thead th a,
.feature-matrix tbody td:first-child a {
color: inherit;
font-weight: inherit;
text-decoration: underline;
text-decoration-color: var(--fm-link-rule);
text-decoration-thickness: 1px;
text-underline-offset: 0.3em;
transition: color 120ms, text-decoration-color 120ms;
}
.feature-matrix thead th a:hover,
.feature-matrix tbody td:first-child a:hover {
color: var(--fm-link);
text-decoration-color: currentColor;
}

/* Row labels: mono, like the web tables. Links stay links, quietly. */
.feature-matrix tbody td:first-child {
padding-left: 1.5rem;
font-family: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, monospace;
font-size: 0.875rem;
color: var(--fm-label);
text-align: left;
white-space: nowrap;
}
/* Nextra appends an arrow icon to external links; keep it, just quiet it. */
.feature-matrix tbody td:first-child a svg,
.feature-matrix thead th a svg {
opacity: 0.6;
}

/* Value cells: centred, ruled between columns, never against the label. */
.feature-matrix tbody td:not(:first-child) {
border-left: 1px solid var(--fm-rule);
font-size: 0.875rem;
text-align: center;
color: var(--fm-label);
}
.feature-matrix tbody td:not(:first-child) .feature-mark {
vertical-align: middle;
}

/* Group-label row: a bold first cell and nothing else in the row.
Reads as a section header (web: RowGroup title), not a scored feature. */
.feature-matrix tbody tr:has(> td:first-child > strong) {
background: transparent;
}
.feature-matrix tbody tr:has(> td:first-child > strong) td:first-child {
padding-top: 1rem;
padding-bottom: 0.75rem;
font-size: 1rem;
font-weight: 300;
}
.feature-matrix tbody tr:has(> td:first-child > strong) strong {
font-weight: inherit;
}
.feature-matrix tbody tr:has(> td:first-child > strong) td:not(:first-child) {
border-left-color: transparent;
}
12 changes: 12 additions & 0 deletions components/feature-matrix.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import "./feature-matrix.css";
import type { ReactNode } from "react";

/* Wraps a markdown feature matrix so it reads like the pricing and Support
comparison tables on authzed.com instead of Nextra's default zebra table:
mono row labels, horizontal rules only, a group-label row for a feature
family (a bold first cell with the rest empty), row hover, plain-text
column headers. Used in MDX as <FeatureMatrix>…table…</FeatureMatrix>
(mdx-components.ts). Styling lives in feature-matrix.css. */
export function FeatureMatrix({ children }: { children: ReactNode }) {
return <div className="feature-matrix">{children}</div>;
}
36 changes: 3 additions & 33 deletions lib/changed-pages.json
Original file line number Diff line number Diff line change
@@ -1,44 +1,14 @@
{
"/materialize/api/client-sdks": {
"status": "updated"
},
"/materialize/api/download-permission-sets": {
"status": "new"
},
"/materialize/api/lookup-permission-sets": {
"status": "updated"
},
"/materialize/api/watch-permission-sets": {
"status": "updated"
},
"/materialize/concepts/hydration": {
"status": "new"
},
"/materialize/concepts/managing-client-state": {
"status": "updated"
},
"/materialize/concepts/permission-set-lifecycle": {
"status": "updated"
},
"/materialize/concepts/permission-sets": {
"status": "updated"
},
"/materialize/concepts/snapshots": {
"status": "updated"
},
"/materialize/concepts/watched-permissions": {
"status": "new"
},
"/materialize/getting-started/limitations": {
"/authzed/guides/picking-a-product": {
"status": "updated"
},
"/materialize/getting-started/overview": {
"status": "updated"
},
"/materialize/guides/recommended-architecture": {
"/spicedb/getting-started/faq": {
"status": "updated"
},
"/materialize/guides/relational-database": {
"/spicedb/modeling/protecting-a-list-endpoint": {
"status": "updated"
}
}
7 changes: 3 additions & 4 deletions lib/materialize-features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ export const FEATURES = {

export type FeatureKey = keyof typeof FEATURES;

/* Every feature is in early access today, so the note's text doesn't vary.
It's per-feature anyway because the note is colour-matched to its pill —
and because these will go GA on different dates. */
/* Per-feature because the note is colour-matched to its pill, and because
these go GA on different dates — Accelerated Queries reached GA first. */
export const EARLY_ACCESS: Record<FeatureKey, boolean> = {
"accelerated-queries": true,
"accelerated-queries": false,
"event-streams": true,
};

Expand Down
5 changes: 4 additions & 1 deletion mdx-components.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { useMDXComponents as getDocsMDXComponents } from "nextra-theme-docs";
import type { Component } from "react";
import { Yes, No } from "@/components/feature-icon";
import { Yes, No, Absent } from "@/components/feature-icon";
import { FeatureBadge } from "@/components/feature-badge";
import { FeatureMatrix } from "@/components/feature-matrix";

const docsComponents = getDocsMDXComponents();

export const useMDXComponents = (components?: Component) => ({
...docsComponents,
Yes,
No,
Absent,
FeatureBadge,
FeatureMatrix,
...components,
});
Loading