diff --git a/apps/learn/components/side-navigation.tsx b/apps/learn/components/side-navigation.tsx
index 644b91673af..770771f7e24 100644
--- a/apps/learn/components/side-navigation.tsx
+++ b/apps/learn/components/side-navigation.tsx
@@ -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() {
- {gettingStarted.title}
+ {courses.title}
- {gettingStarted.items.map((item, i) => (
+ {courses.items.map((item, i) => (
))}
diff --git a/apps/learn/config/docs.ts b/apps/learn/config/docs.ts
index 3b9b0173ac0..60c2586aeec 100644
--- a/apps/learn/config/docs.ts
+++ b/apps/learn/config/docs.ts
@@ -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,
})),
diff --git a/apps/learn/content/foundations/authentication.mdx b/apps/learn/content/foundations/authentication.mdx
new file mode 100644
index 00000000000..f195be17b0b
--- /dev/null
+++ b/apps/learn/content/foundations/authentication.mdx
@@ -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.
diff --git a/apps/learn/content/foundations/data-fundamentals.mdx b/apps/learn/content/foundations/data-fundamentals.mdx
index 185e7f93990..545efa958fa 100644
--- a/apps/learn/content/foundations/data-fundamentals.mdx
+++ b/apps/learn/content/foundations/data-fundamentals.mdx
@@ -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
+ _Example: no duplicate emails._
+
+- Link records safely with foreign keys
+ _Example: delete a user and their notes in one action._
+
+- Express real permissions with RLS
+ _Example: users can read their own notes; admins can read all._
+
+- Query exactly what you need with table joins
+ _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.
diff --git a/apps/learn/content/foundations/edge-functions.mdx b/apps/learn/content/foundations/edge-functions.mdx
new file mode 100644
index 00000000000..545efa958fa
--- /dev/null
+++ b/apps/learn/content/foundations/edge-functions.mdx
@@ -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
+ _Example: no duplicate emails._
+
+- Link records safely with foreign keys
+ _Example: delete a user and their notes in one action._
+
+- Express real permissions with RLS
+ _Example: users can read their own notes; admins can read all._
+
+- Query exactly what you need with table joins
+ _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.
diff --git a/apps/learn/content/foundations/security.mdx b/apps/learn/content/foundations/security.mdx
new file mode 100644
index 00000000000..545efa958fa
--- /dev/null
+++ b/apps/learn/content/foundations/security.mdx
@@ -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
+ _Example: no duplicate emails._
+
+- Link records safely with foreign keys
+ _Example: delete a user and their notes in one action._
+
+- Express real permissions with RLS
+ _Example: users can read their own notes; admins can read all._
+
+- Query exactly what you need with table joins
+ _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.
diff --git a/apps/learn/content/foundations/storage.mdx b/apps/learn/content/foundations/storage.mdx
new file mode 100644
index 00000000000..545efa958fa
--- /dev/null
+++ b/apps/learn/content/foundations/storage.mdx
@@ -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
+ _Example: no duplicate emails._
+
+- Link records safely with foreign keys
+ _Example: delete a user and their notes in one action._
+
+- Express real permissions with RLS
+ _Example: users can read their own notes; admins can read all._
+
+- Query exactly what you need with table joins
+ _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.
diff --git a/apps/learn/content/foundations/vector.mdx b/apps/learn/content/foundations/vector.mdx
new file mode 100644
index 00000000000..545efa958fa
--- /dev/null
+++ b/apps/learn/content/foundations/vector.mdx
@@ -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
+ _Example: no duplicate emails._
+
+- Link records safely with foreign keys
+ _Example: delete a user and their notes in one action._
+
+- Express real permissions with RLS
+ _Example: users can read their own notes; admins can read all._
+
+- Query exactly what you need with table joins
+ _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.
diff --git a/apps/learn/lib/get-next-page.ts b/apps/learn/lib/get-next-page.ts
index 306a4e377b4..4eda18f71cd 100644
--- a/apps/learn/lib/get-next-page.ts
+++ b/apps/learn/lib/get-next-page.ts
@@ -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,
}
}
-