# OBEsoft Architecture Migration Guide

This document explains the problems in the previous OBEsoft project structure, the changes completed during the architecture migration, why the current structure is safer and easier to maintain, how the application layers connect, and where future features should be implemented.

## 1. Executive summary

The previous project mixed frontend code, APIs, the SQLite database, documentation, legacy applications, and runtime files in the repository root. This made deployment, security, database evolution, backup, and future role-based development unnecessarily risky.

The current architecture provides the following improvements:

- Only `public/` is exposed by the web server.
- The live SQLite database is stored privately under `storage/database/`.
- Database changes are applied through ordered, versioned migrations.
- Frontend, API entrypoints, business workflows, authorization, and persistence are separated.
- Admin, Manager, and Teacher role-based access control is available.
- Backup and restore are SQLite WAL-aware and integrity-verified.
- The PHP and optional FastAPI runtimes support the browser's existing API contract.
- Automated syntax, database, preservation, HTTP, backup, and RBAC checks are included.

This is a practical layered architecture for the current OBEsoft codebase and technology stack. It is not presented as the only possible architecture, but it is significantly safer and more maintainable than the previous layout.

---

## 2. Previous structure

The old repository was approximately organized as follows:

```text
OBEsoft-v2/
|-- api/
|-- assets/
|-- backend/
|-- static/
|-- index.php
|-- index.html
|-- obe.db
|-- app.py
|-- run.bat
|-- app_icon*.png/svg
|-- favicon*.png
|-- workflow_infographic*.png/svg
|-- faculty_tasks_infographic*.png/svg
|-- change_log_v*.txt
|-- README.md
`-- other documentation files
```

## 3. Problems in the previous structure

### 3.1 No public/private boundary

The PHP server was started from the repository root:

```text
php -S 127.0.0.1:8000
```

The same web root contained:

- The application entry page
- Public APIs
- The SQLite database
- Python source code
- Documentation
- The legacy application
- Changelogs and internal assets

On a production server, an incorrect configuration could expose files that should never be downloadable.

### 3.2 The database was inside the public root

The live database was stored as:

```text
obe.db
```

Because it was inside the served project root, protection depended on server-specific configuration. An `.htaccess` rule would not protect the file when using the PHP built-in server or Nginx, and it could fail on Apache when overrides were disabled.

### 3.3 `index.html` and `index.php` could conflict

The repository root contained both:

```text
index.html   # Legacy standalone application
index.php    # Active database-backed application
```

The default file selected for `/` could depend on the web server's `DirectoryIndex` order. A deployment could therefore serve the legacy application instead of the active application.

### 3.4 No real database migration system

The old database initialization relied on `CREATE TABLE IF NOT EXISTS`. That command creates a missing table, but it does not add a new column to an existing table.

For example, adding this inside the original table definition would not update an existing database:

```sql
CREATE TABLE IF NOT EXISTS courses (
    ...,
    teacher_id TEXT
);
```

This could cause development and deployed databases to have different schemas.

### 3.5 A single `teacher_id` was not a sufficient assignment model

A teacher can teach multiple course offerings, and one course offering may have multiple teachers. A single `courses.teacher_id` field would make team teaching and reassignment difficult.

The current structure uses a many-to-many relationship:

```text
users <-> course_assignments <-> courses
```

### 3.6 Backup was not WAL-safe

SQLite was using WAL journal mode, but the old backup endpoint downloaded or copied only the main `obe.db` file. Recently committed data may still be stored in `obe.db-wal`. Copying only the main database file can therefore produce an incomplete backup.

### 3.7 Restore validation was insufficient

The previous restore process did not fully enforce:

- Upload size limits
- SQLite file-header validation
- Database integrity validation
- Required OBEsoft table validation
- Safe database replacement
- Reliable rollback material

### 3.8 Sensitive endpoints were not protected

Without authentication and authorization, a deployed backup endpoint could allow database download or replacement without an administrator permission check.

### 3.9 No server-side role-based authorization

The old APIs did not verify:

- Who could view a course
- Who could modify a course
- Whether a teacher was assigned to that course
- Who could manage users and assignments
- Who could download or restore the database

Hiding a frontend button is not security. Authorization must be enforced on the server for every protected request.

### 3.10 PHP and FastAPI contracts were incompatible

The browser client requested endpoints such as:

```text
api/courses.php
```

It expected a response envelope such as:

```json
{"success": true, "courses": []}
```

The FastAPI backend exposed `/api/courses` and returned a raw list. The existing frontend could not use it without changes.

### 3.11 `static/` and `assets/` could not be merged safely

The project had two different CSS files:

```text
assets/css/style.css
static/css/style.css
```

Their contents were not identical. Overwriting one with the other would have caused code loss. The old Python static version is now preserved under `legacy/python-static/`.

### 3.12 Documentation did not match the active application

The previous README described the standalone `index.html`, GitHub Pages, and a no-backend workflow. The active application was already using PHP and SQLite, so the deployment instructions were no longer accurate.

### 3.13 No automated regression protection

There was no automated process to verify:

- File preservation
- Existing row preservation
- Migration behavior
- API CRUD operations
- Backup and restore consistency
- PHP and FastAPI runtime behavior
- Role and permission enforcement

---

## 4. Current structure

```text
OBEsoft-v2/
|-- public/                       # The only web-accessible directory
|   |-- index.php                 # Main frontend shell
|   |-- .htaccess                 # Apache public-directory hardening
|   |-- api/                      # HTTP/API entrypoints
|   |   |-- auth.php
|   |   |-- courses.php
|   |   |-- institution.php
|   |   |-- backup.php
|   |   |-- users.php
|   |   `-- assignments.php
|   `-- assets/                   # Frontend static files
|       |-- css/
|       |-- js/
|       `-- img/
|
|-- src/                          # Private PHP application code
|   |-- Auth/
|   |-- Database/
|   |-- Http/
|   |-- Repositories/
|   |-- Services/
|   `-- bootstrap.php
|
|-- config/
|   `-- app.php                   # Environment-aware configuration
|
|-- database/
|   `-- migrations/               # Ordered and versioned schema changes
|
|-- storage/                       # Private runtime files
|   |-- database/obe.db
|   |-- backups/
|   |-- sessions/
|   |-- logs/
|   `-- test/
|
|-- backend/                       # Optional FastAPI compatibility runtime
|-- tests/                         # Automated verification
|-- docs/                          # Documentation and historical media
|-- legacy/                        # Preserved old implementations
|-- app.py
|-- run.bat
|-- run-python.bat
|-- requirements.txt
|-- .env.example
|-- .gitignore
`-- README.md
```

---

## 5. Why the current structure is better

### 5.1 A real document-root boundary

The application now starts with:

```text
php -S 127.0.0.1:8000 -t public
```

Only these resources are directly web-accessible:

```text
public/index.php
public/api/*
public/assets/*
```

These private resources cannot be requested directly through the application URL:

```text
storage/database/obe.db
storage/backups/
src/
config/
database/migrations/
docs/
legacy/
tests/
```

### 5.2 Clear responsibility boundaries

The main request flow is:

```text
Frontend -> API -> Auth/Service/Repository -> Database
```

Each layer has a focused responsibility, reducing the effect of future changes on unrelated code.

### 5.3 Repeatable database evolution

Schema changes are ordered and versioned:

```text
001_initial_schema.php
002_rbac_foundation.php
003_future_feature.php
```

Applied versions are recorded in the `schema_migrations` table and `PRAGMA user_version`. A completed migration is not executed a second time.

### 5.4 Existing data was preserved

An online SQLite backup was created before migration. After migration, the following were verified:

- Existing course rows are unchanged.
- The institution row is unchanged.
- Database integrity is `ok`.
- The existing course count is unchanged.

### 5.5 Server-side RBAC

For protected requests, the server can now verify:

- Whether the user is authenticated
- Whether the user has the required permission
- Whether a teacher is assigned to the requested course
- Whether an operation is restricted to an administrator

### 5.6 Consistent backup and recoverable restore

The backup service creates a consistent SQLite snapshot. Restore performs the following steps:

1. Validate the upload size.
2. Validate the SQLite file header.
3. Run an integrity check.
4. Verify required OBEsoft tables.
5. Create a consistent safety backup.
6. Archive the current raw database.
7. Activate the replacement database.
8. Run migrations and integrity checks again.
9. Attempt to restore the previous database if activation fails.

### 5.7 Legacy code was preserved

Previous implementations were not overwritten:

```text
legacy/index.html
legacy/php-api-v1/
legacy/python-backend-v1/
legacy/python-static/
```

The original README is preserved as:

```text
docs/LEGACY_STANDALONE_GUIDE.md
```

### 5.8 Automated verification

The repository now includes tests for syntax, database behavior, backup/restore, RBAC, file preservation, and both HTTP runtimes.

---

## 6. Frontend files

The active frontend consists of:

```text
public/index.php
public/assets/css/style.css
public/assets/js/api.js
public/assets/js/app.js
public/assets/img/*
```

### `public/index.php`

Responsibilities:

- Main HTML shell
- Navbar and sidebar structure
- Main content container
- Modal structure
- CSS and JavaScript loading

### `public/assets/js/app.js`

Responsibilities:

- Application state
- UI rendering
- Section and tab navigation
- CO-PO calculations
- Assessment, marks, attainment, and CQI behavior
- Authentication setup and login UI
- Form and button event handling

### `public/assets/js/api.js`

Responsibilities:

- Browser-to-API requests
- Institution and course loading/saving
- Authentication setup, login, and logout calls
- CSRF token handling
- API error handling

### `public/assets/css/style.css`

Responsibilities:

- Layout
- Components
- Responsive behavior
- Color, spacing, and typography

### `public/assets/img/`

Contains public logos, favicons, and application images.

---

## 7. Backend request flow

### Course loading

```text
public/index.php
      |
      v
public/assets/js/app.js
      | API.getCourses()
      v
public/assets/js/api.js
      | HTTP GET
      v
public/api/courses.php
      | permission and course filtering
      v
src/Auth/Auth.php
      | persistence request
      v
src/Repositories/ObeRepository.php
      | connection
      v
src/Database/Database.php
      |
      v
storage/database/obe.db
```

### Course saving

```text
Teacher edits an assigned course
      |
      v
app.js calls API.saveCourse()
      |
      v
api.js sends POST + CSRF token
      |
      v
courses.php checks courses.write
      |
      v
Auth.php checks course_assignments
      |
      v
ObeRepository.php saves the course
      |
      v
storage/database/obe.db
```

### Database backup

```text
Frontend backup action
      |
      v
public/api/backup.php
      | backup.download or backup.restore permission
      v
src/Auth/Auth.php
      |
      v
src/Services/DatabaseBackupService.php
      |
      +--> storage/database/obe.db
      `--> storage/backups/
```

---

## 8. API, Service, and Repository responsibilities

### API entrypoint

Location:

```text
public/api/*.php
```

An API entrypoint should:

- Accept an HTTP request
- Validate the HTTP method
- Read query parameters or JSON input
- Trigger authentication and authorization checks
- Call a Service or Repository
- Return an HTTP/JSON response

Large business workflows should not be implemented directly in an API file.

### Service

Location:

```text
src/Services/
```

A Service coordinates a complete business workflow. It is appropriate when an operation requires validation, multiple database actions, backup, rollback, or other business rules.

#### `DatabaseBackupService.php`

- Creates consistent backups
- Validates uploaded SQLite databases
- Coordinates restore safety and rollback

#### `UserService.php`

- Creates and updates users
- Hashes passwords
- Assigns roles
- Assigns and unassigns courses

### Repository

Location:

```text
src/Repositories/
```

A Repository is responsible for application data persistence.

#### `ObeRepository.php`

- Reads and writes institution settings
- Lists and loads courses
- Creates and updates courses
- Duplicates courses
- Deletes courses

The general rule is:

```text
API        = request and response handling
Service    = business workflow
Repository = database read and write operations
Database   = connection and migration infrastructure
```

---

## 9. Database-related directories are not duplicates

The similar names represent different responsibilities:

| Location | Responsibility |
|---|---|
| `storage/database/obe.db` | The real SQLite database containing application data |
| `database/migrations/` | Versioned instructions for schema changes |
| `src/Database/Database.php` | PDO connection and SQLite configuration |
| `src/Database/Migrator.php` | Finds and applies pending migrations safely |
| `backend/database.py` | SQLite adapter for the optional FastAPI runtime |

There is only one configured live SQLite database. These folders are different layers around that database.

---

## 10. Completed migrations

### `001_initial_schema.php`

Creates or safely adopts:

- `institution`
- `courses`
- The course update index

### `002_rbac_foundation.php`

Creates:

- `users`
- `roles`
- `permissions`
- `user_roles`
- `role_permissions`
- `course_assignments`
- `audit_logs`

Seeds these roles:

- `admin`
- `manager`
- `teacher`

### `003_account_lifecycle.php`

Adds:

- Email verification and password reset tokens
- External identity links for Google sign-in
- Account provider, avatar, verification, and session-version fields
- Authentication rate-limit records and indexes

Never modify an applied migration to add a future schema change. Create a new file instead:

```text
database/migrations/004_feature_name.php
```

---

## 11. Role and permission design

### Admin

- Manage users and roles
- Manage institution settings
- Manage every course
- Manage teacher assignments
- Download backups
- Restore the database

### Manager

- Manage institution settings
- Manage courses
- Manage teacher assignments
- Download backups
- Cannot administer users or restore the database by default

### Teacher

- View assigned courses
- Update assigned courses
- Cannot delete courses
- Cannot download or restore the database
- Cannot manage users or assignments

Teacher access is resolved through:

```text
users
  |
user_roles -> roles
  |
course_assignments
  |
courses
```

---

## 12. Where to add new features

| Requirement | Recommended location |
|---|---|
| New frontend section or tab | `public/index.php` and `public/assets/js/pages/` |
| Page-specific CSS | `public/assets/css/pages/` |
| New HTTP endpoint | `public/api/` |
| Business workflow | `src/Services/` |
| Database query or persistence | `src/Repositories/` |
| Authentication or permission behavior | `src/Auth/` |
| Shared HTTP behavior | `src/Http/` |
| New table, column, or index | New `database/migrations/NNN_*.php` file |
| Runtime database, backup, or session | `storage/` |
| Documentation | `docs/` |
| Automated verification | `tests/` |

### Teacher Dashboard example

```text
public/index.php
public/assets/js/pages/teacher-dashboard.js
public/assets/css/pages/teacher-dashboard.css
public/api/teacher-dashboard.php
src/Services/TeacherDashboardService.php
src/Repositories/TeacherDashboardRepository.php
```

If teacher-specific profile fields require a new table, add:

```text
database/migrations/004_teacher_profiles.php
```

A new table is not required merely to show assigned courses. The existing `users`, `roles`, `course_assignments`, and `courses` tables already support that requirement.

### Directories that must not contain frontend pages

Do not place page markup in:

```text
src/Auth/
src/Database/
database/migrations/
storage/
config/
tests/
```

These directories contain authentication logic, database infrastructure, schema changes, private runtime data, configuration, and tests.

---

## 13. Security improvements

Completed security changes include:

- A private document-root boundary
- Environment-aware database and backup paths
- Same-origin APIs by default
- Restricted and configurable CORS
- Secure session cookie settings
- A private session directory
- Secure password hashing
- Session ID regeneration after login
- CSRF verification
- Server-side role and permission checks
- Teacher course-assignment checks
- Audit logging
- Administrator-only restore
- Upload size and SQLite validation
- Git ignore rules for databases, WAL files, backups, sessions, logs, and secrets

Authentication is enabled by default. It can be disabled only for intentional local compatibility work with:

```text
OBESOFT_AUTH_ENABLED=false
```

The first visit presents the initial administrator setup screen. Local registration, email verification, password recovery, optional Google sign-in, and the `/admin/` management page are implemented. See `docs/AUTHENTICATION_AND_ROLES.md` for configuration and extension guidance.

---

## 14. PHP and FastAPI runtimes

> **Update, September 2026:** The FastAPI runtime has been retired and moved to `legacy/fastapi-runtime/` (see its README). PHP is now the only runtime. The notes below describe the state at the time of the migration.

### Canonical PHP runtime

Start it with:

```text
run.bat
```

or:

```text
php -S 127.0.0.1:8000 -t public
```

Use the PHP runtime for production and authenticated deployments.

### Optional FastAPI compatibility runtime

Start it with:

```text
run-python.bat
```

It:

- Serves `public/index.php` as the browser shell
- Serves `public/assets/`
- Preserves the original FastAPI routes
- Adds `.php`-style compatibility endpoints for the existing browser client

FastAPI intentionally refuses to start when authentication is enabled because it does not currently implement the equivalent PHP RBAC middleware. This prevents it from becoming an authorization bypass.

---

## 15. Documentation and legacy preservation

Documentation was moved to:

```text
docs/changelogs/
docs/infographics/
docs/Attainment_Calculation_Methodology.docx
```

Previous implementations were preserved under:

```text
legacy/index.html
legacy/aust_logo.svg
legacy/svg_to_png.html
legacy/python-static/
legacy/php-api-v1/
legacy/python-backend-v1/
```

Original file preservation is verified using a SHA-256 manifest.

---

## 16. Automated verification

Run the complete suite with:

```powershell
powershell -ExecutionPolicy Bypass -File tests/run.ps1
```

The suite verifies:

- PHP syntax
- JavaScript syntax
- Python syntax
- Preserved-file SHA-256 hashes
- Fresh database migrations
- SQLite integrity
- Course create, read, update, and delete operations
- Course duplication reset behavior
- User and teacher-assignment persistence
- Consistent backup and verified restore
- PHP application shell and API routes
- Authenticated Admin and Teacher RBAC behavior
- Rejection of unauthorized delete and backup operations
- FastAPI frontend and API compatibility

---

## 17. Rollback and recovery

The local pre-migration recovery snapshot is stored at:

```text
storage/backups/pre-restructure-20260920/
```

It contains:

- The original source snapshot
- A SHA-256 file inventory
- An SQLite online backup

This directory is ignored by Git and may contain student or institutional data. It must remain private.

---

## 18. Current limitations and future improvements

The architecture is significantly improved, but several future improvements remain appropriate:

1. `app.js` is still a large frontend file. New features should gradually move into `public/assets/js/pages/` and reusable modules.
2. User and course-assignment APIs exist, but a dedicated visual Admin User Management page has not yet been added.
3. More fixture-based expected-result tests should be added for the calculation engine.
4. Production deployments still require HTTPS, secure environment configuration, and appropriate server-level permissions and logging.
5. If the application grows substantially, a single PHP front controller/router and dependency-injection container may become useful.

These items do not prevent the current application from running; they are recommendations for the next development phase.

---

## 19. Developer checklist

Before implementing a new feature:

- Identify whether it belongs to the frontend, API, Service, Repository, Auth, or database layer.
- Never edit an already applied migration; add a new migration.
- Enforce permissions on the server.
- Check assignment or ownership for teacher resources.
- Keep business workflows out of public API entry files.
- Keep database queries inside a Repository or suitable Service.
- Never place runtime data inside `public/`.
- Add or update automated tests.
- Run the complete verification suite.

```powershell
powershell -ExecutionPolicy Bypass -File tests/run.ps1
```
