Web Structure

From Academic to Professional

From academic MVC to professional web architecture (part 1 of 2)
💡 Professional means: understandable, testable, extensible, secure structure

Development of a modular mini-framework as a long-term project foundation

Goal:

This project serves as an architectural reference for developing scalable web applications. It demonstrates the gradual transition from an academic MVC structure to a professional, modular web architecture.
The end result is not a single project, but a lightweight mini-framework that:

  • serves as a stable foundation for any web project
  • enables long-term extensibility
  • avoids later complete refactors

"Build the right chassis once – then just swap modules."

Starting Point:

To demonstrate this concept practically, I work in two phases with existing demo projects:

Phase 1: As a starting point, I use my DemoMVC project – a typical academic MVC implementation that contains all essential concepts, but does not yet have a professional structure.

Phase 2: In the second phase, I use the Demologin project, built on the same DemoMVC basis, but it already has a complete login functionality implemented.

Stages:

STAGEFOCUSGOALPHASE
1 Academic MVCUnderstanding1
2Folder StructureSecurity & Overview1
3Bootstrap & RouterIndex Relief & Request Flow1
4.htaccess ConfigurationAccess Security (Foundation)1
(5)Services & ClassesStructure & Testability (later)2
(6)Mini-FrameworkLong-term Scalability (later)2

👉 Each stage works independently
👉 No "Start from scratch" moments

Structure:

Goal: Security & Overview, without refactor

Principle: Only public/ is publicly accessible – everything else protected.

Project/
    ├─ app/
    │  ├─ config/
    │  ├─ control/
    │  ├─ helper/
    │  ├─ model/
    │  ├─ Router/
    │  ├─ service/
    │  ├─ view/
    │  └─ bootstrap.php
    │  └─ router.php
    │  └─ session.php
    ├─ doc/...
    ├─ public/    ← only public
    │  ├─ css/
    │  └─ img/
    │  ├─ js/
    │  ├─ index.php    ← Single Entry Point
    ├─ sql/
    ├─ storage/
    │  ├─ logs/
    │  └─ upload/
    └─ README.md

Index Relief:

Problem:

In academic MVC, index.php does too much:

  • Router
  • Controller
  • Security Gate
  • Workflow Orchestrator

👉 Single Point of Chaos

Goal:

index.php becomes:

  • Small
  • Starting point
  • no logic

Solution:

  • Externalize router
  • Centralized bootstrap logic
  • Preparation for autoloading
  • Clear request pipeline

Request Pipeline

Request

public/index.php

Bootstrap

Router

Controller

Service

View / Response

Bootstrap:

Initializes:

  • Config
  • Session
  • Helper
  • Controller & Service
  • Model & View

Router:

Tasks:

  • URL → Controller / Action
  • Extract parameters
  • Handle errors cleanly


Implementation:

  • Create: app/bootstrap.php
  • Move import paths from index to the new bootstrap
  • Move switch($page) into Controller embedded in a function
  • Move Controller contents into Service folder and distribute across new files:
      App/services/
      │  ├─ AuthService.php
      │  ├─ UserService.php
      │  ├─ ProfileService.php
      │  ├─ SessionService.php
      │  └─ UploadService.php
  • Create: app/Router/Router.php
  • Move language and page checks from session.php to router.php

Secure Access with .htaccess (Two-File Architecture)

Goal: Multi-layered protection with clear task separation

Principle: Two .htaccess files work together for maximum security

Base .htaccess (Root):

    # BASE/.HTACCESS (Root directory)
    # Task separation: URL redirection & Basic protection

    # PROTECTION OF .HTACCESS FILE
    RewriteRule ^\.htaccess$ - [F]

    <IfModule mod_rewrite.c>
        RewriteEngine On

        # REWRITE ALL REQUESTS TO PUBLIC/
        RewriteCond %{REQUEST_URI} !/public/
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ public/$1 [QSA,L]

        # DELIVER STATIC FILES DIRECTLY
        RewriteCond %{REQUEST_URI} !/public/
        RewriteCond %{REQUEST_FILENAME} !-f
        # EVERYTHING ELSE TO PUBLIC/INDEX.PHP
        RewriteRule ^(.*)$ public/index.php [QSA,L]
    </IfModule>

Public .htaccess (Application):

    # BASE/PUBLIC/.HTACCESS 
    # Task separation: Application routing

    RewriteRule ^\.htaccess$ - [F]

    <IfModule mod_rewrite.c>
        RewriteEngine On

        # DELIVER EXISTING FILES/DIRECTORIES DIRECTLY
        RewriteCond %{REQUEST_FILENAME} -f [OR]
        RewriteCond %{REQUEST_FILENAME} -d
        RewriteRule ^ - [L]

        # EVERYTHING ELSE → INDEX.PHP (FRONT CONTROLLER)
        RewriteRule ^ index.php [L]
    </IfModule>


Why two files:

  • Multi-layered security: Double protection against directory traversal
  • Task separation: Root manages access, Public manages routing
  • Debugging: Easier to test and maintain
  • Flexibility: Can be adapted per environment

How they work together:

  • Step 1: Root .htaccess redirects all requests to public/
  • Step 2: Public .htaccess checks if file/directory exists
  • Step 3: Static files are delivered directly
  • Step 4: Everything else goes to index.php (Front Controller)

👉 Together with the folder structure, this forms the security foundation of the entire project. No sensitive files are ever publicly accessible.