Skip to main content
Academic Full-Stack Project Verified Public RepositoryFoundational Engineering Capstone

Blogopedia: Relational Modeling & Role-Based Publishing Platform

A full-stack publication system developed during undergraduate coursework to explore relational schema normalization, session-based authentication lifecycles, decorator-driven authorization, and server-side Jinja2 template rendering with Flask and SQLAlchemy.

ClassificationAcademic Capstone
Backend StackPython 3.10+ · Flask
ORM & DatabaseSQLAlchemy · SQLite/PG
Security LayerFlask-Login · Werkzeug
Source Repository WSGI Serverless Configured (Vercel)
Blogopedia Full-Stack Relational Publishing Platform Interface
01 / Academic Context & Motivation

Understanding Server-Side Web Fundamentals from First Principles

In contemporary frontend-heavy ecosystems, developers frequently rely on abstracted Backend-as-a-Service (BaaS) platforms without deeply understanding how session cookies, cryptographic salt hashing, or relational foreign key cascades operate under the hood.

Blogopedia was developed as an academic capstone to master these core backend mechanics from scratch:

  • Relational Integrity & Foreign Keys: Defining parent-child entity constraints across users, blog posts, and nested comments.
  • Session Authentication & Cryptographic Hashing: Implementing salted PBKDF2 hashing, secure cookie serialization, and session restoration via Flask-Login.
  • Form Validation & CSRF Mitigation: Validating client input on the server and binding cryptographic CSRF tokens to every mutating POST request.
  • Route-Level Access Control: Constructing custom Python function decorators to enforce role hierarchies (e.g. distinguishing post authors from system administrators).
02 / Relational Schema Architecture

Normalized SQLAlchemy Relational Schema

The database model establishes strict referential integrity across three core entities using SQLAlchemy ORM: User, BlogPost, and Comment.

Table: usersParent Entity
  • id: Integer (PK)
  • email: String(100) (Unique)
  • password: String(250) (Hashed)
  • name: String(100)
  • → posts (1:M relationship)
  • → comments (1:M relationship)
Table: blog_postsContent Entity
  • id: Integer (PK)
  • author_id: FK → users.id
  • title: String(250) (Unique)
  • subtitle: String(250)
  • date: String(250)
  • body: Text (CKEditor HTML)
  • → comments (1:M relationship)
Table: commentsChild Entity
  • id: Integer (PK)
  • author_id: FK → users.id
  • post_id: FK → blog_posts.id
  • text: Text (Sanitized Body)
  • Both FKs enforce cascading referential integrity.
Relational Entity-Relationship Diagram (ERD)
3NF Normalized (SQLAlchemy ORM)
Foreign Key Cascades & Cardinality
┌───────────────────────────┐
│           User            │
├───────────────────────────┤
│ id (PK)                   │
│ email (Unique)            │
│ password (PBKDF2 Hashed)  │
│ name                      │
└─────────────┬─────────────┘
              │ 1
              │
              │ has many
              ├──────────────────────────────────────────┐
              │ M                                        │ M
              ▼                                          ▼
┌───────────────────────────┐              ┌───────────────────────────┐
│         BlogPost          │              │          Comment          │
├───────────────────────────┤              ├───────────────────────────┤
│ id (PK)                   │              │ id (PK)                   │
│ author_id (FK -> User.id) │ 1            │ author_id (FK -> User.id) │
│ title                     │──has many───>│ post_id   (FK -> Post.id) │
│ subtitle / date / body    │            M │ text                      │
└───────────────────────────┘              └───────────────────────────┘
03 / Authentication & Authorization Mechanics

PBKDF2 Password Hashing & Custom Admin Decorators

Password Storage & Verification

Passwords are never stored in plaintext. Utilizing Werkzeug's security suite, user credentials pass through generate_password_hash(method='pbkdf2:sha256', salt_length=8). During login, check_password_hash verifies user input against stored salt-hash pairs.

The @admin_only Route Decorator

Rather than sprinkling imperative role checks across route handlers, an idiomatic Python decorator (@admin_only) inspects current_user.id == 1. If an unprivileged user attempts to access post creation, edit, or delete endpoints, the decorator intercepts execution and issues an immediate 403 Forbidden.

CSRF Protection with Flask-WTF

Every client form (registration, login, post editing, comment submission) is modeled using WTForms classes. Flask-WTF injects a cryptographic CSRF token that is validated on form submission, protecting the session cookie from cross-site request forgery attacks.

Serverless WSGI Adaptability

The repository includes a vercel.json deployment configuration using the @vercel/python runtime. It maps the Flask WSGI callable (app in main.py) to serverless function invocations without modifying business logic.

04 / Engineering Decisions & Trade-offs

Architectural Choices for a Coursework Capstone

When evaluating Blogopedia within an engineering portfolio, it is vital to assess the intentional choices made during its implementation:

1. Server-Side Jinja2 Rendering vs. Decoupled SPA:

SSR eliminated state synchronization issues, simplified authentication cookie handling, and delivered instantaneous page loads with zero JavaScript bundle overhead.

2. SQLAlchemy ORM vs. Raw SQL:

Abstracted database interactions allowed seamless switching between SQLite for zero-config local development and PostgreSQL for production environments via environment variables.

3. Client Gravatar Avatar Integration:

Instead of maintaining file upload endpoints and object storage buckets, MD5-hashed email addresses query Gravatar to display author avatars dynamically.

05 / Honest Academic Scope Limitations

Limitations of the Coursework Architecture

While robust for educational purposes, the system reflects the boundaries of a foundational capstone:

1. Hardcoded Administrator ID

The @admin_only decorator inspects current_user.id == 1. In an enterprise system, this would be replaced with dynamic role tables, permission claims, or group memberships.

2. Synchronous Monolithic Execution

All requests, database queries, and template renders run synchronously in a single Python thread per worker. High concurrent write throughput would require connection pooling and async workers.

3. Stateful Session Cookies

User sessions rely on signed client cookies. Horizontal scaling across serverless instances requires configuring a shared secret key and maintaining lightweight session payloads.

4. Client-Side Sanitization Reliance

Blog post bodies rely on CKEditor rich text HTML rendering with Jinja2 safe filters. While effective for personal blogging, multi-tenant public input requires rigorous server-side HTML sanitization (e.g. Bleach).