A modern, community-driven Q&A platform for developers — reimagined with the latest web technologies.
🚀 Project Status: Core functionality is in place and the project is in beta/stabilization. Recent work added an optimized multi-model global search bar with in-memory LRU caching, a full-featured jobs board, answer editing and deletion workflows, and Next.js Cache Components with cached data and instant navigations.
🙏 Credits: DevFlow started from the JS Mastery Next.js course project. I then extended it well beyond the course: a full jobs board with applications and applicant tracking, multi-model global search with LRU caching, answer editing and deletion, the Next.js 16 upgrade (proxy.ts, Cache Components), Docker, and CI/CD workflows.
|
Post questions, write detailed answers, and help others grow together. Instant search across questions, answers, users, and tags with category filters ( Organize content with technology tags (React, JavaScript, TypeScript, etc.). Save or remove questions and browse saved questions in your collection. Upvote or downvote questions and answers with optimistic UI updates. Signed-in users get recommended questions based on their interaction history and preferred tags. Questions they have already interacted with are excluded. |
Sign in with Google, GitHub, or email via NextAuth. Seamless theme switching for comfortable viewing. Optimized for desktop, tablet, and mobile devices. Browse members, filter by reputation or popularity, and view each member's questions. View responsive profiles with bio, location, portfolio, activity stats, paginated questions and answers, and upvote/downvote controls on answers. Owners can edit and delete their questions and answers from the profile, with a confirmation dialog before deleting; users can also edit their profile details. Right sidebar highlights top-voted questions and popular tags. User profiles show up to six tags used on the user's questions. |
|
Markdown editor (MDXEditor, loaded client-side only) for questions and answers, with syntax-highlighted code blocks rendered via Bright. Shared filter components and page-number pagination across home, tags, tag details, collection, community, profile, jobs, and answers. Question lists show 3 per page. Request and error logging with Pino for debugging and monitoring. Generate intelligent answers using OpenAI integration. Browse, search and filter jobs, then apply, save or share them. Posters can create, edit and delete their jobs (with company logo upload) and review applicants. Cache Components and Partial Prefetching serve a static shell instantly while page data streams in. Shared lists are cached and invalidated as soon as questions, answers, votes or views change. Centralized global metadata plus entity-aware metadata for questions, tags, profiles, community members, and jobs, including canonical URLs, keywords, Open Graph, Twitter cards, authors, and structured data. Optimized images, lazy-loaded non-critical media, responsive layouts, mobile-safe authentication redirects, and protected application routes for a faster and more consistent mobile experience. |
|
- Global search: Multi-model global search across questions, answers, users, and tags with category filtering (
Question,Answer,User,Tag), debounced URL sync, client-side LRU caching for instant query recall, and outside-click/escape key dismissal. - Search UI & Figma alignment: Pixel-perfect global search bar and dropdown matching Figma specifications with dark/light gradients, rounded-xl container styling, 56px height, and seamless navigation integration.
- Search performance: Eliminated cascading
useEffecthooks in favor of render-phase state synchronization and direct timer management to eliminate render lag and race conditions. - Jobs: job board with search, filters and salary sorting; apply, save and share; posters can create, edit and delete jobs and manage applicants.
- Answers: edit and delete your own answers from the profile Answers tab, with a dedicated answer edit page.
- Deletes: shared confirmation dialog (shadcn AlertDialog) for deleting questions and answers; deletes run in MongoDB transactions and remove related votes.
- Caching: enabled Next.js Cache Components and Partial Prefetching; question and tag lists are cached with tag-based invalidation, and the session is read once per request.
- Next.js caching: migrated high-read question feeds, tag lists/top tags, and job filter options from deprecated
unstable_cachetouse cachewith explicitcacheLifeprofiles andcacheTaginvalidation. - Queries: escaped search input, bounded pagination input, atomic view and answer counters, and new indexes for feeds, votes, saved questions and tag links.
- Recommendations: the home feed's Recommended filter now uses question interactions and preferred tags, removes duplicate tags, excludes previously interacted questions, and falls back to popular unseen questions.
- Authentication: personalized recommendations are used only for signed-in users; logged-out users continue to receive the public question feed.
- Google sign-in: fewer database round trips during OAuth sign-in and a unique index on accounts.
- API:
POST /api/questionsfor creating questions (used by the Thunder Client collection). - Lists: page-number pagination everywhere, with 3 questions per page.
- SEO: centralized metadata constants and a shared dynamic metadata builder now power canonical URLs, keywords, social previews, authors, and entity-specific metadata across public detail pages.
- Authentication security: the main application routes require an authenticated session, and voting controls are hidden for signed-out users and on other users' profile activity.
- Mobile OAuth: Google OAuth callback and redirect handling was hardened for mobile browsers and deployed environments.
- Profiles and tags: profile question cards and Top Tags now read both question tag fields and tag-question relations; a backfill migration repaired legacy questions with missing tag data.
- Images and responsive UX: non-critical images use lazy loading and responsive sizing, while auth and job imagery is optimized for mobile performance.
| Layer | Technology |
|---|---|
| Frontend | Next.js 16 (App Router, Server Components, Server Actions) • React 19 |
| Language | TypeScript |
| Database | MongoDB via Mongoose 8 |
| Auth | NextAuth.js v5 (Google, GitHub, Credentials) |
| Styling | Tailwind CSS 4 • shadcn/ui • Radix UI • Lucide |
| Forms & Validation | React Hook Form • Zod |
| Editor | MDX Editor • next-mdx-remote • Bright |
| AI | OpenAI via Vercel AI SDK |
| Logging | Pino |
✓ Node.js ≥ 22.13
✓ Yarn (via Corepack: `corepack enable`)
✓ MongoDB (local or Atlas)# 1️⃣ Clone the repository
git clone https://github.com/osamaayub/DevFlow.git
cd DevFlow
# 2️⃣ Install dependencies (also applies patches/ via patch-package)
yarn install
# 3️⃣ Create a .env.local file in the project root
# and add the variables listed below
# 4️⃣ At minimum set:
# MONGODB_URI, AUTH_SECRET (OAuth and OpenAI keys are optional)
# 5️⃣ Start development server
yarn dev
# 6️⃣ Open http://localhost:3000 in your browser 🎉📝 Note: Env files are loaded per environment and are git-ignored for security.
| Variable | Description | Example |
|---|---|---|
MONGODB_URI |
MongoDB connection string | mongodb+srv://user:pass@cluster.mongodb.net/devflow |
AUTH_SECRET |
NextAuth encryption key | Generate with: npx auth secret |
OPENAI_API_KEY |
OpenAI API key for AI answers | Get from OpenAI Platform |
| Variable | Provider | How to Get |
|---|---|---|
AUTH_GITHUB_ID |
GitHub OAuth | GitHub OAuth Settings |
AUTH_GITHUB_SECRET |
GitHub OAuth | GitHub OAuth Settings |
AUTH_GOOGLE_ID |
Google OAuth | Google Cloud Console |
AUTH_GOOGLE_SECRET |
Google OAuth | Google Cloud Console |
For Vercel or another production host, add both Google variables in the deployment
environment (not only in .env.local). The exact callback URL must also be registered
in Google Cloud Console: https://<your-domain>/api/auth/callback/google. The app also
accepts GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET as aliases.
| Variable | Default | Values |
|---|---|---|
LOG_LEVEL |
debug (dev) / info (prod) |
debug, info, warn, error |
NEXTAUTH_URL |
Auto-detected (trustHost) |
Your site URL, e.g. http://localhost:3000 |
NEXT_PUBLIC_API_BASE_URL |
https://$VERCEL_URL on Vercel, otherwise localhost |
Base URL used by the API client in lib/api.ts |
# Development
yarn dev # Start dev server (webpack)
# Production
yarn build # Create optimized production build
yarn start # Run production server
# Code Quality
yarn lint # Run ESLint checks
# Database maintenance
npm run db:backfill-question-tags # Restore tags for legacy questions
MONGODB_URI="..." npm run db:cleanup-test-questions # Dry run: list seeded test questions
MONGODB_URI="..." npm run db:cleanup-test-questions -- --apply # Delete them and fix tag counts- Project setup with Next.js 16 & TypeScript
- MongoDB & Mongoose integration with multiple models
- NextAuth.js authentication (Google, GitHub, Email/Password)
- Complete database models (Questions, Answers, Users, Tags, Accounts, Collections, Interaction, Votes, QuestionView, TagQuestion, Job, JobApplication, SavedJob)
- Server actions for CRUD operations (questions, answers, tags, auth)
- Tailwind CSS & component styling with shadcn/ui
- Dark/Light theme support with context provider
- Rich text editor with MDX support
- Tag management system with tag-question relationships
- Multi-model global search across questions, answers, users, and tags with category filtering
- Debounced global search bar with direct event-driven timer management and render-phase state sync
- In-memory LRU client caching for search queries (zero-latency instant feedback)
- Search dropdown with outside-click and escape key dismissal
- Figma design alignment for global search bar and navigation header
- Local search bar with filtering for questions, tags, community, and jobs
- Pagination system
- Error handling with custom error handler
- Validation schemas with Zod
- AI Answer API endpoint with OpenAI integration
- API client functions and centralized route constants
- Core UI pages (home, sign-in, sign-up, ask-question, question details, tags, collections)
- React components (forms, cards, navigation, editor, search, filters, shared utilities)
- User authentication flow (sign up, sign in, OAuth)
- Question creation and editing
- Question edit/delete flow from the profile activity cards with proper ownership checks
- Delete confirmation and toast success/error feedback for question removal
- Profile activity refactor into reusable UI components and a dedicated state/action hook
- Separate paginated profile question and answer server actions
- Optimistic upvote/downvote controls and current-user vote state on profile answer cards
- Profile query indexes for sorted questions, sorted answers, and author-tag aggregation
- Bounded profile tag-name lookup without an aggregation
$lookup - Save and remove questions with a stateful saved-star indicator
- Collection page listing the signed-in user's saved questions
- Answer creation
- Question view tracking
- Responsive design across implemented pages
- Local search bar with filtering
- Navigation sidebar and mobile navigation
- Theme toggle component
- User avatar components
- Relative time display
- Toast notifications with Sonner
- Form validation with React Hook Form
- Database connection management
- Structured logging with Pino
- API route handlers for users, accounts, auth, and AI
- OAuth callback handling and user account creation
- Password hashing with bcrypt
- Username generation for OAuth users
- Session management and JWT callbacks
- MongoDB transaction support for complex operations
- Tag processing and helper functions
- Question filtering (newest, unanswered, popular)
- Personalized question recommendations from user interactions and preferred tags
- Exclude previously interacted questions from recommendations
- Deduplicate tags in recommendation results
- Interaction tracking with reputation updates for posts, votes, bookmarks, views and edits
- Badge system and gamification with bronze, silver and gold profile badges
- URL utilities and helpers
- AI Answer UI integration (API implemented, UI Implemented)
- Vote system (upvotes/downvotes) for questions and answers with optimistic updates
- Home filters (newest, recommended, frequent, unanswered)
- Shared filter component for tags, collection, community, and answers
- Pagination for questions, tags, tag details, answers, collection, and community
- Tag details page
- Community page with search, filters, and member details page
- User profiles with editable profile details, activity tabs, statistics, and per-tab question/answer pagination
- Right sidebar with hot questions and popular tags
- Back button across pages
- MDX editor loaded client-side only (fixes "This page couldn't load" on ask-question and question details)
- CI workflow (lint, type-check, build) and Docker image publishing to GHCR
- Jobs board: listing, search, filters, details, apply, save, share
- Job posting with logo upload, plus edit, delete and applicant management for posters
- Answer editing and deletion from the profile Answers tab
- Shared confirmation dialog for question and answer deletion
- Next.js Cache Components and Partial Prefetching with per-route loading states
-
use cachewith explicitcacheLifeandcacheTagfor question, tag, and job filter data - Cached question and tag lists with tag-based invalidation
-
POST /api/questionsendpoint for creating questions - Global SEO metadata with canonical, Open Graph, Twitter, author, and application metadata
- Dynamic metadata for question, tag, profile, community member, and job detail pages
- Shared metadata builder and centralized metadata constants
- Responsive image optimization and lazy loading for non-critical images
- Mobile Google OAuth callback and redirect handling
- Authenticated application route protection
- Signed-out vote controls hidden across the application
- Profile ownership checks for question and answer actions
- Profile question tags and Top Tags fallback support
- Legacy question tag backfill migration
- Final polish and edge-case validation for remaining UI flows
- Securing the users and accounts REST endpoints
- User management actions
- Live demo deployment
- Admin dashboard
- Real-time notifications
- Advanced analytics and reporting
- Community features (comments, discussions)
- API rate limiting
- Additional OAuth providers
- Enhanced search algorithms
- Performance optimizations
- Additional unit and integration tests
The project has no src folder: app/ and the other folders sit at the project root. app/ holds only routes (pages, layouts, loading states and API handlers), and each route delegates to a feature folder.
DevFlow/
├── app/ # Routes only (App Router)
│ ├── layout.tsx # Root layout: fonts, metadata, Providers
│ ├── Providers.tsx # SessionProvider, ThemeProvider, Toaster
│ ├── (auth)/ # Auth screens (no sidebars)
│ │ ├── layout.tsx
│ │ ├── sign-in/page.tsx
│ │ └── sign-up/page.tsx
│ ├── (root)/ # Main app with navbar and sidebars
│ │ ├── layout.tsx # Navbar, left sidebar, right sidebar
│ │ ├── loading.tsx # Shared Loader fallback
│ │ ├── page.tsx # Home: questions feed
│ │ ├── ask-question/page.tsx
│ │ ├── questions/[id]/ # Question details, answers
│ │ │ └── edit/ # Edit a question
│ │ ├── answers/[id]/edit/ # Edit an answer
│ │ ├── tags/ # All tags
│ │ │ └── [id]/ # Questions under a tag
│ │ ├── collection/ # Saved questions
│ │ ├── community/ # Members
│ │ │ └── [id]/details/ # A member's questions
│ │ ├── profile/
│ │ │ ├── [id]/ # Profile, Top Posts and Answers tabs
│ │ │ └── edit/ # Edit your profile
│ │ └── jobs/ # Jobs board
│ │ ├── new/ # Post a job
│ │ └── [id]/ # Job details
│ │ ├── apply/ # Apply to a job
│ │ ├── applicants/ # Poster's applicant list
│ │ └── edit/ # Edit a job
│ └── api/ # REST route handlers
│ ├── auth/[...nextauth]/ # Auth.js handler
│ ├── ai/answers/ # AI answer generation
│ ├── questions/ # POST: create a question
│ ├── users/ # Users CRUD, /email, /[id]
│ └── accounts/ # Accounts CRUD, /provider, /[id]
│ # Every page folder under (root) also has a loading.tsx that re-exports
│ # the shared Loader, so client navigations stay instant.
│
├── features/ # One folder per domain: actions.ts + components/
│ ├── answers/ # Create, list, edit, delete answers; AnswerForm, EditAnswerForm
│ ├── auth/ # Credentials sign-in/up; AuthForm, SocialAuthForm
│ ├── collections/ # Save/unsave questions, saved list
│ ├── community/ # Members list and member details
│ ├── interaction/ # User interaction tracking, reputation score updates, badges
│ ├── jobs/ # Jobs, applications, saved jobs; types.ts, utils.ts
│ ├── questions/ # Create, edit, delete, list; service.ts (shared create logic)
│ ├── search/ # Global search action across questions, users, answers, tags
│ ├── tags/ # Tag lists and tag questions; tag-helpers.ts
│ ├── users/ # Profile data, activity tabs, profile editing
│ └── votes/ # Votes on questions and answers; hooks/useVote.ts
│
├── server/ # Server-only infrastructure
│ ├── auth.ts # Auth.js config; auth() is cached per request
│ ├── action.ts # Validate + authorize + connect wrapper for actions
│ ├── cache-tags.ts # Cache tag names and revalidation intervals
│ ├── request-time.ts # Defers DB work to request time (Cache Components)
│ ├── errors/ # HTTP error classes and error handler
│ └── db/ # connect.ts, models/, schemas/ (with indexes)
│
├── shared/ # Shared client and server building blocks
│ ├── api/ # Typed fetch client for the REST endpoints
│ ├── components/
│ │ ├── ui/ # shadcn/ui primitives (incl. alert-dialog)
│ │ ├── common/ # Loader, ConfirmDialog, ConfirmDeleteButton, DataRender, ...
│ │ ├── editor/ # MDX editor and preview
│ │ ├── filters/ # Shared filters
│ │ ├── navigation/ # Navbar, sidebars, Pagination
│ │ └── search/ # Global search bar, filters, results dropdown, local search bar
│ ├── constants/ # Routes, filters, empty states, pagination
│ ├── context/ # Theme context
│ ├── lib/ # utils, url, validation, logger, question/recommendation helpers
│ └── types/
│
├── proxy.ts # Request proxy: forwards the question filter header
├── patches/ # patch-package patches (next-themes)
├── public/ # Static assets and icons
├── .github/workflows/ # CI and deploy workflows
└── Dockerfile # Multi-stage standalone build
Dependency rules
app→features→shared;serveris used byappand featureactions.ts, never by client components.- A feature is imported only through its public surface:
@/features/<name>/componentsor@/features/<name>/actions. Features don't reach into each other's internals. - Relative imports stay inside one area; anything crossing areas uses the
@/alias (@/*→ the project root).
All responses follow the standard envelope format:
{ "success": true, "data": {...}, "statusCode": 200 }Note: The app itself uses Server Actions for questions, answers, tags, votes, collections, community and jobs.
POST /api/questionsexists for external tools such as Thunder Client.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/users |
List all users |
POST |
/api/users |
Create new user (201) |
GET |
/api/users/:id |
Get user by ID |
PATCH |
/api/users/:id |
Update user |
DELETE |
/api/users/:id |
Delete user |
POST |
/api/users/email |
Get user by email |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/accounts |
List all accounts |
POST |
/api/accounts |
Create new account |
GET |
/api/accounts/:id |
Get account by ID |
PATCH |
/api/accounts/:id |
Update account |
DELETE |
/api/accounts/:id |
Delete account |
POST |
/api/accounts/provider |
Get account by provider |
| Method | Endpoint | Description |
|---|---|---|
GET/POST |
/api/auth/[...nextauth] |
NextAuth.js handler (Google, GitHub, Credentials) |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/ai/answers |
Generate AI-powered answers with OpenAI |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/questions |
Create a question as the signed-in user (send the authjs.session-token cookie). Body: { title, content, tags }, with Markdown content |
Questions, Answers, Tags, Votes, Collections, Community and Jobs are handled via Server Actions:
| Feature | Action | Description |
|---|---|---|
| Users | getUser |
Get profile data, statistics, top questions and answers, and up to six question tags |
updateUserProfile |
Update your profile details | |
getUserQuestionsActivity |
Get paginated profile questions | |
getUserAnswersActivity |
Get paginated profile answers with the current user's vote state | |
| Questions | createQuestion |
Create new question with tags |
editQuestion |
Edit existing question | |
getQuestion |
Get single question by ID | |
getQuestions |
Get paginated questions with search and filters; uses personalized recommendations for signed-in users when the Recommended filter is selected | |
getRecommendationQuestions |
Get interaction-based recommendations while excluding previously interacted questions | |
getHotQuestions |
Get top questions for the right sidebar | |
incrementQuestionViews |
Track question views | |
deleteQuestion |
Delete your question with its answers and votes | |
| Interactions | createInteraction |
Record user activity and apply reputation changes |
| Answers | createAnswer |
Create answer for question |
getAnswers |
Get paginated answers with filters | |
getAnswerForEdit |
Load your answer for its edit page | |
editAnswer |
Edit your answer | |
deleteAnswer |
Delete your answer and its votes | |
| Tags | getTags |
Get paginated tags with filters |
getTagQuestions |
Get questions for specific tag | |
getTopTags |
Get popular tags for the right sidebar | |
| Search | globalSearch |
Multi-model global search across questions, answers, users, and tags with category filtering and sanitized regex |
| Votes | CreateVote / UpdateVote |
Cast, switch, or remove an upvote/downvote |
hasVoted |
Check the current user's vote on a question or answer | |
getUserVotesForTargets |
Batch-check votes for multiple targets | |
| Collection | toggleSaveQuestion |
Save or unsave a question |
hasSavedQuestion |
Check whether a question is saved | |
getSaveQuestions |
Get the user's saved questions (paginated, filtered) | |
| Community | getUsers |
Get paginated users with search and filters |
getCommunityMember |
Get a member and their questions | |
| Jobs | getJobs |
Get paginated jobs with search, filters and salary sorting |
getJobById / getJobViewerState |
Get a job and the viewer's applied/saved state | |
createJob / editJob / deleteJob |
Post, edit or delete a job (poster only) | |
applyToJob / toggleSaveJob |
Apply to or save a job | |
getJobApplicants / updateApplicationStatus |
Review applicants and set their status | |
| Auth | signUpWithCredentials |
User registration |
signInWithCredentials |
User login | |
logout |
User sign out |
Run the application and a local MongoDB database with Docker Compose:
# Create your local environment file from the template
Copy-Item .env.example .env
# Replace AUTH_SECRET in .env with a generated secret, then build and start
docker compose up --build -d
# Follow application logs
docker compose logs -f app
# Stop the stack (the MongoDB volume is preserved)
docker compose down
# Stop the stack and delete the local MongoDB data
docker compose down -vOpen http://localhost:3000. Compose waits for MongoDB's health check before starting the app, and stores database files in the mongodb_data named volume. Add optional GitHub, Google, and OpenAI credentials to .env to enable those integrations.
This Compose database is for local development. MongoDB is not published to the host, but it has no database authentication on the private Compose network. Use a secured MongoDB deployment such as Atlas for production and set MONGODB_URI to its connection string in your production environment; do not commit .env.
To build only the standalone application image, run docker build -t devflow:latest .. Set MONGODB_URI and AUTH_SECRET when starting the container; add provider/API keys only for features you enable.
GitHub Actions automate testing and deployment:
| Workflow | Trigger | Action |
|---|---|---|
| CI | PR or push to main/dev |
Lint → Type-check → Build |
| Deploy (Dev) | Push to dev |
Build → Push ghcr.io/.../devflow:dev |
| Deploy (Prod) | Push to main |
Build → Push ghcr.io/.../devflow:latest |
- Configure Settings → Environments in your GitHub repo
- Add secrets for
developmentandproductionenvironments:MONGODB_URIAUTH_SECRET- OAuth credentials
- Docker registry credentials (if using GHCR)
- 🎯 Next.js App Router with Server Components and Server Actions
- ⚡ Cache Components & Partial Prefetching: a prerendered static shell (navbar, sidebars, loaders) with page data streamed in
- 🗃️ Cached lists for questions and tags (
use cache+cacheTag), invalidated withupdateTag/revalidateTagon every change - 🔍 Optimized Global Search & In-Memory LRU Cache: Client-side query caching (100-entry LRU) and direct event-driven debounce prevent redundant server actions and deliver zero-latency instant feedback
- 🔐 One session read per request via React
cache()aroundauth() - 🧩 Client-only MDX editor loaded with
next/dynamicto keep it out of server rendering - 🗜️ Optimized Bundle with tree-shaking
- 📦 MongoDB Indexing for feeds, answers by question, vote lookups, saved questions, tag links, accounts and profile queries
- 🏷️ Bounded Tag Retrieval groups profile tags, limits the IDs, then fetches names in one query without
$lookup - 🚀 Docker Multi-stage Build for minimal image size
We welcome contributions! Here's how to get started:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request against the
devbranch
- Follow the existing code style
- Add tests for new features
- Update documentation as needed
- Reference related issues in your PR
# Check your MONGODB_URI format
# Expected: mongodb+srv://username:password@cluster.mongodb.net/dbname
# Make sure your IP is whitelisted in MongoDB Atlas# Regenerate AUTH_SECRET
npx auth secret
# Verify OAuth credentials in your provider settings# Clear cache and reinstall
rm -rf .next node_modules
yarn install
yarn buildThis project is licensed under the MIT License — feel free to use it in your projects!
Have questions or want to contribute?
- 💬 GitHub Discussions — Ask questions & discuss features
- 🐛 Report Issues — Found a bug? Let us know
- 📖 Documentation — Coming soon with API guides & architecture
- 👥 Join Development — We welcome contributors!
- ⭐ Star the repo — Shows your support!
Made with ❤️ by Osama Ayub