organize doc files and remove unecessary files
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 47s
Tests / PHPUnit (push) Successful in 1m21s

This commit is contained in:
root
2026-09-02 23:24:43 -04:00
parent e81a1832ad
commit 8d644a2c85
43 changed files with 1 additions and 804 deletions
+9
View File
@@ -0,0 +1,9 @@
<?php
// In app/Config/Filters.php add the alias:
public array $aliases = [
'csrf' => \CodeIgniter\Filters\CSRF::class,
'toolbar' => \CodeIgniter\Filters\DebugToolbar::class,
'honeypot' => \CodeIgniter\Filters\Honeypot::class,
'authFilter' => \App\Filters\AuthFilter::class,
'apiDocsAuth' => \App\Filters\ApiDocsAuthFilter::class,
];
+296
View File
@@ -0,0 +1,296 @@
# Job Postings Feature — Implementation Plan
## 1. Overview
This feature has two sides:
- **Admin side** — create/manage job position templates, publish open positions, review applicant submissions.
- **Client side** — browse open positions, view details, and submit an application (with resume upload) that triggers a confirmation email.
---
## 2. Data Model
### JobTemplate
| Field | Type | Notes |
|---|---|---|
| `template_id` | UUID | Primary key |
| `title` | string | |
| `description` | text | |
| `department` | string | |
| `location` | string | |
| `employment_type` | string | e.g. full-time, part-time, contract |
| `requirements` | text | |
| `salary_range` | string | optional |
| `version` | int | increments on each edit |
| `is_active` | bool | soft-archive instead of delete |
| `created_by` | user ref | |
| `created_at` / `updated_at` | timestamp | |
### JobPosition
| Field | Type | Notes |
|---|---|---|
| `position_id` | UUID | **Unique ID per job, required** |
| `template_id` | UUID (nullable) | set if created from a template |
| `title`, `description`, `department`, `location`, `employment_type`, `requirements`, `salary_range` | — | copied from template at creation time (not a live reference) |
| `status` | enum | draft / open / closed / filled |
| `created_at` / `updated_at` | timestamp | |
| `posted_by` | user ref | |
### Application
| Field | Type | Notes |
|---|---|---|
| `application_id` | UUID | |
| `position_id` | FK | which job they applied to |
| `first_name`, `last_name` | string | required |
| `email` | string | required, validated |
| `phone` | string | required |
| `resume_file_url` | string | pointer to stored file |
| `submitted_at` | timestamp | |
| `status` | enum | new / reviewed / contacted / rejected / hired |
| `admin_notes` | text | for admin follow-up tracking |
---
## 3. Admin Side
### 3.1 Create Open Position
- Form fields: title, description, department, location, employment type, requirements, salary range.
- Option to start **blank** or **from a template**.
- On save: generate unique `position_id`, default status `draft` → publish sets `open`.
### 3.2 Job Templates (CRUD)
- List / create / edit / archive templates.
- **Editing behavior**: support both
- **Overwrite** current version, or
- **Save as new version** (keeps history)
- Version history viewable/revertible.
- Archiving a template never affects positions already created from it (fields are copied, not linked live).
### 3.3 Create Position from Template
- Admin selects a template → fields pre-fill a new position form → admin edits as needed → save generates a new `position_id`.
### 3.4 Review Applications
- Dashboard listing all submissions, filterable by position, status, or date.
- Detail view: applicant info, resume preview/download, position applied to.
- Status + notes fields so admin can track follow-up (contacted, rejected, hired).
- Nice-to-have: CSV export, direct email link to applicant.
---
## 4. Client Side
### 4.1 Open Positions Listing
- Public page listing all positions where `status = open`.
- Card/list view: title, department, location, short summary.
### 4.2 Position Detail Page
- Full description, requirements, etc.
- "Apply" call-to-action.
### 4.3 Application Form
- Fields: First Name, Last Name, Email, Phone, Resume upload (PDF/DOC).
- Client-side validation: required fields, email format, file type/size limits.
- Submits to create an `Application` tied to `position_id`.
### 4.4 Confirmation Email
- Sent automatically to the applicant's email on successful submission.
- References the position title and sets expectation of review/follow-up.
- Optional: parallel notification email to admin/HR inbox.
---
## 5. API Endpoints (suggested)
**Admin**
```
POST /admin/templates
PUT /admin/templates/:id
GET /admin/templates
POST /admin/positions (optional template_id)
PUT /admin/positions/:id
GET /admin/positions
GET /admin/applications (filter by position, status)
PATCH /admin/applications/:id (update status/notes)
```
**Client (public)**
```
GET /positions (open only)
GET /positions/:id
POST /positions/:id/apply (multipart form, includes resume)
```
---
## 6. Infrastructure Notes
- **File storage**: resumes go to object storage (S3 or equivalent); store the file URL/key on the Application record, not the binary in the database.
- **Email**: use a transactional email provider (SendGrid, SES, Postmark) for confirmation + admin notification emails, driven by templates.
- **Auth**: admin routes require authenticated/role-gated access; client routes remain public.
---
## 7. Database Migrations
Assumes PostgreSQL syntax (adjust types for MySQL/SQLite as needed). Each migration is additive and ordered so foreign keys resolve correctly.
### Migration 001 — create `job_templates`
```sql
-- up
CREATE TABLE job_templates (
template_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
description TEXT,
department VARCHAR(255),
location VARCHAR(255),
employment_type VARCHAR(50),
requirements TEXT,
salary_range VARCHAR(100),
version INT NOT NULL DEFAULT 1,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_job_templates_active ON job_templates (is_active);
-- down
DROP TABLE IF EXISTS job_templates;
```
### Migration 002 — create `job_template_versions` (version history)
```sql
-- up
CREATE TABLE job_template_versions (
version_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
template_id UUID NOT NULL REFERENCES job_templates(template_id) ON DELETE CASCADE,
version INT NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
department VARCHAR(255),
location VARCHAR(255),
employment_type VARCHAR(50),
requirements TEXT,
salary_range VARCHAR(100),
saved_by UUID REFERENCES users(id),
saved_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_template_versions_template_id ON job_template_versions (template_id);
-- down
DROP TABLE IF EXISTS job_template_versions;
```
### Migration 003 — create `job_positions`
```sql
-- up
CREATE TYPE position_status AS ENUM ('draft', 'open', 'closed', 'filled');
CREATE TABLE job_positions (
position_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
template_id UUID REFERENCES job_templates(template_id) ON DELETE SET NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
department VARCHAR(255),
location VARCHAR(255),
employment_type VARCHAR(50),
requirements TEXT,
salary_range VARCHAR(100),
status position_status NOT NULL DEFAULT 'draft',
posted_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_job_positions_status ON job_positions (status);
-- down
DROP TABLE IF EXISTS job_positions;
DROP TYPE IF EXISTS position_status;
```
### Migration 004 — create `applications`
```sql
-- up
CREATE TYPE application_status AS ENUM ('new', 'reviewed', 'contacted', 'rejected', 'hired');
CREATE TABLE applications (
application_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
position_id UUID NOT NULL REFERENCES job_positions(position_id) ON DELETE CASCADE,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL,
phone VARCHAR(30) NOT NULL,
resume_file_url TEXT NOT NULL,
status application_status NOT NULL DEFAULT 'new',
admin_notes TEXT,
submitted_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_applications_position_id ON applications (position_id);
CREATE INDEX idx_applications_status ON applications (status);
CREATE INDEX idx_applications_email ON applications (email);
-- down
DROP TABLE IF EXISTS applications;
DROP TYPE IF EXISTS application_status;
```
### Migration 005 — updated_at auto-touch triggers (optional, Postgres)
```sql
-- up
CREATE OR REPLACE FUNCTION set_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_job_templates_updated_at
BEFORE UPDATE ON job_templates
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
CREATE TRIGGER trg_job_positions_updated_at
BEFORE UPDATE ON job_positions
FOR EACH ROW EXECUTE FUNCTION set_updated_at();
-- down
DROP TRIGGER IF EXISTS trg_job_templates_updated_at ON job_templates;
DROP TRIGGER IF EXISTS trg_job_positions_updated_at ON job_positions;
DROP FUNCTION IF EXISTS set_updated_at();
```
### Migration order & notes
1. `job_templates` → 2. `job_template_versions` → 3. `job_positions` → 4. `applications` → 5. triggers.
2. `users` table is assumed to already exist (for `created_by` / `posted_by`); drop those FK constraints if no auth/user table exists yet.
3. Run each migration's `up` in order; `down` scripts reverse in the opposite order for rollback.
4. If using a migration tool (Knex, Prisma, Sequelize, Alembic, Rails ActiveRecord, etc.), split each numbered migration above into that tool's file format/naming convention — the SQL logic stays the same.
---
## 8. Build Phases
| Phase | Scope |
|---|---|
| 1 | Data models + admin CRUD for Positions (no templates yet) |
| 2 | Template CRUD + versioning + "create position from template" |
| 3 | Client-facing listing + detail pages |
| 4 | Application form + file upload + submission handling |
| 5 | Confirmation email + admin notification email |
| 6 | Admin review dashboard (applications list, status, notes) |
| 7 | Polish: validation, admin auth/permissions, testing |
---
## 9. Open Questions
- How is admin access authenticated/restricted (login system, roles)?
- Should duplicate applications (same email + position) be blocked or allowed?
- What resume file types/size limits are acceptable?
- Should closed positions remain visible (marked "closed") or disappear from the client list entirely?
+62
View File
@@ -0,0 +1,62 @@
<?php
// Add this group to app/Config/Routes.php
$routes->group('api/v1', ['namespace' => 'App\Controllers\Api'], static function($routes) {
// Assignments
$routes->get('assignments', 'AssignmentController::index');
$routes->post('assignments', 'AssignmentController::store');
$routes->get('assignments/(:num)', 'AssignmentController::show/$1');
$routes->put('assignments/(:num)', 'AssignmentController::update/$1');
$routes->delete('assignments/(:num)', 'AssignmentController::delete/$1');
$routes->get('assignments/student/(:num)', 'AssignmentController::student/$1');
// Attendance
$routes->get('attendance', 'AttendanceController::index');
$routes->post('attendance', 'AttendanceController::store');
$routes->get('attendance/(:num)', 'AttendanceController::show/$1');
$routes->put('attendance/(:num)', 'AttendanceController::update/$1');
$routes->delete('attendance/(:num)', 'AttendanceController::delete/$1');
$routes->get('attendance/student/(:num)', 'AttendanceController::student/$1');
// Attendance Tracking
$routes->post('attendance-tracking/record', 'AttendanceTrackingController::record');
$routes->get('attendance-tracking/violations', 'AttendanceTrackingController::violations');
$routes->get('attendance-tracking/student/(:num)', 'AttendanceTrackingController::student/$1');
// Authorized Users
$routes->get('authorized-users', 'AuthorizedUsersController::index');
$routes->post('authorized-users', 'AuthorizedUsersController::store');
$routes->get('authorized-users/(:num)', 'AuthorizedUsersController::show/$1');
$routes->delete('authorized-users/(:num)', 'AuthorizedUsersController::delete/$1');
// Broadcast Email
$routes->post('broadcast-email/send', 'BroadcastEmailController::send');
$routes->get('broadcast-email/parents', 'BroadcastEmailController::parents');
// Calendar
$routes->get('calendar', 'CalendarController::index');
$routes->post('calendar', 'CalendarController::store');
$routes->get('calendar/(:num)', 'CalendarController::show/$1');
$routes->put('calendar/(:num)', 'CalendarController::update/$1');
$routes->delete('calendar/(:num)', 'CalendarController::delete/$1');
// Classes
$routes->get('classes', 'ClassController::index');
$routes->get('classes/(:num)', 'ClassController::show/$1');
$routes->get('classes/(:num)/students', 'ClassController::students/$1');
// Class Preparation
$routes->get('class-preparation', 'ClassPreparationController::index');
$routes->get('class-preparation/(:num)', 'ClassPreparationController::show/$1');
$routes->post('class-preparation/calculate', 'ClassPreparationController::calculate');
// Communications
$routes->get('communications', 'CommunicationController::index');
$routes->post('communications/send', 'CommunicationController::send');
$routes->get('communications/conversation', 'CommunicationController::conversation');
$routes->delete('communications/(:num)', 'CommunicationController::delete/$1');
});
// API Docs routes
$routes->get('docs', 'App\Controllers\DocsController::index');
$routes->get('docs/api', 'App\Controllers\ApiDocsController::index', ['filter' => 'apiDocsAuth']);
$routes->get('docs/api/public', 'App\Controllers\ApiDocsController::public');
+94
View File
@@ -0,0 +1,94 @@
<!--
Steps for enrollment process:
Admission under review
Payment pending //we should generate invoice
Enrolled
Steps for Withdrawn:
Withdraw under review
Refund pending
After providing refund if any -> Withdrawn
add Withdraw deadline at configuration table
##########################################################################################################################
cron job command for paypal to update payment table:
*/15 * * * * /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark sync_paypal_payments >> /home/u280815660/domains/alrahmaisgl.org/alrahma/writable/logs/paypal_cron.log 2>&1
###########################################################################################################################
dX7!aPz9#LmqR2@t
curl -i -X POST https://test.alrahmaisgl.org/api/paypal-webhook \
-H "Content-Type: application/json" \
-d @payload.json
curl -i -X POST http://localhost:8080/api/paypal-webhook \
-H "Content-Type: application/json" \
-d @payload.json
get:
'balance', and 'paid_amount', from invoice table
invoice table has parent_id = user_id
webhook_id, client_id, and secret should ideally be stored in .env or config files.
################################################
<table id="myTable" class="display">
<?= $this->section('scripts') ?>
<script>
$(document).ready(function() {
$('#myTable').DataTable();
});
</script>
<?= $this->endSection() ?>
#####################################################
when the payment status=paid update the enrollment status = enrolled
refund amount at http://localhost:8080/invoice_payment/invoice_management need to be updated
need to track the refund status either refunded or not
################################################################################
#very important to add to deployment script
If the file is currently in writable/uploads/checks/, then you need to:
# From project root
ln -s writable/uploads public/uploads
Then it can be accessed via:
<?= base_url('uploads/checks/' . $refund['check_file']) ?>
##########################################################################
I want to design pages to show everything about the school:
financial report
number of students
number of teachers
number of admins
number of parents
expenses
number of tables chairs
+52
View File
@@ -0,0 +1,52 @@
# Scope Discipline Rules
These rules override any general instinct to "improve while I'm in there." Follow them on every task, no exceptions.
## Before touching any code
1. Restate the task in one sentence: what behavior must change, and what the expected outcome is.
2. Identify the smallest set of files/functions responsible for that behavior. This is your **allowed scope**. Everything else is **protected**.
3. Read the relevant code before editing it. Do not edit based on assumptions about how it probably works.
## The hard rule: ask before expanding scope
If, while working, you find that:
- a file outside your allowed scope needs to change,
- a dependency needs to be added/updated,
- a test needs modification,
- an unrelated bug is blocking you,
- or a "cleaner" implementation would touch more than the minimum,
**stop and ask me before making that change.** Explain:
- what you were trying to do,
- why the fix requires going outside the original scope,
- exactly what you want to change and where.
Wait for my answer. Do not proceed on your own judgment, even if you're confident it's correct or trivial.
This applies even to small things (renaming a variable for clarity, fixing a typo in an unrelated comment, reformatting a block you had to scroll past). If it's not required to satisfy the request, ask first.
## While editing
- Make the fewest-line, fewest-file change that correctly satisfies the request.
- Preserve existing naming, structure, patterns, and formatting. Match the codebase's existing style, don't impose your own.
- Never run project-wide formatters/linters-with-autofix/import-organizers as a side effect of a small change.
- Never touch tests except to add new ones that validate the requested behavior — and only after confirming that's in scope.
- Treat any uncommitted/staged changes already in the working tree as off-limits. Don't revert, reset, or absorb them into your edit.
## Before reporting done
Review your own diff, file by file, line by line. For anything you can't justify with "this was required by the explicit request," revert it.
Then report:
- **Files changed** — list, with a one-line reason each tied directly to the request.
- **Scope confirmation** — explicitly state: "No files, dependencies, tests, or config outside this list were modified."
- **Anything you noticed but didn't touch** — unrelated bugs, tech debt, cleanup opportunities. Mention them, don't fix them.
## If the task genuinely can't be done without expanding scope
Say so plainly, explain what would need to change and why, and wait for confirmation. Don't silently do the bigger version, and don't pretend a partial/incorrect fix is complete.
---
**Default when uncertain: don't make the change, ask instead.**
+34
View File
@@ -0,0 +1,34 @@
- Islamic Studies - Student Workbook - Level 8: **$5.00**
- Islamic Studies - Student Workbook - Level 7: **$5.00**
- Islamic Studies - Student Workbook - Level 6: **$5.00**
- Islamic Studies - Student Workbook - Level 5: **$5.00**
- Islamic Studies - Student Workbook - Level 4: **$5.00**
- Islamic Studies - Student Workbook - Level 3: **$5.00**
- Islamic Studies - Student Workbook - Level 2: **$5.00**
- Islamic Studies - Student Workbook - Level 1: **$5.00**
- Arabic Writing Workbook: **$11.00**
- Beginners Arabic Reading: **$6.00**
- Ready to Write Alif Ba Ta: **$11.00**
- Teacher's Manual - Level 8: **$20.00**
- Teacher's Manual - Level 7: **$20.00**
- Teacher's Manual - Level 6: **$20.00**
- Teacher's Manual - Level 5: **$20.00**
- Teacher's Manual - Level 4: **$20.00**
- Teacher's Manual - Level 3: **$20.00**
- Teacher's Manual - Level 2: **$20.00**
- Teacher's Manual - Level 1: **$20.00**
- Juz Tabarak: **$14.00**
- Juz Amma Workbook - Vol 2: **$8.00**
- Juz Amma Workbook - Vol 1: **$8.00**
- Juz Amma Workbook - Vol 1 (B&W version): **$4.00**
- Juz Amma for School Students: **$14.00**
- Islamic Studies Level 9 (Revised and Enlarged Edition): **$17.00**
- Islamic Studies Level 8 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 7 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 6 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 5 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 4 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 3 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 2 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level 1 (Revised & Enlarged Edition): **$17.00**
- Islamic Studies Level K (Revised & Enlarged Edition): **$17.00**
+64
View File
@@ -0,0 +1,64 @@
# Careers Section (Home Page) — Implementation Plan
## 1. Goals & Scope
- Attract candidates and showcase company culture directly from the home page
- Careers lives as a **section on the home page**, not a standalone `/careers` page
- Section should link out to a full job detail view or an ATS for the actual application step
- Decide: in-house application handling vs. linking out to an ATS (Greenhouse, Lever, Workable, etc.)
## 2. Content Structure (Home Page Section)
- **Section heading/hero** — tagline + short pitch on why to work here
- **Culture/values snippet** — a few photos or highlights, benefits teaser (health, remote work, PTO, equity, etc.)
- **Open positions preview** — short list (e.g., top 35) with title, department, location, type
- **"View all openings" CTA** — links to full listing (could be a modal, an anchor-expanded list, or an external ATS board)
- **Application CTA** — "Apply Now" per role, linking to a form, email, or ATS
- **Optional extras** — employee testimonials, office photos/video, perks grid
## 3. Data Model
Fields per job posting:
```
title
department
location
employment_type
description
requirements
salary_range (optional)
posted_date
status (open/closed)
apply_link
```
Store in a CMS (Sanity, Contentful, Strapi) or a simple JSON/database table if no CMS exists.
## 4. Technical Approach
- **Static list** — hardcode JSON if roles change rarely
- **CMS-driven** — non-technical team can add/remove postings without code
- **ATS integration** — pull live listings via API (Greenhouse/Lever both offer public job board APIs) for least maintenance
- **Application handling** — form → email service (e.g., SendGrid) or direct link to ATS application page
## 5. Pages / Routes
- `/` (home page) — Careers section embedded, e.g. `#careers` anchor for nav linking
- `/careers/[job-slug]` — individual job detail page (linked from the home section)
- `/careers/apply/[job-slug]` — application form (optional)
- Consider adding "Careers" to the main nav, scrolling/linking to the `#careers` section
## 6. Design Considerations
- Keep the section concise — it's part of the home page, not the main focus, so limit to a handful of featured/open roles
- Mobile-responsive job cards, and ensure the section doesn't overload home page load time
- Clear, prominent "View openings" / "Apply" CTAs
- SEO: `JobPosting` schema.org structured data on the linked job detail pages so roles surface in Google Jobs search
- Make sure the section is reachable via nav (e.g., "Careers" nav item scrolls to the section or links to `/#careers`)
## 7. Build Order
1. Design mockups/wireframe for the home page section (placement, hero, mini job list)
2. Set up data source (CMS or ATS API) for job postings
3. Build the home page Careers section + "view all/apply" links
4. Build job detail page(s) linked from the section
5. Wire up application flow
6. Add SEO schema markup on job detail pages
7. Test on mobile; submit a test application
8. Launch and monitor applications
## Open Questions
- What is the site built with (React/Next.js, WordPress, Webflow, plain HTML)?
- Use an existing ATS (Greenhouse/Lever) or handle applications via email/form?
+28
View File
@@ -0,0 +1,28 @@
# Set env + cd to project so Spark loads correctly
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
CI_ENVIRONMENT=production
# Sundays @ 9:50 AM — turn ON
50 9 * * 0 cd /opt/lampp/htdocs/alrahma_school_sunday && /usr/bin/php spark config:update -t enable_attendance_on --tz=America/New_York >> /var/log/ci4_config_update.log 2>&1
# Sundays @ 1:00 PM — turn OFF
0 13 * * 0 cd /opt/lampp/htdocs/alrahma_school_sunday && /usr/bin/php spark config:update -t enable_attendance_off --tz=America/New_York >> /var/log/ci4_config_update.log 2>&1
# June 1 @ 00:10 America/New_York
10 0 1 6 * cd /opt/lampp/htdocs/alrahma_school_sunday && /usr/bin/php spark config:update -t update_date_age_reference --tz=America/New_York >> /var/log/ci4_config_update.log 2>&1
# Daily @ 8:00 AM - send registration opening email only when today matches school_years.registration_starts_on
0 8 * * * cd /opt/lampp/htdocs/alrahma_school_sunday && /usr/bin/php spark registration:send-opening-email --tz=America/New_York >> /var/log/ci4_registration_opening_email.log 2>&1
*/15 * * * * /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark users:delete-inactive-users
*/15 * * * * /usr/bin/php /home/u280815660/domains/test.alrahmaisgl.org/alrahma/spark users:delete-inactive-users
0 2 * * * /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark payments:sync-paypal >> /home/u280815660/domains/alrahmaisgl.org/alrahma/writable/logs/paypal_cron.log 2>&1
50 9 * * 7 /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark config:update -t enable_attendance_on --tz=America/New_York >> /var/log/ci4_config_update.log 2>&1
0 13 * * 7 /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark config:update -t enable_attendance_off --tz=America/New_York >> /var/log/ci4_config_update.log 2>&1
0 0 1 7 * /usr/bin/php /home/u280815660/domains/alrahmaisgl.org/alrahma/spark config:update -t update_date_age_reference --tz=America/New_York >> /var/log/ci4_config_update.log 2>&1
0 2 * * * php /path/to/your/project/public/index.php notifications:cleanup >> /path/to/your/project/writable/logs/cron_cleanup.log 2>&1
+180
View File
@@ -0,0 +1,180 @@
#--------------------------------------------------------------------
# Example Environment Configuration file
#
# This file can be used as a starting point for your own
# custom .env files, and contains most of the possible settings
# available in a default install.
#
# By default, all of the settings are commented out. If you want
# to override the setting, you must un-comment it by removing the '#'
# at the beginning of the line.
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = development
# Which profile to use if none is supplied to sendEmail()
# Options: default, communication, payment, ...
MAIL_PROFILE_DEFAULT=default
# ===== DEFAULT (system) =====
# ---- Legacy fallbacks (kept for compatibility) ----
SMTP_HOST = smtp.gmail.com
SMTP_USER = alrahma.sunday.school@gmail.com
SMTP_PASS = "psnp emdq dykw ypul"
SMTP_PORT = 587
SMTP_ENCRYPTION = tls # was SSL; set to ssl to match 587
# Reply-To for all mail profiles
MAIL_DEFAULT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_DEFAULT_REPLY_TO_NAME="Al Rahma Sunday School"
MAIL_COMMUNICATION_REPLY_TO=alrahma.isgl@gmail.com
MAIL_COMMUNICATION_REPLY_TO_NAME="School Communications"
MAIL_PAYMENT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_PAYMENT_REPLY_TO_NAME="School Payments"
MAIL_DEFAULT_REPLY_TO="alrahma.isgl@gmail.com"
# Optional sender directory you already use elsewhere
MAIL_SENDERS="{\"general\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma No-Reply\"},\
\"registration\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Register Office\"},\
\"notifications\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Notifications\"},\
\"finance\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Finance Office\"}}"
# Principal notification recipient for TimeOff requests (comma-separated allowed)
PRINCIPAL_EMAIL="principal@alrahmaisgl.org"
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
# If you have trouble with `.`, you could also use `_`.
app_baseURL = 'http://localhost:8080/'
# app.forceGlobalSecureRequests = true
# app.CSPEnabled = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
database.default.hostname = 127.0.0.1
database.default.database = school
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
#--------------------------------------------------------------------
# CONTENT SECURITY POLICY
#--------------------------------------------------------------------
# contentsecuritypolicy.reportOnly = false
# contentsecuritypolicy.defaultSrc = 'none'
# contentsecuritypolicy.scriptSrc = 'self'
# contentsecuritypolicy.styleSrc = 'self'
# contentsecuritypolicy.imageSrc = 'self'
# contentsecuritypolicy.baseURI = null
# contentsecuritypolicy.childSrc = null
# contentsecuritypolicy.connectSrc = 'self'
# contentsecuritypolicy.fontSrc = null
# contentsecuritypolicy.formAction = null
# contentsecuritypolicy.frameAncestors = null
# contentsecuritypolicy.frameSrc = null
# contentsecuritypolicy.mediaSrc = null
# contentsecuritypolicy.objectSrc = null
# contentsecuritypolicy.pluginTypes = null
# contentsecuritypolicy.reportURI = null
# contentsecuritypolicy.sandbox = false
# contentsecuritypolicy.upgradeInsecureRequests = false
# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}'
# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}'
# contentsecuritypolicy.autoNonce = true
#--------------------------------------------------------------------
# COOKIE
#--------------------------------------------------------------------
# cookie.prefix = ''
# cookie.expires = 0
# cookie.path = '/'
# cookie.domain = ''
# cookie.secure = false
# cookie.httponly = false
# cookie.samesite = 'Lax'
# cookie.raw = false
#--------------------------------------------------------------------
# ENCRYPTION
#--------------------------------------------------------------------
# encryption.key =
# encryption.driver = OpenSSL
# encryption.blockSize = 16
# encryption.digest = SHA512
#--------------------------------------------------------------------
# HONEYPOT
#--------------------------------------------------------------------
# honeypot.hidden = 'true'
# honeypot.label = 'Fill This Field'
# honeypot.name = 'honeypot'
# honeypot.template = '<label>{label}</label><input type="text" name="{name}" value=""/>'
# honeypot.container = '<div style="display:none">{template}</div>'
#--------------------------------------------------------------------
# SECURITY
#--------------------------------------------------------------------
# security.csrfProtection = 'cookie'
# security.tokenRandomize = false
# security.tokenName = 'csrf_token_name'
# security.headerName = 'X-CSRF-TOKEN'
# security.cookieName = 'csrf_cookie_name'
# security.expires = 7200
# security.regenerate = true
# security.redirect = false
# security.samesite = 'Lax'
#--------------------------------------------------------------------
# SESSION
#--------------------------------------------------------------------
# session.driver = 'CodeIgniter\Session\Handlers\FileHandler'
# session.cookieName = 'ci_session'
# session.expiration = 7200
# session.savePath = null
# session.matchIP = false
# session.timeToUpdate = 300
# session.regenerateDestroy = false
#--------------------------------------------------------------------
# LOGGER
#--------------------------------------------------------------------
# logger.threshold = 4
#--------------------------------------------------------------------
# CURLRequest
#--------------------------------------------------------------------
# curlrequest.shareOptions = false
mail.protocol = smtp
mail.SMTPHost = ${SMTP_HOST}
mail.SMTPUser = ${SMTP_USER}
mail.SMTPPass = ${SMTP_PASS}
mail.SMTPPort = ${SMTP_PORT}
mail.SMTPCrypto = tls
mail.fromEmail = ${SMTP_USER}
mail.fromName = "Al Rahma Sunday School"
mail.mailType = text
mail.charset = UTF-8
+94
View File
@@ -0,0 +1,94 @@
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = development
# Which profile to use if none is supplied to sendEmail()
# Options: default, communication, payment, ...
MAIL_PROFILE_DEFAULT=default
# ===== DEFAULT (system) =====
MAIL_DEFAULT_HOST=smtp.hostinger.com
MAIL_DEFAULT_USER=no-replay@alrahmaisgl.org
MAIL_DEFAULT_PASS="W8;xZ/5g"
MAIL_DEFAULT_PORT=587
MAIL_DEFAULT_ENCRYPTION=ssl
MAIL_DEFAULT_FROM_EMAIL=no-replay@alrahmaisgl.org
MAIL_DEFAULT_FROM_NAME="Al Rahma Sunday School"
# Optional Reply-To (uncomment if you want a replyable inbox)
MAIL_DEFAULT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_DEFAULT_REPLY_TO_NAME="No-Reply"
# Optional bounce address (envelope sender)
# MAIL_DEFAULT_RETURN_PATH=bounces@alrahmaisgl.org
# Optional DKIM
# MAIL_DEFAULT_DKIM_DOMAIN=alrahmaisgl.org
# MAIL_DEFAULT_DKIM_SELECTOR=default
# MAIL_DEFAULT_DKIM_PRIVATE=/path/to/private.key
# ===== COMMUNICATION =====
MAIL_COMMUNICATION_HOST=smtp.hostinger.com
MAIL_COMMUNICATION_USER=no-replay@alrahmaisgl.org
MAIL_COMMUNICATION_PASS="W8;xZ/5g"
MAIL_COMMUNICATION_PORT=587
MAIL_COMMUNICATION_ENCRYPTION=ssl
MAIL_COMMUNICATION_FROM_EMAIL=no-replay@alrahmaisgl.org
MAIL_COMMUNICATION_FROM_NAME="School Communications"
MAIL_COMMUNICATION_REPLY_TO=alrahma.isgl@gmail.com
MAIL_COMMUNICATION_REPLY_TO_NAME="School Communications"
# MAIL_COMMUNICATION_RETURN_PATH=bounces@alrahmaisgl.org
# ===== PAYMENT =====
MAIL_PAYMENT_HOST=smtp.hostinger.com
MAIL_PAYMENT_USER=no-replay@alrahmaisgl.org
MAIL_PAYMENT_PASS="W8;xZ/5g"
MAIL_PAYMENT_PORT=587
MAIL_PAYMENT_ENCRYPTION=ssl
MAIL_PAYMENT_FROM_EMAIL=no-replay@alrahmaisgl.org
MAIL_PAYMENT_FROM_NAME="School Payments"
MAIL_PAYMENT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_PAYMENT_REPLY_TO_NAME="School Payments"
# MAIL_PAYMENT_RETURN_PATH=bounces@alrahmaisgl.org
# ---- Legacy fallbacks (kept for compatibility) ----
SMTP_HOST = smtp.hostinger.com
SMTP_USER = no-replay@alrahmaosgl.org
SMTP_PASS = "W8;xZ/5g"
SMTP_PORT = 587
SMTP_ENCRYPTION = ssl # was SSL; set to ssl to match 587
# Optional sender directory you already use elsewhere
MAIL_SENDERS="{\"general\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma No-Reply\"},\
\"registration\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Register Office\"},\
\"notifications\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Notifications\"},\
\"finance\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Finance Office\"}}"
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
app.baseURL = 'http://localhost:8080/'
app.forceGlobalSecureRequests = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
database.default.hostname = 127.0.0.1
database.default.database = school
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
#--------------------------------------------------------------------
# CODEIGNITER EMAIL (only used if you use CI Email class)
# These don't affect PHPMailer but keep them aligned anyway.
mail.protocol = smtp
mail.SMTPHost = ${SMTP_HOST}
mail.SMTPUser = ${SMTP_USER}
mail.SMTPPass = ${SMTP_PASS}
mail.SMTPPort = ${SMTP_PORT}
mail.SMTPCrypto = ssl
mail.fromEmail = ${SMTP_USER}
mail.fromName = "Al Rahma Sunday School"
mail.mailType = html
mail.charset = UTF-8
+242
View File
@@ -0,0 +1,242 @@
#--------------------------------------------------------------------
# Example Environment Configuration file
#
# This file can be used as a starting point for your own
# custom .env files, and contains most of the possible settings
# available in a default install.
#
# By default, all of the settings are commented out. If you want
# to override the setting, you must un-comment it by removing the '#'
# at the beginning of the line.
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = production
# Which profile to use if none is supplied to sendEmail()
# Options: default, communication, payment, ...
MAIL_PROFILE_DEFAULT=default
# ===== DEFAULT (system) =====
MAIL_DEFAULT_HOST=smtp.gmail.com
MAIL_DEFAULT_USER=alrahma.sunday.school@gmail.com
MAIL_DEFAULT_PASS="psnp emdq dykw ypul"
MAIL_DEFAULT_PORT=587
MAIL_DEFAULT_ENCRYPTION=tls
MAIL_DEFAULT_FROM_EMAIL=alrahma.sunday.school@gmail.com
MAIL_DEFAULT_FROM_NAME="Al Rahma Sunday School"
# Optional Reply-To (uncomment if you want a replyable inbox)
# MAIL_DEFAULT_REPLY_TO=communications@alrahmaisgl.org
MAIL_DEFAULT_REPLY_TO_NAME="No-Reply"
# Optional bounce address (envelope sender)
# MAIL_DEFAULT_RETURN_PATH=bounces@alrahmaisgl.org
# Optional DKIM
# MAIL_DEFAULT_DKIM_DOMAIN=alrahmaisgl.org
# MAIL_DEFAULT_DKIM_SELECTOR=default
# MAIL_DEFAULT_DKIM_PRIVATE=/path/to/private.key
# ===== COMMUNICATION =====
MAIL_COMMUNICATION_HOST=smtp.gmail.com
MAIL_COMMUNICATION_USER=alrahma.sunday.school@gmail.com
MAIL_COMMUNICATION_PASS="psnp emdq dykw ypul"
MAIL_COMMUNICATION_PORT=587
MAIL_COMMUNICATION_ENCRYPTION=tls
MAIL_COMMUNICATION_FROM_EMAIL=alrahma.sunday.school@gmail.com
MAIL_COMMUNICATION_FROM_NAME="School Communications"
MAIL_COMMUNICATION_REPLY_TO=alrahma.sunday.school@gmail.com
MAIL_COMMUNICATION_REPLY_TO_NAME="School Communications"
# MAIL_COMMUNICATION_RETURN_PATH=bounces@alrahmaisgl.org
# ===== PAYMENT =====
MAIL_PAYMENT_HOST=smtp.gmail.com
MAIL_PAYMENT_USER=alrahma.sunday.school@gmail.com
MAIL_PAYMENT_PASS="psnp emdq dykw ypul"
MAIL_PAYMENT_PORT=587
MAIL_PAYMENT_ENCRYPTION=tls
MAIL_PAYMENT_FROM_EMAIL=alrahma.sunday.school@gmail.com
MAIL_PAYMENT_FROM_NAME="School Payments"
# MAIL_PAYMENT_RETURN_PATH=bounces@alrahmaisgl.org
# ---- Legacy fallbacks (kept for compatibility) ----
SMTP_HOST = smtp.gmail.com
SMTP_USER = alrahma.sunday.school@gmail.com
SMTP_PASS = "psnp emdq dykw ypul"
SMTP_PORT = 587
SMTP_ENCRYPTION = tls # was SSL; set to ssl to match 587
# Reply-To for all mail profiles
MAIL_DEFAULT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_DEFAULT_REPLY_TO_NAME="Al Rahma Sunday School"
MAIL_COMMUNICATION_REPLY_TO=alrahma.isgl@gmail.com
MAIL_COMMUNICATION_REPLY_TO_NAME="School Communications"
MAIL_PAYMENT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_PAYMENT_REPLY_TO_NAME="School Payments"
# Optional sender directory you already use elsewhere
MAIL_SENDERS="{\"general\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma No-Reply\"},\
\"registration\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Register Office\"},\
\"notifications\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Notifications\"},\
\"finance\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Finance Office\"}}"
# Principal notification recipient for TimeOff requests (comma-separated allowed)
PRINCIPAL_EMAIL="principal@alrahmaisgl.org"
MAIL_PARENT_REPORT_TO="alrahma.isgl@gmail.com"
MAIL_FROM_ADDRESS = "alrahma.sunday.school@gmail.com"
session.expiration = 43200
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
# If you have trouble with `.`, you could also use `_`.
app.baseURL = 'https://test.alrahmaisgl.org/'
# app.forceGlobalSecureRequests = true
# app.CSPEnabled = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
database.default.hostname = localhost
database.default.database = u280815660_school
database.default.username = u280815660_melabidi
database.default.password = >tNxlRzP/W8
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
#--------------------------------------------------------------------
# CONTENT SECURITY POLICY
#--------------------------------------------------------------------
# contentsecuritypolicy.reportOnly = false
# contentsecuritypolicy.defaultSrc = 'none'
# contentsecuritypolicy.scriptSrc = 'self'
# contentsecuritypolicy.styleSrc = 'self'
# contentsecuritypolicy.imageSrc = 'self'
# contentsecuritypolicy.baseURI = null
# contentsecuritypolicy.childSrc = null
# contentsecuritypolicy.connectSrc = 'self'
# contentsecuritypolicy.fontSrc = null
# contentsecuritypolicy.formAction = null
# contentsecuritypolicy.frameAncestors = null
# contentsecuritypolicy.frameSrc = null
# contentsecuritypolicy.mediaSrc = null
# contentsecuritypolicy.objectSrc = null
# contentsecuritypolicy.pluginTypes = null
# contentsecuritypolicy.reportURI = null
# contentsecuritypolicy.sandbox = false
# contentsecuritypolicy.upgradeInsecureRequests = false
# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}'
# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}'
# contentsecuritypolicy.autoNonce = true
#--------------------------------------------------------------------
# COOKIE
#--------------------------------------------------------------------
# cookie.prefix = ''
# cookie.expires = 0
# cookie.path = '/'
# cookie.domain = ''
# cookie.secure = false
# cookie.httponly = false
# cookie.samesite = 'Lax'
# cookie.raw = false
#--------------------------------------------------------------------
# ENCRYPTION
#--------------------------------------------------------------------
# encryption.key =
# encryption.driver = OpenSSL
# encryption.blockSize = 16
# encryption.digest = SHA512
#--------------------------------------------------------------------
# HONEYPOT
#--------------------------------------------------------------------
# honeypot.hidden = 'true'
# honeypot.label = 'Fill This Field'
# honeypot.name = 'honeypot'
# honeypot.template = '<label>{label}</label><input type="text" name="{name}" value=""/>'
# honeypot.container = '<div style="display:none">{template}</div>'
#--------------------------------------------------------------------
# SECURITY
#--------------------------------------------------------------------
# security.csrfProtection = 'cookie'
# security.tokenRandomize = false
# security.tokenName = 'csrf_token_name'
# security.headerName = 'X-CSRF-TOKEN'
# security.cookieName = 'csrf_cookie_name'
# security.expires = 7200
# security.regenerate = true
# security.redirect = false
# security.samesite = 'Lax'
#--------------------------------------------------------------------
# SESSION
#--------------------------------------------------------------------
# session.driver = 'CodeIgniter\Session\Handlers\FileHandler'
# session.cookieName = 'ci_session'
# session.expiration = 7200
# session.savePath = null
# session.matchIP = false
# session.timeToUpdate = 300
# session.regenerateDestroy = false
#--------------------------------------------------------------------
# LOGGER
#--------------------------------------------------------------------
# logger.threshold = 4
#--------------------------------------------------------------------
# CURLRequest
#--------------------------------------------------------------------
# curlrequest.shareOptions = false
mail.protocol = smtp
mail.SMTPHost = ${SMTP_HOST}
mail.SMTPUser = ${SMTP_USER}
mail.SMTPPass = ${SMTP_PASS}
mail.SMTPPort = ${SMTP_PORT}
mail.SMTPCrypto = tls
mail.fromEmail = ${SMTP_USER}
mail.fromName = "Al Rahma Sunday School"
mail.mailType = text
mail.charset = UTF-8
# ---- Printer Mode (network, usb, windows, or disabled)
PRINTER_MODE=disabled
# ---- Network printer settings
PRINTER_HOST=192.168.1.100
PRINTER_PORT=9100
# ---- USB printer settings (used when PRINTER_MODE=usb)
PRINTER_USB_VID=0x0dd4
PRINTER_USB_PID=0x0285
PRINTER_WINDOWS_NAME="CUSTOM P3L"
# ---- Formatting
# 80mm paper ~ 48-56 characters per line
PRINTER_CHARS_PER_LINE=48
PRINTER_FEED_LINES=3
+211
View File
@@ -0,0 +1,211 @@
#--------------------------------------------------------------------
# Example Environment Configuration file
#
# This file can be used as a starting point for your own
# custom .env files, and contains most of the possible settings
# available in a default install.
#
# By default, all of the settings are commented out. If you want
# to override the setting, you must un-comment it by removing the '#'
# at the beginning of the line.
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = production
# Which profile to use if none is supplied to sendEmail()
# Options: default, communication, payment, ...
MAIL_PROFILE_DEFAULT=default
# ===== DEFAULT (system) =====
MAIL_DEFAULT_HOST=smtp.gmail.com
MAIL_DEFAULT_USER=alrahma.sunday.school@gmail.com
MAIL_DEFAULT_PASS="psnp emdq dykw ypul"
MAIL_DEFAULT_PORT=587
MAIL_DEFAULT_ENCRYPTION=tls
MAIL_DEFAULT_FROM_EMAIL=alrahma.sunday.school@gmail.com
MAIL_DEFAULT_FROM_NAME="Al Rahma Sunday School"
# Optional Reply-To (uncomment if you want a replyable inbox)
MAIL_DEFAULT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_DEFAULT_REPLY_TO_NAME="No-Reply"
# Optional bounce address (envelope sender)
# MAIL_DEFAULT_RETURN_PATH=bounces@alrahmaisgl.org
# Optional DKIM
# MAIL_DEFAULT_DKIM_DOMAIN=alrahmaisgl.org
# MAIL_DEFAULT_DKIM_SELECTOR=default
# MAIL_DEFAULT_DKIM_PRIVATE=/path/to/private.key
# ===== COMMUNICATION =====
MAIL_COMMUNICATION_HOST=smtp.gmail.com
MAIL_COMMUNICATION_USER=alrahma.sunday.school@gmail.com
MAIL_COMMUNICATION_PASS="psnp emdq dykw ypul"
MAIL_COMMUNICATION_PORT=587
MAIL_COMMUNICATION_ENCRYPTION=tls
MAIL_COMMUNICATION_FROM_EMAIL=alrahma.sunday.school@gmail.com
MAIL_COMMUNICATION_FROM_NAME="School Communications"
MAIL_COMMUNICATION_REPLY_TO=alrahma.isgl@gmail.com
MAIL_COMMUNICATION_REPLY_TO_NAME="School Communications"
# MAIL_COMMUNICATION_RETURN_PATH=bounces@alrahmaisgl.org
# ===== PAYMENT =====
MAIL_PAYMENT_HOST=smtp.gmail.com
MAIL_PAYMENT_USER=alrahma.sunday.school@gmail.com
MAIL_PAYMENT_PASS="psnp emdq dykw ypul"
MAIL_PAYMENT_PORT=587
MAIL_PAYMENT_ENCRYPTION=tls
MAIL_PAYMENT_FROM_EMAIL=alrahma.sunday.school@gmail.com
MAIL_PAYMENT_FROM_NAME="School Payments"
MAIL_PAYMENT_REPLY_TO=alrahma.isgl@gmail.com
MAIL_PAYMENT_REPLY_TO_NAME="School Payments"
# MAIL_PAYMENT_RETURN_PATH=bounces@alrahmaisgl.org
# ---- Legacy fallbacks (kept for compatibility) ----
SMTP_HOST = smtp.gmail.com
SMTP_USER = alrahma.sunday.school@gmail.com
SMTP_PASS = "psnp emdq dykw ypul"
SMTP_PORT = 587
SMTP_ENCRYPTION = tls # was SSL; set to ssl to match 587
# Optional sender directory you already use elsewhere
MAIL_SENDERS="{\"general\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma No-Reply\"},\
\"registration\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Register Office\"},\
\"notifications\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Notifications\"},\
\"finance\":{\"email\":\"alrahma.isgl@gmail.com\",\"name\":\"Al Rahma Finance Office\"}}"
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
# If you have trouble with `.`, you could also use `_`.
app.baseURL = 'https://test.alrahmaisgl.org/'
# app.forceGlobalSecureRequests = true
# app.CSPEnabled = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
database.default.hostname = localhost
database.default.database = u280815660_schooltest
database.default.username = u280815660_moulay
database.default.password = E3s6F?jn$;
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
#--------------------------------------------------------------------
# CONTENT SECURITY POLICY
#--------------------------------------------------------------------
# contentsecuritypolicy.reportOnly = false
# contentsecuritypolicy.defaultSrc = 'none'
# contentsecuritypolicy.scriptSrc = 'self'
# contentsecuritypolicy.styleSrc = 'self'
# contentsecuritypolicy.imageSrc = 'self'
# contentsecuritypolicy.baseURI = null
# contentsecuritypolicy.childSrc = null
# contentsecuritypolicy.connectSrc = 'self'
# contentsecuritypolicy.fontSrc = null
# contentsecuritypolicy.formAction = null
# contentsecuritypolicy.frameAncestors = null
# contentsecuritypolicy.frameSrc = null
# contentsecuritypolicy.mediaSrc = null
# contentsecuritypolicy.objectSrc = null
# contentsecuritypolicy.pluginTypes = null
# contentsecuritypolicy.reportURI = null
# contentsecuritypolicy.sandbox = false
# contentsecuritypolicy.upgradeInsecureRequests = false
# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}'
# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}'
# contentsecuritypolicy.autoNonce = true
#--------------------------------------------------------------------
# COOKIE
#--------------------------------------------------------------------
# cookie.prefix = ''
# cookie.expires = 0
# cookie.path = '/'
# cookie.domain = ''
# cookie.secure = false
# cookie.httponly = false
# cookie.samesite = 'Lax'
# cookie.raw = false
#--------------------------------------------------------------------
# ENCRYPTION
#--------------------------------------------------------------------
# encryption.key =
# encryption.driver = OpenSSL
# encryption.blockSize = 16
# encryption.digest = SHA512
#--------------------------------------------------------------------
# HONEYPOT
#--------------------------------------------------------------------
# honeypot.hidden = 'true'
# honeypot.label = 'Fill This Field'
# honeypot.name = 'honeypot'
# honeypot.template = '<label>{label}</label><input type="text" name="{name}" value=""/>'
# honeypot.container = '<div style="display:none">{template}</div>'
#--------------------------------------------------------------------
# SECURITY
#--------------------------------------------------------------------
# security.csrfProtection = 'cookie'
# security.tokenRandomize = false
# security.tokenName = 'csrf_token_name'
# security.headerName = 'X-CSRF-TOKEN'
# security.cookieName = 'csrf_cookie_name'
# security.expires = 7200
# security.regenerate = true
# security.redirect = false
# security.samesite = 'Lax'
#--------------------------------------------------------------------
# SESSION
#--------------------------------------------------------------------
# session.driver = 'CodeIgniter\Session\Handlers\FileHandler'
# session.cookieName = 'ci_session'
# session.expiration = 7200
# session.savePath = null
# session.matchIP = false
# session.timeToUpdate = 300
# session.regenerateDestroy = false
#--------------------------------------------------------------------
# LOGGER
#--------------------------------------------------------------------
# logger.threshold = 4
#--------------------------------------------------------------------
# CURLRequest
#--------------------------------------------------------------------
# curlrequest.shareOptions = false
mail.protocol = smtp
mail.SMTPHost = ${SMTP_HOST}
mail.SMTPUser = ${SMTP_USER}
mail.SMTPPass = ${SMTP_PASS}
mail.SMTPPort = ${SMTP_PORT}
mail.SMTPCrypto = tls
mail.fromEmail = ${SMTP_USER}
mail.fromName = "Al Rahma Sunday School"
mail.mailType = text
mail.charset = UTF-8
+190
View File
@@ -0,0 +1,190 @@
#--------------------------------------------------------------------
# Example Environment Configuration file
#
# This file can be used as a starting point for your own
# custom .env files, and contains most of the possible settings
# available in a default install.
#
# By default, all of the settings are commented out. If you want
# to override the setting, you must un-comment it by removing the '#'
# at the beginning of the line.
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
CI_ENVIRONMENT = development
# Which profile to use if none is supplied to sendEmail()
# Options: default, communication, payment, ...
MAIL_PROFILE_DEFAULT=default
# ===== DEFAULT (system) =====
# ---- Legacy fallbacks (kept for compatibility) ----
SMTP_HOST = smtp.gmail.com
SMTP_USER = alrahma.sunday.school@gmail.com
SMTP_PASS = "psnp emdq dykw ypul"
SMTP_PORT = 587
SMTP_ENCRYPTION = tls # was SSL; set to ssl to match 587
# Optional sender directory you already use elsewhere
MAIL_SENDERS="{\"general\":{\"email\":\"alrahma.sunday.school@gmail.com\",\"name\":\"Al Rahma No-Reply\"},\
\"registration\":{\"email\":\"alrahma.sunday.school@gmail.com\",\"name\":\"Al Rahma Register Office\"},\
\"notifications\":{\"email\":\"alrahma.sunday.school@gmail.com\",\"name\":\"Al Rahma Notifications\"},\
\"finance\":{\"email\":\"alrahma.sunday.school@gmail.com\",\"name\":\"Al Rahma Finance Office\"}}"
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
# If you have trouble with `.`, you could also use `_`.
app_baseURL = 'http://localhost:8080/'
# app.forceGlobalSecureRequests = true
# app.CSPEnabled = false
#--------------------------------------------------------------------
# DATABASE
#--------------------------------------------------------------------
database.default.hostname = 127.0.0.1
database.default.database = school
database.default.username = root
database.default.password =
database.default.DBDriver = MySQLi
database.default.DBPrefix =
database.default.port = 3306
database.default.DBDebug = true
database.default.charset = utf8mb4
database.default.DBCollat = utf8mb4_unicode_ci # or utf8mb4_general_ci, or on MySQL 8: utf8mb4_0900_ai_ci
#--------------------------------------------------------------------
# CONTENT SECURITY POLICY
#--------------------------------------------------------------------
# contentsecuritypolicy.reportOnly = false
# contentsecuritypolicy.defaultSrc = 'none'
# contentsecuritypolicy.scriptSrc = 'self'
# contentsecuritypolicy.styleSrc = 'self'
# contentsecuritypolicy.imageSrc = 'self'
# contentsecuritypolicy.baseURI = null
# contentsecuritypolicy.childSrc = null
# contentsecuritypolicy.connectSrc = 'self'
# contentsecuritypolicy.fontSrc = null
# contentsecuritypolicy.formAction = null
# contentsecuritypolicy.frameAncestors = null
# contentsecuritypolicy.frameSrc = null
# contentsecuritypolicy.mediaSrc = null
# contentsecuritypolicy.objectSrc = null
# contentsecuritypolicy.pluginTypes = null
# contentsecuritypolicy.reportURI = null
# contentsecuritypolicy.sandbox = false
# contentsecuritypolicy.upgradeInsecureRequests = false
# contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}'
# contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}'
# contentsecuritypolicy.autoNonce = true
#--------------------------------------------------------------------
# COOKIE
#--------------------------------------------------------------------
# cookie.prefix = ''
# cookie.expires = 0
# cookie.path = '/'
# cookie.domain = ''
# cookie.secure = false
# cookie.httponly = false
# cookie.samesite = 'Lax'
# cookie.raw = false
#--------------------------------------------------------------------
# ENCRYPTION
#--------------------------------------------------------------------
# encryption.key =
# encryption.driver = OpenSSL
# encryption.blockSize = 16
# encryption.digest = SHA512
#--------------------------------------------------------------------
# HONEYPOT
#--------------------------------------------------------------------
# honeypot.hidden = 'true'
# honeypot.label = 'Fill This Field'
# honeypot.name = 'honeypot'
# honeypot.template = '<label>{label}</label><input type="text" name="{name}" value=""/>'
# honeypot.container = '<div style="display:none">{template}</div>'
#--------------------------------------------------------------------
# SECURITY
#--------------------------------------------------------------------
# security.csrfProtection = 'cookie'
# security.tokenRandomize = false
# security.tokenName = 'csrf_token_name'
# security.headerName = 'X-CSRF-TOKEN'
# security.cookieName = 'csrf_cookie_name'
# security.expires = 7200
# security.regenerate = true
# security.redirect = false
# security.samesite = 'Lax'
#--------------------------------------------------------------------
# SESSION
#--------------------------------------------------------------------
# session.driver = 'CodeIgniter\Session\Handlers\FileHandler'
# session.cookieName = 'ci_session'
# session.expiration = 7200
# session.savePath = null
# session.matchIP = false
# session.timeToUpdate = 300
# session.regenerateDestroy = false
#--------------------------------------------------------------------
# LOGGER
#--------------------------------------------------------------------
# logger.threshold = 4
#--------------------------------------------------------------------
# CURLRequest
#--------------------------------------------------------------------
# curlrequest.shareOptions = false
mail.protocol = smtp
mail.SMTPHost = ${SMTP_HOST}
mail.SMTPUser = ${SMTP_USER}
mail.SMTPPass = ${SMTP_PASS}
mail.SMTPPort = ${SMTP_PORT}
mail.SMTPCrypto = tls
mail.fromEmail = ${SMTP_USER}
mail.fromName = "Al Rahma Sunday School"
mail.mailType = text
mail.charset = UTF-8
# ---- Printer Mode (network or usb)
PRINTER_MODE=network
# ---- Network printer settings
PRINTER_HOST=192.168.1.100
PRINTER_PORT=9100
# ---- USB printer settings (used when PRINTER_MODE=usb)
PRINTER_USB_VID=0x0dd4
PRINTER_USB_PID=0x0285
PRINTER_WINDOWS_NAME="Custom Engineering SPA Receipt"
# ---- Formatting
# 80mm paper ~ 48-56 characters per line
PRINTER_CHARS_PER_LINE=48
PRINTER_FEED_LINES=3
+128
View File
@@ -0,0 +1,128 @@
<?php
// Configuration
$sqlFile = __DIR__ . '/schema.sql';
$migrationPath = __DIR__ . '/app/Database/Migrations/';
if (!file_exists($sqlFile)) {
die("❌ SQL file not found at $sqlFile\n");
}
$sql = file_get_contents($sqlFile);
// Match CREATE TABLE statements
preg_match_all('/CREATE TABLE\s+(?:IF NOT EXISTS\s+)?`?(\w+)`?\s*\((.*?)\)\s*(?:ENGINE|CHARSET|;)/is', $sql, $matches, PREG_SET_ORDER);
echo "Found " . count($matches) . " table(s).\n";
foreach ($matches as $match) {
$tableName = $match[1];
$columnsSql = trim($match[2]);
$className = 'Create' . ucfirst(camelCase($tableName)) . 'Table';
$timestamp = date('YmdHis');
$filename = $timestamp . '_create_' . strtolower($tableName) . '_table.php';
sleep(1); // Avoid filename collisions
$columnsArray = parseColumns($columnsSql);
$fieldDefs = array_map(
fn($name, $def) => is_numeric($name)
? " $def,"
: " '$name' => $def,",
array_keys($columnsArray),
$columnsArray
);
$fieldDefsText = implode("\n", $fieldDefs);
$migrationContent = <<<PHP
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class $className extends Migration
{
public function up()
{
\$this->forge->addField([
$fieldDefsText
]);
\$this->forge->addKey('id', true); // Adjust if needed
\$this->forge->createTable('$tableName');
}
public function down()
{
\$this->forge->dropTable('$tableName');
}
}
PHP;
file_put_contents($migrationPath . $filename, $migrationContent);
echo "✅ Created migration for `$tableName`: $filename\n";
}
function parseColumns(string $columnsSql): array
{
$lines = preg_split('/,\n|\n/', $columnsSql);
$result = [];
foreach ($lines as $line) {
$line = trim($line);
// Skip keys, constraints
if (preg_match('/^(PRIMARY|UNIQUE|KEY|CONSTRAINT|FOREIGN)/i', $line)) {
continue;
}
// Handle ENUM as raw SQL
if (preg_match("/^`(\w+)`\s+enum\((.*?)\)(.*)/i", $line, $enumMatch)) {
$name = $enumMatch[1];
$values = $enumMatch[2];
$rest = $enumMatch[3];
// Wrap the whole ENUM in double quotes, and escape single quotes
$enumSQL = '"' . "$name ENUM($values)$rest" . '"';
$enumSQL = str_replace("`", "", $enumSQL);
$result[] = $enumSQL;
continue;
}
if (preg_match('/^`(\w+)`\s+([a-zA-Z]+)(\(([^)]+)\))?/i', $line, $col)) {
$field = $col[1];
$type = strtoupper($col[2]);
$length = $col[4] ?? null;
$definition = [];
$definition[] = "'type' => '$type'";
if ($length && !in_array($type, ['TEXT', 'DATE', 'DATETIME', 'TIMESTAMP'])) {
$definition[] = "'constraint' => $length";
}
$definition[] = stripos($line, 'NOT NULL') !== false ? "'null' => false" : "'null' => true";
if (stripos($line, 'AUTO_INCREMENT') !== false) {
$definition[] = "'auto_increment' => true";
}
if (preg_match('/DEFAULT\s+([^\s,]+)/i', $line, $defMatch)) {
$default = trim($defMatch[1], "'\"");
if (strtoupper($default) !== 'NULL') {
$definition[] = "'default' => '$default'";
}
}
$result[$field] = '[' . implode(', ', $definition) . ']';
}
}
return $result;
}
function camelCase(string $str): string
{
return str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $str)));
}
+53
View File
@@ -0,0 +1,53 @@
# Disable directory browsing
Options -Indexes
# ----------------------------------------------------------------------
# Rewrite engine
# ----------------------------------------------------------------------
# Turning on the rewrite engine is necessary for the following rules and features.
# FollowSymLinks must be enabled for this to work.
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
# If you installed CodeIgniter in a subfolder, you will need to
# change the following line to match the subfolder you need.
# http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
#RewriteBase /alrahma/
# Redirect Trailing Slashes...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Rewrite "www.example.com" and "https://test.alrahmaisgl.org" to "https://example.com"
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
# Masking URL: Redirect all requests to a specific page while keeping the URL visible in the address bar
# Example: Mask the actual URL path and display "/masked-url" in the address bar
RewriteRule ^masked-url$ /actual-path/to/page.php [L]
# Checks to see if the user is attempting to access a valid file,
# such as an image or CSS document; if this isn't true it sends the
# request to the front controller, index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
# Ensure Authorization header is passed along
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>
<IfModule !mod_rewrite.c>
# If we don't have mod_rewrite installed, all 404's
# can be sent to index.php, and everything works as normal.
ErrorDocument 404 index.php
</IfModule>
# Disable server signature start
ServerSignature Off
# Disable server signature end
+254
View File
@@ -0,0 +1,254 @@
Grade,Unit,Unit Title,chapter
1,1,Aqaid: Our Belief,1. Allah: Our Creator
1,1,Aqaid: Our Belief,2. Islam
1,1,Aqaid: Our Belief,3. Our Faith
1,1,Aqaid: Our Belief,4. Nabi Muhammad (s)
1,1,Aqaid: Our Belief,5. The Quran
1,2,Knowing Allah,6. Allah Loves Us
1,2,Knowing Allah,7. Remembering Allah
1,2,Knowing Allah,8. Allah Rewards Us
1,3,Our Ibadat,9. Five Pillars of Islam
1,3,Our Ibadat,10. Shahadah: The First Pillar
1,3,Our Ibadat,11. Salat: The Second Pillar
1,3,Our Ibadat,12. Zakat: The Third Pillar
1,3,Our Ibadat,13. Fasting: The Fourth Pillar
1,3,Our Ibadat,14. Hajj: The Fifth Pillar
1,4,Messengers of Allah,15. Adam (A): The First Nabi
1,4,Messengers of Allah,16. Nuh (A): Saved From the Great Flood
1,4,Messengers of Allah,17. Ibrahim (A): Never Listen to Shaitan
1,4,Messengers of Allah,18. Musa (A): Challenging a Bad Ruler
1,4,Messengers of Allah,19. Isa (A): A Great Nabi of Allah
1,5,Other Basics of Islam,20. Angels: They Always Work for Allah
1,5,Other Basics of Islam,21. Shaitan: Our Enemy
1,5,Other Basics of Islam,22. Makkah and Madinah
1,5,Other Basics of Islam,23. Eid: Two Festivals
1,6,Akhlaq and Adab in Islam,24. Good Manners
1,6,Akhlaq and Adab in Islam,25. Kindness and Sharing
1,6,Akhlaq and Adab in Islam,26. Respect
1,6,Akhlaq and Adab in Islam,27. Forgiveness
1,6,Akhlaq and Adab in Islam,28. Thanking Allah
2,1,The Creator and His Message,1. Allah: Our Creator
2,1,The Creator and His Message,2. How Does Allah Create?
2,1,The Creator and His Message,3. What Does Allah Do?
2,1,The Creator and His Message,4, Allah: What Does He Not Do
2,1,The Creator and His Message,5. The Quran
2,1,The Creator and His Message,6. Hadith and Sunnah
2,2,Our Ibadat,7. Shahadah: The First Pillar
2,2,Our Ibadat,8. Salat: The Second Pillar
2,2,Our Ibadat,9. Zakah: The Third Pillar
2,2,Our Ibadat,10. Sawm: The Fourth Pillar
2,2,Our Ibadat,11. Hajj: The Fifth Pillar
2,2,Our Ibadat,12. Wudu: Cleaning Before Salat
2,3,The Messengers of Allah,13. Ibrahim (A): A Friend of Allah
2,3,The Messengers of Allah,14. Yaqub (A) and Yusuf (A)
2,3,The Messengers of Allah,15. Musa (A) and Harun (A)
2,3,The Messengers of Allah,16. Yunus (A)
2,3,The Messengers of Allah,17. Nabi Muhammad ﷺ
2,4,Learning About Islam,18. Obey Allah, Obey Rasul ﷺ
2,4,Learning About Islam,19. Day of Judgment
2,4,Learning About Islam,20. Our Masjid
2,4,Learning About Islam,21. Islamic Phrases
2,4,Learning About Islam,22. Food that We May Eat
2,5,Akhlaq and Adab in Islam,23. Truthfulness
2,5,Akhlaq and Adab in Islam,24. Kindness
2,5,Akhlaq and Adab in Islam,25. Respect
2,5,Akhlaq and Adab in Islam,26. Responsibility
2,5,Akhlaq and Adab in Islam,27. Obedience
2,5,Akhlaq and Adab in Islam,28. Cleanliness
2,5,Akhlaq and Adab in Islam,29. Honesty
3,1,Knowing About Allāh ﷺ,1. Who Is Allāh ﷺ?
3,1,Knowing About Allāh ﷺ,2. What Allāh ﷺ Is and Is Not
3,1,Knowing About Allāh ﷺ,3. Allāh ﷺ: The Most-Merciful, Most-Rewarding
3,1,Knowing About Allāh ﷺ,4. Allāh ﷺ: The Best Judge
3,1,Knowing About Allāh ﷺ,5. What Does Allāh ﷺ Want Us to Do?
3,2,Teachings of Islam,6. We Are Muslims: We Have ‘Īmān
3,2,Teachings of Islam,7. Belief in the Qur’ān
3,2,Teachings of Islam,8. Belief in the Messengers
3,2,Teachings of Islam,9. Hadīth and Sunnah
3,2,Teachings of Islam,10. Jinn
3,2,Teachings of Islam,11. Muslims in North America
3,2,Teachings of Islam,12. The Straight Path: The Right Path
3,3,Nabi Muhammad ﷺ,13. Kindness of Rasūlullāh ﷺ
3,3,Nabi Muhammad ﷺ,14. How Rasūlullāh ﷺ Treated Others
3,3,Nabi Muhammad ﷺ,15. Our Relationship With Rasūlullāh ﷺ
3,4,Messengers of Allāh ﷺ,16. Ismā‘īl (A) and Ishāq (A): Nabi of Allāh ﷺ
3,4,Messengers of Allāh ﷺ,17. Shuaib (A): A Nabi of Allāh ﷺ
3,4,Messengers of Allāh ﷺ,18. Dāwūd (A): A Nabi of Allāh ﷺ
3,4,Messengers of Allāh ﷺ,19. ‘Īsā (A): A Nabi of Allāh ﷺ
3,5,Learning About Islam,20. The Kabah
3,5,Learning About Islam,21. Masjid an-Nabawī: The Nabis Masjid
3,5,Learning About Islam,22. Bilāl ibn Rabāh
3,5,Learning About Islam,23. Zaid ibn Hārithah
3,6,Akhlaq and Adab in Islam,24. Ways To Be a Good Person
3,6,Akhlaq and Adab in Islam,25. Kindness: A Virtue of the Believers
3,6,Akhlaq and Adab in Islam,26. Forgiveness: A Quality of the Believers
3,6,Akhlaq and Adab in Islam,27. Good Deeds: A Duty of the Believers
3,6,Akhlaq and Adab in Islam,28. Perseverance: Never Give Up
3,6,Akhlaq and Adab in Islam,29. Punctuality: Doing Things on Time
4,1,Knowing the Creator,1. Rewards of Allah: Everybody Receives Them
4,1,Knowing the Creator,1. Discipline of Allah: Because He Loves Us
4,1,Knowing the Creator,3. Names of Allah
4,1,Knowing the Creator,4. Books of Allah
4,2,How Islam Changed Arabia,5. Pre-Islamic Arabia: Age of Ignorance
4,2,How Islam Changed Arabia,6. The Year of the Elephant
4,2,How Islam Changed Arabia,7. Early Life of Muhammad ﷺ
4,2,How Islam Changed Arabia,8. Life Before Becoming a Nabi
4,2,How Islam Changed Arabia,9. First Revelation
4,2,How Islam Changed Arabia,10. Makkah Period: The Early Years of the Muslims
4,2,How Islam Changed Arabia,11. Hijrat to Madinah: The Migration that Shaped History
4,2,How Islam Changed Arabia,12. Madinah Period: Islam Prospers
4,3,The Rightly Guided Khalifah,13. Abū Bakr (R): The First Khalifah
4,3,The Rightly Guided Khalifah,14. Umar al-Khaṭṭāb (R): The Second Khalifah
4,3,The Rightly Guided Khalifah,15. Uthman Ibn Affān (R): The Third Khalifah
4,3,The Rightly Guided Khalifah,16. Ali Ibn Abu Ṭālib (R): The Fourth Khalifah
4,4,Messengers of Allah,17. Hūd (A): Struggle to Guide Mankind
4,4,Messengers of Allah,18. Ṣāliḥ (A): Struggle to Guide the Misguided
4,4,Messengers of Allah,19. Mūsā (A): His Life and Achievements
4,4,Messengers of Allah,20. Sulaimān (A): A King and a Servant of Allah ﷺ
4,5,Fiqh of Salat,21. Preparation for Salat
4,5,Fiqh of Salat,22. The Requirements of Salat
4,5,Fiqh of Salat,23. Mubṭilāt-us-Salāt: Things that Invalidate Salāt
4,5,Fiqh of Salat,24. How to Pray Behind an Imām
4,6,General Islamic Topics,25. Compilers of Hadīth
4,6,General Islamic Topics,26. Shaitans Mode of Operation
4,6,General Islamic Topics,27. Day of Judgment: The Day of Ultimate Justice
4,6,General Islamic Topics,28. Eid: Significance of the Festivities
4,6,General Islamic Topics,29. Truthfulness: An Important Quality for Muslims
4,6,General Islamic Topics,30. Perseverance: Keep on Trying
5,1,The Creator,1. His Message, and His Messengers,Tawhid, Kafir, Kufr, Shirk, Nifaq
5,1,The Creator,2. His Message, and His Messengers,Why Should We Worship Allah?
5,1,The Creator,3. His Message, and His Messengers,The Revelation of the Quran
5,1,The Creator,4. His Message, and His Messengers,Characteristics of the Messengers
5,2,The Battles and Other Developments,5. Pledges of Aqabah: Invitation to Migrate
5,2,The Battles and Other Developments,6. The Battle of Badr: Allah Supports the Righteous
5,2,The Battles and Other Developments,7. The Battle of Uhud: Obey Allah and Obey the Rasul ﷺ
5,2,The Battles and Other Developments,8. The Battle of the Trench: A Bloodless Battle
5,2,The Battles and Other Developments,9. The Treaty of Hudaibiyah: A Clear Victory
5,2,The Battles and Other Developments,10. Liberation of Makkah: A Bloodless Victory
5,3,Stories of the Messengers of Allah,11. Adam (A): The Creation of Human Beings
5,3,Stories of the Messengers of Allah,12. Ibrahim (A): His Debate with the Polytheists
5,3,Stories of the Messengers of Allah,13. Ibrahim (A): His Plan Against the Idols
5,3,Stories of the Messengers of Allah,14. Luqmān (A): A Wise Mans Lifelong Advice
5,3,Stories of the Messengers of Allah,15. Yūsuf (A): His Childhood and Life in Azizs Home
5,3,Stories of the Messengers of Allah,16. Yūsuf (A): Standing Up for Righteousness
5,3,Stories of the Messengers of Allah,17. Yūsuf (A): A Childhood Dream Comes True
5,4,Islam in The World,20. Major Masājid in the World
5,5,Islamic Values and Teachings,21. Upholding Truth: A Duty of All Believers
5,5,Islamic Values and Teachings,22. Responsibility and Punctuality
5,5,Islamic Values and Teachings,23. My Mind, My Body: The Body is a Mirror of the Mind
5,5,Islamic Values and Teachings,24. Kindness and Forgiveness
5,5,Islamic Values and Teachings,25. The Middle Path: Ways to Avoid the Two Extremes
5,5,Islamic Values and Teachings,26. Salat: Its Significance
5,5,Islamic Values and Teachings,27. Sawm: Its Significance
5,5,Islamic Values and Teachings,28. Zakat and Sadaqah: Similarities and Differences
6,1,The Creator,1. His Message, and His Messengers,Tawhid, Kafir, Kufr, Shirk, Nifaq
6,1,The Creator,2. His Message, and His Messengers,Why Should We Worship Allah?
6,1,The Creator,3. His Message, and His Messengers,The Revelation of the Quran
6,1,The Creator,4. His Message, and His Messengers,Characteristics of the Messengers
6,2,The Battles and Other Developments,5. Pledges of Aqabah: Invitation to Migrate
6,2,The Battles and Other Developments,6. The Battle of Badr: Allah Supports the Righteous
6,2,The Battles and Other Developments,7. The Battle of Uhud: Obey Allah and Obey the Rasul ﷺ
6,2,The Battles and Other Developments,8. The Battle of the Trench: A Bloodless Battle
6,2,The Battles and Other Developments,9. The Treaty of Hudaibiyah: A Clear Victory
6,2,The Battles and Other Developments,10. Liberation of Makkah: A Bloodless Victory
6,3,Stories of the Messengers of Allah,11. Adam (A): The Creation of Human Beings
6,3,Stories of the Messengers of Allah,12. Ibrahim (A): His Debate with the Polytheists
6,3,Stories of the Messengers of Allah,13. Ibrahim (A): His Plan Against the Idols
6,3,Stories of the Messengers of Allah,14. Luqmān (A): A Wise Mans Lifelong Advice
6,3,Stories of the Messengers of Allah,15. Yūsuf (A): His Childhood and Life in Azizs Home
6,3,Stories of the Messengers of Allah,16. Yūsuf (A): Standing Up for Righteousness
6,3,Stories of the Messengers of Allah,17. Yūsuf (A): A Childhood Dream Comes True
6,4,Islam in The World,20. Major Masājid in the World
6,5,Islamic Values and Teachings,21. Upholding Truth: A Duty of All Believers
6,5,Islamic Values and Teachings,22. Responsibility and Punctuality
6,5,Islamic Values and Teachings,23. My Mind, My Body: The Body is a Mirror of the Mind
6,5,Islamic Values and Teachings,24. Kindness and Forgiveness
6,5,Islamic Values and Teachings,25. The Middle Path: Ways to Avoid the Two Extremes
6,5,Islamic Values and Teachings,26. Salat: Its Significance
6,5,Islamic Values and Teachings,27. Sawm: Its Significance
6,5,Islamic Values and Teachings,28. Zakat and Sadaqah: Similarities and Differences
7,1,The Creator,1. Why Islam? What is Islam?
7,1,The Creator,2. Belief in Allah
7,1,The Creator,3. The Quran: Its Qualitative Names
7,1,The Creator,4. Istighfār: Seeking Forgiveness and Protection
7,1,The Creator,5. Allah: Angry or Kind?
7,2,Stories of the Messengers,6. Ādam (A): The Trial of the First Messenger
7,2,Stories of the Messengers,7. The Life of Ibrāhīm (A): Beginning a Nation
7,2,Stories of the Messengers,8. The Sacrifice of Ibrāhīm (A)
7,2,Stories of the Messengers,9. Lūt (A): A Message for Modern Societies
7,2,Stories of the Messengers,10. Yūsuf (A): The Will to Overcome Temptation
7,3,Stories from the Quran,11. The Companions of the Cave
7,3,Stories from the Quran,12. Dhu al-Qarnain: The Journey of a King
7,3,Stories from the Quran,13. Effective Debate and Negotiation Styles in the Quran
7,4,Two Companions Who Shaped Islam,14. Abū Sufyān: His Life and Achievements
7,4,Two Companions Who Shaped Islam,15. Khālid Ibn al-Walīd: The “Sword of Allah”
7,5,Knowledge Enrichment,16. Character of the Messengers
7,5,Knowledge Enrichment,17. Rasūlullāhs Marriages
7,5,Knowledge Enrichment,18. Lailatul Qadr: The Night of Majesty
7,5,Knowledge Enrichment,19. Fasting During Ramadan: The Month of Benefits
7,5,Knowledge Enrichment,20. My Family is Muslim Now
7,5,Knowledge Enrichment,21. Science in the Quran
7,5,Knowledge Enrichment,22. Lessons From Past Civilizations
7,6,Akhlaq and Adab in Islam,23. Amr Bil Marūf: Enjoin Good Deeds
7,6,Akhlaq and Adab in Islam,24. Guard Your Tongue: Think Before You Speak
7,6,Akhlaq and Adab in Islam,25. Islamic Greeting: Wishing Peace
7,6,Akhlaq and Adab in Islam,26. How to Achieve Success
7,6,Akhlaq and Adab in Islam,27. Permitted and Prohibited
7,6,Akhlaq and Adab in Islam,28. Types of Behavior Allah Loves
8,1,Knowing the Creator,1. Divine Names
8,1,Knowing the Creator,2. Sunan of Allah
8,1,Knowing the Creator,3. Objectives of the Quran
8,1,Knowing the Creator,4. Lessons from Sūrah al-Hujurāt
8,1,Knowing the Creator,5. True Piety: A Synthesis of Belief, Practice, and Conduct
8,1,Knowing the Creator,6. Āyatul Kursi: The Throne Verse
8,2,Knowing the Messenger ﷺ,7. The Person Muhammad ﷺ
8,2,Knowing the Messenger ﷺ,8. Farewell Pilgrimage
8,2,Knowing the Messenger ﷺ,9. Finality of Prophethood
8,2,Knowing the Messenger ﷺ,10. Hadith: Collection and Classification
8,3,Challenges in Madinah,11. Hypocrites
8,3,Challenges in Madinah,12. Banu Qaynuqa: Threat Within Madinah
8,3,Challenges in Madinah,13. Banu Nadir: Treachery Within Madinah
8,3,Challenges in Madinah,14. Banu Qurayzah
8,3,Challenges in Madinah,15. Mission to Tabūk: A Test of Steadfastness
8,4,Islamic Ethical Framework,16. Friends and Friendship: Who is a Good Friend?
8,4,Islamic Ethical Framework,17. Friendship With Non-Muslims
8,4,Islamic Ethical Framework,18. Dating: How Islam Views the Practice
8,4,Islamic Ethical Framework,19. Hold Firmly the Rope of Allah
8,4,Islamic Ethical Framework,20. Elements of a Bad Life
8,5,Islamic Values and Teachings,21. Duties Towards Parents
8,5,Islamic Values and Teachings,22. Hope, Hopefulness, Hopelessness
8,5,Islamic Values and Teachings,23. Trials in Life: Everyone Will Experience Them
8,5,Islamic Values and Teachings,24. Permitted and Prohibited Food
8,5,Islamic Values and Teachings,25. Performance of Hajj
8,5,Islamic Values and Teachings,26. Parables in the Quran
8,6,Islam After the Messenger ﷺ,27. Early History of Shiah Muslims
8,6,Islam After the Messenger ﷺ,28. Umayyad Dynasty
8,6,Islam After the Messenger ﷺ,29. Abbasid Dynasty
9,1,A Reflection on the Divine,1. Signs of Allahﷻ in Nature
9,1,A Reflection on the Divine,2. Pondering the Quran
9,1,A Reflection on the Divine,3. Preservation and Compilation of the Quran
9,1,A Reflection on the Divine,4. Ibadat—Easy Ways to Do It
9,1,A Reflection on the Divine,5. Surah Baqarah—Statement of Faith and Commitment
9,2,Islam and Muslim,6. Why Human Beings Are Superior
9,2,Islam and Muslim,7. Life Cycle of Truth
9,2,Islam and Muslim,8. Is Islam a Violent Religion?
9,2,Islam and Muslim,9. Present Life: Vanity, Deception, Play
9,2,Islam and Muslim,10. Shariah
9,2,Islam and Muslim,11. Justice in Islam
9,3,Ethical Standard in Islam,12. Choices We Make
9,3,Ethical Standard in Islam,13. Peer Pressure
9,3,Ethical Standard in Islam,14. Islamic Perspective on Dating
9,3,Ethical Standard in Islam,15. Indecency
9,3,Ethical Standard in Islam,16. Alcohol and Gambling
9,3,Ethical Standard in Islam,17. Permitted and Prohibited Food
9,3,Ethical Standard in Islam,18. Food of the People of the Book
9,3,Ethical Standard in Islam,19. Let Ramadan Bring The Best in Us
9,4,Essays on Rasulullahﷺ,20. Khadijah (ra)
9,4,Essays on Rasulullahﷺ,21. Rasulullahﷺ Multiple Marriages
9,4,Essays on Rasulullahﷺ,22. Marriage to Zainab (ra)
9,4,Essays on Rasulullahﷺ,23. Rasulullahﷺ: A Great Army General
9,4,Essays on Rasulullahﷺ,24. Prophecy of Muhammadﷺ in the Bible
9,4,Essays on Rasulullahﷺ,25. Allegations Against Rasulullahﷺ
9,5,Faith-Based Wealth Building,26. Faith Based Wealth Building
9,5,Faith-Based Wealth Building,27. Earn, Save, Spend, Invest
9,5,Faith-Based Wealth Building,28. Let Investment Work for You
1 Grade Unit Unit Title chapter
2 1 1 Aqaid: Our Belief 1. Allah: Our Creator
3 1 1 Aqaid: Our Belief 2. Islam
4 1 1 Aqaid: Our Belief 3. Our Faith
5 1 1 Aqaid: Our Belief 4. Nabi Muhammad (s)
6 1 1 Aqaid: Our Belief 5. The Qur’an
7 1 2 Knowing Allah 6. Allah Loves Us
8 1 2 Knowing Allah 7. Remembering Allah
9 1 2 Knowing Allah 8. Allah Rewards Us
10 1 3 Our Ibadat 9. Five Pillars of Islam
11 1 3 Our Ibadat 10. Shahadah: The First Pillar
12 1 3 Our Ibadat 11. Salat: The Second Pillar
13 1 3 Our Ibadat 12. Zakat: The Third Pillar
14 1 3 Our Ibadat 13. Fasting: The Fourth Pillar
15 1 3 Our Ibadat 14. Hajj: The Fifth Pillar
16 1 4 Messengers of Allah 15. Adam (A): The First Nabi
17 1 4 Messengers of Allah 16. Nuh (A): Saved From the Great Flood
18 1 4 Messengers of Allah 17. Ibrahim (A): Never Listen to Shaitan
19 1 4 Messengers of Allah 18. Musa (A): Challenging a Bad Ruler
20 1 4 Messengers of Allah 19. Isa (A): A Great Nabi of Allah
21 1 5 Other Basics of Islam 20. Angels: They Always Work for Allah
22 1 5 Other Basics of Islam 21. Shaitan: Our Enemy
23 1 5 Other Basics of Islam 22. Makkah and Madinah
24 1 5 Other Basics of Islam 23. Eid: Two Festivals
25 1 6 Akhlaq and Adab in Islam 24. Good Manners
26 1 6 Akhlaq and Adab in Islam 25. Kindness and Sharing
27 1 6 Akhlaq and Adab in Islam 26. Respect
28 1 6 Akhlaq and Adab in Islam 27. Forgiveness
29 1 6 Akhlaq and Adab in Islam 28. Thanking Allah
30 2 1 The Creator and His Message 1. Allah: Our Creator
31 2 1 The Creator and His Message 2. How Does Allah Create?
32 2 1 The Creator and His Message 3. What Does Allah Do?
33 2 1 The Creator and His Message 4 Allah: What Does He Not Do
34 2 1 The Creator and His Message 5. The Qur’an
35 2 1 The Creator and His Message 6. Hadith and Sunnah
36 2 2 Our Ibadat 7. Shahadah: The First Pillar
37 2 2 Our Ibadat 8. Salat: The Second Pillar
38 2 2 Our Ibadat 9. Zakah: The Third Pillar
39 2 2 Our Ibadat 10. Sawm: The Fourth Pillar
40 2 2 Our Ibadat 11. Hajj: The Fifth Pillar
41 2 2 Our Ibadat 12. Wudu: Cleaning Before Salat
42 2 3 The Messengers of Allah 13. Ibrahim (A): A Friend of Allah
43 2 3 The Messengers of Allah 14. Yaqub (A) and Yusuf (A)
44 2 3 The Messengers of Allah 15. Musa (A) and Harun (A)
45 2 3 The Messengers of Allah 16. Yunus (A)
46 2 3 The Messengers of Allah 17. Nabi Muhammad ﷺ
47 2 4 Learning About Islam 18. Obey Allah Obey Rasul ﷺ
48 2 4 Learning About Islam 19. Day of Judgment
49 2 4 Learning About Islam 20. Our Masjid
50 2 4 Learning About Islam 21. Islamic Phrases
51 2 4 Learning About Islam 22. Food that We May Eat
52 2 5 Akhlaq and Adab in Islam 23. Truthfulness
53 2 5 Akhlaq and Adab in Islam 24. Kindness
54 2 5 Akhlaq and Adab in Islam 25. Respect
55 2 5 Akhlaq and Adab in Islam 26. Responsibility
56 2 5 Akhlaq and Adab in Islam 27. Obedience
57 2 5 Akhlaq and Adab in Islam 28. Cleanliness
58 2 5 Akhlaq and Adab in Islam 29. Honesty
59 3 1 Knowing About Allāh ﷺ 1. Who Is Allāh ﷺ?
60 3 1 Knowing About Allāh ﷺ 2. What Allāh ﷺ Is and Is Not
61 3 1 Knowing About Allāh ﷺ 3. Allāh ﷺ: The Most-Merciful Most-Rewarding
62 3 1 Knowing About Allāh ﷺ 4. Allāh ﷺ: The Best Judge
63 3 1 Knowing About Allāh ﷺ 5. What Does Allāh ﷺ Want Us to Do?
64 3 2 Teachings of Islam 6. We Are Muslims: We Have ‘Īmān
65 3 2 Teachings of Islam 7. Belief in the Qur’ān
66 3 2 Teachings of Islam 8. Belief in the Messengers
67 3 2 Teachings of Islam 9. Hadīth and Sunnah
68 3 2 Teachings of Islam 10. Jinn
69 3 2 Teachings of Islam 11. Muslims in North America
70 3 2 Teachings of Islam 12. The Straight Path: The Right Path
71 3 3 Nabi Muhammad ﷺ 13. Kindness of Rasūlullāh ﷺ
72 3 3 Nabi Muhammad ﷺ 14. How Rasūlullāh ﷺ Treated Others
73 3 3 Nabi Muhammad ﷺ 15. Our Relationship With Rasūlullāh ﷺ
74 3 4 Messengers of Allāh ﷺ 16. Ismā‘īl (A) and Ishāq (A): Nabi of Allāh ﷺ
75 3 4 Messengers of Allāh ﷺ 17. Shu‘aib (A): A Nabi of Allāh ﷺ
76 3 4 Messengers of Allāh ﷺ 18. Dāwūd (A): A Nabi of Allāh ﷺ
77 3 4 Messengers of Allāh ﷺ 19. ‘Īsā (A): A Nabi of Allāh ﷺ
78 3 5 Learning About Islam 20. The Ka‘bah
79 3 5 Learning About Islam 21. Masjid an-Nabawī: The Nabi’s Masjid
80 3 5 Learning About Islam 22. Bilāl ibn Rabāh
81 3 5 Learning About Islam 23. Zaid ibn Hārithah
82 3 6 Akhlaq and Adab in Islam 24. Ways To Be a Good Person
83 3 6 Akhlaq and Adab in Islam 25. Kindness: A Virtue of the Believers
84 3 6 Akhlaq and Adab in Islam 26. Forgiveness: A Quality of the Believers
85 3 6 Akhlaq and Adab in Islam 27. Good Deeds: A Duty of the Believers
86 3 6 Akhlaq and Adab in Islam 28. Perseverance: Never Give Up
87 3 6 Akhlaq and Adab in Islam 29. Punctuality: Doing Things on Time
88 4 1 Knowing the Creator 1. Rewards of Allah: Everybody Receives Them
89 4 1 Knowing the Creator 1. Discipline of Allah: Because He Loves Us
90 4 1 Knowing the Creator 3. Names of Allah
91 4 1 Knowing the Creator 4. Books of Allah
92 4 2 How Islam Changed Arabia 5. Pre-Islamic Arabia: Age of Ignorance
93 4 2 How Islam Changed Arabia 6. The Year of the Elephant
94 4 2 How Islam Changed Arabia 7. Early Life of Muhammad ﷺ
95 4 2 How Islam Changed Arabia 8. Life Before Becoming a Nabi
96 4 2 How Islam Changed Arabia 9. First Revelation
97 4 2 How Islam Changed Arabia 10. Makkah Period: The Early Years of the Muslims
98 4 2 How Islam Changed Arabia 11. Hijrat to Madinah: The Migration that Shaped History
99 4 2 How Islam Changed Arabia 12. Madinah Period: Islam Prospers
100 4 3 The Rightly Guided Khalifah 13. Abū Bakr (R): The First Khalifah
101 4 3 The Rightly Guided Khalifah 14. ‘Umar al-Khaṭṭāb (R): The Second Khalifah
102 4 3 The Rightly Guided Khalifah 15. ‘Uthman Ibn ‘Affān (R): The Third Khalifah
103 4 3 The Rightly Guided Khalifah 16. ‘Ali Ibn Abu Ṭālib (R): The Fourth Khalifah
104 4 4 Messengers of Allah 17. Hūd (A): Struggle to Guide Mankind
105 4 4 Messengers of Allah 18. Ṣāliḥ (A): Struggle to Guide the Misguided
106 4 4 Messengers of Allah 19. Mūsā (A): His Life and Achievements
107 4 4 Messengers of Allah 20. Sulaimān (A): A King and a Servant of Allah ﷺ
108 4 5 Fiqh of Salat 21. Preparation for Salat
109 4 5 Fiqh of Salat 22. The Requirements of Salat
110 4 5 Fiqh of Salat 23. Mubṭilāt-us-Salāt: Things that Invalidate Salāt
111 4 5 Fiqh of Salat 24. How to Pray Behind an Imām
112 4 6 General Islamic Topics 25. Compilers of Hadīth
113 4 6 General Islamic Topics 26. Shaitan’s Mode of Operation
114 4 6 General Islamic Topics 27. Day of Judgment: The Day of Ultimate Justice
115 4 6 General Islamic Topics 28. ‘Eid: Significance of the Festivities
116 4 6 General Islamic Topics 29. Truthfulness: An Important Quality for Muslims
117 4 6 General Islamic Topics 30. Perseverance: Keep on Trying
118 5 1 The Creator 1. His Message and His Messengers Tawhid Kafir Kufr Shirk Nifaq
119 5 1 The Creator 2. His Message and His Messengers Why Should We Worship Allah?
120 5 1 The Creator 3. His Message and His Messengers The Revelation of the Qur’an
121 5 1 The Creator 4. His Message and His Messengers Characteristics of the Messengers
122 5 2 The Battles and Other Developments 5. Pledges of ‘Aqabah: Invitation to Migrate
123 5 2 The Battles and Other Developments 6. The Battle of Badr: Allah Supports the Righteous
124 5 2 The Battles and Other Developments 7. The Battle of Uhud: Obey Allah and Obey the Rasul ﷺ
125 5 2 The Battles and Other Developments 8. The Battle of the Trench: A Bloodless Battle
126 5 2 The Battles and Other Developments 9. The Treaty of Hudaibiyah: A Clear Victory
127 5 2 The Battles and Other Developments 10. Liberation of Makkah: A Bloodless Victory
128 5 3 Stories of the Messengers of Allah 11. Adam (A): The Creation of Human Beings
129 5 3 Stories of the Messengers of Allah 12. Ibrahim (A): His Debate with the Polytheists
130 5 3 Stories of the Messengers of Allah 13. Ibrahim (A): His Plan Against the Idols
131 5 3 Stories of the Messengers of Allah 14. Luqmān (A): A Wise Man’s Lifelong Advice
132 5 3 Stories of the Messengers of Allah 15. Yūsuf (A): His Childhood and Life in Aziz’s Home
133 5 3 Stories of the Messengers of Allah 16. Yūsuf (A): Standing Up for Righteousness
134 5 3 Stories of the Messengers of Allah 17. Yūsuf (A): A Childhood Dream Comes True
135 5 4 Islam in The World 20. Major Masājid in the World
136 5 5 Islamic Values and Teachings 21. Upholding Truth: A Duty of All Believers
137 5 5 Islamic Values and Teachings 22. Responsibility and Punctuality
138 5 5 Islamic Values and Teachings 23. My Mind My Body: The Body is a Mirror of the Mind
139 5 5 Islamic Values and Teachings 24. Kindness and Forgiveness
140 5 5 Islamic Values and Teachings 25. The Middle Path: Ways to Avoid the Two Extremes
141 5 5 Islamic Values and Teachings 26. Salat: Its Significance
142 5 5 Islamic Values and Teachings 27. Sawm: Its Significance
143 5 5 Islamic Values and Teachings 28. Zakat and Sadaqah: Similarities and Differences
144 6 1 The Creator 1. His Message and His Messengers Tawhid Kafir Kufr Shirk Nifaq
145 6 1 The Creator 2. His Message and His Messengers Why Should We Worship Allah?
146 6 1 The Creator 3. His Message and His Messengers The Revelation of the Qur’an
147 6 1 The Creator 4. His Message and His Messengers Characteristics of the Messengers
148 6 2 The Battles and Other Developments 5. Pledges of ‘Aqabah: Invitation to Migrate
149 6 2 The Battles and Other Developments 6. The Battle of Badr: Allah Supports the Righteous
150 6 2 The Battles and Other Developments 7. The Battle of Uhud: Obey Allah and Obey the Rasul ﷺ
151 6 2 The Battles and Other Developments 8. The Battle of the Trench: A Bloodless Battle
152 6 2 The Battles and Other Developments 9. The Treaty of Hudaibiyah: A Clear Victory
153 6 2 The Battles and Other Developments 10. Liberation of Makkah: A Bloodless Victory
154 6 3 Stories of the Messengers of Allah 11. Adam (A): The Creation of Human Beings
155 6 3 Stories of the Messengers of Allah 12. Ibrahim (A): His Debate with the Polytheists
156 6 3 Stories of the Messengers of Allah 13. Ibrahim (A): His Plan Against the Idols
157 6 3 Stories of the Messengers of Allah 14. Luqmān (A): A Wise Man’s Lifelong Advice
158 6 3 Stories of the Messengers of Allah 15. Yūsuf (A): His Childhood and Life in Aziz’s Home
159 6 3 Stories of the Messengers of Allah 16. Yūsuf (A): Standing Up for Righteousness
160 6 3 Stories of the Messengers of Allah 17. Yūsuf (A): A Childhood Dream Comes True
161 6 4 Islam in The World 20. Major Masājid in the World
162 6 5 Islamic Values and Teachings 21. Upholding Truth: A Duty of All Believers
163 6 5 Islamic Values and Teachings 22. Responsibility and Punctuality
164 6 5 Islamic Values and Teachings 23. My Mind My Body: The Body is a Mirror of the Mind
165 6 5 Islamic Values and Teachings 24. Kindness and Forgiveness
166 6 5 Islamic Values and Teachings 25. The Middle Path: Ways to Avoid the Two Extremes
167 6 5 Islamic Values and Teachings 26. Salat: Its Significance
168 6 5 Islamic Values and Teachings 27. Sawm: Its Significance
169 6 5 Islamic Values and Teachings 28. Zakat and Sadaqah: Similarities and Differences
170 7 1 The Creator 1. Why Islam? What is Islam?
171 7 1 The Creator 2. Belief in Allah
172 7 1 The Creator 3. The Qur’an: Its Qualitative Names
173 7 1 The Creator 4. Istighfār: Seeking Forgiveness and Protection
174 7 1 The Creator 5. Allah: Angry or Kind?
175 7 2 Stories of the Messengers 6. Ādam (A): The Trial of the First Messenger
176 7 2 Stories of the Messengers 7. The Life of Ibrāhīm (A): Beginning a Nation
177 7 2 Stories of the Messengers 8. The Sacrifice of Ibrāhīm (A)
178 7 2 Stories of the Messengers 9. Lūt (A): A Message for Modern Societies
179 7 2 Stories of the Messengers 10. Yūsuf (A): The Will to Overcome Temptation
180 7 3 Stories from the Qur’an 11. The Companions of the Cave
181 7 3 Stories from the Qur’an 12. Dhu al-Qarnain: The Journey of a King
182 7 3 Stories from the Qur’an 13. Effective Debate and Negotiation Styles in the Qur’an
183 7 4 Two Companions Who Shaped Islam 14. Abū Sufyān: His Life and Achievements
184 7 4 Two Companions Who Shaped Islam 15. Khālid Ibn al-Walīd: The “Sword of Allah”
185 7 5 Knowledge Enrichment 16. Character of the Messengers
186 7 5 Knowledge Enrichment 17. Rasūlullāh’s Marriages
187 7 5 Knowledge Enrichment 18. Lailatul Qadr: The Night of Majesty
188 7 5 Knowledge Enrichment 19. Fasting During Ramadan: The Month of Benefits
189 7 5 Knowledge Enrichment 20. My Family is Muslim Now
190 7 5 Knowledge Enrichment 21. Science in the Qur’an
191 7 5 Knowledge Enrichment 22. Lessons From Past Civilizations
192 7 6 Akhlaq and Adab in Islam 23. Amr Bil Ma’rūf: Enjoin Good Deeds
193 7 6 Akhlaq and Adab in Islam 24. Guard Your Tongue: Think Before You Speak
194 7 6 Akhlaq and Adab in Islam 25. Islamic Greeting: Wishing Peace
195 7 6 Akhlaq and Adab in Islam 26. How to Achieve Success
196 7 6 Akhlaq and Adab in Islam 27. Permitted and Prohibited
197 7 6 Akhlaq and Adab in Islam 28. Types of Behavior Allah Loves
198 8 1 Knowing the Creator 1. Divine Names
199 8 1 Knowing the Creator 2. Sunan of Allah
200 8 1 Knowing the Creator 3. Objectives of the Qur’an
201 8 1 Knowing the Creator 4. Lessons from Sūrah al-Hujurāt
202 8 1 Knowing the Creator 5. True Piety: A Synthesis of Belief Practice and Conduct
203 8 1 Knowing the Creator 6. Āyatul Kursi: The Throne Verse
204 8 2 Knowing the Messenger ﷺ 7. The Person Muhammad ﷺ
205 8 2 Knowing the Messenger ﷺ 8. Farewell Pilgrimage
206 8 2 Knowing the Messenger ﷺ 9. Finality of Prophethood
207 8 2 Knowing the Messenger ﷺ 10. Hadith: Collection and Classification
208 8 3 Challenges in Madinah 11. Hypocrites
209 8 3 Challenges in Madinah 12. Banu Qaynuqa: Threat Within Madinah
210 8 3 Challenges in Madinah 13. Banu Nadir: Treachery Within Madinah
211 8 3 Challenges in Madinah 14. Banu Qurayzah
212 8 3 Challenges in Madinah 15. Mission to Tabūk: A Test of Steadfastness
213 8 4 Islamic Ethical Framework 16. Friends and Friendship: Who is a Good Friend?
214 8 4 Islamic Ethical Framework 17. Friendship With Non-Muslims
215 8 4 Islamic Ethical Framework 18. Dating: How Islam Views the Practice
216 8 4 Islamic Ethical Framework 19. Hold Firmly the Rope of Allah
217 8 4 Islamic Ethical Framework 20. Elements of a Bad Life
218 8 5 Islamic Values and Teachings 21. Duties Towards Parents
219 8 5 Islamic Values and Teachings 22. Hope Hopefulness Hopelessness
220 8 5 Islamic Values and Teachings 23. Trials in Life: Everyone Will Experience Them
221 8 5 Islamic Values and Teachings 24. Permitted and Prohibited Food
222 8 5 Islamic Values and Teachings 25. Performance of Hajj
223 8 5 Islamic Values and Teachings 26. Parables in the Qur’an
224 8 6 Islam After the Messenger ﷺ 27. Early History of Shi‘ah Muslims
225 8 6 Islam After the Messenger ﷺ 28. Umayyad Dynasty
226 8 6 Islam After the Messenger ﷺ 29. Abbasid Dynasty
227 9 1 A Reflection on the Divine 1. Signs of Allahﷻ in Nature
228 9 1 A Reflection on the Divine 2. Pondering the Qur’an
229 9 1 A Reflection on the Divine 3. Preservation and Compilation of the Qur’an
230 9 1 A Reflection on the Divine 4. Ibadat—Easy Ways to Do It
231 9 1 A Reflection on the Divine 5. Surah Baqarah—Statement of Faith and Commitment
232 9 2 Islam and Muslim 6. Why Human Beings Are Superior
233 9 2 Islam and Muslim 7. Life Cycle of Truth
234 9 2 Islam and Muslim 8. Is Islam a Violent Religion?
235 9 2 Islam and Muslim 9. Present Life: Vanity Deception Play
236 9 2 Islam and Muslim 10. Shariah
237 9 2 Islam and Muslim 11. Justice in Islam
238 9 3 Ethical Standard in Islam 12. Choices We Make
239 9 3 Ethical Standard in Islam 13. Peer Pressure
240 9 3 Ethical Standard in Islam 14. Islamic Perspective on Dating
241 9 3 Ethical Standard in Islam 15. Indecency
242 9 3 Ethical Standard in Islam 16. Alcohol and Gambling
243 9 3 Ethical Standard in Islam 17. Permitted and Prohibited Food
244 9 3 Ethical Standard in Islam 18. Food of the People of the Book
245 9 3 Ethical Standard in Islam 19. Let Ramadan Bring The Best in Us
246 9 4 Essays on Rasulullahﷺ 20. Khadijah (ra)
247 9 4 Essays on Rasulullahﷺ 21. Rasulullahﷺ Multiple Marriages
248 9 4 Essays on Rasulullahﷺ 22. Marriage to Zainab (ra)
249 9 4 Essays on Rasulullahﷺ 23. Rasulullahﷺ: A Great Army General
250 9 4 Essays on Rasulullahﷺ 24. Prophecy of Muhammadﷺ in the Bible
251 9 4 Essays on Rasulullahﷺ 25. Allegations Against Rasulullahﷺ
252 9 5 Faith-Based Wealth Building 26. Faith Based Wealth Building
253 9 5 Faith-Based Wealth Building 27. Earn Save Spend Invest
254 9 5 Faith-Based Wealth Building 28. Let Investment Work for You
+93
View File
@@ -0,0 +1,93 @@
<!-- NEW SECTION -->
<div class="row">
<!-- Medical Conditions -->
<div class="col-md-6 mb-3">
<label class="form-label">Medical Conditions (Select all that apply from the 33 items below) <span class="text-danger">*</span></label>
<div class="border rounded p-2 bg-white ps-3" style="max-height: 200px; overflow-y: auto;">
<?php
$medicalOptions = [
"None",
"ADHD (Attention-Deficit/Hyperactivity Disorder)",
"Anxiety or Emotional Disorders",
"Asthma",
"Autism Spectrum Disorder (ASD)",
"Behavioral or Conduct Disorders",
"Blindness / Vision Impairment",
"Celiac Disease (Gluten Intolerance)",
"Cerebral Palsy",
"Cystic Fibrosis",
"Depression",
"Diabetes (Type 1 or Type 2)",
"Down Syndrome",
"Dyslexia or Learning Disabilities",
"Eating Disorders",
"Eczema / Severe Skin Conditions",
"Epilepsy / Seizure Disorders",
"Hearing Impairments / Deafness",
"Heart Conditions (congenital or acquired)",
"Hemophilia / Bleeding Disorders",
"Kidney Disease",
"Migraines / Chronic Headaches",
"Obsessive-Compulsive Disorder (OCD)",
"Physical Disabilities / Mobility Impairments",
"PTSD (Post-Traumatic Stress Disorder)",
"Sickle Cell Anemia",
"Speech and Language Disorders",
"Thyroid Disorders",
"Tourette Syndrome",
"Traumatic Brain Injury (TBI)",
"Rheumatic diseases",
"Ulcerative Colitis / Crohns Disease",
"Other"
];
foreach ($medicalOptions as $opt): ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="medical_conditions[][]" value="<?= esc($opt) ?>" data-base-name="medical_conditions">
<label class="form-check-label ms-1"><?= esc($opt) ?></label>
</div>
<?php endforeach; ?>
</div>
<input type="text" class="form-control mt-2 d-none medical-condition-other" name="medical_condition_other[]" placeholder="Please specify if 'Other' selected">
</div>
<!-- Allergies -->
<div class="col-md-6 mb-3">
<label class="form-label">Allergies (Select all that apply from the 24 items below) <span class="text-danger">*</span></label>
<div class="border rounded p-2 bg-white ps-3" style="max-height: 200px; overflow-y: auto; overflow-x: hidden;">
<?php
$allergyOptions = [
"None",
"Animal Dander (cats, dogs, etc.)",
"Antibiotics",
"Bee stings",
"Cockroach",
"Corn",
"Dust Mites",
"Egg",
"Fire ant stings",
"Fish",
"Fragrances / Perfumes",
"Latex",
"Milk / Dairy",
"Mold",
"Mosquito bites",
"Peanut",
"Pollen (grass, tree, weed)",
"Sesame",
"Shellfish (shrimp, crab, lobster, etc.)",
"Soy",
"Tree Nuts (almond, cashew, walnut, etc.)",
"Wasp stings",
"Wheat / Gluten",
"Other"
];
foreach ($allergyOptions as $opt): ?>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="allergies[][]" value="<?= esc($opt) ?>" data-base-name="allergies">
<label class="form-check-label ms-1"><?= esc($opt) ?></label>
</div>
<?php endforeach; ?>
</div>
<input type="text" class="form-control mt-2 d-none allergy-other" name="allergy_other[]" placeholder="Please specify if 'Other' selected">
</div>
</div>
+139
View File
@@ -0,0 +1,139 @@
AdditionalChargeModel.php
AdminNotificationSubjectModel.php
ApplicationModel.php
AttendanceCommentTemplateModel.php
AttendanceDataModel.php
AttendanceDayModel.php
AttendanceEmailTemplateModel.php
AttendanceRecordModel.php
AttendanceTrackingModel.php
AuthorizedUserModel.php
BadgePrintLogModel.php
BelowSixtyDecisionModel.php
CalendarModel.php
CertificateRecordModel.php
ClassModel.php
ClassPrepAdjustmentModel.php
ClassPreparationLogModel.php
ClassProgressAttachmentModel.php
ClassProgressReportModel.php
ClassSectionModel.php
CommunicationLogModel.php
CompetitionClassWinnerModel.php
CompetitionModel.php
CompetitionScoreModel.php
CompetitionWinnerModel.php
ConfigurationModel.php
ContactUsModel.php
CurrentFlagModel.php
DiscountUsageModel.php
DiscountVoucherModel.php
EarlyDismissalSignatureModel.php
EmailTemplateModel.php
EmergencyContactModel.php
EnrollmentAgeRuleModel.php
EnrollmentEmailRecordModel.php
EnrollmentExceptionModel.php
EnrollmentFlagModel.php
EnrollmentModel.php
EnrollmentTransitionAuditModel.php
EventChargesModel.php
EventModel.php
ExamDraftModel.php
ExamModel.php
ExpenseModel.php
FamilyCommPrefModel.php
FamilyGuardianModel.php
FamilyModel.php
FamilyStudentModel.php
FinalExamModel.php
FinalScoreModel.php
FinancialAidEstimateModel.php
FinancialAidRequestModel.php
FlagModel.php
GradingLockModel.php
HomeworkModel.php
InventoryCategoryModel.php
InventoryItemModel.php
InventoryItemYearModel.php
InventoryMovementModel.php
InvoiceEventModel.php
InvoiceModel.php
InvoiceStudentListModel.php
IpAttemptModel.php
JobPositionModel.php
JobTemplateModel.php
JobTemplateVersionModel.php
LateSlipLogModel.php
LoginActivityModel.php
ManualPaymentModel.php
MessageModel.php
MidtermExamModel.php
MissingScoreOverrideModel.php
NavItemModel.php
NotificationModel.php
ParentAttendanceReportModel.php
ParentMeetingScheduleModel.php
ParentModel.php
ParentNotificationModel.php
ParentPolicyAcceptanceModel.php
ParticipationModel.php
PasswordResetModel.php
PasswordResetRequestModel.php
PaymentCorrectionModel.php
PaymentErrorModel.php
PaymentModel.php
PaymentNotificationLogModel.php
PaymentTransactionModel.php
PermissionModel.php
PlacementBatchModel.php
PlacementLevelModel.php
PlacementScoreModel.php
PreferencesModel.php
PrintRequestModel.php
ProjectModel.php
PromotionQueueModel.php
PurchaseOrderItemModel.php
PurchaseOrderModel.php
QuizModel.php
RefundModel.php
RefundPayoutModel.php
ReimbursementBatchAdminFileModel.php
ReimbursementBatchItemModel.php
ReimbursementBatchModel.php
ReimbursementModel.php
ReportCardAcknowledgementModel.php
RoleModel.php
RoleNavItemModel.php
RolePermissionModel.php
SchoolYearClosingBatchModel.php
SchoolYearClosingItemModel.php
SchoolYearModel.php
SchoolYearTransitionLogModel.php
ScoreCommentModel.php
SectionModel.php
SemesterScoreModel.php
SettingsModel.php
StaffAttendanceModel.php
StaffModel.php
StudentAllergyModel.php
StudentBookIssueModel.php
StudentClassModel.php
StudentDecisionModel.php
StudentMedicalConditionModel.php
StudentModel.php
StudentSectionDistributionDraftModel.php
StudentYearStatusModel.php
SubjectCurriculumModel.php
SupplyCategoryModel.php
TeacherClassModel.php
TeacherModel.php
TeacherSubmissionNotificationHistoryModel.php
UserAccessProfileModel.php
UserModel.php
UserNotificationModel.php
UserRoleModel.php
WhatsappGroupLinkModel.php
WhatsappGroupMembershipModel.php
WhatsappInviteLogModel.php
WithdrawalFinancialCalculationModel.php
+492
View File
@@ -0,0 +1,492 @@
# Payment Data Repair Plan
## Scope
This plan fixes the payment table, invoice/payment display logic, and manual payment write flow.
Reviewed inputs:
- `invoices(2).sql`
- `payments(1).sql`
- `PaymentController(2).php`
- `PaymentTransactionController(1).php`
## Current findings
| Check | Result |
|---|---:|
| Invoice rows | 126 |
| Payment rows | 321 |
| Invoice `paid_amount` vs `SUM(payments.paid_amount)` mismatches | 0 |
| Payment rows where `payments.total_amount` differs from linked invoice total | 106 |
| Invoices affected by stale `payments.total_amount` | 66 |
| Payment rows with negative `payments.balance` | 5 |
| Payment rows whose `semester` / `school_year` differs from linked invoice | 26 |
| Invoice IDs with no payment rows | 46, 76, 77, 108, 112, 122 |
Main conclusion: payment rows are not missing. The system is reading and storing payment context inconsistently. The payment table is being treated as both a transaction ledger and a cached invoice snapshot, which is why the UI looks wrong.
---
## Priority 1 — Protect production before repair
- [ ] Take a database backup.
- [ ] Export `invoices`, `payments`, `discount_usages`, `refunds`, `balance_transfers`, and any `payment_transactions` table.
- [ ] Run all reconciliation SQL in read-only mode first.
- [ ] Apply data repair only after confirming the result count of each query.
Recommended backup command:
```bash
mysqldump -u <user> -p <database> invoices payments discount_usages refunds balance_transfers payment_transactions > payment_repair_backup.sql
```
---
## Priority 2 — Add missing schema support
The PHP controller writes `installment_seq`, but the uploaded `payments` schema only has `number_of_installments`.
Add a dedicated installment sequence column:
```sql
ALTER TABLE payments
ADD COLUMN installment_seq INT NULL AFTER number_of_installments;
UPDATE payments
SET installment_seq = number_of_installments
WHERE installment_seq IS NULL;
```
Change `payment_date` from `DATE` to `DATETIME` so multiple same-day payments can be sorted correctly:
```sql
ALTER TABLE payments
MODIFY payment_date DATETIME NOT NULL;
```
Add indexes:
```sql
CREATE INDEX idx_payments_invoice_id ON payments(invoice_id);
CREATE INDEX idx_payments_parent_year ON payments(parent_id, school_year, semester);
CREATE UNIQUE INDEX uq_payments_transaction_id ON payments(transaction_id);
CREATE INDEX idx_invoices_parent_year ON invoices(parent_id, school_year, semester);
```
---
## Priority 3 — Repair existing payment school year and semester
Payments should inherit their term from the linked invoice. The current data has payments marked `Spring` while their invoice is `Fall`.
Preview first:
```sql
SELECT
p.id AS payment_id,
p.invoice_id,
p.parent_id,
p.school_year AS payment_school_year,
p.semester AS payment_semester,
i.school_year AS invoice_school_year,
i.semester AS invoice_semester
FROM payments p
JOIN invoices i ON i.id = p.invoice_id
WHERE p.school_year <> i.school_year
OR p.semester <> i.semester
ORDER BY p.id;
```
Repair:
```sql
UPDATE payments p
JOIN invoices i ON i.id = p.invoice_id
SET
p.school_year = i.school_year,
p.semester = i.semester
WHERE
p.school_year <> i.school_year
OR p.semester <> i.semester;
```
---
## Priority 4 — Stop trusting stale copied fields
Do not use these fields as authoritative in the UI:
- `payments.total_amount`
- `payments.balance`
- `payments.status` as invoice status
Use:
- `payments.paid_amount` as the actual transaction amount.
- `invoices.total_amount` as the invoice total.
- `InvoiceLedgerService` for current invoice balance.
- Invoice status from recalculation, not from the latest payment row.
The payment history table should display:
```text
invoice_number
payment_date
paid_amount
payment_method
check_number
transaction_id
installment_seq
balance_after_payment
invoice_total
invoice_current_balance
invoice_status
school_year
semester
```
---
## Priority 5 — Fix `manualPayUpdate()` term assignment
Current bug: the controller locks the invoice and reads the invoice school year, but then passes `$this->schoolYear` and `$this->semester` into `processPayment()`. That stores payment rows under the active config term instead of the invoice term.
Change the invoice lock query:
```php
$row = $this->db->query(
'SELECT id, parent_id, total_amount, school_year, semester FROM invoices WHERE id = ? FOR UPDATE',
[$invoiceId]
)->getRowArray();
$parentId = (int) ($row['parent_id'] ?? 0);
$invYear = (string) ($row['school_year'] ?? $this->schoolYear);
$invSemester = (string) ($row['semester'] ?? $this->semester);
```
Then pass the invoice term into `processPayment()`:
```php
$ok = $this->processPayment(
$invoiceId,
$amount,
$paymentMethod,
$checkFile,
$transactionId,
$paymentDate,
$invYear,
$invSemester,
$checkNumber,
$installmentSeq,
(array) $this->invoiceModel->find($invoiceId),
$currentBalance
);
```
Do not use the current configuration term when recording a payment for an existing invoice. The invoice owns the term.
---
## Priority 6 — Replace weak parent payment queries
Current parent payment lookup is too broad and does not include enough invoice context.
Replace simple payment-only queries with invoice-joined queries.
Example:
```php
$selectedYear = $this->request->getGet('school_year') ?? $this->schoolYear;
$selectedSemester = $this->request->getGet('semester') ?? null;
$paymentsQuery = $this->paymentModel
->select([
'payments.id',
'payments.invoice_id',
'invoices.invoice_number',
'payments.transaction_id',
'payments.paid_amount',
'payments.payment_method',
'payments.check_number',
'payments.check_file',
'payments.payment_date',
'payments.installment_seq',
'payments.number_of_installments',
'payments.balance AS balance_after_payment',
'payments.status AS payment_status',
'invoices.total_amount AS invoice_total',
'invoices.balance AS invoice_current_balance',
'invoices.status AS invoice_status',
'invoices.school_year',
'invoices.semester',
])
->join('invoices', 'invoices.id = payments.invoice_id', 'inner')
->where('payments.parent_id', $parentId)
->where('invoices.school_year', $selectedYear);
if ($selectedSemester !== null && $selectedSemester !== '') {
$paymentsQuery->where('invoices.semester', $selectedSemester);
}
$payments = $paymentsQuery
->orderBy('payments.payment_date', 'DESC')
->orderBy('payments.id', 'DESC')
->paginate(10);
```
Apply this to:
- `getByParent()`
- `manualPaySearch()`
- Any dashboard or parent profile payment history endpoint
- Any admin finance page reading payment history
---
## Priority 7 — Normalize payment status
Payment status and invoice status must not mean the same thing.
Payment statuses should be transaction-level:
```text
Recorded
Voided
Refunded
Failed
Reversed
Chargeback
```
Invoice statuses should be computed:
```text
Unpaid
Partially Paid
Paid
Overpaid
Cancelled
```
After the UI stops depending on `payments.status` as invoice status, normalize existing successful payment rows:
```sql
UPDATE payments
SET status = 'Recorded'
WHERE LOWER(status) IN ('paid', 'partially paid', 'payment recorded');
```
Update `FinancialStatus` to include transaction statuses separately from invoice statuses.
---
## Priority 8 — Decide what to do with `payment_transactions`
`PaymentTransactionController` writes to a separate transaction model, but manual payments are recorded directly into `payments`.
Pick one architecture:
### Preferred
Use `payments` as the single payment transaction ledger.
Then:
- [ ] Retire payment transaction pages/routes if unused.
- [ ] Do not build UI reports from `payment_transactions`.
- [ ] Keep gateway attempts in a separate `payment_attempts` or `online_payment_transactions` table only if needed.
### Alternative
If `payment_transactions` must stay:
- [ ] Create a transaction row every time a payment row is inserted.
- [ ] Do it inside the same DB transaction.
- [ ] Never show `payment_transactions` without joining back to `payments`.
Preferred option is cleaner. Two ledgers become two lies unless aggressively synchronized.
---
## Priority 9 — Recalculate invoice ledger
After schema and controller fixes, recalculate every invoice through `InvoiceLedgerService`.
Required behavior:
- [ ] Sum successful payments from `payments`.
- [ ] Subtract discounts from `discount_usages`.
- [ ] Apply refunds/credits consistently.
- [ ] Include additional/event charges if they belong in invoice total.
- [ ] Update cached `invoices.paid_amount`, `invoices.balance`, and `invoices.status`.
- [ ] Never calculate invoice balance directly inside controllers.
Suggested maintenance command:
```php
foreach ($invoiceModel->findAll() as $invoice) {
$invoiceLedgerService->recalculateInvoice((int) $invoice['id']);
}
```
Run this from a CLI command, not from a browser request.
---
## Priority 10 — Reconciliation SQL
Run these checks after repair.
### Stale payment totals
```sql
SELECT
p.id AS payment_id,
p.invoice_id,
p.parent_id,
p.total_amount AS payment_total_amount,
i.total_amount AS invoice_total_amount,
p.paid_amount,
p.balance,
p.payment_date
FROM payments p
JOIN invoices i ON i.id = p.invoice_id
WHERE p.total_amount <> i.total_amount
ORDER BY p.invoice_id, p.id;
```
Expected after UI fix: rows may still exist historically, but the UI must not rely on `payments.total_amount`.
### Term mismatch
```sql
SELECT
p.id AS payment_id,
p.invoice_id,
p.parent_id,
p.school_year AS payment_school_year,
p.semester AS payment_semester,
i.school_year AS invoice_school_year,
i.semester AS invoice_semester
FROM payments p
JOIN invoices i ON i.id = p.invoice_id
WHERE p.school_year <> i.school_year
OR p.semester <> i.semester
ORDER BY p.id;
```
Expected: zero rows.
### Negative payment balance snapshots
```sql
SELECT
id,
parent_id,
invoice_id,
total_amount,
paid_amount,
balance,
status,
payment_date
FROM payments
WHERE balance < 0
ORDER BY invoice_id, id;
```
Expected: zero rows after balance snapshot repair, or ignored if `payments.balance` is deprecated.
### Invoices with no payment rows
```sql
SELECT
i.id,
i.parent_id,
i.invoice_number,
i.total_amount,
i.paid_amount,
i.balance,
i.has_discount,
i.status
FROM invoices i
LEFT JOIN payments p ON p.invoice_id = i.id
WHERE p.id IS NULL
ORDER BY i.id;
```
Expected: only invoices fully covered by discounts, credits, cancellations, or legitimate zero-payment states.
### Invoice paid amount consistency
```sql
SELECT
i.id AS invoice_id,
i.parent_id,
i.invoice_number,
i.paid_amount AS invoice_paid_amount,
COALESCE(SUM(p.paid_amount), 0) AS payment_sum
FROM invoices i
LEFT JOIN payments p ON p.invoice_id = i.id
GROUP BY i.id, i.parent_id, i.invoice_number, i.paid_amount
HAVING ROUND(i.paid_amount, 2) <> ROUND(payment_sum, 2)
ORDER BY i.id;
```
Expected: zero rows, unless invoice paid amount intentionally includes imported legacy payments that are not in `payments`.
---
## Priority 11 — Tests to add
### Unit tests
- [ ] Payment creation uses invoice `school_year` and `semester`, not config term.
- [ ] Payment amount cannot exceed current ledger balance.
- [ ] Card payment must equal full current balance.
- [ ] Editing a payment recalculates invoice balance.
- [ ] `installment_seq` increments only successful payments.
- [ ] Voided/refunded/failed payments are excluded from balance.
- [ ] `payments.total_amount` is never used as current invoice total in DTOs.
### Integration tests
- [ ] Parent payment history returns payments joined to invoice number.
- [ ] Parent payment history filters by invoice school year.
- [ ] Parent payment history filters by invoice semester.
- [ ] Admin finance table shows transaction amount and current invoice balance correctly.
- [ ] Manual payment insert, invoice recalculation, and notification event are atomic.
### Data repair tests
- [ ] Term mismatch query returns zero rows after repair.
- [ ] Negative payment balance query returns zero rows or deprecated field is hidden.
- [ ] Invoice paid amount consistency query returns zero rows.
- [ ] Invoices with no payments are manually classified as discount-only, cancelled, imported, or broken.
---
## Acceptance criteria
The fix is complete only when:
- [ ] Existing payments are visible in parent and admin payment history.
- [ ] Payment history shows transaction amount, not stale invoice total.
- [ ] Payment rows inherit school year and semester from invoice.
- [ ] No payment row has mismatched invoice term.
- [ ] No new payment insert depends on global config term for existing invoices.
- [ ] `installment_seq` exists and is populated.
- [ ] Invoice balances are recalculated by `InvoiceLedgerService`.
- [ ] `payment_transactions` is either retired or explicitly separated as gateway-attempt history.
- [ ] Reconciliation SQL has been run and saved as evidence.
---
## Do not do this
- Do not manually edit invoice balances row by row.
- Do not use `payments.total_amount` as invoice total.
- Do not use `payments.status` as invoice status.
- Do not filter payment history only by `payments.school_year` if invoice term exists.
- Do not keep two independent payment ledgers unless one is clearly marked as gateway attempts.
- Do not trust the latest payment row balance as the current invoice balance.
+104
View File
@@ -0,0 +1,104 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
/*
*---------------------------------------------------------------
* Sample file for Preloading
*---------------------------------------------------------------
* See https://www.php.net/manual/en/opcache.preloading.php
*
* How to Use:
* 0. Copy this file to your project root folder.
* 1. Set the $paths property of the preload class below.
* 2. Set opcache.preload in php.ini.
* php.ini:
* opcache.preload=/path/to/preload.php
*/
// Load the paths config file
require __DIR__ . '/app/Config/Paths.php';
// Path to the front controller
define('FCPATH', __DIR__ . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR);
class preload
{
/**
* @var array Paths to preload.
*/
private array $paths = [
[
'include' => __DIR__ . '/vendor/codeigniter4/framework/system', // Change this path if using manual installation
'exclude' => [
'/system/bootstrap.php',
// Not needed if you don't use them.
'/system/Database/OCI8/',
'/system/Database/Postgre/',
'/system/Database/SQLite3/',
'/system/Database/SQLSRV/',
// Not needed.
'/system/Database/Seeder.php',
'/system/Test/',
'/system/Language/',
'/system/CLI/',
'/system/Commands/',
'/system/Publisher/',
'/system/ComposerScripts.php',
'/Views/',
// Errors occur.
'/system/Config/Routes.php',
'/system/ThirdParty/',
],
],
];
public function __construct()
{
$this->loadAutoloader();
}
private function loadAutoloader(): void
{
$paths = new Config\Paths();
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php';
CodeIgniter\Boot::preload($paths);
}
/**
* Load PHP files.
*/
public function load(): void
{
foreach ($this->paths as $path) {
$directory = new RecursiveDirectoryIterator($path['include']);
$fullTree = new RecursiveIteratorIterator($directory);
$phpFiles = new RegexIterator(
$fullTree,
'/.+((?<!Test)+\.php$)/i',
RecursiveRegexIterator::GET_MATCH
);
foreach ($phpFiles as $key => $file) {
foreach ($path['exclude'] as $exclude) {
if (str_contains($file[0], $exclude)) {
continue 2;
}
}
require_once $file[0];
echo 'Loaded: ' . $file[0] . "\n";
}
}
}
}
(new preload())->load();
+75
View File
@@ -0,0 +1,75 @@
//create the docker image:
docker build -t lamp-codeigniter4 .
docker build --no-cache -t lamp-codeigniter4 .
//run the container only port 80 exposed.
docker run -d -p 8080:80 --name lamp-codeigniter4-container lamp-codeigniter4
//run the container with port 80, 3306 exposed.
docker run -d -p 8080:80 -p 3306:3306 --name lamp-codeigniter4-container lamp-codeigniter4
//run the shell on container:
docker exec -it lamp-codeigniter4-container bash
//install nano
apt install nano
//open mysql and execute the following
mysql -u root -ppassword
//create user and grant access to localhost
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'alrahma'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
//create user and grant access to "192.168.3.%"
CREATE USER 'alrahma'@'192.168.3.%' IDENTIFIED BY '@alrahma2024';
GRANT ALL PRIVILEGES ON *.* TO 'alrahma'@'192.168.3.%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
//exit mysql.
//update the config to enable accepting requests from all IP's
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf //and add thefollowing line
bind-address = 0.0.0.0
sudo service mysql restart
//update these files database config, open each file
nano /var/www/html/codeigniter4/app/Views/frontend/partials/navbar.php
nano /var/www/html/codeigniter4/app/db_connection.php
nano /var/www/codeigniter/app/Config/Database.php
nano /var/www/codeigniter/app/Controllers/ParentController.php
and look for those lines
$host = 'localhost';
$dbname = 'school';
$username = 'root';
$password = '';
and update them as follow:
// new Database configuration
$host = '127.0.0.1';
$dbname = 'school';
$username = 'admin';
$password = 'password';
// Database configuration
$host = '192.168.3.110';
$dbname = 'school';
$username = 'alrahma';
$password = '@alrahma2024';
+29
View File
@@ -0,0 +1,29 @@
apt update
apt upgrade
nano /var/ww/codeigniter/app/Config/App.php
#copy the content of the project folder into "/var/www/codeigniter/"
#make sure the permissions is granted
chown -R www-data:www-data /var/www/codeigniter/writable/cache/
chmod -R 775 /var/www/codeigniter/writable/cache/
chown -R www-data:www-data /var/www/codeigniter/writable/session/
chmod -R 775 /var/www/codeigniter/writable/session/
rm -rf /var/www/codeigniter/writable/cache/*
systemctl restart apache2
nano /etc/mysql/mariadb.conf.d/50-server.cnf or nano /etc/mysql/my.cnf
bind-address = 0.0.0.0
#run myphpadmin in docker container poiting to remote database
docker run --name myphpmyadmin -d \
-e PMA_HOST=192.168.3.126 \
-e PMA_PORT=3306 \
-e PMA_USER=alrahma \
-e PMA_PASSWORD=@alrahma2024 \
-p 8080:80 \
phpmyadmin
+150
View File
@@ -0,0 +1,150 @@
ALTER TABLE `student_class`
ADD UNIQUE KEY `uq_student_semester_year` (`student_id`, `semester`, `school_year`);
ALTER TABLE `enrollments`
ADD INDEX `idx_enrollment_lookup` (`student_id`, `semester`, `school_year`);
-- 1) Add generated normalized columns (stored so they can be indexed)
ALTER TABLE students
ADD COLUMN firstname_norm VARCHAR(100)
GENERATED ALWAYS AS (LOWER(TRIM(firstname))) STORED,
ADD COLUMN lastname_norm VARCHAR(100)
GENERATED ALWAYS AS (LOWER(TRIM(lastname))) STORED;
-- 2) Prevent duplicates for the same student, same DOB & school year
-- 2) (Optional but recommended) If you have a multi-school setup, include school identifier
-- Otherwise, skip school_id in the index.
CREATE UNIQUE INDEX ux_students_unique_per_year_global
ON students (school_year, dob, firstname_norm, lastname_norm);
-- Or, if you have multiple schools:
-- CREATE UNIQUE INDEX ux_students_unique_per_year_global
-- ON students (school_id, school_year, dob, firstname_norm, lastname_norm);
CREATE TABLE IF NOT EXISTS email_templates (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
template_key VARCHAR(64) NOT NULL UNIQUE, -- 'attendance_notice', 'grade_update', 'behavior_note'
name VARCHAR(100) NOT NULL,
subject VARCHAR(255) NOT NULL,
body MEDIUMTEXT NOT NULL,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS families (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
family_code VARCHAR(32) UNIQUE,
household_name VARCHAR(120) NULL,
address_line1 VARCHAR(150) NULL,
address_line2 VARCHAR(150) NULL,
city VARCHAR(80) NULL,
state VARCHAR(40) NULL,
postal_code VARCHAR(20) NULL,
country VARCHAR(2) NULL,
primary_phone VARCHAR(40) NULL,
preferred_lang VARCHAR(10) DEFAULT 'en',
preferred_contact_method ENUM('email','sms','phone') DEFAULT 'email',
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS family_students (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
family_id INT UNSIGNED NOT NULL,
student_id INT UNSIGNED NOT NULL,
is_primary_home TINYINT(1) DEFAULT 1,
notes VARCHAR(255) NULL,
UNIQUE KEY uq_family_student (family_id, student_id),
KEY idx_fs_student (student_id),
CONSTRAINT fk_fs_family FOREIGN KEY (family_id) REFERENCES families(id) ON DELETE CASCADE,
CONSTRAINT fk_fs_student FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS family_comm_prefs (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
family_id INT UNSIGNED NOT NULL,
category ENUM('attendance','grade','behavior','general') NOT NULL,
via_email TINYINT(1) DEFAULT 1,
via_sms TINYINT(1) DEFAULT 0,
cc_all_guardians TINYINT(1) DEFAULT 1,
UNIQUE KEY uq_family_category (family_id, category),
CONSTRAINT fk_fcp_family FOREIGN KEY (family_id) REFERENCES families(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS communication_logs (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
student_id INT UNSIGNED NOT NULL,
family_id INT UNSIGNED NULL,
student_name VARCHAR(150) NOT NULL,
template_key VARCHAR(64) NOT NULL,
subject VARCHAR(255) NOT NULL,
body MEDIUMTEXT NOT NULL,
recipients TEXT NOT NULL,
cc TEXT NULL,
bcc TEXT NULL,
attachments TEXT NULL,
status ENUM('sent','failed') NOT NULL,
error_message TEXT NULL,
sent_by INT UNSIGNED NULL,
metadata JSON NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
KEY idx_comm_student (student_id),
KEY idx_comm_family (family_id),
KEY idx_comm_template (template_key),
CONSTRAINT fk_comm_family
FOREIGN KEY (family_id) REFERENCES families(id)
ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT IGNORE INTO email_templates (template_key, name, subject, body) VALUES
('attendance_notice', 'Attendance Notice',
'Attendance Update for {{student_fullname}}',
'Dear {{parent_salutation}},\n\nThis is an update regarding {{student_fullname}} ({{student_grade}}). {{attendance_message}}\n\nDate: {{date}}\nClass/Section: {{class_section}}\n\nIf you have any questions, please reply to this email.\n\nRegards,\n{{school_name}}'),
('grade_update', 'Grade Update',
'Grade Update for {{student_fullname}}',
'Dear {{parent_salutation}},\n\nWe would like to share a grade update for {{student_fullname}} ({{student_grade}}).\n\nAssessment: {{assessment_name}}\nScore: {{score_obtained}} / {{score_total}}\nComments: {{teacher_comments}}\n\nPlease reach out if you need more details.\n\nRegards,\n{{teacher_name}} — {{school_name}}'),
('behavior_note', 'Behavior Note',
'Behavior Note for {{student_fullname}}',
'Dear {{parent_salutation}},\n\nWe want to inform you about {{student_fullname}}\'s behavior on {{date}}.\n\nSummary: {{behavior_summary}}\nActions Taken: {{actions_taken}}\nNext Steps: {{next_steps}}\n\nThank you for your partnership.\n\nRegards,\n{{teacher_name}} — {{school_name}}');
CREATE TABLE `family_guardians` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`family_id` INT UNSIGNED NOT NULL,
`user_id` INT UNSIGNED NOT NULL,
`relation` VARCHAR(32) DEFAULT NULL,
`is_primary` TINYINT(1) DEFAULT 0,
`receive_emails` TINYINT(1) DEFAULT 1,
`receive_sms` TINYINT(1) DEFAULT 0,
`custody_notes` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_family_user` (`family_id`,`user_id`),
KEY `idx_fg_family` (`family_id`),
KEY `idx_fg_user` (`user_id`),
CONSTRAINT `fk_fg_family`
FOREIGN KEY (`family_id`) REFERENCES `school`.`families` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_family_guardians_user_id`
FOREIGN KEY (`user_id`) REFERENCES `school`.`users` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE roles
ADD COLUMN slug VARCHAR(64) DEFAULT NULL AFTER name,
ADD COLUMN dashboard_route VARCHAR(255) NOT NULL DEFAULT '/landing_page/guest_dashboard' AFTER description,
ADD COLUMN priority INT(10) UNSIGNED NOT NULL DEFAULT 100 AFTER dashboard_route,
ADD COLUMN is_active TINYINT(1) NOT NULL DEFAULT 1 AFTER priority;