A modern Vue 3 application with Supabase authentication integration, featuring email, password, and GitHub authentication flows. This project demonstrates how to effectively integrate Supabase with Vue 3, Pinia, Vue-router 4, TailwindCSS, and includes testing with Vitest and Cypress.
|
I'm a Software Developer who passionate about coding and building tools that help people with their daily tasks.
I'm currently exploring AI solutions and working with modern tech stacks. I'm also on a journey to level up my
Spaghetti Code skills. Support us by make some donate and I really appricate that.
Got a question? Feel free to contact me anytime. |
- 🔐 Complete authentication system with Supabase
- 📧 Email & Password authentication
- 🔑 GitHub OAuth integration
- 💱 KHQR payment integration
- 🧩 Vue 3 Composition API
- 🏪 Pinia for state management
- 🛣️ Vue Router for navigation
- 🎨 TailwindCSS for styling
- 🧪 Testing with Vitest and Cypress
- Node.js (v16 or later recommended)
- npm or yarn
- Git
- Supabase account
-
Clone the repository
git clone https://github.com/MyKhode/ihub.git cd ihub -
Install dependencies
npm install
-
Create a
.envfile in the root directory based on the example below:VITE_SUPABASE_URL=your_supabase_url VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
-
Head over to Supabase and create a new project
-
Choose your Project name, password, region, and pricing plan (free tier works fine)
-
Once the project is created, navigate to Authentication > Settings
-
Configure Site URL and Additional Redirect URLs:
Field Value Site URL https://your-production-url.com/Additional Redirect URLs http://localhost:3000/resetpassword,https://your-production-url.com/resetpassword,http://localhost:3000,http://localhost:3000/callback,https://your-production-url.com/callback -
Save your changes
To set up the database tables and triggers in Supabase, run the following SQL scripts:
-- Create orders table in Supabase
CREATE TABLE orders (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
order_number VARCHAR(20) NOT NULL,
status VARCHAR(20) CHECK (status IN ('active', 'completed', 'cancelled')) NOT NULL,
date_ordered DATE NOT NULL,
expected_delivery DATE,
color VARCHAR(50),
size VARCHAR(10),
price VARCHAR(20) NOT NULL,
product_name VARCHAR(100) NOT NULL,
product_image TEXT,
user_id UUID REFERENCES auth.users(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Create an index on order_number for faster lookups
CREATE INDEX idx_orders_order_number ON orders(order_number);
-- Create an index on status for filtering
CREATE INDEX idx_orders_status ON orders(status);
-- Create a trigger to update the updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_orders_updated_at
BEFORE UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- Set up row level security (RLS)
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
-- Create policies
-- Policy for users to see only their own orders
CREATE POLICY "Users can view their own orders" ON orders
FOR SELECT USING (auth.uid() = user_id);
-- Policy for users to insert their own orders
CREATE POLICY "Users can insert their own orders" ON orders
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Policy for users to update their own orders
CREATE POLICY "Users can update their own orders" ON orders
FOR UPDATE USING (auth.uid() = user_id);
-- Policy for users to delete their own orders (optional)
CREATE POLICY "Users can delete their own orders" ON orders
FOR DELETE USING (auth.uid() = user_id);-- Step 1: Drop existing trigger and function
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
DROP FUNCTION IF EXISTS public.handle_new_user;
-- Step 2: Check if table exists, create if it doesn't
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM pg_tables
WHERE schemaname = 'public'
AND tablename = 'user_profiles'
) THEN
CREATE TABLE public.user_profiles (
user_id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT NOT NULL,
username TEXT,
avatar_url TEXT,
token INTEGER DEFAULT 500,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create index for faster lookups
CREATE INDEX idx_user_profiles_user_id ON public.user_profiles(user_id);
END IF;
END $$;
-- Step 3: Create the function
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.user_profiles (
user_id,
email,
username,
avatar_url,
token,
created_at
)
VALUES (
NEW.id,
NEW.email,
COALESCE(NEW.raw_user_meta_data->>'name', ''),
COALESCE(NEW.raw_user_meta_data->>'avatar_url', ''),
500,
NOW()
)
ON CONFLICT (user_id) DO UPDATE SET
email = EXCLUDED.email,
username = EXCLUDED.username,
avatar_url = EXCLUDED.avatar_url;
-- Do NOT update token or created_at for existing users
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Step 4: Create the trigger
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION public.handle_new_user();- Go to GitHub Developer Settings
- Create a new OAuth App
- Set the Authorization callback URL to your Supabase Auth callback URL (found in Supabase Dashboard)
- Copy the Client ID and Client Secret
- In Supabase Dashboard, go to Authentication > Providers
- Enable GitHub provider and enter your Client ID and Client Secret
- Save your changes
The KHQR (Khmer QR Code) is a standardized QR code payment system used in Cambodia that enables interoperability between different financial institutions. It allows users to make payments through any bank or payment provider in Cambodia, including popular ones like ABA, Acleda, Wing, and more.
- Universal Acceptance: Works with all major Cambodian banks and payment providers
- Convenience: Users can pay using their preferred banking app
- Security: Transactions are secured through the banking infrastructure
- Instant Payments: Real-time transaction processing
-
Import the KHQR module in your component:
import { khqr } from 'ts-khqr';
-
Configure KHQR parameters in your application:
const qrData = khqr.generate({ merchantName: 'YOUR_MERCHANT_NAME', merchantID: 'YOUR_MERCHANT_ID', merchantCity: 'YOUR_CITY', amount: transactionAmount, currency: 'USD', // or 'KHR' for Cambodian Riel acquiringBank: 'YOUR_ACQUIRING_BANK', billNumber: 'UNIQUE_BILL_ID' });
-
Generate a QR code using the qrcode library:
import QRCode from 'qrcode'; // Generate QR code in component QRCode.toCanvas(document.getElementById('qr-canvas'), qrData, { width: 250, margin: 2 });
-
Set up payment listener in your Pinia store or component to handle transaction callbacks.
-
- Users browse available products
- Select Product to see quick view model pop up
-
- View product details
- Select size, color, and quantity
- Click "Buy Now" button and it take a few operation to verify user have enough money and other condition verify
- Payment Successfully if pass all condition
-
- Users can add funds to their account
- KHQR payment option enables payment via any Cambodian bank app
- Scan QR code with banking app (ABA, Acleda, Wing, etc.)
- Funds are instantly credited to the user's account
-
Checkout Process
- Click Product Card to view Product Detail Options
- Confirm order details
- Pay using account balance (topped up via KHQR)
-
Order Confirmation
-
- Users can view their past orders
- Track order status (active, completed, cancelled)
- View expected delivery dates
npm run devThis will start the development server at http://localhost:3000
npm run buildnpm run previewThis will serve the production build at http://localhost:5050
npm run test:vitestnpm run test:unitnpm run test:e2eIf you're using the integrated server functionality:
npm run serveThis will start the server defined in server.js
-
Build your application for production
npm run build
-
Deploy the contents of the
distfolder to your web hosting service -
Make sure to configure your hosting service to handle SPA routing by redirecting all requests to
index.html
Contributions are welcome! Please feel free to submit a Pull Request.
MIT
- Repository: https://github.com/MyKhode/ihub
- Issues: https://github.com/MyKhode/ihub/issues
- Supabase Documentation: https://supabase.com/docs
- Vue 3 Documentation: https://vuejs.org/guide/introduction.html
- KHQR Documentation: https://www.npmjs.com/package/ts-khqr





