Codegs Framework v2.0

Lightweight PHP AMVFC framework. Fast, direct, no magic. Built for real projects.

✓ Router + URL Alias ✓ Middleware Pipeline ✓ SpamGuard 5-Layer ✓ .env Config ✓ Mailer (SMTP) ✓ Activity Log ✓ Newsletter ✓ Password Reset PHP 8.2+ required

⚡ Quick Start

1
Database তৈরি করো
phpMyAdmin এ database বানাও, codegs.sql import করো।
2
.env setup করো
.env.example কপি করে .env বানাও। DB_OFFLINE_NAME এ তোমার DB নাম দাও।
3
APP_URL সেট করো
.envAPP_URL=http://localhost/yourproject দাও।
4
Admin account বানাও
http://localhost/yourproject/setup.php — email + password দাও।
5
setup.php মুছে ফেলো!
Login করার পরপরই setup.php delete করো।
⚠️ গুরুত্বপূর্ণ APP_URL এ trailing slash দিও না। সঠিক: http://localhost/codegs — ভুল: http://localhost/codegs/

📁 Folder Structure

yourproject/
├── index.php                   ← Front controller — সব request এখান থেকে শুরু
├── .env                        ← Credentials (git এ push করো না!)
├── .env.example                ← Template
├── config/
│   ├── config.php              ← সব constants define হয় এখানে
│   ├── env.php                 ← .env file loader
│   └── Router.php              ← সব route এক জায়গায়
├── controller/
│   ├── GS_GUI.php              ← Auth, home, profile, password reset
│   ├── BlogController.php      ← Blog CRUD + public show
│   ├── ContactController.php   ← Contact form + admin inbox
│   ├── UserController.php      ← User management (admin)
│   ├── SettingsController.php  ← Site settings + Route Manager
│   ├── NewsletterController.php← Subscribe/unsubscribe + broadcast
│   ├── TestimonialController.php← Testimonials CRUD
│   ├── ActivityController.php  ← Activity log viewer
│   ├── BaseController.php      ← সব controller এর parent
│   └── supporters/
│       └── supporters.php      ← Supporter class (helpers সব এখানে)
├── middleware/
│   ├── MiddlewarePipeline.php  ← Pipeline — order এখানে
│   ├── AuthMiddleware.php      ← Login check + public routes whitelist
│   ├── RateLimitMiddleware.php ← Brute force protection (file-based, IP+route কী)
│   └── VisitorMiddleware.php   ← Auto visitor tracking
├── model/
│   ├── db.php                  ← Database + GS_Model + QueryBuilder
│   ├── Blog_Model.php
│   ├── Contact_Model.php
│   └── User_Model.php
├── view/
│   ├── index.php               ← Homepage (blog section সহ)
│   ├── get_in.php              ← Login page
│   ├── sign_up.php             ← Register page
│   ├── forgot_password.php     ← Forgot password
│   ├── reset_password.php      ← Reset password
│   ├── my_profile.php          ← User profile
│   ├── change_password.php     ← Change password
│   ├── admin/                  ← Admin panel views
│   ├── gs/                     ← Public frontend views
│   └── errors/                 ← 404, 403, 500, 419
├── features/
│   └── CGS_Mailer.php          ← Email sending (PHPMailer wrapper)
├── logs/                       ← Spam logs (browser থেকে access বন্ধ)
├── assets/                     ← CSS, JS, images, uploads
│   └── uploads/
│       ├── blog/               ← Blog images
│       └── users/              ← User avatars
└── setup.php                   ← Admin setup (use করার পর delete করো)

🧩 AMVFC Pattern

Codegs এর নিজস্ব pattern — Laravel বা CodeIgniter না, একদম সরল।

Letter কী কোথায়
A Assets — CSS, JS, images assets/
M Model — Database queries model/
V View — HTML templates view/
F Features — External tools features/ (Mailer, SMS)
C Controller — Logic controller/

Request flow: Browser → index.php → Middleware → Controller → Model → View

🗃️ Database Tables

Framework এর সাথে আসা সব tables — codegs.sql import করলেই ready।

users
posts
contacts
subscribers
testimonials
general_settings
social_links
route_aliases
activity_logs
visitors
password_resets
notifications
companies
services
categories

নিজের project এর জন্য নতুন table বানাতে হলে phpMyAdmin এ বানাও বা CLI migration use করো।

🛣️ Routing System v2.0 নতুন

সব URL এক জায়গায় manage হয় — config/Router.php এ।

তিনটি URL format কাজ করে

Type Example কখন ব্যবহার করবে
Clean URL /blog, /contact সবসময় — recommended
Controller/Function /BlogController/index .htaccess active থাকলে
Query String ?controller=Blog&function=index Form action এ, legacy support

Route define করা

// config/Router.php এ যোগ করো:

// Public route (login ছাড়া access করা যাবে)
Router::get('products', 'ProductController', 'index', ['label' => 'Products', 'group' => 'public']);

// Dynamic/parameterized route — {param} দিয়ে যেকোনো segment placeholder বানাও
// URL: /blogs/5-minutes-thats-all-it-takes → $_GET['slug'] = '5-minutes-thats-all-it-takes'
Router::get('blogs/{slug}', 'BlogController', 'show', ['label' => 'Blog Post', 'group' => 'public']);

// POST route
Router::post('do-subscribe', 'NewsletterController', 'subscribe', ['group' => 'public']);

// Login required
Router::any('profile', 'GS_GUI', 'profile', ['auth' => true, 'group' => 'account']);

// Admin only
Router::any('admin-products', 'ProductController', 'admin', ['admin' => true, 'group' => 'admin']);
⚠️ Public route বানালে middleware/AuthMiddleware.php এর $publicRoutes array তেও যোগ করতে হবে।

Dynamic Route ({param}) — v2.1 নতুন

slug এ {param} লিখলে সেটা automatically dynamic route হয়ে যায় — কোনো আলাদা registration লাগে না। এটা multi-segment URL সাপোর্ট করে, যেমন Blog details পেজ এখন query-string না দিয়ে /blogs/{slug} ফরম্যাটে কাজ করে (আগে ছিল ?controller=BlogController&function=show&slug=...)।

Image Optimization — WebP Auto-Convert (v2.1 নতুন)

যেকোনো image upload (Blog cover, Site logo, Profile picture ইত্যাদি — Supporter::upload_file() বা সরাসরি হ্যান্ডলার দিয়ে) এখন automatically WebP এ convert + compress হয়ে যায় (config/ImageOptimizer.php)।

URL Alias — Settings থেকে change করো

Admin → Settings → URL Route Manager থেকে যেকোনো route এর URL পরিবর্তন করা যায়, code না ছুঁয়েই।

Route Key Default URL Custom Alias উদাহরণ
blog /blog /articles
contact /contact /reach-us
register /register /join-us

View এ URL বানাও

<!-- Named route (alias থাকলে alias URL দেবে) -->
<a href="<?= $Supporter->route('blog') ?>">Blog</a>

<!-- Controller + function থেকে -->
<a href="<?= $Supporter->url('BlogController', 'index') ?>">Blog</a>

<!-- Direct query string (সবসময় কাজ করবে) -->
<a href="index.php?controller=BlogController&function=index">Blog</a>

🎮 Controllers

নতুন Controller তৈরি

php codegs make:controller Product
# → controller/ProductController.php তৈরি হবে

Controller structure

<?php
require_once __DIR__ . '/BaseController.php';
require_once __DIR__ . '/../model/Product_Model.php';

class ProductController extends BaseController
{
    private Product_Model $product;

    public function __construct()
    {
        parent::__construct();
        $this->product = new Product_Model();
    }

    // Admin list
    public function index(): void
    {
        $this->requireAdmin();
        $items = $this->product->get_all();
        $this->view('admin/products', compact('items'));
    }

    // Public page
    public function show(): void
    {
        // requireAdmin() বা requireLogin() নেই = public
        $items = $this->product->get_published();
        $this->view('gs/products', compact('items'));
    }

    // Form save
    public function store(): void
    {
        $this->requireAdmin();
        $this->csrf();                           // CSRF check
        $this->Supporter->spam_guard();          // Spam check

        $name = trim($_POST['name'] ?? '');
        if (!$name) {
            $this->back_with_error('Name required.', 'ProductController', 'index');
        }

        $this->product->create(['name' => $name]);
        $this->back_with_success('Product added!', 'ProductController', 'index');
    }

    public function delete(): void
    {
        $this->requireAdmin();
        $id = (int)($_GET['id'] ?? 0);
        $this->product->delete($id);
        $this->back_with_success('Deleted.', 'ProductController', 'index');
    }
}

BaseController methods

Method কী করে
$this->view('admin/page', $data) View render করো — $data array এর keys view এ variable হয়ে যায়
$this->requireAdmin() Admin / Super admin login required — না থাকলে login page এ redirect
$this->requireLogin() যেকোনো logged-in user — না থাকলে login page এ redirect
$this->csrf() POST form এর CSRF token verify করো
$this->back_with_success($msg, $ctrl, $fn) Flash success + redirect
$this->back_with_error($msg, $ctrl, $fn) Flash error + redirect
$this->json($data, $status) JSON response + exit
$this->showError(404) Error page দেখাও + exit
$this->redirectTo($ctrl, $fn) Simple redirect

🗄️ Models & Database

নতুন Model তৈরি

php codegs make:model Product
# → model/Product_Model.php তৈরি হবে

GS_Model — Direct SQL

// সব rows
$rows = $this->model->read_query("SELECT * FROM posts WHERE status = ?", ['published']);

// একটা row
$post = $this->model->read_one("SELECT * FROM posts WHERE id = ? LIMIT 1", [$id]);

// Single value (count, sum, etc.)
$count = $this->model->read_value("SELECT COUNT(*) FROM users");

// Insert / Update / Delete
$this->model->execute_query(
    "INSERT INTO posts (title, slug) VALUES (?, ?)",
    [$title, $slug]
);

// Last inserted ID
$newId = $this->model->last_insert_id();

// Table exists check
if ($this->model->tableExist('products')) { ... }

QueryBuilder — Fluent Style

// SELECT
$posts = $this->model->table('posts')
    ->select('id, title, slug, created_at')
    ->where('status', '=', 'published')
    ->where('user_id', '=', $userId)
    ->orderBy('created_at', 'DESC')
    ->limit(10)
    ->offset(20)
    ->get();

// Count
$total = $this->model->table('posts')->where('status','=','published')->count();

// First
$post = $this->model->table('posts')->where('slug','=',$slug)->first();

// Insert
$id = $this->model->table('posts')->insert([
    'title' => 'Hello',
    'slug'  => 'hello',
]);

// Update
$this->model->table('posts')->where('id', '=', $id)->update(['title' => 'New Title']);

// Delete
$this->model->table('posts')->where('id', '=', $id)->delete();

// whereIn
$this->model->table('posts')->whereIn('id', [1, 2, 3])->get();

Transaction

$this->model->transaction(function($db) use ($data) {
    $db->execute_query("INSERT INTO orders ...", [...]);
    $db->execute_query("UPDATE stock SET qty = qty - 1 WHERE ...", [...]);
});

🛠️ Supporter Class

controller/supporters/supporters.php — framework এর সব helper এক জায়গায়। Controller এ $this->Supporter দিয়ে access করো, view এ $Supporter দিয়ে।

Auth

check_session()
admin / super admin required — না থাকলে login redirect
check_login()
যেকোনো logged-in user required
is_logged_in(): bool
login আছে কিনা check
is_admin(): bool
admin বা super admin কিনা
is_super_admin(): bool
super admin কিনা

Flash Messages

set_flash_success($msg)
success message session এ রাখো
set_flash_error($msg)
error message session এ রাখো
flashMessage()
view এ alert HTML output করো

Security

csrf_token(): string
CSRF token string return করো
csrf_field(): string
<input type="hidden" name="_token"> HTML return করো
spam_guard($opts)
5-layer spam protection — POST এ call করো
form_token(): string
Honeypot + timestamp hidden fields — form এ print করো
verify_recaptcha($secret)
Google reCAPTCHA v2 verify করো

Routing

route('blog'): string
named route URL — alias থাকলে alias দেবে
url($ctrl, $fn, $params)
controller+function থেকে URL বানাও
location($fn, $ctrl)
redirect করো

Validation

$errors = $this->Supporter->validate($_POST, [
    'name'    => 'required|min:2|max:100',
    'email'   => 'required|email',
    'age'     => 'required|numeric',
    'phone'   => 'min:11|max:14',
    'password'=> 'required|min:6',
]);

if ($errors) {
    // $errors['name'][0] = 'Name is required.'
}

Password

password_maker($pw): string
bcrypt hash — cost config.php এ PASSWORD_COST constant
password_verify($pw, $hash): bool
hash verify করো

Utilities

slug($text): string
'Hello World' → 'hello-world'
str_limit($text, $n): string
text truncate করো
e($value): string
htmlspecialchars shorthand
now(): string
'Y-m-d H:i:s' format current datetime
today(): string
'Y-m-d' format current date
get_client_ip(): string
visitor IP address
is_ajax(): bool
AJAX request কিনা
upload_file($file, $dest, $allowed)
file upload করো — array return করে। 🔒 extension এর পাশাপাশি real MIME type (finfo দিয়ে) verify করে।
json_response($data, $status)
JSON output + exit
dd(...$vars)
dump & die — debug এ কাজে আসে
dump(...$vars)
dump (die করে না)
generate_jwt($payload): string
JWT token তৈরি করো
verify_jwt($token): array|false
JWT verify + payload return করো

🔗 Middleware

প্রতিটা request এ controller এর আগে চলে।

Default Pipeline — MiddlewarePipeline.php

public static function default(): static
{
    return (new static())
        ->add(new VisitorMiddleware())    // IP log করে visitors table এ
        ->add(new RateLimitMiddleware())  // login brute force block করে
        ->add(new AuthMiddleware());      // login check করে
}

Public Routes — AuthMiddleware.php

এই routes গুলো login ছাড়াই access করা যাবে। নতুন public route যোগ করলে এখানে add করো।

private array $publicRoutes = [
    'GS_GUI:home',
    'GS_GUI:get_in',
    'GS_GUI:login',
    'GS_GUI:sign_up',
    'GS_GUI:register',
    'GS_GUI:forgot_password',
    'GS_GUI:forgot_send',
    'GS_GUI:reset_password',
    'GS_GUI:reset_do',
    'GS_GUI:ajax_ping',
    'BlogController:show',
    'ContactController:index',
    'ContactController:submit',
    'NewsletterController:subscribe',
    'NewsletterController:unsubscribe',
    // নতুন public route এখানে যোগ করো:
    // 'ProductController:index',
];

নতুন Middleware

php codegs make:middleware RoleCheck

🛡️ SpamGuard — 5 Layer Protection Security

যেকোনো public form এ একটা লাইনে সম্পূর্ণ spam protection।

1
Honeypot — Hidden field (hp_website) bot fill করলেই block। Human দেখতে পায় না, tab করা যায় না।
2
Keyword Scan — URL link, telegram, casino, slot, SEO spam, crypto, pharma keywords detect করে।
3
IP Rate Limit — একই IP থেকে ঘণ্টায় max ১০টা submit। Session-based, DB ছাড়াই কাজ করে।
4
Time Check — ২ সেকেন্ডের কম সময়ে form fill করলে bot। form_token() দিয়ে timestamp set হয়।
5
Bot User-Agent — curl, python-requests, scrapy, sqlmap, wget, zgrab — সব block।

ব্যবহার

// Controller — csrf() এর পরে:
$this->csrf();
$this->Supporter->spam_guard();

// Custom options:
$this->Supporter->spam_guard([
    'min_time'     => 3,          // minimum 3 seconds to fill form
    'max_per_hour' => 5,          // max 5 submissions per IP per hour
    'log_path'     => 'logs/',    // spam log save location
    'bot_ua'       => true,       // bot user-agent detection
    'honeypot'     => true,       // honeypot field check
    'keywords'     => true,       // spam keyword scan
]);

// View — form এর ভেতরে:
<input type="hidden" name="_token" value="<?= $Supporter->csrf_token() ?>">
<?= (new Supporter())->form_token() ?>   <!-- honeypot + timestamp -->

reCAPTCHA (optional)

// .env এ:
RECAPTCHA_SITE_KEY=your_site_key
RECAPTCHA_SECRET=your_secret_key

// View এ:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="<?= RECAPTCHA_SITE_KEY ?>"></div>

// Controller এ (spam_guard এর পরে):
if (!$this->Supporter->verify_recaptcha()) {
    $this->back_with_error('reCAPTCHA failed.', 'ContactController', 'index');
}
Spam log logs/spam.log এ save হয়। Browser থেকে access বন্ধ (logs/.htaccess দিয়ে)।

🔐 CSRF Protection

<!-- View — প্রতিটা POST form এ অবশ্যই: -->
<form method="POST">
    <input type="hidden" name="controller" value="ProductController">
    <input type="hidden" name="function"   value="store">
    <input type="hidden" name="_token"     value="<?= $Supporter->csrf_token() ?>">
    <!-- অথবা shorthand: -->
    <?= $Supporter->csrf_field() ?>
    ...
</form>

// Controller এ:
$this->csrf();   // fail হলে session expired page দেখাবে
🔒 আপডেট: delete/toggle এর মতো GET-link (যেমন <a href="...&function=delete&id=5">) এখন CSRF থেকে সুরক্ষিত। $this->csrf() এখন $_POST['_token'] এর পাশাপাশি $_GET['_token']-ও check করে।
<!-- GET link এ token যোগ করতে হবে: -->
<a href="index.php?controller=BlogController&function=delete&id=<?= $p['id'] ?>&_token=<?= urlencode($Supporter->csrf_token()) ?>">Delete</a>

// Controller method এ:
$this->requireAdmin();
$this->Supporter->requirePermission('blog', 'delete');
$this->csrf();   // GET বা POST, দুই জায়গার token-ই চেক হবে

এই pattern already apply করা আছে: BlogController, ContactController, TestimonialController, NewsletterController, UserController — এদের সব delete/toggle link এ।

👤 Auth & Roles — RBAC v3 আপডেট

Role System

Role Slug Default Access
Super Admin super-admin সব কিছু — কোনো restriction নেই
Admin admin Blog, Users, Contacts, Settings, Newsletter, Testimonials
Editor editor Blog manage, Testimonials view
Support support Contacts view ও edit
User user নিজের Profile, Change Password

Permission Check — Controller এ

// পুরনো method (এখনো কাজ করে)
$this->requireAdmin();    // admin + super admin চেক
$this->requireLogin();    // যেকোনো logged-in user

// নতুন RBAC method
$this->Supporter->requirePermission('blog', 'create');  // না থাকলে 403
$this->Supporter->requirePermission('users', 'delete'); // না থাকলে 403

// Boolean check
if ($this->Supporter->can('blog', 'edit')) {
    // edit button দেখাও
}
if ($this->Supporter->can('settings', 'view')) {
    // settings menu দেখাও
}

// Actions: view | create | edit | delete

View এ Permission Check

// View file এ $Supporter available থাকে
if ($Supporter->can('blog', 'create')) {
    echo '<a href="...">New Post</a>';
}
if ($Supporter->is_super_admin()) {
    // super admin only
}
if ($Supporter->is_admin()) {
    // admin menu
}

Custom Role বানানো

Admin Panel → Users → Roles এ গিয়ে নতুন role তৈরি করো, তারপর প্রতিটা module এর জন্য permission set করো।

RBAC কাজ করতে php codegs migrate একবার run করো — rolespermissions table তৈরি হবে।

🔑 Password Reset

Forgot password → email link → reset password flow সম্পূর্ণ built-in।

URL কী করে
/forgot-password Email input form
Email এ link আসে Token generate হয়, password_resets table এ save
/reset-password?token=... New password set করো
কাজ করতে হলে .env এ SMTP credentials দিতে হবে।

📝 Blog Module

Admin URLs

  • /admin-blog — Post list
  • ?function=create — নতুন post
  • ?function=edit&id=X — Edit
  • ?function=toggle&id=X — Draft/Published
  • ?function=delete&id=X — Delete

Public URL

  • /blog — Homepage blog section
  • ?controller=BlogController&function=show&slug=post-slug — Post detail

Image upload, auto slug, view count, author name — সব built-in।

👥 User Module

URL / Action কী করে
/admin-users All users list (paginated)
?function=create নতুন user বানাও (admin করতে পারে)
?function=edit&id=X User edit করো — role, status, password change
?function=toggle&id=X Active ↔ Inactive toggle
?function=delete&id=X User delete (নিজেকে করা যাবে না)
/profile নিজের profile edit
/change-password Password change

📬 Contact Module

Public Form

/contact — Visitor এখানে message পাঠায়।

  • SpamGuard protection আছে
  • Settings থেকে contact info দেখায়

Admin Inbox

/admin-contacts — সব messages।

  • Read / Unread badge
  • Message detail view
  • Reply via email link
  • Delete

📨 Newsletter Module

Action কী করে
Public subscribe Email form submit → subscribers table এ save
Unsubscribe Email link এ click করলে auto unsubscribe
/admin-newsletter Subscriber list + broadcast email
Broadcast সব active subscriber কে email পাঠাও — SMTP required

Homepage এ subscribe form যোগ করো

<?php include 'view/gs/partials/newsletter_form.php'; ?>

⭐ Testimonials Module

🔒 আপডেট: এখন testimonials module এর view/create/edit/delete — সবগুলোই RBAC permission দিয়ে check হয় (আগে শুধু requireAdmin() ছিল)।
URL কী করে
/admin → Testimonials menu All testimonials list
Create / Edit / Delete Name, designation, company, rating, message, avatar
Toggle Active ↔ Inactive
// Homepage বা যেকোনো view এ testimonials দেখাতে:
$testimonials = $this->model->read_query(
    "SELECT * FROM testimonials WHERE status = 'active' ORDER BY id DESC"
);

📋 Activity Log

Admin এর সব action log হয় — কে কখন কী করেছে।

// যেকোনো জায়গা থেকে log করো:
ActivityController::log(
    'post_created',
    'Created blog post: Hello World',
    $_SESSION['user_id']  // optional
);

// Admin এ দেখো:
// /admin-activity → সব log list
// Clear all logs button আছে

⚙️ Settings Module

Admin → /admin-settings থেকে সব site settings control করো।

General Info

  • Site name, email, phone, address
  • Site logo upload
  • SEO meta title & description

System Mode

  • Active — Normal
  • Maintenance — Visitors maintenance page দেখবে
  • Coming Soon — Coming soon page দেখাবে

URL Route Manager

যেকোনো route এর URL slug পরিবর্তন করো — code না ছুঁয়েই।

DB এর route_aliases table এ save হয়।

Social Links

Facebook, WhatsApp, Instagram, YouTube — সব manage করো। Platform, URL, icon class দাও।

View এ settings access করো

// GS_GUI home() এ already load হয়:
$general_settings['site_name']
$general_settings['site_email']
$general_settings['system_mode']

// যেকোনো controller থেকে:
$settings = $this->Supporter->get_settings();

📧 Mailer — CGS_Mailer

require_once __DIR__ . '/../features/CGS_Mailer.php';

// Static call — সহজ
$sent = CGS_Mailer::send(
    to: 'user@example.com',
    subject: 'Welcome to ' . APP_NAME,
    body: CGS_Mailer::template('Welcome!', '<p>Your account is ready.</p>')
);

if (!$sent) {
    // email fail হয়েছে — log করো বা error দেখাও
}

Built-in HTML template

$body = CGS_Mailer::template(
    title: 'Password Reset',
    body: '<p>Click the link below to reset your password:</p>
           <a href="' . $resetUrl . '">Reset Password</a>'
);

CGS_Mailer::send('user@example.com', 'Reset your password', $body);

.env SMTP config

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your@gmail.com
SMTP_PASS=your_app_password    # Gmail App Password (2FA এ)
SMTP_FROM=your@gmail.com
SMTP_FROM_NAME=CodeGS

💻 CLI Commands

🔒 আপডেট: cli.php (web CLI) এখন DEV_MODE flag ছাড়াও DEV_IPS (.env, default 127.0.0.1,::1) দিয়ে IP allow-list check করে — .htaccess/rewrite কোনো কারণে স্কিপ হলেও একটা extra safety net থাকবে। Remote থেকে dev করলে নিজের IP DEV_IPS এ যোগ করে দাও।
php codegs help                        → সব command দেখো
php codegs --version                   → version
php codegs serve                       → Dev server localhost:8000
php codegs serve localhost:9000        → Custom port

# Code generation
php codegs make:controller Product    → controller/ProductController.php
php codegs make:model Product         → model/Product_Model.php
php codegs make:middleware RoleCheck  → middleware/RoleCheckMiddleware.php
php codegs make:migration products    → model/migrations/YYYY_MM_DD_products.php
php codegs make:command notify:send   → commands/notify_send.php

# Security
php codegs key:generate               → নতুন JWT secret key

Database Migration Commands v3 নতুন

# Pending সব migration run করো — DB automatically update হবে
php codegs migrate

# কোন migration ran, কোনটা pending দেখো
php codegs migrate:status

# সর্বশেষ migration rollback করো
php codegs migrate:rollback

# সব rollback করে fresh migrate করো (সতর্ক!)
php codegs migrate:fresh
Migration কীভাবে কাজ করে: model/migrations/ folder এর সব .php file alphabetical order এ run হয়। প্রতিটা migration এ version, up, down থাকে। _migrations table এ track রাখা হয় কোনটা already ran। Module এর migrations/ folder ও automatically scan হয়।

Migration file structure

<?php
// model/migrations/2026_04_20_create_products.php

return [
    'version'     => '2026_04_20_create_products',
    'description' => 'Create products table',

    'up' => "
        CREATE TABLE IF NOT EXISTS `products` (
          `id`         INT UNSIGNED NOT NULL AUTO_INCREMENT,
          `name`       VARCHAR(255) NOT NULL,
          `price`      DECIMAL(10,2) NOT NULL DEFAULT 0,
          `status`     ENUM('active','inactive') DEFAULT 'active',
          `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
          PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ",

    'down' => "DROP TABLE IF EXISTS `products`;",
];

🧩 Module System v3 নতুন

Codegs এ দুটো উপায়ে module বানানো যায়:

Pluggable Module — কীভাবে কাজ করে

প্রতিটা module modules/ folder এর ভেতরে একটা আলাদা folder। ভেতরে একটা module.json manifest থাকে। index.php boot করার সময় ModuleLoader সব enabled module automatically load করে — routes, migrations, event listeners সব।

modules/
└── InvoiceModule/
    ├── module.json              ← manifest (required)
    ├── InvoiceController.php    ← auto-loaded
    ├── Invoice_Model.php        ← auto-loaded
    ├── views/
    │   ├── index.php
    │   └── admin.php
    └── migrations/
        └── 2026_04_20_invoices.php

module.json — Manifest

{
  "name":        "InvoiceModule",
  "version":     "1.0.0",
  "description": "Invoice management module",
  "author":      "Alamin",
  "enabled":     true,

  "routes": [
    {
      "method":     "any",
      "slug":       "invoices",
      "controller": "InvoiceController",
      "function":   "index",
      "options":    { "label": "Invoices", "group": "admin", "admin": true }
    }
  ],

  "permissions": ["invoice.view", "invoice.create", "invoice.edit", "invoice.delete"],

  "events": {
    "contact.submitted": "InvoiceNotificationListener"
  },

  "depends": []
}

নতুন Pluggable Module বানানোর steps

1
Folder structure তৈরি করো
mkdir -p modules/MyModule/views
mkdir -p modules/MyModule/migrations
2
module.json তৈরি করো
modules/ExampleModule/module.json copy করে rename করো, তারপর edit করো।
3
Controller তৈরি করো
<?php
require_once __DIR__ . '/../../controller/BaseController.php';

class MyController extends BaseController
{
    public function index(): void
    {
        $this->Supporter->requirePermission('my-module', 'view');
        $viewPath = ModuleLoader::viewPath('MyModule', 'index');
        $Supporter = $this->Supporter;
        include $viewPath;
    }
}
4
Migration তৈরি করো
<?php
// modules/MyModule/migrations/2026_04_20_my_table.php
return [
    'version'     => '2026_04_20_my_table',
    'description' => 'Create my_items table',
    'up'   => "CREATE TABLE IF NOT EXISTS `my_items` (...);",
    'down' => "DROP TABLE IF EXISTS `my_items`;",
];
5
Module enable করো
module.json"enabled": true করো।
6
DB migrate করো
php codegs migrate
Module এর migrations/ folder ও automatically scan হবে।

Event Listener (Module এ)

<?php
// modules/MyModule/ContactListener.php

class ContactListener
{
    public function handle(array $data): void
    {
        // contact submit হলে এই function call হবে
        // $data['name'], $data['email'] etc. পাবে
    }
}

// module.json এ:
// "events": { "contact.submitted": "ContactListener" }

Event fire করা (core controller থেকে)

// যেকোনো controller এ:
EventDispatcher::fire('contact.submitted', [
    'name'    => $name,
    'email'   => $email,
    'message' => $message,
]);

Module disable করা

module.json"enabled": false করলে module পুরোপুরি বন্ধ — কোনো code change নেই।

অন্য project এ Module নিয়ে যাওয়া

পুরো modules/MyModule/ folder copy করো নতুন project এ। তারপর php codegs migrate। ব্যস।

➕ Classic Module বানানো (পুরনো way)

উদাহরণ: Product module।

1
Migration তৈরি করো
php codegs make:migration products
# model/migrations/YYYY_MM_DD_products.php এ SQL লেখো
php codegs migrate    # run করো
2
Model বানাও
php codegs make:model Product
# model/Product_Model.php এ query methods লেখো
3
Controller বানাও
php codegs make:controller Product
# controller/ProductController.php এ logic লেখো
4
Route যোগ করো — config/Router.php
Router::get('products',       'ProductController', 'show',  ['group' => 'public']);
Router::any('admin-products', 'ProductController', 'index', ['admin' => true, 'group' => 'admin']);
5
Permission check যোগ করো (RBAC)
// Controller এ:
$this->Supporter->requirePermission('products', 'view');

🚀 Production Deploy Checklist

⚠️ Deploy এর আগে অবশ্যই করো — না করলে security risk!
1
.env update করো
DEV_MODE=false
APP_URL=https://yourdomain.com    # trailing slash দিও না
DB_ONLINE_HOST=your_host
DB_ONLINE_USER=your_user
DB_ONLINE_PASS=your_pass
DB_ONLINE_NAME=your_db
2
JWT Secret পরিবর্তন করো
php codegs key:generate
# output টা .env এর JWT_SECRET এ দাও
3
setup.php মুছে ফেলো
Server এ upload করার আগেই delete করো।
4
.env git এ push করো না
.gitignore এ already আছে — তবু confirm করো।
5
File permissions check করো
logs/ এবং assets/uploads/ folder এ write permission দাও (755 বা 775)।
6
reCAPTCHA keys যোগ করো (recommended)
RECAPTCHA_SITE_KEY=your_site_key
RECAPTCHA_SECRET=your_secret
7
Admin password পরিবর্তন করো
Local এ test করা password production এ রাখো না।

🔒 Security Hardening Log জুলাই ২০২৬

একটা security review এর পর নিচের fix গুলো apply করা হয়েছে। কোনো existing feature/UI ভাঙা হয়নি — সবগুলো targeted, backward-compatible change।
# ইস্যু কী ফিক্স করা হলো
1 GET link (delete/toggle) এ CSRF ছিল না BaseController::csrf() এখন $_GET['_token']-ও চেক করে। Blog/Contact/Testimonial/Newsletter/User — সব delete ও toggle action + সংশ্লিষ্ট admin view link আপডেট হয়েছে।
2 Login rate-limit শুধু session-based ছিল — cookie ফেলে দিয়ে বাইপাস করা যেত RateLimitMiddleware এখন logs/ratelimit/ ফোল্ডারে file-lock সহ IP+route ভিত্তিক persistent storage ব্যবহার করে।
3 Session cookie hardening ছিল না index.php-তে session_set_cookie_params() যোগ হয়েছে — httponly, auto-detect secure (HTTPS), samesite=Lax
4 File upload শুধু extension check করত, real content-type verify হতো না Blog/Settings/Testimonial — তিন জায়গাতেই finfo দিয়ে real MIME type extension-এর সাথে মিলছে কিনা check হয়। Site-logo আপলোড থেকে SVG বাদ দেওয়া হয়েছে (embedded script দিয়ে stored XSS ঝুঁকি ছিল)।
5 cli.php শুধু .htaccess + DEV_MODE-এর উপর নির্ভরশীল ছিল বিদ্যমান DEV_IPS constant ব্যবহার করে IP allow-list চেক যোগ হয়েছে — extra defense-in-depth।
6 TestimonialController-এ কোনো RBAC permission check ছিল না (শুধু requireAdmin()) index/create/store/edit/update/toggle/delete — সবগুলোতে requirePermission('testimonials', ...) যোগ হয়েছে। DB-তে permission matrix আগে থেকেই ছিল, এখন সেটা কার্যকর হবে।
⚠️ নিজে করতে হবে (কোডে ফিক্স করা যায়নি, এটা তোমার নিজের ডেটা): .env ও SQL dump ফাইলে (codegs.sql, codegs (10).sql) real production DB credentials আর real user password hash আছে। এই প্রজেক্ট কোথাও publicly শেয়ার/আপলোড করার আগে এগুলো সরিয়ে ফেলো বা blank_codegs.sql ব্যবহার করো।

🛡️ Role Manager — কোথায় পাবো, কীভাবে ব্যবহার করবো

📍 URL: index.php?controller=SettingsController&function=roles
Admin sidebar → Role Manager link থেকেও যেতে পারবে।

Role Manager হলো RBAC-এর visual control center। এখান থেকে কোন role কোন module access করতে পারবে সেটা checkbox দিয়ে toggle করা যায় — কোনো SQL লিখতে হবে না।

Permission Matrix — কীভাবে কাজ করে

Column মানে
View সেই module-এর list/index দেখতে পারবে
Create নতুন item তৈরি করতে পারবে
Edit existing item update করতে পারবে
Delete item মুছতে পারবে
All (হলুদ checkbox) একসাথে সব toggle করে

Default Roles এবং তাদের Access

Role Blog Users Contacts Settings Roles
Super Admin ✅ সব ✅ সব ✅ সব ✅ সব ✅ সব
Admin ✅ সব View+Create+Edit View+Edit+Delete View+Edit ❌ নেই
Editor View+Create+Edit ❌ নেই ❌ নেই ❌ নেই ❌ নেই
Support View only ❌ নেই View+Edit ❌ নেই ❌ নেই
User ❌ নেই ❌ নেই ❌ নেই ❌ নেই ❌ নেই

নতুন Role তৈরি করতে

Role Manager page-এর ডানদিকে "New Role" form আছে। Name + Description দিয়ে Create করো। Role তৈরি হওয়ার পর Permission Matrix থেকে সেই role select করে permissions set করো।

⚠️ System Roles: Super Admin, Admin, User — এই তিনটা is_system=1 তাই delete করা যাবে না। Editor ও Support delete করা যাবে।

User কে Role assign করতে

Admin Panel → Users → Edit → Role dropdown থেকে role select করো। User login করলে সেই role-এর permissions automatically load হবে।


🔐 RBAC System — কোথায় কোথায় কাজ করে

v4 এ যোগ হয়েছে: BlogController, UserController, ContactController, TestimonialController — সব admin method এ requirePermission() apply করা হয়েছে।

Controller এ RBAC ব্যবহার

// BaseController এ built-in — যেকোনো controller এ call করো
$this->Supporter->requirePermission('blog', 'delete');
// Permission না থাকলে → 403 page দেখাবে, exit করবে

কোন Controller এ কোন Permission চেক হয়

Controller Method Required Permission
BlogController index() blog → view
create(), store() blog → create
edit(), update(), toggle() blog → edit
delete() blog → delete
show() — (public, no check)
UserController index() users → view
create(), store() users → create
edit(), update(), toggle() users → edit
delete() users → delete
ContactController inbox(), show() contacts → view
toggle_read() contacts → edit
delete() contacts → delete
submit() — (public form)
TestimonialController index() testimonials → view
create(), store() testimonials → create
edit(), update(), toggle() testimonials → edit
delete() testimonials → delete

View থেকে Permission check করতে

// View file এ Supporter সবসময় available
<?php if ($Supporter->can('blog', 'delete')): ?>
  <a href="...delete...">Delete</a>
<?php endif; ?>

Session Cache

Permissions login করার সময় $_SESSION['permissions'] এ cache হয়। Role Manager থেকে permissions update করলে সেই user-এর session এ cache clear হয় — পরের request থেকে নতুন permissions load হবে।


⚡ Event System — কোথায় fire হয়, কীভাবে listen করবো

v4 এ যোগ হয়েছে: ContactController এ contact.submitted event fire হয়।

এখন পর্যন্ত যেসব Events fire হয়

Event Name কোথায় fire হয় Data যা পাওয়া যায়
contact.submitted ContactController::submit() name, email, phone, subject, message

Listener তৈরি করতে (Module এ)

// modules/MyModule/ContactListener.php
class ContactListener {
    public function handle(array $data): void {
        // $data['name'], $data['email'], $data['message']
        // e.g. Slack notification, CRM integration
        error_log("New contact from: " . $data['name']);
    }
}

তারপর module.json এ register করো:

"events": {
  "contact.submitted": "ContactListener"
}

নিজে Event fire করতে

// যেকোনো controller বা model থেকে
EventDispatcher::fire('user.registered', [
    'user_id' => $id,
    'email'   => $email,
]);

// Listener register করতে (bootstrap এ)
EventDispatcher::listen('user.registered', function(array $data) {
    // welcome email পাঠাও
});

🧩 Module System — কীভাবে কাজ করে

v4 এ fix হয়েছে: index.php এ module controller lookup যোগ হয়েছে। এখন module enable করলে controller সঠিকভাবে found হবে।

Module Structure

modules/
└── MyModule/
    ├── module.json          ← manifest (required)
    ├── MyModuleController.php
    ├── MyModule_Model.php   ← optional
    ├── views/
    │   ├── index.php
    │   └── admin.php
    └── migrations/
        └── 2026_01_01_my_table.php

module.json এর structure

{
  "name":    "MyModule",
  "version": "1.0.0",
  "enabled": true,
  "routes": [
    {
      "method":     "any",
      "slug":       "my-page",
      "controller": "MyModuleController",
      "function":   "index"
    }
  ],
  "permissions": ["my-module.view", "my-module.create"],
  "events": {
    "contact.submitted": "MyContactListener"
  },
  "depends": []
}

Module enable/disable করতে

module.json"enabled": true করলে framework automatically boot করবে। false করলে ignore করবে — কোনো code change লাগবে না।

Module এর view load করতে

// Controller এ
$viewPath = ModuleLoader::viewPath('MyModule', 'index');
if (file_exists($viewPath)) {
    $Supporter = $this->Supporter;
    include $viewPath;
}

📦 make:module CLI Command

v4 এ নতুন: একটা command এ পুরো module scaffold তৈরি হয়।
php codegs make:module InvoiceModule

এটা automatically তৈরি করবে:

তারপর করতে হবে:

1
module.json"enabled": true করো
2
Route slug customize করো (default: invoice-module)
3
Controller এ নিজের logic লেখো
4
Migration দরকার হলে php codegs make:migration invoice_items চালাও

CLI browser UI থেকেও চালানো যাবে: cli.php → sidebar এ make:module দেখবে।


✅ v4 — সব Changes এক জায়গায়

Category কী পরিবর্তন হয়েছে কোথায় কন্ট্রোল করবে
Bug Fix index.php — module controller lookup Automatic — module enable করলেই কাজ করবে
Bug Fix cli.php — migrate commands এখন browser CLI তে কাজ করে cli.php → Database group → migrate/status/rollback
RBAC BlogController, UserController, ContactController এ permission check Admin → Role Manager থেকে permission দাও/সরাও
Role Manager নতুন admin page — permission matrix visual UI ?controller=SettingsController&function=roles
Event System contact.submitted event fire হয় ContactController এ Module এর module.jsonevents block
make:module CLI command — পুরো module scaffold auto-generate php codegs make:module ModuleName বা cli.php
ExampleModule views/index.php + views/admin.php তৈরি হয়েছে module.json এ enabled: true করলে error হবে না
Database roles + permissions table, users.role_id column codegs.sql import করো বা php codegs migrate চালাও

Codegs Framework v4.0  ·  Author: Alamin  ·  AMVFC Pattern  ·  PHP 8.2+