Cursor rule
.cursor/rules/mpa-strict-rules.mdcMPA-First Development Mandate - Strict rules for building performant, resilient Multi-Page Applications
Cursor rules
Quality
66/100
Scores the file, not the repository.Length
1,828 words
18 headings · 12 code blocksRepository
10
— · pushed 241 days agoLast changed
3 days ago
First indexed 3 days ago.1234567891011# AI Coding Agent Guidelines: The MPA-First Mandate1213## Introduction: Why We Build This Way1415For over a decade, web development has trended towards complex, JavaScript-heavy Single-Page Applications (SPAs). The promise was a slick, "app-like" user experience. The reality, in most cases, has been bloated, fragile, and over-engineered websites that are slow to load, difficult to maintain, and hostile to users and search engines.1617This document outlines a return to a more resilient, performant, and durable web. We are intentionally choosing a **Multi-Page Application (MPA)** architecture. The guiding principle is to **use the platform**. We build upon the native strengths of HTML, CSS, and the browser itself, which have evolved significantly. Modern features like CSS View Transitions and Speculation Rules now provide the fluid user experience that once required megabytes of JavaScript, but without the performance penalty.1819We are choosing simplicity, speed, and maintainability over unnecessary complexity. We build for users and outcomes, not for developer experience (DX) or architectural novelty. JavaScript is a powerful tool for progressive enhancement, not the default foundation for every page.2021---2223## PRIME DIRECTIVE: MPA-Only Architecture2425- You **MUST** create server-rendered, multi-page websites (MPAs). Each distinct page or view must be its own unique file (e.g., `.html`, `.php`) served at a distinct URL.26- Navigation **MUST** use standard anchor links (`<a href="...">`) that trigger a full page navigation. The browser will handle the request, and the server will respond with a new HTML document.27- The goal is to produce sites that are fundamentally functional with zero client-side JavaScript. JS should only be used to enhance, not to enable, core functionality.2829### 🚫 BANNED TECHNOLOGIES & PATTERNS3031- **DO NOT** use or reference any Single-Page Application (SPA) frameworks, libraries, or patterns.32 - This includes, but is not limited to: React, Angular, Vue, Svelte, Next.js, Nuxt.js.33- **DO NOT** use JSX, TSX, TypeScript-based routing, or any form of client-side routing.3435---3637## Guiding Complex Changes3839When approaching a complex change or refactoring a large file, prioritize clarity and communication:40411. **Outline a Plan:** Before diving in, briefly describe your approach. What is the goal? Which parts of the code will you touch?422. **Communicate as You Go:** Explain your changes in small, logical steps. This allows for feedback and course correction without rigid, multi-step approval gates.433. **Focus on Conceptual Changes:** Group your edits logically. For example, a commit might be "Refactor user authentication logic," not "Change 15 different files."4445---4647## Folder Structure4849This structure promotes a clean separation of concerns and follows the Model-View-Controller (MVC) architectural pattern:5051```52project-root/53├── public/ # Web root, all publicly accessible files54│ ├── assets/55│ │ ├── css/56│ │ ├── js/57│ │ ├── images/58│ │ ├── fonts/59│ └── index.php # Or index.html60├── src/ # Application source code61│ ├── controllers/ # Handles user requests62│ ├── models/ # Business logic and data interaction63│ ├── views/ # HTML templates/partials64│ └── utilities/ # Helper functions, etc.65├── vendor/ # Composer dependencies66├── config/ # Configuration files67├── tests/ # Automated tests68└── docs/ # Project documentation69```7071---7273## SEO Best Practices: A Top Priority7475Excellent SEO is not an afterthought; it's a direct result of building a clean, semantic, and performant MPA.7677### 1. The Head is Everything7879Ensure every page has a comprehensive and valid `<head>` section:8081**Example: Detailed `<head>` for a Blog Post**8283```html84<!DOCTYPE html>85<html lang="en">86<head>87 <meta charset="UTF-8">88 <meta name="viewport" content="width=device-width, initial-scale=1.0">89 <title>It's Time for Modern CSS to Kill the SPA | My Awesome Blog</title>90 <meta name="description" content="Native CSS transitions have quietly killed the strongest argument for client-side routing. Learn how to build faster, simpler websites.">9192 <link rel="canonical" href="https://www.example.com/blog/css-kills-spa">9394 <meta property="og:title" content="It's Time for Modern CSS to Kill the SPA">95 <meta property="og:description" content="Native CSS transitions have quietly killed the strongest argument for client-side routing. Learn how to build faster, simpler websites.">96 <meta property="og:type" content="article">97 <meta property="og:url" content="https://www.example.com/blog/css-kills-spa">98 <meta property="og:image" content="https://www.example.com/assets/images/blog/og-image-css-spa.jpg">99 <meta property="og:image:width" content="1200">100 <meta property="og:image:height" content="630">101 <meta property="og:site_name" content="My Awesome Blog">102103 <meta name="twitter:card" content="summary_large_image">104 <meta name="twitter:site" content="@MyAwesomeBlog">105 <meta name="twitter:title" content="It's Time for Modern CSS to Kill the SPA">106 <meta name="twitter:description" content="Native CSS transitions have quietly killed the strongest argument for client-side routing.">107 <meta name="twitter:image" content="https://www.example.com/assets/images/blog/twitter-card-css-spa.jpg">108</head>109<body>110</body>111</html>112```113114### 2. Structured Data with JSON-LD115116Embed structured data to help search engines understand your content. This is critical for rich results (reviews, recipes, events, etc.):117118**Example: JSON-LD for an Article**119120```html121<script type="application/ld+json">122{123 "@context": "https://schema.org",124 "@type": "BlogPosting",125 "headline": "It's Time for Modern CSS to Kill the SPA",126 "datePublished": "2025-07-24T09:00:00Z",127 "dateModified": "2025-07-25T10:30:00Z",128 "author": {129 "@type": "Person",130 "name": "Jono Alderson",131 "url": "https://www.example.com/authors/jono-alderson"132 },133 "image": {134 "@type": "ImageObject",135 "url": "https://www.example.com/assets/images/blog/og-image-css-spa.jpg",136 "width": 1200,137 "height": 630138 },139 "publisher": {140 "@type": "Organization",141 "name": "My Awesome Blog",142 "logo": {143 "@type": "ImageObject",144 "url": "https://www.example.com/assets/images/logo.png",145 "width": 600,146 "height": 60147 }148 },149 "description": "Native CSS transitions have quietly killed the strongest argument for client-side routing. Learn how to build faster, simpler websites.",150 "mainEntityOfPage": {151 "@type": "WebPage",152 "@id": "https://www.example.com/blog/css-kills-spa"153 }154}155</script>156```157158---159160## HTML Requirements161162- **Semantic HTML is Mandatory:** Use `<header>`, `<nav>`, `<main>`, `<article>`, `<section>`, `<footer>`, `<aside>`, etc., correctly. This is foundational for accessibility and SEO.163- **Accessibility (A11Y):** Adhere to WCAG 2.1 Level AA.164 - All form inputs must have a corresponding `<label>`.165 - Provide descriptive alt text for all meaningful images (`alt=""` for decorative ones).166 - Use ARIA roles where semantic HTML isn't sufficient.167- **Responsive Images:** Use `srcset` and `sizes` to serve appropriately sized images. Use modern formats like WebP or AVIF with a fallback.168- **Prerender for Instant Navigation:** Use Speculation Rules to make navigation feel instantaneous.169170**Example: Instant Prerendering with Speculation Rules**171172```html173<script type="speculationrules">174{175 "prerender": [{176 "source": "document",177 "where": {178 "href_matches": "/*"179 },180 "eagerness": "moderate"181 }]182}183</script>184```185186---187188## CSS Requirements189190- **Embrace Modern CSS:** Use Flexbox and Grid for layouts. Use Custom Properties for theming and maintainability.191- **Native View Transitions:** This is our primary tool for creating "app-like" fluid navigation without JavaScript.192193**Example: Cross-Page Fade Transition**194195```css196/* Add to every page for a simple, elegant fade */197@view-transition {198 navigation: auto;199}200201::view-transition-old(root),202::view-transition-new(root) {203 animation: fade-out 0.3s ease-out both;204}205206@keyframes fade-out {207 from { opacity: 1; }208 to { opacity: 0; }209}210```211212---213214## PHP Requirements215216- **Modern & Strict:** Target PHP 8.1+. Always start files with `declare(strict_types=1);`.217- **Clean Code:** Adhere to a standard like PSR-12. Prefer composition over inheritance. Use exceptions for error handling.218- **Leverage Modern Features:** Use constructor property promotion, `match` expressions, enums, and the nullsafe operator.219220**Example: Modern PHP Class**221222```php223<?php224declare(strict_types=1);225226namespace App\Models;227228use App\Db;229use App\Enums\UserStatus;230231readonly class User232{233 public function __construct(234 private Db $db,235 public int $id,236 public string $name,237 public UserStatus $status = UserStatus::Active,238 ) {}239240 public function getProfileUrl(): string241 {242 return '/users/' . $this->id;243 }244}245```246247---248249## JavaScript Requirements (Progressive Enhancement Only)250251- **Vanilla JS ONLY:** NO libraries or frameworks (including jQuery).252- **Unobtrusive:** Assume JS might fail or be disabled. Core functionality must not depend on it.253- **Modern & Safe:** Use ES2020+ features like `async/await`, optional chaining (`?.`), and `const`/`let`. Handle errors gracefully with `try/catch`.254255**Example: Unobtrusive JS for a Toggle Button**256257HTML (works without JS):258259```html260<a href="?show_details=true#details" class="toggle-link">Show Details</a>261```262263JavaScript (enhances the experience if it runs):264265```javascript266document.querySelector('.toggle-link')?.addEventListener('click', async (event) => {267 event.preventDefault(); // Prevent default navigation268 const details = document.querySelector('#details');269 if (details) {270 const isHidden = details.hidden;271 // Use a View Transition for a smooth reveal if available272 if (document.startViewTransition) {273 document.startViewTransition(() => {274 details.hidden = !isHidden;275 event.target.textContent = isHidden ? 'Hide Details' : 'Show Details';276 });277 } else {278 // Fallback for older browsers279 details.hidden = !isHidden;280 event.target.textContent = isHidden ? 'Hide Details' : 'Show Details';281 }282 }283});284```285286---287288## General Considerations289290### 1. Database291292Choose a database appropriate for the project's needs. SQLite is excellent for many sites due to its simplicity. For high-concurrency writes, consider MySQL or PostgreSQL. Regardless of the choice, always use **parameterized queries** to prevent SQL injection.293294**Example: Secure Parameterized Query in PHP (PDO)**295296```php297<?php298// Unsafe query (vulnerable to SQL injection)299// $statement = $pdo->query("SELECT * FROM users WHERE id = " . $_GET['id']);300301// Safe, parameterized query302$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');303$stmt->execute(['id' => $_GET['id']]);304$user = $stmt->fetch();305```306307### 2. Documentation308309Consistent documentation is crucial. Follow established standards like PHPDoc for PHP and JSDoc for JavaScript to describe what a function does, its parameters, and what it returns:310311**Example: Documenting a PHP Function (PHPDoc style)**312313```php314<?php315/**316 * Retrieves a user from the database by their ID.317 *318 * @param PDO $pdo The database connection object.319 * @param int $userId The ID of the user to fetch.320 * @return array|false The user data as an associative array, or false if not found.321 * @throws InvalidArgumentException if the user ID is not a positive integer.322 */323function findUserById(PDO $pdo, int $userId): array|false324{325 if ($userId <= 0) {326 throw new InvalidArgumentException('User ID must be a positive integer.');327 }328 $stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');329 $stmt->execute(['id' => $userId]);330 return $stmt->fetch(PDO::FETCH_ASSOC);331}332```333334### 3. Security335336Security is a prerequisite, not a feature:337338- **Sanitize Inputs, Escape Outputs:** Never trust user-provided data. Sanitize it on input and always escape it for the specific context of its output (e.g., HTML, SQL).339- **CSRF Protection:** All state-changing requests (e.g., forms submitted via POST) must be protected against Cross-Site Request Forgery.340- **Content Security Policy (CSP):** Implement a strict CSP to mitigate the risk of XSS and data injection attacks.341342**Example: Basic CSRF Token Implementation**343344```php345<?php346// In the script that displays the form:347session_start();348if (empty($_SESSION['csrf_token'])) {349 $_SESSION['csrf_token'] = bin2hex(random_bytes(32));350}351?>352<form action="/submit" method="post">353 <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">354 <button type="submit">Submit</button>355</form>356357<?php358// In the /submit script that processes the form:359session_start();360if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {361 // Token is invalid or missing, reject the request.362 http_response_code(403);363 die('CSRF validation failed.');364}365// Proceed with processing the form...366// Note: Do NOT unset the token here. Reusing the same token for the367// user's session is more robust and prevents issues with multiple368// tabs or the back button.369?>370```371372**Example: Setting a Strict Content Security Policy Header in PHP**373374```php375<?php376// This is a strict policy. It requires that all CSS and JavaScript377// be loaded from external files hosted on the same domain.378// No inline styles or scripts are allowed.379$csp = "default-src 'self'; " .380 "img-src 'self' https://images.example.com; " .381 "style-src 'self'; " .382 "script-src 'self'; " .383 "form-action 'self'; " .384 "frame-ancestors 'none'; " .385 "object-src 'none'; " .386 "base-uri 'self';";387388header("Content-Security-Policy: " . $csp);389?>390```391392---393394## A Living Document395396These guidelines are a starting point. The web platform evolves, and so should our practices. The core philosophy—simplicity, performance, and leveraging the native power of the web—remains constant. We champion this approach to build a better, faster, and more accessible web for everyone.397
Also in RealistSec/mpa-first-guidelines
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| RealistSec/mpa-first-guidelines.github/copilot-instructions.md · 10 | Copilot instructions | styledependenciesuido-not+2 | 59/100 | 3 days ago | |
| RealistSec/mpa-first-guidelines.cursor/rules/mpa-relaxed-rules.mdc · 10 | Cursor rules | stylearchsecurityui+2 | 77/100 | 3 days ago |
