This is a Flutter blog app that follows the Clean Architecture
and SOLID principles
. The app allows users to sign up, log in, create, and view blogs. The app uses Supabase
as the backend. Local data is cached using Hive
. The app also uses Easy Localization
for localization and Internet Connection Checker
to check for internet connectivity. The app follows the BLoC
pattern for state management and uses GetIt
for dependency injection.
- Screenshots 📸
- Clean Architecture 🏗
- Features 🎉
- SOLID Principles 🌟
- Clean Architecture + SOLID Principles 🚀
- Getting Started 🚀
- Thanks 🙏
SignUp | LogIn | Blogs |
NewBlog | BlogDetails |
The Clean Architecture is a software design philosophy that separates the software into layers. Each layer has its own responsibilities and dependencies. The layers are:
- Domain: This layer contains the business logic of the application. It is the innermost layer and does not depend on any other layer. It contains entities, use cases, and repositories.
- Data: This layer contains the implementation of the repositories. It depends on the domain layer.
- Presentation: This layer contains the UI of the application. It depends on the domain layer.
The Clean Architecture allows for the separation of concerns and makes the codebase more maintainable and testable.
- Authentication: Users can sign up and log in to the app.
- Blogs: Users can create and view blogs.
The SOLID principles are a set of five design principles that help make software designs more understandable, flexible, and maintainable. The principles are:
- Single Responsibility Principle (SRP): A class should have only one reason to change.
- Open/Closed Principle (OCP): Software entities should be open for extension but closed for modification.
- Liskov Substitution Principle (LSP): Objects of a superclass should be replaceable with objects of its subclasses without affecting the functionality of the program.
- Interface Segregation Principle (ISP): A client should not be forced to implement an interface that it does not use.
- Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
The SOLID principles help make software designs more modular, flexible, and maintainable.
The Clean Architecture and SOLID principles work well together. The Clean Architecture provides a structure for the software, while the SOLID principles provide guidelines for writing clean and maintainable code. By following the Clean Architecture and SOLID principles, developers can create software that is easy to understand, test, and maintain.
- Clone the repository:
git clone
- Navigate to the project directory:
cd flutter_blog_clean_arc_app
- Install the dependencies:
flutter pub get
- Create a
assets/env/.env
andassets/env/.dev.env
file in the root directory and add the following:
SupabaseUrl=YOUR_SUPABASE_URL
SupabaseAnonKey=YOUR_SUPABASE_ANON_KEY
SupabaseServiceRoleKey=YOUR_SUPABASE_SERVICE_ROLE_KEY
- Supabase:
- Auth > Enable Email & Password
- Database > profiles > SQL > Run the following query:
create table profiles (
id uuid references auth.users on delete cascade not null primary key,
updated_at timestamp with time zone,
name text,
constraint name_lenght check (char_length(name) >= 2)
);
alter table profiles
enable row level security;
create policy "Public profiles are viewable by everyone." on profiles
for select using (true);
create policy "Users can insert their own profile." on profiles
for insert with check (auth.uid() = id);
create policy "Users can update own profile." on profiles
for update using (auth.uid() = id);
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.profiles (id, name)
values (new.id, new.raw_user_meta_data->>'name');
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
- Database > blogs > SQL > Run the following query:
create table blogs (
id uuid not null primary key,
updated_at timestamp with time zone,
owner_user_id uuid not null,
title text not null,
content text not null,
image_url text,
topics text array,
foreign key (owner_user_id) references public.profiles(id)
);
alter table profiles
enable row level security;
create policy "Public blogs are viewable by everyone." on blogs
for select using (true);
create policy "Users can insert their own blogs." on blogs
for insert with check (auth.uid() = id);
create policy "Users can update own blogs." on blogs
for update using (auth.uid() = id);
insert into storage.buckets (id, name)
values ('blog_images', 'blog_images');
create policy "Avatar images are publicly accessible." on storage.objects
for select using (bucket_id = 'blog_images');
create policy "Anyone can upload an avatar." on storage.objects
for insert with check (bucket_id = 'blog_images');
create policy "Anyone can update their own avatar." on storage.objects
for update using (auth.uid() = owner) with check (bucket_id = 'blog_images');
- Storage > Create a bucket with the name
blog_images
- Run the app:
flutter run
- UI 📱
- State Management 🚀
- Serialization 📦
- Dependency Injection 💉
- Network 🌐
- Security 🔒
- Localization 🌍
- Cache 📦
- Utils 🛠
- Analysis 📊
- Code Generation 🏗
- Rivaan Ranawat for the Blog App