Architecture
Simple Page is designed to give you control, without sacrificing user experience.
Home | User Guide | About
Overview
SimplePage operates as a three-tier decentralized system:
- Smart Contracts (Ethereum): Manage page subscriptions, indexing coordination, and ENS integration
- Frontend Application (Web): User interface for content creation, editing, and publishing
- DService node (Indexer + IPFS): Handle content storage, retrieval, and blockchain indexing
Data Flow
User writes content (in Frontend) → Content is uploaded (to DService) → ENS contenthash update (in Frontend) → Content available globally (your ENS name)
Smart Contracts
The platform is built on three core smart contracts deployed on Ethereum:
SimplePage
- Purpose: Main contract managing pages and storage units
- Functionality:
- Mints an NFTs representing page
- NFT contains number of Units with their expiry dates
- The most recent patron of a page becomes the NFT owner
Currently the Simple Page system only utilizes a single unit for every page. In the future multiple units could be used to allow for larger storage quotas.
SimplePageManager
- Purpose: Handles subscription purchases
- Functionality:
- Manages storage unit purchases and expiration
- Handles subscription renewals
- Handles price conversion (fees are priced in USD, but payed in ETH)
TokenRenderer
- Purpose: Renders NFT metadata as SVG
- Functionality:
- Renders an SVG on-chain when the SimplePage NFT tokenURI is queried
DService (Decentralized Service)
A Node.js backend service that bridges smart contracts with IPFS storage:
Core Functionality
Indexer Service
- Monitors SimplePage contract events for new page registrations
- Tracks ENS contenthash updates for registered domains
- Synchronizes blockchain state with IPFS storage
- Retrieves page data from other nodes over IPFS
API Service
- Provides REST endpoints for page operations
- Handles page uploads with CAR (Content Addressable aRchive) files
- Generates automatic OpenAPI documentation
- Manages allow/block lists for domains
Key Endpoints
GET
:/page?cid=<content-id>
- Retrieve page contentPOST
:/page?domain=<ens-name>
- Upload new pageGET
:/info
- Service informationGET
:/docs
- Interactive API documentation
DService ENS Record
In order to mitigate the centralization vector of hard coding the API into the SimplePage frontend, an ENS text record is used. Briefly, an array of indexer URLs (currently only simplepg.org
) are stored in the dservice
ENS TEXT record. When the frontend is loaded it fetches these endpoints using the Ethereum RPC API. This DService endpoint is currently stored on the new.simplepage.eth
domain.
Frontend
A React-based web application with modern UI/UX:
Core Features
- Markdown Editor: Live preview with syntax highlighting
- Web3 Integration: Wallet connection via Wagmi and Viem
- Page Management: Create, edit, and organize multiple pages
- Subscription Dashboard: Manage storage units and payments
- Fork System: Remix any existing SimplePage site
- Static HTML: Your website will render even if your users have javascript disabled
Data Structure
SimplePage uses a hierarchical file system structure stored on IPFS, with each page represented by both markdown and HTML files:
Root Directory Structure:
├── index.md # Home page markdown
├── index.html # Home page HTML
├── about/
│ ├── index.md # About page markdown
│ └── index.html # About page HTML
├── blog/
│ ├── index.md # Blog index markdown
│ ├── index.html # Blog index HTML
│ └── post/
│ ├── index.md # Blog post markdown
│ └── index.html # Blog post HTML
├── _template.html # HTML template for all pages
├── _redirects # URL redirects configuration
├── manifest.webmanifest # Web app manifest
└── _prev/
└── 0/ # Previous version
├── index.md
├── index.html
└── about/
├── index.md
└── index.html
Page Storage Pattern
Dual File Format
Every page is stored in two formats:
index.md
: Raw markdown content with frontmatter metadata, this is the content which the user editsindex.html
: Rendered HTML with populated template
Path Structure
- Pages use URL-style paths (e.g.,
/
,/about/
,/blog/post/
) - Each path corresponds to a directory containing
index.md
andindex.html
- The root page is stored directly in the root directory
- Nested pages create nested directory structures
Template System
_template.html
: Master HTML template used for all pages- Template is populated with page content, metadata, and navigation
- Each page's HTML is generated by combining template + markdown content
- New version of the
_template.html
and other files get published onnew.simplepage.eth
, during the publishing process the user is prompted to upgrade their site if a new Simple Page version is available
Version History System
_prev
Directory Structure
The _prev
directory maintains a recursive version history of the repository:
Current Repository Root:
├── index.md # Current version
├── index.html
├── about/
│ ├── index.md
│ └── index.html
└── _prev/
└── 0/ # Previous version
├── index.md
├── index.html
├── about/
│ ├── index.md
│ └── index.html
└── _prev/
└── 0/ # Even older version (recursive structure)
├── index.md
└── index.html
Version Management Process
- Current State: The active repository root contains the latest version
- Commit Process: When changes are committed:
- Current root is copied to
_prev/0/
- Previous versions remain in their existing
_prev/0/
structure - New content becomes the new root
- Current root is copied to
- Recursive History: Each version contains its own
_prev/0/
pointing to the previous version - Rollback Capability: Any previous version can be accessed by following the
_prev/0/
chain
Version Naming Convention
_prev/0/
: Always points to the previous version- Currently only
/0/
is supported, but numbered for future expansion - Future versions may support multiple previous versions (e.g.,
/1/
,/2/
) for scenarios like:- Fork and merge workflows
- Multiple parallel development branches
- Conflict resolution with multiple parent versions
Recursive Structure Benefits
- Complete History: Every version maintains its own history chain
- Efficient Access: Direct access to any previous version
- Branch Support: Future support for multiple previous versions
- Immutable History: Previous versions cannot be modified
Content Addressing
IPFS Integration
- All content is stored using IPFS Content Identifiers (CIDs)
- Each file and directory has a unique cryptographic hash
- Content is immutable - changes create new CIDs
- Directory structures are represented as IPFS DAGs
CAR File Format
- Content is distributed as CAR (Content Addressable aRchive) files
- CAR files contain all blocks needed to reconstruct the file system
- Efficient for uploading/downloading entire repositories
- Includes only necessary blocks, excluding previous versions
Metadata and Configuration
Page Metadata
- Stored in markdown frontmatter (YAML format)
- Includes title, description, and possible future extensions
- Automatically parsed and used in HTML generation
Site Configuration
manifest.webmanifest
: Web app configuration_redirects
: URL redirection rules_template.html
: Master template for all pages
Special Directories
_prev/
: Version history_assets/
: Various assets needed by the application_css/
: Default styling for SimplePage_js/
: Application javascript code
Developer CLI Tool
A command-line interface for advanced users and developers:
Features
- Static Webapp Support: Host any static web application on ENS domains
- Direct Publishing: Deploy content directly from local directories
- CAR File Generation: Creates efficient IPFS uploads
- Subscription Management: Check and manage domain subscriptions
Usage Example
# Publish a static website
npx @simplepg/cli publish myapp.eth ./dist
# Check subscription status
npx @simplepg/cli info myapp.eth