A Laravel-based REST API for managing Schools, Managers, Admins, Teachers, Grades, Fees, Ratings, and Comments. The API uses SQLite and provides role-based access control with JWT authentication for three user types: Admin, Manager, and User.
- PHP 8.2+ with Laravel 12
- SQLite database (file at
database/database.sqlite) - JWT Authentication (
tymon/jwt-auth) with three separate guards - Form Request Validation for all inputs
- API Resource Classes for standardized JSON responses
- PHPUnit for testing
Prerequisites: PHP 8.2+, Composer installed
composer installCopy the example environment file and generate application key:
cp .env.example .env
php artisan key:generateGenerate JWT secret key:
php artisan jwt:secretThis adds JWT_SECRET to your .env file for signing authentication tokens.
The SQLite file should already exist at database/database.sqlite. If missing, create it:
touch database/database.sqliteRun migrations and seed the database:
php artisan migrate:fresh --seedThis creates all tables and adds sample data:
- 3 Schools with Managers and Admins
- 12 Grades (Grade 1-12)
- 3 Teachers
- 2 Users
- Sample Fees, Ratings, and Comments
php artisan serve --port=8001The API will be available at http://127.0.0.1:8001
Base URL: http://127.0.0.1:8001/api
The API follows a role-based access control pattern with three distinct user types:
- Authentication: phone_number + password
- Permissions: Full CRUD on Schools, Managers, Teachers; Read-only access to Success Ratings
- Login:
POST /api/admin/login
- Authentication: phone_number + password
- Permissions: Manage Grades, Fees, School-Teacher assignments, Success Ratings (scoped to their school)
- Login:
POST /api/manager/login
- Authentication: email + password
- Permissions: Create and manage their own Ratings and Comments for schools
- Registration:
POST /api/user/register - Login:
POST /api/user/login
All three user types use JWT (JSON Web Token) authentication with separate guards.
After running seeders, you can use these credentials:
Admin:
{
"phone_number": "0987654321",
"password": "password"
}Manager:
{
"phone_number": "1234567890",
"password": "password"
}User:
{
"email": "user@example.com",
"password": "password"
}- Login to your respective endpoint
- Receive JWT token in response:
{ "access_token": "eyJ0...", ... } - Include token in all subsequent requests:
Authorization: Bearer {your-token} - Logout when done:
POST /api/{role}/logout
The API manages the following entities:
-
School - Educational institutions
- Fields:
name,address,status(active|inactive),type(male|uni_gender),level(primary|secondary) - Has many: Managers, Teachers
- Fields:
-
Manager - School administrators
- Fields:
name,username,phone_number,password,schoolID - Belongs to: School
- Authentication: phone_number
- Fields:
-
Admin - System administrators
- Fields:
name,username,phone_number,password - Authentication: phone_number
- Fields:
-
Grade - Education levels (Grade 1-12)
- Fields:
name - Independent entity (no school relationship)
- Fields:
-
Teacher - Teaching staff
- Fields:
name,subject,experience - Can be assigned to schools via pivot table
- Fields:
-
User - Public users (parents/students)
- Fields:
name,email,password - Authentication: email
- Fields:
-
Fee - Tuition fees per school and grade
- Fields:
schoolID,gradeID,amount
- Fields:
-
SchoolTeacher (Pivot) - Teacher assignments to schools
- Fields:
schoolID,teacherID,gradeID,year
- Fields:
-
Rating - User ratings for schools
- Fields:
schoolID,userID,rating(enum: '1'-'5') - User can rate each school only once
- Fields:
-
Comment - User comments about schools
- Fields:
schoolID,userID,comment
- Fields:
-
SuccessRating - Academic performance metrics per school and grade
- Fields:
schoolID,gradeID,total_students,A,B,C,D
- Fields:
The API uses camelCase suffixes for foreign keys:
schoolID(not school_id)gradeID(not grade_id)teacherID(not teacher_id)userID(not user_id)
All endpoints require JWT authentication except login and registration endpoints.
Authentication:
POST /api/admin/login- Login with phone_number and passwordPOST /api/admin/logout- Logout and invalidate token
Schools:
GET /api/admin/schools- List all schoolsPOST /api/admin/schools- Create schoolGET /api/admin/schools/{id}- Get school detailsPUT /api/admin/schools/{id}- Update schoolDELETE /api/admin/schools/{id}- Delete school
Managers:
GET /api/admin/managers- List all managersPOST /api/admin/managers- Create managerGET /api/admin/managers/{id}- Get manager detailsPUT /api/admin/managers/{id}- Update managerDELETE /api/admin/managers/{id}- Delete manager
Teachers:
GET /api/admin/teachers- List all teachersPOST /api/admin/teachers- Create teacherGET /api/admin/teachers/{id}- Get teacher detailsPUT /api/admin/teachers/{id}- Update teacherDELETE /api/admin/teachers/{id}- Delete teacher
Success Ratings (Read-Only):
GET /api/admin/school-success-rate- List all success ratingsGET /api/admin/school-success-rate/{schoolId}- Get ratings for specific school
Authentication:
POST /api/manager/login- Login with phone_number and passwordPOST /api/manager/logout- Logout and invalidate token
Grades:
GET /api/manager/grades- List all gradesPOST /api/manager/grades- Create gradeGET /api/manager/grades/{id}- Get grade detailsPUT /api/manager/grades/{id}- Update gradeDELETE /api/manager/grades/{id}- Delete grade
Fees:
GET /api/manager/fees- List fees for manager's schoolPOST /api/manager/fees- Create feeGET /api/manager/fees/{id}- Get fee detailsPUT /api/manager/fees/{id}- Update feeDELETE /api/manager/fees/{id}- Delete fee
School-Teacher Assignments:
GET /api/manager/schools/{schoolId}/teachers- List teachers in schoolPOST /api/manager/schools/{schoolId}/teachers- Assign teacher to schoolPUT /api/manager/schools/{schoolId}/teachers/{teacherId}- Update assignmentDELETE /api/manager/schools/{schoolId}/teachers/{teacherId}- Remove teacher
Success Ratings:
GET /api/manager/success-ratings- List ratings for manager's schoolPOST /api/manager/success-ratings- Create success ratingGET /api/manager/success-ratings/{id}- Get rating detailsPUT /api/manager/success-ratings/{id}- Update ratingDELETE /api/manager/success-ratings/{id}- Delete rating
Authentication:
POST /api/user/register- Register new user accountPOST /api/user/login- Login with email and passwordPOST /api/user/logout- Logout and invalidate token
Ratings:
GET /api/user/ratings- List user's own ratingsPOST /api/user/ratings- Create rating for a schoolGET /api/user/ratings/{id}- Get rating detailsPUT /api/user/ratings/{id}- Update ratingDELETE /api/user/ratings/{id}- Delete rating
Comments:
GET /api/user/comments- List user's own commentsPOST /api/user/comments- Create comment for a schoolGET /api/user/comments/{id}- Get comment detailsPUT /api/user/comments/{id}- Update commentDELETE /api/user/comments/{id}- Delete comment
Request:
curl -X POST http://127.0.0.1:8001/api/admin/schools \
-H "Authorization: Bearer {admin-token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Central High School",
"address": "123 Main Street",
"status": "active",
"type": "male",
"level": "secondary"
}'Response:
{
"data": {
"id": 1,
"name": "Central High School",
"address": "123 Main Street",
"status": "active",
"type": "male",
"level": "secondary"
}
}Request:
curl -X POST http://127.0.0.1:8001/api/manager/fees \
-H "Authorization: Bearer {manager-token}" \
-H "Content-Type: application/json" \
-d '{
"gradeID": 1,
"amount": 750.00
}'Response:
{
"data": {
"id": 1,
"schoolID": 1,
"gradeID": 1,
"amount": 750.00
}
}Request:
curl -X POST http://127.0.0.1:8001/api/user/ratings \
-H "Authorization: Bearer {user-token}" \
-H "Content-Type: application/json" \
-d '{
"schoolID": 1,
"rating": "5"
}'Response:
{
"data": {
"id": 1,
"schoolID": 1,
"userID": 1,
"rating": "5"
}
}All create and update operations use Laravel Form Request classes with comprehensive validation rules:
- Required fields are enforced
- Unique constraints on phone numbers and emails
- Enum validation for status, type, level, rating fields
- Foreign key validation ensures referenced records exist
- Authorization policies ensure users can only modify their own resources
Two Postman collections are available in the postman/ directory:
File: postman/software-development-4207-updated.postman_collection.json
This collection includes:
- ✅ All 56 current API endpoints
- ✅ Correct base URL (port 8001)
- ✅ Separate folders for Admin, Manager, and User
- ✅ Auto-capture JWT tokens from login responses
- ✅ Updated field naming (schoolID, gradeID, etc.)
- ✅ Pre-configured test credentials
- ✅ Auto-capture resource IDs for request chaining
To use:
- Import
postman/software-development-4207-updated.postman_collection.jsoninto Postman - Start with authentication endpoints (Admin/Manager/User Login)
- Token will be automatically saved and used in subsequent requests
- Created resource IDs are automatically captured for testing
File: postman/software-development-4207.postman_collection.json
Contains the original structure with polymorphic relationships. Not compatible with current API.
Run the test suite:
php artisan testOr using PHPUnit directly:
vendor/bin/phpunitA comprehensive testing guide is available in API_TESTING_GUIDE.md with curl commands for all 56 endpoints.
Quick test script:
# Make the script executable
chmod +x run_tests.sh
# Run tests (requires server running on port 8001)
./run_tests.shNote: Keep the Laravel server running in a separate terminal when testing:
php artisan serve --port=8001app/
├── Http/
│ ├── Controllers/
│ │ ├── Admin/ # Admin role controllers
│ │ ├── Manager/ # Manager role controllers
│ │ └── User/ # User role controllers
│ ├── Requests/ # Form Request validation (14 classes)
│ └── Resources/ # API Resources for JSON responses
├── Models/ # Eloquent models
└── Providers/
database/
├── migrations/ # Database schema
└── seeders/ # Sample data seeders (9 seeders)
postman/
├── software-development-4207-updated.postman_collection.json # Current
routes/
└── api.php # All API routes (56 endpoints)
The project follows Laravel best practices:
- Thin Controllers: Business logic in Form Requests and Models
- Form Request Validation: All inputs validated before reaching controllers
- API Resources: Standardized JSON response format
- JWT Guards: Separate authentication contexts for each role
- Eloquent Relationships: Proper model relationships with eager loading
- Database Seeders: Reproducible test data
"JWT secret not set"
- Run:
php artisan jwt:secret - Verify
JWT_SECRETexists in.env
"No such table" errors
- Run:
php artisan migrate:fresh --seed - Verify
database/database.sqliteexists
Authentication fails with valid credentials
- Check you're using the correct login endpoint for your role:
- Admin:
/api/admin/loginwithphone_number - Manager:
/api/manager/loginwithphone_number - User:
/api/user/loginwithemail
- Admin:
"Unauthenticated" on protected endpoints
- Verify JWT token is included:
Authorization: Bearer {token} - Check token hasn't expired
- Ensure you're using the correct guard's token
Server not responding
- Confirm server is running:
php artisan serve --port=8001 - Check correct port in requests (8001, not 8000)
Validation errors
- Check field names use camelCase suffixes:
schoolID,gradeID, notschool_id,grade_id - Verify rating values are strings:
"1"to"5", not integers - Ensure all required fields are provided
Foreign key constraint errors
- Verify referenced IDs exist (schoolID, gradeID, etc.)
- Check user has permission to access the resource
- API Testing Guide: See
API_TESTING_GUIDE.mdfor detailed endpoint documentation with curl examples - Endpoint Tests: See
ENDPOINT_TESTS.mdfor block-by-block testing commands - Test Script: See
run_tests.shfor automated testing
When making changes:
- Update Form Request validation rules in
app/Http/Requests/ - Update API Resources in
app/Http/Resources/for response formatting - Follow the thin controller pattern - keep controllers simple
- Use camelCase for foreign key fields (schoolID, gradeID, etc.)
- Update tests in
tests/directory - Update this README and documentation files
MIT