Add db and auth pages

This commit is contained in:
Terry Sutton committed 2025-11-05 17:07:20 -03:30
1 parent 697d457f1d
commit b2497cefb8
9 files changed
+786 -38

No files matched your search

+3 -3
View File
@@ -1,7 +1,7 @@
import Link from 'next/link'
import NavigationItem from '@/components/side-navigation-item'
import { gettingStarted } from '@/config/docs'
import { courses } from '@/config/docs'
import { CommandMenu } from './command-menu'
import { ThemeSwitcherDropdown } from './theme-switcher-dropdown'
@@ -68,10 +68,10 @@ function SideNavigation() {
</div>
<div className="pb-6 px-6">
<h3 className="text-xs font-semibold text-foreground-lighter/75 uppercase tracking-wider mb-3">
{gettingStarted.title}
{courses.title}
</h3>
<ul className="space-y-1">
{gettingStarted.items.map((item, i) => (
{courses.items.map((item, i) => (
<NavigationItem item={item} key={`${item.href}-${i}`} />
))}
</ul>
+18 -2
View File
@@ -1,6 +1,6 @@
import { SidebarNavGroup } from 'types/nav'
export const gettingStarted: SidebarNavGroup = {
export const courses: SidebarNavGroup = {
title: 'Courses',
items: [
{
@@ -23,6 +23,22 @@ export const gettingStarted: SidebarNavGroup = {
title: 'Authentication',
href: '/foundations/authentication',
},
{
title: 'Security',
href: '/foundations/security',
},
{
title: 'Storage',
href: '/foundations/storage',
},
{
title: 'Edge Functions',
href: '/foundations/edge-functions',
},
{
title: 'Vector Search',
href: '/foundations/vector-search',
},
],
commandItemLabel: 'Foundations',
},
@@ -45,7 +61,7 @@ export const gettingStarted: SidebarNavGroup = {
}
export const COMMAND_ITEMS = [
...gettingStarted.items.map((item) => ({
...courses.items.map((item) => ({
label: item.commandItemLabel,
href: item.href,
})),
@@ -0,0 +1,103 @@
---
title: Authentication
description: Learn how Supabase manages users and how signed-in requests connect to the database.
chapterNumber: 3
---
Most applications need to know who is using them. Authentication is how we identify
a user and attach their actions to their own data. Supabase includes an
authentication system that works directly with the database, so user identity
flows naturally into queries and permissions.
Authentication in Supabase is handled by Supabase Auth. It manages creating
accounts, signing in, and issuing tokens that represent the current user.
---
## Users
A user in Supabase has an id and some optional profile information (such as
email). When someone signs up, Supabase creates a new user record and assigns
them a unique identifier.
You do not need to create or manage the users table yourself. Supabase stores it
internally and keeps it updated.
Example of the kind of data Supabase stores for a user:
```text
id: 74d2...af1
email: maria@example.com
created: 2025-01-12 09:44:21
```
You can reference this user id in your tables when you want to link data to a
specific user.
---
## Tokens and identity
When a user signs in, Supabase returns a token. This token proves who the user
is. Your application includes this token in each API request.
Inside the database, this token becomes the value returned by `auth.uid()`.
This lets policies decide which data belongs to which user.
For example:
```text
select auth.uid();
```
returns the id of the signed-in user who made the request.
---
## Sign up and sign in
Supabase Auth supports several sign-in methods:
- Email and password
- Magic links (sign in by clicking a link in an email)
- OAuth providers (Google, GitHub, etc.)
- Phone number (SMS)
For now, we will use email and password, since it is the simplest starting point.
---
## Where authentication connects to data
Authentication by itself only identifies a user. It does not control access.
The next step is **Row Level Security (RLS)**. RLS uses the user id from the
token to decide which rows the user can read or write.
So the flow looks like this:
```text
User signs in
↓
Supabase gives the client a user token
↓
Client sends token with API requests
↓
Postgres receives token and sets auth.uid()
↓
RLS policies use auth.uid() to enforce access rules
```
Authentication says who the user is.
RLS decides what they are allowed to do.
---
## What we learned
- Supabase Auth manages user accounts and sign-in.
- Each user has a unique id that you can reference in your tables.
- When a user signs in, Supabase provides a token.
- The token tells the database who the user is through `auth.uid()`.
- Authentication by itself does not control access. RLS does that part.
Understanding this identity flow is important before we begin writing policies.
@@ -1,52 +1,136 @@
---
title: Data Fundamentals
description: Learn the foundations of Supabase, the Postgres development platform.
description: 'Learn how data is structured in Postgres: tables, rows, columns, and keys.'
chapterNumber: 2
---
In this chapter, you'll learn how to create a table in Supabase, insert data into it, and query it using the REST API.
Before we store any information in Supabase, we need to understand how data is
organized in Postgres. Supabase uses Postgres as its database, which means data
is arranged in a structured and predictable way. This helps keep your app
organized, consistent, and easy to query.
## What you'll learn
- **Data fundamentals**: create tables, insert and retrieve data, and explore our generated APIs.
The core ideas are simple: you create tables to hold related data, and each
table has rows (records) and columns (fields). Once you understand that pattern,
you can model almost anything.
---
## Prerequisites
## Tables, rows, and columns
- A [Supabase account](https://supabase.com/) (free)
- Basic familiarity with a terminal to run queries.
A table is like a spreadsheet. It has:
- **Columns**: the fields that define what kind of data the table stores
- **Rows**: the individual entries in the table
Imagine a table for storing notes:
```text
| id | content | created_at |
|----|------------------|----------------------|
| 1 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | Call the dentist | 2025-01-10 15:08:54 |
```
- Each **row** is a single note.
- Each **column** represents one piece of information about the note.
---
## Course outline
## Data types
The course is split into 7 chapters, each approximately 10 minutes long.
Every column has a data type. This describes the kind of value that can be
stored there.
1. **What is Supabase?**
Get an overview of Supabase's architecture and core products. Create your first project and make a simple API call.
2. **Your First Table**
Create a Postgres table in Supabase, insert data, and query it through the REST API.
3. **Authentication Basics**
Add users, sign them in, and understand how Supabase secures your APIs with JWTs.
4. **Secure Your Data with Row-Level Security**
Enable Row-Level Security and write policies to ensure users only access their own data.
5. **Storage**
Store files in Supabase Storage and upload and serve files from your buckets.
6. **Edge Functions**
Deploy simple functions to run backend logic close to your users using Deno.
7. **Vector Search**
Store and query embeddings for AI-powered search and recommendations using Supabase Vector.
Some common data types:
```text
| Data type | Example value | Meaning |
| ----------- | ---------------- | ----------------------------- |
| text | Hello world | A string of characters |
| integer | 42 | A number without decimals |
| boolean | true | Yes/no or on/off values |
| timestamptz | 2025-01-10 14:22 | Date and time (with timezone) |
| json | {"name": "John"} | A JSON object |
```
Choosing correct types makes your data easier to work with and protects you from
unexpected values.
---
## Before you begin
## Primary keys
Create a new project at [supabase.com](https://supabase.com), open the **Supabase Dashboard**, and grab your **API URL** and **anon key** from the [Connect dialog](https://supabase.com/dashboard/project/_/settings/api?showConnect=true&connectTab=frameworks).
You'll use them throughout the course to send real requests to your database and APIs.
Most tables include a primary key. This is a column that uniquely identifies each
row. In many Supabase projects, this column is named `id` and uses a type called
`uuid`, which automatically generates a unique value.
You create this column in the table definition like this:
```text
id uuid primary key default gen_random_uuid()
```
You generally don't need to think about it after setting it up. It simply gives
each record a stable identity.
---
## Duration
## Relationships between tables
Approx. **1 hour** — a fast, hands-on introduction to the Supabase platform.
You can link tables together using foreign keys. This is how you express things
like:
- A user has many notes
- A project has many tasks
- A team has many members
For example:
```text
| id | user_id | content | created_at |
|----|--------------------------------------|------------------|----------------------|
| 1 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Call the dentist | 2025-01-10 15:08:54 |
```
Here, `user_id` refers to a row in a `users` table. This means the note belongs
to that user, and we can see that this user has two notes.
Relationships let you organize data without repeating information.
---
## Why relational data is useful in practice
Relational data is really useful in practice because it allows you to:
- Keep data valid with constraints <br />
_Example: no duplicate emails._
- Link records safely with foreign keys <br />
_Example: delete a user and their notes in one action._
- Express real permissions with RLS <br />
_Example: users can read their own notes; admins can read all._
- Query exactly what you need with table joins <br />
_Example: fetch notes with the author's email._
---
## What we learned
A database in Supabase is made up of tables.
Each table has:
- columns (which describe the type of information stored)
- rows (the individual pieces of data in that table)
You can relate tables to each other using foreign keys.
This lets you model real situations, such as:
- a user has many notes
- a team has many members
- a project has many tasks
Thinking in tables, rows, and relationships is the foundation of working with data in Supabase.
@@ -0,0 +1,136 @@
---
title: Data Fundamentals
description: 'Learn how data is structured in Postgres: tables, rows, columns, and keys.'
chapterNumber: 2
---
Before we store any information in Supabase, we need to understand how data is
organized in Postgres. Supabase uses Postgres as its database, which means data
is arranged in a structured and predictable way. This helps keep your app
organized, consistent, and easy to query.
The core ideas are simple: you create tables to hold related data, and each
table has rows (records) and columns (fields). Once you understand that pattern,
you can model almost anything.
---
## Tables, rows, and columns
A table is like a spreadsheet. It has:
- **Columns**: the fields that define what kind of data the table stores
- **Rows**: the individual entries in the table
Imagine a table for storing notes:
```text
| id | content | created_at |
|----|------------------|----------------------|
| 1 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | Call the dentist | 2025-01-10 15:08:54 |
```
- Each **row** is a single note.
- Each **column** represents one piece of information about the note.
---
## Data types
Every column has a data type. This describes the kind of value that can be
stored there.
Some common data types:
```text
| Data type | Example value | Meaning |
| ----------- | ---------------- | ----------------------------- |
| text | Hello world | A string of characters |
| integer | 42 | A number without decimals |
| boolean | true | Yes/no or on/off values |
| timestamptz | 2025-01-10 14:22 | Date and time (with timezone) |
| json | {"name": "John"} | A JSON object |
```
Choosing correct types makes your data easier to work with and protects you from
unexpected values.
---
## Primary keys
Most tables include a primary key. This is a column that uniquely identifies each
row. In many Supabase projects, this column is named `id` and uses a type called
`uuid`, which automatically generates a unique value.
You create this column in the table definition like this:
```text
id uuid primary key default gen_random_uuid()
```
You generally don't need to think about it after setting it up. It simply gives
each record a stable identity.
---
## Relationships between tables
You can link tables together using foreign keys. This is how you express things
like:
- A user has many notes
- A project has many tasks
- A team has many members
For example:
```text
| id | user_id | content | created_at |
|----|--------------------------------------|------------------|----------------------|
| 1 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Call the dentist | 2025-01-10 15:08:54 |
```
Here, `user_id` refers to a row in a `users` table. This means the note belongs
to that user, and we can see that this user has two notes.
Relationships let you organize data without repeating information.
---
## Why relational data is useful in practice
Relational data is really useful in practice because it allows you to:
- Keep data valid with constraints <br />
_Example: no duplicate emails._
- Link records safely with foreign keys <br />
_Example: delete a user and their notes in one action._
- Express real permissions with RLS <br />
_Example: users can read their own notes; admins can read all._
- Query exactly what you need with table joins <br />
_Example: fetch notes with the author's email._
---
## What we learned
A database in Supabase is made up of tables.
Each table has:
- columns (which describe the type of information stored)
- rows (the individual pieces of data in that table)
You can relate tables to each other using foreign keys.
This lets you model real situations, such as:
- a user has many notes
- a team has many members
- a project has many tasks
Thinking in tables, rows, and relationships is the foundation of working with data in Supabase.
+136
View File
@@ -0,0 +1,136 @@
---
title: Data Fundamentals
description: 'Learn how data is structured in Postgres: tables, rows, columns, and keys.'
chapterNumber: 2
---
Before we store any information in Supabase, we need to understand how data is
organized in Postgres. Supabase uses Postgres as its database, which means data
is arranged in a structured and predictable way. This helps keep your app
organized, consistent, and easy to query.
The core ideas are simple: you create tables to hold related data, and each
table has rows (records) and columns (fields). Once you understand that pattern,
you can model almost anything.
---
## Tables, rows, and columns
A table is like a spreadsheet. It has:
- **Columns**: the fields that define what kind of data the table stores
- **Rows**: the individual entries in the table
Imagine a table for storing notes:
```text
| id | content | created_at |
|----|------------------|----------------------|
| 1 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | Call the dentist | 2025-01-10 15:08:54 |
```
- Each **row** is a single note.
- Each **column** represents one piece of information about the note.
---
## Data types
Every column has a data type. This describes the kind of value that can be
stored there.
Some common data types:
```text
| Data type | Example value | Meaning |
| ----------- | ---------------- | ----------------------------- |
| text | Hello world | A string of characters |
| integer | 42 | A number without decimals |
| boolean | true | Yes/no or on/off values |
| timestamptz | 2025-01-10 14:22 | Date and time (with timezone) |
| json | {"name": "John"} | A JSON object |
```
Choosing correct types makes your data easier to work with and protects you from
unexpected values.
---
## Primary keys
Most tables include a primary key. This is a column that uniquely identifies each
row. In many Supabase projects, this column is named `id` and uses a type called
`uuid`, which automatically generates a unique value.
You create this column in the table definition like this:
```text
id uuid primary key default gen_random_uuid()
```
You generally don't need to think about it after setting it up. It simply gives
each record a stable identity.
---
## Relationships between tables
You can link tables together using foreign keys. This is how you express things
like:
- A user has many notes
- A project has many tasks
- A team has many members
For example:
```text
| id | user_id | content | created_at |
|----|--------------------------------------|------------------|----------------------|
| 1 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Call the dentist | 2025-01-10 15:08:54 |
```
Here, `user_id` refers to a row in a `users` table. This means the note belongs
to that user, and we can see that this user has two notes.
Relationships let you organize data without repeating information.
---
## Why relational data is useful in practice
Relational data is really useful in practice because it allows you to:
- Keep data valid with constraints <br />
_Example: no duplicate emails._
- Link records safely with foreign keys <br />
_Example: delete a user and their notes in one action._
- Express real permissions with RLS <br />
_Example: users can read their own notes; admins can read all._
- Query exactly what you need with table joins <br />
_Example: fetch notes with the author's email._
---
## What we learned
A database in Supabase is made up of tables.
Each table has:
- columns (which describe the type of information stored)
- rows (the individual pieces of data in that table)
You can relate tables to each other using foreign keys.
This lets you model real situations, such as:
- a user has many notes
- a team has many members
- a project has many tasks
Thinking in tables, rows, and relationships is the foundation of working with data in Supabase.
+136
View File
@@ -0,0 +1,136 @@
---
title: Data Fundamentals
description: 'Learn how data is structured in Postgres: tables, rows, columns, and keys.'
chapterNumber: 2
---
Before we store any information in Supabase, we need to understand how data is
organized in Postgres. Supabase uses Postgres as its database, which means data
is arranged in a structured and predictable way. This helps keep your app
organized, consistent, and easy to query.
The core ideas are simple: you create tables to hold related data, and each
table has rows (records) and columns (fields). Once you understand that pattern,
you can model almost anything.
---
## Tables, rows, and columns
A table is like a spreadsheet. It has:
- **Columns**: the fields that define what kind of data the table stores
- **Rows**: the individual entries in the table
Imagine a table for storing notes:
```text
| id | content | created_at |
|----|------------------|----------------------|
| 1 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | Call the dentist | 2025-01-10 15:08:54 |
```
- Each **row** is a single note.
- Each **column** represents one piece of information about the note.
---
## Data types
Every column has a data type. This describes the kind of value that can be
stored there.
Some common data types:
```text
| Data type | Example value | Meaning |
| ----------- | ---------------- | ----------------------------- |
| text | Hello world | A string of characters |
| integer | 42 | A number without decimals |
| boolean | true | Yes/no or on/off values |
| timestamptz | 2025-01-10 14:22 | Date and time (with timezone) |
| json | {"name": "John"} | A JSON object |
```
Choosing correct types makes your data easier to work with and protects you from
unexpected values.
---
## Primary keys
Most tables include a primary key. This is a column that uniquely identifies each
row. In many Supabase projects, this column is named `id` and uses a type called
`uuid`, which automatically generates a unique value.
You create this column in the table definition like this:
```text
id uuid primary key default gen_random_uuid()
```
You generally don't need to think about it after setting it up. It simply gives
each record a stable identity.
---
## Relationships between tables
You can link tables together using foreign keys. This is how you express things
like:
- A user has many notes
- A project has many tasks
- A team has many members
For example:
```text
| id | user_id | content | created_at |
|----|--------------------------------------|------------------|----------------------|
| 1 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Call the dentist | 2025-01-10 15:08:54 |
```
Here, `user_id` refers to a row in a `users` table. This means the note belongs
to that user, and we can see that this user has two notes.
Relationships let you organize data without repeating information.
---
## Why relational data is useful in practice
Relational data is really useful in practice because it allows you to:
- Keep data valid with constraints <br />
_Example: no duplicate emails._
- Link records safely with foreign keys <br />
_Example: delete a user and their notes in one action._
- Express real permissions with RLS <br />
_Example: users can read their own notes; admins can read all._
- Query exactly what you need with table joins <br />
_Example: fetch notes with the author's email._
---
## What we learned
A database in Supabase is made up of tables.
Each table has:
- columns (which describe the type of information stored)
- rows (the individual pieces of data in that table)
You can relate tables to each other using foreign keys.
This lets you model real situations, such as:
- a user has many notes
- a team has many members
- a project has many tasks
Thinking in tables, rows, and relationships is the foundation of working with data in Supabase.
+136
View File
@@ -0,0 +1,136 @@
---
title: Data Fundamentals
description: 'Learn how data is structured in Postgres: tables, rows, columns, and keys.'
chapterNumber: 2
---
Before we store any information in Supabase, we need to understand how data is
organized in Postgres. Supabase uses Postgres as its database, which means data
is arranged in a structured and predictable way. This helps keep your app
organized, consistent, and easy to query.
The core ideas are simple: you create tables to hold related data, and each
table has rows (records) and columns (fields). Once you understand that pattern,
you can model almost anything.
---
## Tables, rows, and columns
A table is like a spreadsheet. It has:
- **Columns**: the fields that define what kind of data the table stores
- **Rows**: the individual entries in the table
Imagine a table for storing notes:
```text
| id | content | created_at |
|----|------------------|----------------------|
| 1 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | Call the dentist | 2025-01-10 15:08:54 |
```
- Each **row** is a single note.
- Each **column** represents one piece of information about the note.
---
## Data types
Every column has a data type. This describes the kind of value that can be
stored there.
Some common data types:
```text
| Data type | Example value | Meaning |
| ----------- | ---------------- | ----------------------------- |
| text | Hello world | A string of characters |
| integer | 42 | A number without decimals |
| boolean | true | Yes/no or on/off values |
| timestamptz | 2025-01-10 14:22 | Date and time (with timezone) |
| json | {"name": "John"} | A JSON object |
```
Choosing correct types makes your data easier to work with and protects you from
unexpected values.
---
## Primary keys
Most tables include a primary key. This is a column that uniquely identifies each
row. In many Supabase projects, this column is named `id` and uses a type called
`uuid`, which automatically generates a unique value.
You create this column in the table definition like this:
```text
id uuid primary key default gen_random_uuid()
```
You generally don't need to think about it after setting it up. It simply gives
each record a stable identity.
---
## Relationships between tables
You can link tables together using foreign keys. This is how you express things
like:
- A user has many notes
- A project has many tasks
- A team has many members
For example:
```text
| id | user_id | content | created_at |
|----|--------------------------------------|------------------|----------------------|
| 1 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Buy groceries | 2025-01-10 14:22:11 |
| 2 | 9f1b1c94-3e7b-4d6a-9fa7-1e2a3c4ba987 | Call the dentist | 2025-01-10 15:08:54 |
```
Here, `user_id` refers to a row in a `users` table. This means the note belongs
to that user, and we can see that this user has two notes.
Relationships let you organize data without repeating information.
---
## Why relational data is useful in practice
Relational data is really useful in practice because it allows you to:
- Keep data valid with constraints <br />
_Example: no duplicate emails._
- Link records safely with foreign keys <br />
_Example: delete a user and their notes in one action._
- Express real permissions with RLS <br />
_Example: users can read their own notes; admins can read all._
- Query exactly what you need with table joins <br />
_Example: fetch notes with the author's email._
---
## What we learned
A database in Supabase is made up of tables.
Each table has:
- columns (which describe the type of information stored)
- rows (the individual pieces of data in that table)
You can relate tables to each other using foreign keys.
This lets you model real situations, such as:
- a user has many notes
- a team has many members
- a project has many tasks
Thinking in tables, rows, and relationships is the foundation of working with data in Supabase.
+5 -4
View File
@@ -1,5 +1,5 @@
import { allDocs } from 'contentlayer/generated'
import { gettingStarted } from '@/config/docs'
import { courses } from '@/config/docs'
import { SidebarNavItem } from '@/types/nav'
/**
@@ -32,9 +32,11 @@ export function normalizeSlug(slug: string): string {
/**
* Gets the next page in the navigation structure based on the current page slug
*/
export function getNextPage(currentSlug: string): { title: string; href: string; description?: string; chapterNumber?: number } | null {
export function getNextPage(
currentSlug: string
): { title: string; href: string; description?: string; chapterNumber?: number } | null {
// Flatten all navigation items
const allPages = flattenNavItems(gettingStarted.items)
const allPages = flattenNavItems(courses.items)
// Normalize the current slug for comparison
const normalizedCurrentSlug = normalizeSlug(currentSlug)
@@ -78,4 +80,3 @@ export function getNextPage(currentSlug: string): { title: string; href: string;
chapterNumber,
}
}