High-Performance Server-Side Rendered (SSR) Publishing Engine & Content Management System — An end-to-end dynamic blogging platform engineered with Python, Flask, SQLAlchemy, and Supabase Cloud Storage.
- 🌟 Overview & Value Proposition
- ⚡ Architecture Comparison: SSR vs. Single Page Apps (SPA)
- ✨ Key Features
- 🏛️ System Architecture
- 🔄 Core Execution Workflows
- 📂 Directory Structure
- 🛠️ Technology Stack
- 🚀 Getting Started & Local Setup
- ⚙️ Environment Configuration
- 🔌 Routes & Interface Reference
- 💡 Usage Guide & Typical Workflows
- 📸 Visual UI & Styling Architecture
- 🧪 Testing & Verification
- 🚢 Deployment Guide
- 🛡️ Security & Operational Considerations
- 💼 Engineering Highlights & Design Decisions
- 🤝 Contributing
- 👤 Author & License
In the modern web landscape, many content platforms rely on bloated Single Page Application (SPA) architectures that require downloading megabytes of client-side JavaScript before rendering a single word. This leads to sluggish First Contentful Paint (FCP), brittle search engine indexing, and fragile dependency chains.
Coding Thunder solves this problem by combining the speed, resilience, and crawlability of pure Server-Side Rendering (SSR) with modern cloud primitives:
- Instantaneous Page Delivery: HTML is hydrated server-side via Flask and Jinja2 in single-digit milliseconds, delivering semantic, pre-rendered markup ready for instant viewing on desktop and mobile browsers.
- Cloud-Native Media Ingestion: Direct integration with Supabase Storage isolates media assets from local container filesystems, preventing disk bloat and ensuring high-availability asset streaming via global CDN URLs.
- Decoupled Asynchronous Lead Pipeline: Visitor contact submissions are persisted locally to transactional database storage and dispatched via HTTP webhooks to an external Google Apps Script automation service, avoiding SMTP port blocks and rate limits.
- Dual-Database Flexibility: Seamlessly run with local MySQL during development and switch to cloud-hosted PostgreSQL (Supabase) in production through unified SQLAlchemy ORM models.
| Dimension | ⚡ Coding Thunder (Flask SSR) | 🐢 Client-Side Rendering (CSR / SPA) | 🐘 Heavy Monolithic CMS (e.g. WordPress) |
|---|---|---|---|
| First Contentful Paint (FCP) | < 150ms — Direct server-rendered HTML | 1.5s – 4.5s — Blocked waiting for JS bundles | Variable (300ms – 2.0s) depending on plugin bloat |
| SEO & Crawler Indexing | 100% Native — Zero headless rendering needed | Requires dynamic rendering or complex SSR workarounds | Native, but prone to bloated DOM hierarchies |
| Client Memory Footprint | Zero JS execution overhead (~1.2 KB custom JS) | High RAM & CPU consumption on low-end devices | Moderate to high due to tracking scripts and plugins |
| Media Persistence | Cloud Object Storage (Supabase CDN) | Often requires separate S3 microservices | Local disk storage prone to container wipedowns |
| Operational Complexity | Single WSGI process, minimal dependencies | Multi-repo builds, hydration mismatches, API versioning | PHP runtime, Apache/Nginx, caching plugins, heavy DB |
- Semantic Article Hydration: Renders comprehensive blog posts with custom titles, subheadings, and authored timestamps directly from the relational database.
- Deterministic Pagination Engine: Configurable post density per page (
no_of_posts) with mathematical boundary calculations and bidirectional navigation links (/?page=N). - Dynamic Mastheads & Branding: Header imagery and global styling adapt dynamically to environment configuration with automatic fallback to local assets.
- Session-Guarded Access: Secure admin authentication via
/dashboardverifying credentials against environment-isolated variables (admin_user,admin_password). - Unified Post Editor: Single dual-mode route (
/edit/<sno>) capable of creating new entries (sno=0) and modifying existing records (sno>0). - Cascade Deletion: Immediate removal of obsolete articles with session authorization verification (
/delete/<sno>).
- Inline Image Processing: Direct multipart file upload via the post editor (
/edit/<sno>) with MIME-type validation (image/*). - Collision-Resistant Naming: Generates timestamped safe filenames (
YYYYMMDD_HHMMSS_ffffff_filename.ext) using Werkzeug'ssecure_filename. - Dedicated Asset Uploader: Standalone
/uploaderendpoint that queries bucket contents viasupabase.storage.from_("Images").list(), uploads binaries, and pre-populates the new post workflow via session tracking (session['uploaded_image_url']).
- Dual-Layer Ingestion: Form submissions are immediately committed to the
Contactsrelational table with atomic transaction rollback on failure. - Serverless Webhook Forwarding: Dispatches structured payload (
name,email,phone,message,token) to a Google Apps Script web endpoint viarequests.postwith a 30-second timeout. - Reactive UI Feedback: Asynchronous client-side alert indicators that render success or failure notices based on template response context.
The architecture of Coding Thunder cleanly separates the client layer, server-side controller layer, and cloud persistence services:
flowchart TD
Client["Web Browser / Client"]
Admin["Admin User"]
Crawler["Search Engine Crawler"]
subgraph Server ["Flask Application Server"]
Router["Request Router"]
AuthGuard{"Session Auth Guard"}
Jinja["Jinja2 SSR Engine (Bootstrap 5)"]
end
subgraph Storage ["Data & Storage Layer"]
SQLAlchemy["SQLAlchemy ORM"]
Database[("Relational Database (MySQL / Supabase Postgres)")]
CloudBucket[("Supabase Storage ('Images' Bucket)")]
end
Webhook["Google Apps Script (Email Webhook)"]
Client -->|HTTP GET| Router
Crawler -->|Crawls HTML| Router
Admin -->|Admin Actions| Router
Router -->|Public Routes| Jinja
Router -->|Protected Routes| AuthGuard
AuthGuard -->|Authorized| Jinja
AuthGuard -->|Unauthorized| Router
Jinja -->|Query Posts & Contacts| SQLAlchemy
SQLAlchemy --> Database
Router -->|Upload Media| CloudBucket
CloudBucket -.->|Public CDN URL| Router
Router -->|Dispatch Contact Form| Webhook
- Client Layer: Standard browsers, authenticated admins, and web crawlers consume fully hydrated semantic HTML documents. No client-side compilation or heavy runtime is required.
- Flask Application Engine: Powered by Flask 3.x and WSGI (Gunicorn in production), managing URL routing, request parsing, session storage, and Jinja2 template rendering.
- Session Auth Guard: Intercepts mutations on
/edit,/uploader, and/deleteroutes to enforce strict credential-backed session authorization. - Data Persistence (SQLAlchemy): Provides vendor-agnostic object-relational mapping. Connects dynamically to MySQL for local development or PostgreSQL on Supabase in production.
- Supabase Cloud Storage: Stores image assets in an external cloud bucket, generating permanent, secure CDN URLs referenced by the
Postsdatabase model. - External Email Webhook: Handles lead notifications via Google Apps Script without coupling the web server to SMTP daemons.
This workflow illustrates how an administrator writes a blog post, uploads a header image to Supabase, and publishes it to the database:
sequenceDiagram
autonumber
actor Admin as Admin User
participant Router as Flask Router (/edit/<sno>)
participant Storage as Supabase Storage
participant DB as PostgreSQL / MySQL
participant Jinja as Jinja2 Template Engine
Admin->>Router: POST /edit/0 (Form Data + Image File)
Note over Router: Validate session['user'] == ADMIN_USER
Note over Router: Validate MIME type (image/*) & sanitize filename
Router->>Storage: upload(YYYYMMDD_HHMMSS_filename, binary_bytes)
Storage-->>Router: Confirm upload success
Router->>Storage: get_public_url(filename)
Storage-->>Router: Return Public CDN URL
Router->>DB: INSERT INTO Posts (title, slug, content, img_file, tagline, date)
DB-->>Router: Commit Transaction (sno created)
Router-->>Admin: Redirect to /dashboard
actor Visitor as Public Reader
Visitor->>Router: GET /post/<slug>
Router->>DB: SELECT * FROM Posts WHERE slug = <slug>
DB-->>Router: Return Post Record
Router->>Jinja: render_template('post.html', post=post)
Jinja-->>Visitor: Deliver fully hydrated HTML with CDN image
This sequence shows the resilient dual-stage persistence and notification mechanism for visitor inquiries:
sequenceDiagram
autonumber
actor Visitor as Website Visitor
participant Router as Flask Router (/contact)
participant DB as Contacts Table
participant Webhook as Google Apps Script Webhook
participant UI as Contact Page Alert UI
Visitor->>Router: POST /contact (name, email, phone, message)
Note over Router: Validate required fields (name, email, message)
critical Database Persistence
Router->>DB: INSERT INTO Contacts (name, email, phone_num, msg, date)
DB-->>Router: Commit OK
option Database Exception
Router->>DB: db.session.rollback()
Router-->>UI: Return status="error" ("Message could not be saved")
end
critical Webhook Dispatch
Router->>Webhook: POST json={token, name, email, phone, message} (timeout=30s)
Webhook-->>Router: Return {success: true}
Router-->>UI: Return status="success" ("Your message has been sent successfully!")
option Webhook Failure / Timeout
Router-->>UI: Return status="error" ("Message saved, but email dispatch failed")
end
UI-->>Visitor: Display real-time alert banner
webproject/
├── .env.example # Environment configuration template
├── .gitignore # Version control ignore definitions (venv, cache, local tests)
├── main.py # Central application entry point: routes, models, storage
├── requirements.txt # Python dependency specifications
├── static/ # Static assets delivered directly to clients
│ ├── assets/
│ │ ├── favicon.ico # Website browser icon
│ │ └── img/
│ │ └── post_back.jpg # Fallback masthead background image
│ ├── css/
│ │ ├── signin.css # Layout styling for the admin sign-in portal
│ │ └── styles.css # Clean Blog theme stylesheet (Bootstrap 5)
│ └── js/
│ └── scripts.js # Responsive mobile navigation & scroll-reactive header logic
└── templates/ # Jinja2 server-side rendering HTML templates
├── about.html # Static biography and project information page
├── contact.html # Contact form with validation and dynamic status alerts
├── dashboard.html # Protected administrative control panel (post table & uploader)
├── edit.html # Blog post authoring form (Create/Update with file attachment)
├── index.html # Public homepage listing blog posts with dynamic pagination
├── layout.html # Master boilerplate template (navigation, footer, font imports)
├── login.html # Administrator authentication form
└── post.html # Full article reading interface with masthead hero
- Python 3.10+: Primary application runtime.
- Flask 3.x: WSGI microframework for routing and SSR rendering.
- Werkzeug: Filename sanitization (
secure_filename). - python-dotenv: 12-Factor environment variable management.
- Flask-SQLAlchemy: Object-relational mapping and connection management.
- PostgreSQL (Supabase): Production relational database.
- MySQL (mysqlclient): Local development database.
- psycopg2-binary & psycopg: PostgreSQL drivers for Python.
- Supabase Python SDK (
supabase): Cloud Object Storage integration for media assets.
- Jinja2: Server-side template hydration.
- Bootstrap 5.2.3: Responsive CSS components.
- Font Awesome 6.3.0: Vector icons.
- Requests: Asynchronous webhook dispatch for contact inquiries.
- Gunicorn: Multi-worker UNIX WSGI HTTP server.
- Python 3.10+ installed
- Git installed
- A running relational database (local MySQL or a Supabase PostgreSQL instance)
- A Supabase project with a public storage bucket named
Images
Follow the unified terminal steps below. Note the commented alternative for your specific operating system:
# 1. Clone the repository
git clone https://github.com/varkush123/webproject.git
cd webproject
# 2. Create a virtual environment
python -m venv venv
# 3. Activate the virtual environment
# --- On Windows (PowerShell) ---
.\venv\Scripts\Activate.ps1
# --- On Linux / macOS ---
source venv/bin/activate
# 4. Install dependencies
python -m pip install --upgrade pip
pip install -r requirements.txt
# 5. Copy environment template
# --- On Windows (PowerShell) ---
Copy-Item .env.example .env
# --- On Linux / macOS ---
cp .env.example .env
# 6. Configure your variables in .env (see section below)
# Open .env with your editor of choice (e.g. notepad, code, nano, or vim)
# 7. Start the development server
python main.pyThe application will be accessible at:
http://127.0.0.1:5000/
All environment variables, requirement statuses, and default fallback values are documented directly inside .env.example.
To configure your environment:
- Copy
.env.exampleto.env. - Review the inline explanations inside
.envto configure your database connection, admin credentials, and Supabase storage keys.
Important
Database Mode (local_server): Set local_server=True for local development against MySQL (uses local_uri and maps post image column to "img_file"). Set local_server=False in production when connecting to Supabase PostgreSQL (uses prod_uri and maps post image column to "image_url").
GET /: Homepage with paginated blog post cards (?page=N).GET /post/<post_slug>: Full article reading view querying by URL slug.GET /about: Biographical page renderingabout_text.GET, POST /contact: Contact form rendering (GET) and lead submission with webhook dispatch (POST).GET /hello: Lightweight health check endpoint (200 OK).
GET, POST /dashboard: Admin authentication form (POST) and post management table (GET, session-guarded).GET, POST /edit/<sno>: Create a new post (sno=0) or edit existing article (sno>0) with file upload to Supabase.POST /uploader: Quick file upload to Supabase"Images"bucket with redirect to/edit/0.GET, POST /delete/<sno>: Removes post by ID with admin session verification.GET /logout: Clears admin session and redirects to/dashboard.
- Navigate to
/dashboard. - Enter the credentials configured in
admin_userandadmin_password. - View the management catalog with Edit/Delete controls and upload tools.
- Click Add a new post (
/edit/0). - Fill in the Title, Tagline, Slug (e.g.,
getting-started-with-flask), and Content. - Select an image file under Upload new image.
- Click Submit — the binary is uploaded to Supabase Storage, the CDN URL is attached, and the record is stored in the database.
- Clean Blog Design System: Built on Bootstrap 5 (
static/css/styles.css) with Google Fonts (Lora and Open Sans). - Adaptive Sticky Navigation:
static/js/scripts.jscalculates scroll position: scrolling down hides the bar; scrolling up reveals a fixed navigation bar with background blur. - Fallback Imagery: Defaults to local asset
static/assets/img/post_back.jpgwhenever cloud hero images are omitted.
-
Endpoint Health Check:
curl -I http://127.0.0.1:5000/hello # Expected: HTTP/1.1 200 OK -
Database & Storage Connectivity: On application startup (
python main.py),ping_supabase()executes in the entry point hook to confirm database and storage bucket accessibility.
gunicorn -w 4 -b 0.0.0.0:5000 main:app- Link your GitHub repository.
- Build command:
pip install -r requirements.txt. - Start command:
gunicorn main:app. - Add environment variables from
.env.example, settinglocal_server=Falseto connect to production PostgreSQL.
- Secret Decoupling: Credentials and database URIs remain in
.envand are never committed to version control. - File Sanitization: Uploaded filenames are sanitized through Werkzeug's
secure_filename. - Session Protection: Flask cookies are signed using
FLASK_SECRET_KEY. - Storage Cleanup: Deleting a post removes the database record; deleting remote assets directly from the Supabase bucket can be performed via the Supabase dashboard.
- SSR Performance: Server-side hydration renders pages with zero client-side JavaScript bundle download delays, achieving fast initial load times and seamless crawler indexing.
- Cloud Storage Offloading: Storing uploaded images in Supabase Storage instead of local container filesystems ensures zero disk bloat and persistent assets across container redeploys.
- Decoupled Webhook Dispatch: Delegating contact emails to a Google Apps Script webhook eliminates SMTP port restrictions common to cloud hosting providers.
- Fork the repository (
https://github.com/varkush123/webproject). - Create your feature branch (
git checkout -b feature/AmazingFeature). - Commit your changes (
git commit -m 'Add some AmazingFeature'). - Push to the branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
- Varsha Kushwaha (@varkush123) — Primary Maintainer & Developer
- Email: kushwahavarsha270@gmail.com
- Repository: varkush123/webproject
This project is open-source software published under the MIT License.