- Assessment Requirements
- Overview
- Key Features
- Tech Stack
- Getting Started
- Database Setup
- Project Structure
- Security Implementation
Note: This project is strictly for a technical assessment demonstration.
This application was built to fullfill the following specific trainee assessment criteria:
Core Objective: Build a simple blog web application using ReactJS in 5 days.
Conditions & Status:
- Tech Stack: Use TypeScript
- State Management: Use Redux
- Backend: Use Supabase
- Authentication Pages:
- Registration (Email confirmation disabled)
- Login
- Logout
- Blog Operations:
- Create a blog
- Update a blog
- Delete a blog
- Listing blogs with pagination
- Deployment:
- Deploy to public host (Vercel/Netlify)
- Provide GitHub Repository
A production-ready blog application demonstrating modern full-stack development practices. Built as a comprehensive technical assessment showcasing proficiency in React 19, TypeScript, Redux state management, Supabase backend integration, and secure authentication patterns.
β
Complete CRUD Operations - Create, Read, Update, and Delete blog posts
β
Secure Authentication - Email/password registration and login system via Supabase Auth
β
Row-Level Security - Backend-enforced user permissions via Supabase RLS
β
State Management - Centralized Redux Toolkit store with typed hooks
β
Rich Text Editing - Markdown support for writing and viewing posts
β
Responsive Design - Mobile-first Tailwind CSS styling (v4) with dark mode support
β
Real-time Feedback - Toast notifications for user actions
- User Registration - Email/password signup with instant access.
- Secure Login/Logout - JWT-based session management.
- Persistent Sessions - Automatic session restoration on page reload.
- Author Attribution - Automatic username resolution via database triggers.
| Feature | Description | Security |
|---|---|---|
| Create | Authenticated users can publish new posts | User ID automatically attached |
| Read | Public access to all published posts | No authentication required |
| Update | Edit your own posts only | RLS policy enforced |
| Delete | Remove your own posts only | RLS policy enforced |
| Rich Text | Markdown editor with preview | Sanitized output |
|
|
- Node.js 18+ and npm/yarn
- Supabase Account (free tier available)
1οΈβ£ Clone the Repository
git clone <repository-url>
cd blog-app2οΈβ£ Install Dependencies
npm install3οΈβ£ Environment Configuration
Create a .env file in the root directory:
VITE_SUPABASE_URL=your_supabase_project_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_keyπ‘ Tip: Find your Supabase credentials at:
Project Settings β API
4οΈβ£ Run Development Server
npm run devThe application will be available at http://localhost:5173
Navigate to the SQL Editor in your Supabase dashboard and run the following script to set up the database, RLS policies, and triggers:
-- 1. Create the 'posts' table
create table public.posts (
id uuid default gen_random_uuid() primary key,
created_at timestamp with time zone default timezone('utc'::text, now()) not null,
title text not null,
content text not null,
user_id uuid references auth.users not null,
author_name text
);
-- 2. Enable Row Level Security (RLS)
alter table public.posts enable row level security;
-- 3. Create Security Policies
-- Policy: Public read access
create policy "Public posts are viewable by everyone"
on public.posts for select
using (true);
-- Policy: Authenticated users can insert their own posts
create policy "Users can insert their own posts"
on public.posts for insert
with check (auth.uid() = user_id);
-- Policy: Users can update their own posts
create policy "Users can update own posts"
on public.posts for update
using (auth.uid() = user_id);
-- Policy: Users can delete their own posts
create policy "Users can delete own posts"
on public.posts for delete
using (auth.uid() = user_id);
-- 4. Create Author Name Trigger
-- This function automatically populates author_name from user metadata
create or replace function public.handle_new_post_author()
returns trigger
language plpgsql
security definer
set search_path = public
as $$
declare
user_name text;
begin
select
coalesce(
raw_user_meta_data->>'username',
split_part(email, '@', 1),
'Anonymous'
) into user_name
from auth.users
where id = new.user_id;
new.author_name := user_name;
return new;
end;
$$;
-- Attach the trigger
create trigger on_auth_user_created_post
before insert on public.posts
for each row execute procedure public.handle_new_post_author();blog-app/
βββ src/
β βββ app/
β β βββ store.ts # Redux store configuration
β β βββ hooks.ts # Typed useAppDispatch & useAppSelector
β β
β βββ features/
β β βββ auth/
β β β βββ authSlice.ts # Authentication state & reducers
β β β
β β βββ blogs/
β β βββ blogsSlice.ts # Blog posts state & reducers
β β
β βββ components/
β β βββ Navbar.tsx # Navigation bar
β β βββ BlogList.tsx # Component to list blog posts
β β βββ PostItem.tsx # Individual post item component
β β
β βββ services/
β β βββ authService.ts # Auth API calls
β β βββ blogService.ts # Blog CRUD API calls
β β
β βββ pages/
β β βββ Home.tsx # Landing page
β β βββ Login.tsx # Sign in page
β β βββ Register.tsx # Sign up page
β β βββ CreatePost.tsx # Post creation page
β β βββ EditPost.tsx # Post editing page
β β βββ PostDetail.tsx # Single post view
β β
β βββ supabaseClient.ts # Supabase client initialization
β βββ App.tsx # Main component & routing
β βββ main.tsx # Entry point
β
βββ public/ # Static assets
βββ supabase_setup.sql # Database schema reference
βββ package.json # Dependencies & scripts
The application relies on Supabase's RLS to ensure data integrity and security directly at the database layer.
| Operation | Enforcement |
|---|---|
| View Posts | Open to public. |
| Add Post | Restricted to authenticated users. User ID must match the session. |
| Edit/Delete | Restricted to the original author of the post. |
- Route Guards: Creation and editing routes are protected; unauthenticated users are redirected to login.
- UI Logic: "Edit" and "Delete" buttons are only rendered if the current logged-in user matches the post's author ID.