-
Notifications
You must be signed in to change notification settings - Fork 529
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
782 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,48 @@ | ||
import { source } from "@/app/source"; | ||
import { RootToggle } from "fumadocs-ui/components/layout/root-toggle"; | ||
import { DocsLayout } from "fumadocs-ui/layouts/docs"; | ||
import { Code, Component, Handshake, Terminal } from "lucide-react"; | ||
|
||
import type { ReactNode } from "react"; | ||
import { baseOptions } from "../layout.config"; | ||
|
||
export default function Layout({ children }: { children: ReactNode }) { | ||
return ( | ||
<DocsLayout tree={source.pageTree} {...baseOptions}> | ||
<DocsLayout | ||
tree={source.pageTree} | ||
{...baseOptions} | ||
sidebar={{ | ||
tabs: [ | ||
{ | ||
title: "Contributing", | ||
description: "Create your first PR", | ||
url: "/docs/contributing", | ||
icon: <Code className="size-4 text-blue-600 dark:text-blue-400" />, | ||
}, | ||
/* | ||
{ | ||
title: "Company", | ||
description: "How we work", | ||
url: "/docs/company", | ||
icon: <Handshake className="size-4 text-amber-600 dark:text-amber-400" />, | ||
}, | ||
*/ | ||
{ | ||
title: "API Design", | ||
description: "Look and feel", | ||
url: "/docs/api-design", | ||
icon: <Terminal className="size-4 text-emerald-600 dark:text-emerald-400" />, | ||
}, | ||
{ | ||
title: "Architecture", | ||
description: "How does Unkey work", | ||
url: "/docs/architecture", | ||
icon: <Component className="size-4 text-purple-600 dark:text-purple-400" />, | ||
}, | ||
] | ||
}} | ||
> | ||
{children} | ||
</DocsLayout> | ||
</DocsLayout > | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"use client"; | ||
|
||
type Props = { | ||
date: Date | string; | ||
}; | ||
|
||
export const LocalDate: React.FC<Props> = (props) => { | ||
const date = typeof props.date === "string" ? new Date(props.date) : props.date; | ||
|
||
return <span suppressHydrationWarning>{date.toLocaleDateString()}</span>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { rfcSource } from "@/app/source"; | ||
import { Card } from "fumadocs-ui/components/card"; | ||
import defaultMdxComponents from "fumadocs-ui/mdx"; | ||
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from "fumadocs-ui/page"; | ||
import type { Metadata } from "next"; | ||
import { LocalDate } from "./local-date"; | ||
|
||
import { notFound } from "next/navigation"; | ||
|
||
export default async function Page({ | ||
params, | ||
}: { | ||
params: { slug?: string[] }; | ||
}) { | ||
|
||
const page = rfcSource.getPage(params.slug); | ||
|
||
if (!page) { | ||
notFound(); | ||
} | ||
|
||
if (page.slugs.length === 0) { | ||
return ( | ||
<div className="min-h-screen border text-center -mt-16 pt-16 flex items-center w-screen justify-center "> | ||
<div> | ||
<h1 className="text-7xl md:text-8xl font-bold leading-none uppercase tracking-tight"> | ||
RFCS | ||
|
||
</h1> | ||
<p className="text-xl mt-8 font-light ">Check the sidebar</p> | ||
</div> | ||
</div> | ||
|
||
) | ||
} | ||
|
||
const MDX = page.data.body; | ||
|
||
return ( | ||
<DocsPage toc={page.data.toc} full={page.data.full}> | ||
<DocsTitle>{page.data.title}</DocsTitle> | ||
|
||
<Card title=""> | ||
<div className="grid grid-cols-2 font-mono"> | ||
<span>ID</span> | ||
<span>{page.data.title.split(" ").at(0)}</span> | ||
<span>{page.data.authors.length > 1 ? "Authors" : "Author"}</span> | ||
<span>{page.data.authors.join(", ")}</span> | ||
<span>Date</span> | ||
<LocalDate date={new Date(page.data.date)} /> | ||
</div> | ||
</Card> | ||
<DocsDescription>{page.data.description}</DocsDescription> | ||
|
||
<DocsBody > | ||
<MDX components={{ ...defaultMdxComponents }} /> | ||
</DocsBody> | ||
</DocsPage> | ||
); | ||
} | ||
|
||
export async function generateStaticParams() { | ||
return rfcSource.generateParams(); | ||
} | ||
|
||
export function generateMetadata({ params }: { params: { slug?: string[] } }) { | ||
const page = rfcSource.getPage(params.slug); | ||
if (!page) { | ||
notFound(); | ||
} | ||
|
||
return { | ||
title: page.data.title, | ||
description: page.data.description, | ||
} satisfies Metadata; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { rfcSource } from "@/app/source"; | ||
import { DocsLayout } from "fumadocs-ui/layouts/notebook"; | ||
import type { ReactNode } from "react"; | ||
import { baseOptions } from "../layout.config"; | ||
|
||
export default function Layout({ children }: { children: ReactNode }) { | ||
return ( | ||
<DocsLayout tree={rfcSource.pageTree} {...baseOptions}> | ||
{children} | ||
</DocsLayout> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,13 @@ | ||
import { docs, meta } from "@/.source"; | ||
import { docs, meta, rfcs } from "@/.source"; | ||
import { loader } from "fumadocs-core/source"; | ||
import { createMDXSource } from "fumadocs-mdx"; | ||
|
||
export const source = loader({ | ||
baseUrl: "/docs", | ||
source: createMDXSource(docs, meta), | ||
}); | ||
|
||
export const rfcSource = loader({ | ||
baseUrl: "/rfcs", | ||
source: createMDXSource(rfcs, []), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
{ | ||
"title": "API Design", | ||
"description": "Intuitive and helpful", | ||
"icon": "Terminal2", | ||
"icon": "Code", | ||
"root": true, | ||
"pages": ["rpc", "errors"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
{ | ||
"title": "Architecture", | ||
"description": "How does Unkey work", | ||
"icon": "Building2", | ||
"icon": "Pencil", | ||
"root": true, | ||
"pages": ["index", "---Services---", "vault", "clickhouse", "clickhouse-proxy"] | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"pages": ["contributing", "company", "api-design", "architecture"] | ||
"pages": ["contributing", "api-design", "company", "architecture"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
--- | ||
title: 0001 RBAC | ||
authors: | ||
- Andreas Thomas | ||
date: 2023-12-12 | ||
--- | ||
|
||
|
||
To reduce the scope and time to implementation, we will be reducing our initial permission model to RBAC instead of ReBAC. This has fewer moving parts and can be implemented with just 1 new table. | ||
|
||
There are many ways to store this data. Initially I had a 2 table setup, one for roles and one for an M:N relation between roles and keys, but there are some operational issues with that, mainly around planetscale’s foreignkeys and the lack of an easy “upsert” method. This requires us to query all roles of a workspace, then figuring out which ones are missing and creating them. For every key creation… That’s not amazing. | ||
|
||
Here’s a much simpler proposal using a single table: | ||
|
||
### Table Schema | ||
|
||
- `id` | ||
|
||
unique id for this row | ||
|
||
- `workspaceId` | ||
|
||
Every role is scoped to a workspace, no role sharing between tenants | ||
|
||
- `keyId` | ||
|
||
The key holding this role | ||
|
||
- `role: string` | ||
|
||
the actual name of a role, ie: `finance` (or more elaborate, see below) | ||
This is completely up to the user, the only limitation is a length ≤ 512chars | ||
|
||
for our own roles, we’ll likely do some schema for roles, like `api::{id}::create_key` | ||
|
||
|
||
This single table design is the simplest form of doing roles. By adding indices for these queries, it should scale far enough: | ||
|
||
- roles by key | ||
- roles by workspace | ||
- keys by role | ||
|
||
### Unkey internal role schema | ||
|
||
`*` denotes either an id or a wildcard | ||
|
||
```tsx | ||
root_key::*::read_root_key | ||
root_key::*::create_root_key // a root key MUST NOT be allowed to create another key with more permissions than itself | ||
root_key::*::delete_root_key | ||
root_key::*::update_root_key | ||
api::*::create_api | ||
api::*::delete_api // either wildcard or a specific id -> api::api_123::delete_api | ||
api::*::read_api | ||
api::*::update_api | ||
api::*::read_key | ||
api::*::create_key | ||
api::*::update_key | ||
api::*::delete_key | ||
``` | ||
|
||
Some of these internal roles (`api::*::create_api`) seem overly complicated, because the wildcard will always be present, since it’s impossible to write this role in advance without knowing the api_id that will get generated later, but by sticking with this schema, we stay consistent and can build our types and tooling more easily. | ||
|
||
We could go deeper like `api::*::keys::*::read_key` but I’m not convinced anyone needs this and it just adds complexity for now. It’s trivial to add more roles later, let’s wait it out. | ||
|
||
### Examples | ||
|
||
1. A key should be allowed to create new apis, modify them and be able to perform all actions on keys. | ||
|
||
```tsx | ||
api::*::create_api | ||
api::*::update_api | ||
api::*::read_key | ||
api::*::create_key | ||
api::*::update_key | ||
api::*::delete_key | ||
``` | ||
|
||
2. Update access to one api and its keys, read access to all apis and their keys | ||
|
||
```tsx | ||
api::api_123::update | ||
api::api_123::update_key | ||
api::*::read_api | ||
api::*::read_key | ||
``` |
Oops, something went wrong.