Supabase API - HelgaZhizhka/yes-code-merch GitHub Wiki
Supabase Documentation
[Supabase Docs](https://supabase.com/dashboard/project/tlnboeuoaezawexbrblg/api?page=users-management)
Supabase automatically documents all the data added to it. You can explore all tables, fields, and also see example queries.
All API interactions are handled in the shared
layer.
1. Domain Layer – API Functions and Interfaces
shared/api/supabase-client.ts Initializes the Supabase client and sets up basic configuration.
shared/api/database.types.ts Contains types auto-generated based on the Supabase schema.
shared/api/auth Contains interfaces related to authentication and user data:
LoginDTO
– Login dataSignUpDTO
– Basic signup dataRegisterDTO
– Extended registration data
Provides functions for handling auth:
login
– Sign in via Supabase Authlogout
– Sign outsignUp
– Create an accountcreateViewer
– Create an extended user profile via an RPC (Remote Procedure Call). This allows the client to ask the server to run a predefined function likecomplete_registration
, passing arguments as if calling a regular procedure.register
– Combines signup + extended profile creation
Utility functions:
mapViewerDataToRpcArgs
– Converts frontend user data into the format required for the RPC call
2. Viewer Segment
shared/viewer/model.ts – Stores current session data and provides selectors to check auth status
shared/session/hooks.ts – Hooks for session management. Subscribes to auth state on app init, cleans up on unmount, and provides hooks like
useViewerState
3. Page-specific Components
pages/login/hooks.ts Hook for login form:
useLoginForm
– Integrates React Hook Form with login mutation
pages/registration/hooks.ts Hook for registration form:
useRegistrationForm
– Manages form data and triggers the API call
Data Flow Overview
Session Initialization: On app load, the auth state is checked and stored in a global Zustand store.
User Login:
- Login form collects data
useLogin
calls thelogin
function- The result is saved into the session store
User Registration:
- Registration form collects profile info
useRegister
callsregister
register
performs two sequential actions:signUp
(create account) +createViewer
(save extended profile via RPC)
User Logout:
useLogout
calls thelogout
function- Clears session store and resets query cache
User Registration Flow
Registration happens in two steps:
signUp
via Supabase AuthcreateViewer
via Supabase RPC function
complete_registration
RPC does:
What -
Inserts or updates the profile in the
customers
table. -
Creates one or two addresses in the
addresses
table:- always creates a shipping address
- adds a billing address if
useShippingAsBilling = false
Example RegisterDTO sent from the form:
{
email: '[email protected]',
password: 'password',
firstName: 'Olga',
lastName: 'Zh',
phone: '123456789',
title: 'Ms.',
dateOfBirth: '1977-09-19',
company: 'Yes Code',
shippingAddresses: [
{
country: 'ES',
city: 'Madrid',
streetName: 'Calle Nueva',
streetNumber: '12',
postalCode: '100000',
isDefault: true
}
],
useShippingAsBilling: true
}
Form Step Breakdown:
- Email + Password
- First name, last name, phone, (optional: title, DOB, company)
- Shipping address
useShippingAsBilling
– default istrue
. Iffalse
, user provides billing address
All this is submitted once when clicking Submit.
RPC Details
-
Inserts/updates entry in
public.customers
first_name
,last_name
,title
,phone
,email
date_of_birth
,company
user_id
fromauth.uid()
-
Inserts entries into
public.addresses
Shipping address:
- Always created
is_shipping_address = true
is_default_shipping
set from input- If
useShippingAsBilling = true
, it also acts as billing
Billing address:
- Only created if
useShippingAsBilling = false
is_billing_address = true
is_default_billing
set from input
Client-side uses mapDataRegistrationFormToRpcArgs(viewer)
to format form data into snake_case
arguments for the RPC call.
API Architecture Pattern
DTO → Mapper → Model
[ DTO ]
↓
[ Mapper (model/mappers.ts) ]
↓
[ Model (model/types.ts) ]
Example DTO:
{
"product_id": 123,
"product_name": "Cool T-Shirt",
"product_price": 29.99,
"created_at": "2024-04-22T10:00:00Z"
}
Mapped Model:
interface Product {
id: number;
title: string;
price: number;
createdAt: Date;
}
Mapper Function:
export const mapDtoToProduct = (dto: ProductDto): Product => ({
id: dto.product_id,
title: dto.product_name,
price: dto.product_price,
createdAt: new Date(dto.created_at),
});
countries
Table
Stores a list of supported countries. The app currently uses a single region hardcoded in shared/config
: REGION = 'EU'
.
Each country includes:
iso_code
– two-letter code (e.g. 'ES')name
– full country name (e.g. 'Spain')region
– default is 'EU'
How to fetch countries from the client:
const { data: countries } = await supabase
.from('countries')
.select('iso_code, name')
.eq('region', EU_REGION);
Postal Code Validation
Use RegExp per country for postal code validation. See: https://en.wikipedia.org/wiki/List_of_postal_codes
You can also explore libraries or npm packages that offer postal code validation per country.