This project is a simple blogging backend API:
- Users can sign up, log in, and update their profile (including an avatar).
- Authenticated users can create, list, update, and delete blog posts.
- Posts belong to categories.
- Users can comment on posts (supports threaded replies via
parent_id). - When a new post is published, other users receive an in-app notification (stored in the database) delivered via a queued job.
- Auth: Token-based auth via Laravel Sanctum.
- Users:
userstable +Usermodel (roles:userdefault;adminfor category admin actions). - Categories:
categoriestable +Categorymodel; admin-only create/delete. - Posts:
poststable +Postmodel; supports optional featured image upload. - Comments:
commentstable +Commentmodel; polymorphiccommentable_type/commentable_idplusparent_idfor replies. - Notifications:
notificationstable; new post notifications stored using Laravel’s database notification channel. - Queue:
jobstable; new post notifications are dispatched/processed asynchronously.
- Laravel 12: application framework.
- Laravel Sanctum (
laravel/sanctum): API authentication using personal access tokens. - Cloudinary PHP SDK (
cloudinary/cloudinary_php): image upload/delete for avatars and post images. - Database queue + database notifications: built-in Laravel drivers, chosen so the app can run without Redis/SQS in local/dev.
- PHP 8.2+
- Composer
- PostgreSQL (recommended / used in this project)
composer installIf you don’t have one yet:
copy .env.example .env
php artisan key:generateRecommended local config (PostgreSQL):
APP_NAME="Blog App"
APP_ENV=local
APP_KEY=base64:...generated...
APP_DEBUG=true
APP_URL=http://127.0.0.1:8000
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5433
DB_DATABASE=blog_app
DB_USERNAME=postgres
DB_PASSWORD=your_password
QUEUE_CONNECTION=database
# Cloudinary (recommended if you use avatar/post images)
# Option A (most common):
CLOUDINARY_URL=cloudinary://API_KEY:API_SECRET@CLOUD_NAME
# Sanctum (only needed for SPA cookie auth; safe defaults are already set)
# FRONTEND_URL=http://localhost:5173
# SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1,127.0.0.1:8000FRONTEND_URL=http://localhost:5173
Notes:
- If Cloudinary is not configured and you call endpoints that upload images, those requests will fail.
- Notifications are stored in the database (no email config required).
### 4) Create the database
#### PostgreSQL
Create the database (choose one approach):
- Using `psql`:
```bash
psql -U postgres -c "CREATE DATABASE blog_app;"
- Or using
createdb:
createdb -U postgres blog_appRun all migrations:
php artisan migrateRun the default seeder:
php artisan db:seedOr reset and reseed in one command:
php artisan migrate:fresh --seedSeeder behavior:
DatabaseSeedercreates a single user:test@example.com.
Start the API:
php artisan serveBecause new post notifications are queued, run a worker in another terminal:
php artisan queue:workThis API uses Laravel Sanctum personal access tokens.
- On signup/login, the server sets an
api_tokencookie. - Middleware
CookieTokenToHeaderconverts the cookie into anAuthorization: Bearer ...header when the header is missing.
For API clients (including Postman), you can:
- Use the cookie automatically, or
- Extract the token and send it as
Authorization: Bearer <token>.
Base URL (local): http://127.0.0.1:8000
POST /api/signup(JSON:name,email,password)POST /api/login(JSON:email,password)POST /api/logout(auth)GET /api/check-auth(auth)PUT /api/updateProfile(auth, multipart: optionalname,email,password,avatarfile)
GET /api/getCategories(auth)POST /api/addCategory(auth + admin, JSON:name)DELETE /api/deleteCategory(auth + admin, JSON:name)
POST /api/createPost(auth, multipart:title,content,category_id, optionalimagefile)GET /api/getPosts(auth, query: optionalcategory_id,user_id) - paginatedPUT /api/posts/{post}(auth, multipart: optionaltitle,content,category_id, optionalimagefile)DELETE /api/posts/{post}(auth)
GET /api/comments(auth, query:commentable_type,commentable_id)GET /api/comments/{comment}/replies(auth)POST /api/comments(auth, JSON:body,commentable_id,commentable_type, optionalparent_id)PUT /api/comments/{comment}(auth, JSON:body)DELETE /api/comments/{comment}(auth)
GET /api/notifications(auth)GET /api/notifications/unread(auth)PATCH /api/notifications/{id}/read(auth)PATCH /api/notifications/read-all(auth)
Category creation/deletion requires an admin user (role = 'admin').