Skip to content

Single-file PHP job board app inspired by Pieter Levels' RemoteOK architecture. No framework, no dependencies — just one index.php, SQLite, and jQuery. An annotated study of "duct tape programming" that made $65k/month.

License

Notifications You must be signed in to change notification settings

kohld/levelsio-php-architecture

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

levelsio PHP architecture

"The people discussing what programming language is best are not shipping products. The people who don't care what programming language they're using are shipping products." — Pieter Levels

A fully functional job board web app in a single PHP file (index.php), inspired by Pieter Levels' RemoteOK — the remote job board that generated over $65,000/month as a single index.php.

Table of Contents

What is this?

This repo is a learning and reference project. It demonstrates how to build a functional web application with deliberately simple tools — one PHP file, SQLite, jQuery, no framework — that is immediately runnable.

This approach stands in contrast to modern web development with its build pipelines, dependency trees, and layers of abstraction. Levels calls it "Duct Tape Programming": pragmatic, fast, iterative. Not pretty, but profitable.

This repo is not a production template, but an annotated study of this architectural philosophy. Every section of the code is thoroughly documented so you can understand how and why things are structured the way they are.

Architecture Overview

┌──────────────────────────────────────────────────────────────┐
│                       index.php                              │
│                                                              │
│  ┌──────────────┐  Section 1: Configuration                  │
│  │   define()   │  Constants instead of .env / config class  │
│  └──────┬───────┘                                            │
│         ▼                                                    │
│  ┌──────────────┐  Section 2: Database                       │
│  │ SQLite + PDO │  Schema auto-created on first run          │
│  └──────┬───────┘  No MySQL server required                  │
│         ▼                                                    │
│  ┌──────────────┐  Section 3: Helper Functions               │
│  │  slugify()   │  Small utilities: escaping, CSRF,          │
│  │  e(), csrf() │  time formatting, redirects                │
│  └──────┬───────┘                                            │
│         ▼                                                    │
│  ┌──────────────┐  Section 4: Controllers / Actions          │
│  │  action_home │  Each function = one page                  │
│  │  action_job  │  Contains DB queries + logic               │
│  │  action_post │  Calls render_page() at the end            │
│  │  action_api  │                                            │
│  └──────┬───────┘                                            │
│         ▼                                                    │
│  ┌──────────────┐  Section 5: Router                         │
│  │  router()    │  Parses REQUEST_URI                        │
│  │  if/elseif   │  Calls the appropriate action_*()          │
│  └──────┬───────┘                                            │
│         ▼                                                    │
│  ┌──────────────┐  Section 6: Views (HTML/CSS/JS)            │
│  │ render_page()│  Everything inline: CSS in <head>,         │
│  │  if ($view)  │  JS before </body>, HTML mixed with PHP    │
│  └──────┬───────┘                                            │
│         ▼                                                    │
│  ┌──────────────┐  Section 7: Bootstrap                      │
│  │  router();   │  One line starts the entire app            │
│  └───────────┬──┘                                            │
└──────────────┼───────────────────────────────────────────────┘
               ▼
         (Bootstrap)

Request Lifecycle

Browser → NGINX → index.php → router()
                                  │
                      ┌───────────┼───────────┐
                      ▼           ▼           ▼
                 action_home  action_job  action_post
                      │           │           │
                      ▼           ▼           ▼
                   db()->query()  ...      db()->exec()
                      │                       │
                      └───────┬───────────────┘
                              ▼
                    render_page($view, $data)
                              │
                              ▼
                     HTML + CSS + JS → Browser

Prerequisites

  • PHP 8.0+ (tested with 8.2)
  • No other dependencies — no Composer, no npm, no build step

Getting Started

# Clone the repository
git clone https://github.com/YOUR-USERNAME/levelsio-php-architecture.git
cd levelsio-php-architecture

# Start — that's it
php -S localhost:8000 index.php

# Open your browser
open http://localhost:8000

The SQLite database (database.sqlite) is created automatically on the first request. No setup, no migration script, no seed command.

Project Structure

.
├── index.php           ← The entire app (the only file you need)
├── database.sqlite     ← Auto-created on first request
├── LICENSE             ← MIT License
└── README.md           ← This file

Yes, that's everything. That's the point.

Levelsio Principles Applied

Principle Implementation
Single File Everything in index.php — routing, logic, views, CSS, JS
SQLite No MySQL setup, the DB is just a file
No Framework Vanilla PHP, no Laravel/Symfony
jQuery Instead of React/Vue — loaded from CDN
Inline CSS No build tools, no Webpack, no PostCSS
SFTP Deploy Upload the file = deployment done
Pragmatic Functional > Elegant. Shipping > Perfection

Extension Ideas

  • Stripe Payment: Checkout session before publishing a job
  • Email Alerts: SQLite table subscribers + cron job
  • RSS Feed: Simply add as another route /feed
  • Telegram Bot: Cron job that posts new jobs via Bot API
  • Admin Panel: Route /admin with password check

Sources & References — Pieter Levels' Architecture

The Famous Tweet

The tweet that made the "Single PHP File" philosophy famous:

Blog Posts by Levels

  • "How I build my minimum viable products" — Detailed description of his project structure, tech stack (NGINX, Linode, PHP, SQLite) and workflow: https://levels.io/how-i-build-my-minimum-viable-products/

  • "Normalization of non-deviance" — Why he deliberately uses "primitive" tools (SFTP deploy, Sublime Text, no framework), and how he later adopted Git/Composer: https://levels.io/deviance/

  • "How I built Remote OK and launched it to #1 on Product Hunt" — The origin story of RemoteOK, how he scrapes job feeds, normalizes data, and handles URL routing via NGINX: https://levels.io/remote-ok/

His Book

  • "MAKE: The Indie Maker Blueprint" — Levels' complete philosophy on building profitable startups without funding. Idea → Build → Launch → Grow → Monetize: https://readmake.com/

Podcasts & Interviews

Hacker News Discussions

Analysis & Summaries

Levels' Products (All Built With This Approach)

Product URL Description
RemoteOK https://remoteok.com The job board (single PHP file origin)
Nomad List https://nomadlist.com City index for digital nomads
Photo AI https://photoai.com AI photo generation
Interior AI https://interiorai.com AI interior design
Hoodmaps https://hoodmaps.com Crowdsourced neighborhood maps

Related Project (Single-File Style, Job Board Directory)


Production: NGINX Configuration

For production use (instead of php -S) you need an NGINX config that routes all requests to index.php — exactly how Levels does it:

server {
    listen 80;
    server_name jobboard.example.com;
    root /var/www/jobboard;
    index index.php;

    # Everything that isn't a real file → index.php
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # Prevent SQLite DB from being accessible via web
    location ~ \.sqlite$ {
        deny all;
    }
}

What You Can Learn From This

This project is particularly useful for understanding the following concepts:

  • Request routing without a framework — How URLs are mapped to functions
  • SQLite as an embedded database — When it's enough and when it's not
  • Inline rendering — HTML/CSS/JS in one file, no template engine
  • CSRF protection — Manual token implementation without middleware
  • Pragmatic validation — Direct checks instead of validation libraries
  • SEO-friendly URLs — NGINX rewrite + PHP routing combined
  • Monetization patterns — Featured/Standard pricing like RemoteOK

Contributing

This repo is intended as a learning resource. Contributions are welcome, especially:

  • Improve comments — Even clearer explanations in index.php
  • Add more Levelsio patterns — e.g. RSS feed, Telegram bot, admin panel
  • Fix bugs — If you spot something, feel free to open an issue or PR
  • Translations — Additional language versions of the documentation

Please do not introduce frameworks, build tools, or dependency managers — that would defeat the purpose of this project. The constraint of a single file and vanilla PHP is intentional.

Disclaimer

This project is not affiliated with Pieter Levels or RemoteOK. It is an independent, annotated recreation of his publicly documented architecture for educational purposes. RemoteOK® is a registered trademark of Pieter Levels.

The code in this repository is a simplified example. For production use it is missing, among other things: rate limiting, input sanitization for XSS in rich-text fields, Stripe integration, email verification, and an admin panel.

License

MIT License — see LICENSE.

You are free to use, modify, and distribute this code. Attribution is appreciated but not required.

About

Single-file PHP job board app inspired by Pieter Levels' RemoteOK architecture. No framework, no dependencies — just one index.php, SQLite, and jQuery. An annotated study of "duct tape programming" that made $65k/month.

Topics

Resources

License

Stars

Watchers

Forks

Languages