Skip to main content

Article Management System

A comprehensive Flask-based Content Management System (CMS) designed for managing articles with advanced SEO optimization, admin panel, and automated maintenance features.

Features

Core Functionality

  • Article Management: Create, read, update, and delete articles with server-side rendering
  • SEO Optimization:
    • Meta tag management (title, description, keywords)
    • JSON-LD schema.org structured data
    • Self-canonicalization
    • Descriptive URLs (auto-generated slugs)
    • SEO scoring and recommendations
  • HTML Import: Automatically parse and extract article data from HTML with schema.org markup
  • Admin Panel: Full-featured admin interface for content management
  • Responsive Design: Mobile-friendly horizontal card layout with Bootstrap 5
  • Pagination: Efficiently display 9 articles per page with full pagination support
  • User Authentication: Secure login/registration system with role-based access control
  • Comments System: Integrated with rcomments package for threaded comments
  • Likes/Dislikes: User engagement tracking
  • View Tracking: Automatic view count incrementation
  • Maintenance Automation:
    • Auto-delete articles older than configurable threshold (default: 30 days)
    • Keep maximum number of articles (default: 90)
    • Scheduled daily maintenance with APScheduler
    • Manual maintenance trigger

API Endpoints

Full RESTful API for React/TypeScript frontend integration:

  • GET /api/articles - Paginated article listing
  • GET /api/article/<slug> - Single article details
  • GET /api/article/<slug>/comments - Comments with pagination
  • POST /api/article/<slug>/comment - Add comment (authenticated)
  • DELETE /api/comment/<id> - Delete comment
  • POST /api/article/<slug>/like - Toggle like/dislike
  • GET /api/admin/analytics - Admin analytics dashboard
  • POST /api/admin/maintenance/run - Manual maintenance trigger
  • POST /api/admin/seo/analyze - SEO score analysis

Installation

Prerequisites

  • Python 3.8+
  • PostgreSQL 10+
  • pip (Python package installer)

Basic Installation

# Install from PyPI
pip install article-management-system

Database Setup

  1. Create a PostgreSQL database:
CREATE DATABASE article_management;
CREATE USER article_user WITH PASSWORD 'your-password';
GRANT ALL PRIVILEGES ON DATABASE article_management TO article_user;
  1. Configure environment variables (or use .env file):
export DATABASE_URL=postgresql://article_user:your-password@localhost:5432/article_management
export SECRET_KEY=your-secret-key-here
export SITE_URL=http://yourdomain.com

Initialize Database

# Initialize database and create default admin user
flask init-db

# Or using the CLI command
ams-cli init-db

Configuration

Environment Variables

Variable Default Description
SECRET_KEY (required) Flask secret key for sessions
DATABASE_URL (required) PostgreSQL connection URL
SITE_URL http://localhost:5000 Base URL of your site
SITE_NAME Article Management System Site name for meta tags
ARTICLES_PER_PAGE 9 Number of articles per page
MAINTENANCE_DAYS_THRESHOLD 30 Delete articles older than X days
MAINTENANCE_MAX_ARTICLES 90 Maximum articles to keep
RCOMMENTS_ENABLED true Enable/disable comments

Database Configuration

The system supports flexible database configuration:

Option 1: Full DATABASE_URL

export DATABASE_URL=postgresql://user:password@localhost:5432/dbname

Option 2: Individual components

export DB_USER=myuser
export DB_PASSWORD=mypassword
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=article_management

Option 3: SQLite for development (not recommended for production)

export DATABASE_URL=sqlite:///dev.db

Custom Configuration Class

You can create a custom configuration class to override any setting:

from article_management.config import Config

class CustomConfig(Config):
    ARTICLES_PER_PAGE = 12
    MAINTENANCE_DAYS_THRESHOLD = 60
    SITE_NAME = "My Custom Site"
    SITE_URL = "https://mywebsite.com"
    # Override any other settings

Then pass it to create_app():

from article_management import create_app
app = create_app('my_module.CustomConfig')

Customization Guide

Custom Authentication (OAuth, SSO, etc.)

The system is designed to be extensible. You can replace or extend the authentication system:

1. Create a custom User model (optional):

# models.py
from article_management import db
from flask_login import UserMixin

class CustomUser(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False)
    # Add OAuth fields: oauth_provider, oauth_id, avatar_url, etc.

2. Create custom auth routes:

# routes/custom_auth.py
from flask import Blueprint, redirect, url_for
from flask_login import login_user

custom_auth_bp = Blueprint('custom_auth', __name__)

@custom_auth_bp.route('/login/google')
def google_login():
    # Implement OAuth flow
    # Redirect to Google OAuth endpoint
    pass

@custom_auth_bp.route('/login/google/callback')
def google_callback():
    # Handle OAuth callback
    # Get or create user
    # login_user(user)
    return redirect(url_for('main.index'))

3. Override the auth blueprint:

# In your application factory
def create_app(config_class='article_management.config.Config'):
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    # Don't register the default auth blueprint
    # from article_management.routes.auth import bp as auth_bp
    # app.register_blueprint(auth_bp, url_prefix='/auth')
    
    # Register your custom auth instead
    from myapp.routes.custom_auth import custom_auth_bp
    app.register_blueprint(custom_auth_bp, url_prefix='/auth')

4. Use Flask-Dance or Authlib (recommended for OAuth):

from flask_dance.contrib.google import make_google_blueprint

google_bp = make_google_blueprint(
    client_id=os.getenv('GOOGLE_CLIENT_ID'),
    client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
    scope=["profile", "email"]
)
app.register_blueprint(google_bp, url_prefix="/login")

Custom Templates

Override any template by creating a templates/ directory and setting TEMPLATES_PATH in your config:

class CustomConfig(Config):
    TEMPLATES_PATH = ['/path/to/custom/templates', 'article_management/templates']

Flask will search paths in order, allowing you to override specific templates while keeping the rest.

Custom Static Files

Add custom CSS/JS by placing files in your own static directory:

class CustomConfig(Config):
    STATIC_FOLDER = '/path/to/custom/static'

Or use Flask's send_static_file override for more control.

Adding New Routes

Create a new blueprint in routes/ and register it in your app factory:

# routes/custom.py
from flask import Blueprint, render_template

custom_bp = Blueprint('custom', __name__)

@custom_bp.route('/custom-page')
def custom_page():
    return render_template('custom_page.html')

Then in your app:

from myapp.routes.custom import custom_bp
app.register_blueprint(custom_bp)

Extending the Article Model

Add custom fields to the Article model by creating a migration:

# In a migration file
op.add_column('articles', sa.Column('custom_field', sa.String(500)))

Then update your forms and templates accordingly.

Latest Updates (v1.1.0)

Recent Improvements

  1. Enhanced Reading Experience (March 2026)

    • Fixed article content width alignment with title (now both 800px)
    • Improved typography with serif fonts (Georgia, Times New Roman)
    • Better line-height (1.8) and font size (1.125rem)
    • Text justification with hyphenation for clean flow
    • Enhanced heading hierarchy with visual styling
    • Improved blockquotes, lists, code blocks, and tables
    • Responsive design with mobile-friendly padding
  2. Maintenance Fixes (March 2026)

    • Fixed MaintenanceSettings.run_maintenance() to work regardless of is_enabled flag
    • Manual "Run Maintenance Now" button now always executes
    • Fixed missing MaintenanceSettings import in API routes
    • Removed CSRF exemption issue from API endpoint
  3. Bug Fixes

    • Fixed import errors in API routes
    • Improved error handling in maintenance tasks

API Reference

Authentication Endpoints

  • GET /auth/login - Login page
  • POST /auth/login - Login submission
  • GET /auth/register - Registration page
  • POST /auth/register - Registration submission
  • GET /auth/logout - Logout

Article Endpoints

  • GET /api/articles - Paginated article listing
    • Query params: page, per_page, sort_by (date_published, view_count), order (asc, desc)
  • GET /api/article/<slug> - Single article details with JSON-LD
  • GET /api/article/<slug>/comments - Paginated comments
  • POST /api/article/<slug>/comment - Add comment (requires auth)
  • DELETE /api/comment/<id> - Delete comment (requires admin or comment author)
  • POST /api/article/<slug>/like - Toggle like/dislike (requires auth)

Admin Endpoints

  • GET /api/admin/analytics - Analytics dashboard data
  • POST /api/admin/maintenance/run - Manually trigger maintenance (requires admin)
  • POST /api/admin/seo/analyze - SEO score analysis (requires admin)

CLI Commands

The package includes a powerful CLI:

# Initialize database and create admin
ams-cli init-db

# Create admin user
ams-cli create-admin

# List all articles
ams-cli list-articles

# Delete article by ID
ams-cli delete-article 123

# Run maintenance manually
ams-cli run-maintenance

# Export all articles to JSON
ams-cli export-articles -o backup.json

Project Structure

article_management/
├── __init__.py          # Application factory
├── config.py            # Configuration classes
├── models.py            # Database models
├── seo_utils.py         # SEO utilities
├── html_parser.py       # HTML content parser
├── forms.py             # WTForms definitions
├── decorators.py        # Custom decorators
├── cli.py               # CLI commands
├── routes/
│   ├── __init__.py
│   ├── main.py          # Public routes
│   ├── admin.py         # Admin routes
│   ├── auth.py          # Authentication routes
│   └── api.py           # API endpoints
├── templates/           # Jinja2 templates
│   ├── base.html
│   ├── index.html
│   ├── article_detail.html
│   ├── auth/
│   └── admin/
├── static/
│   ├── css/style.css
│   └── js/main.js
└── wsgi.py              # WSGI entry point

Database Schema

Main Tables

  • users: User accounts with authentication
  • articles: Article content with SEO fields
  • comments: Threaded comments (integrated with rcomments)
  • likes: User likes/dislikes tracking
  • maintenance_settings: Maintenance configuration

Relationships

  • User → Comments (one-to-many)
  • User → Likes (one-to-many)
  • Article → Comments (one-to-many, cascade delete)
  • Article → Likes (one-to-many, cascade delete)
  • Comment → Replies (self-referential)

Deployment

Production Configuration

  1. Environment Setup:
export FLASK_ENV=production
export SECRET_KEY=your-very-secure-secret-key
export DATABASE_URL=postgresql://user:pass@host:5432/db
  1. Use a Production WSGI Server:
# Using Gunicorn
pip install gunicorn
gunicorn -w 4 "article_management.wsgi:app" -b 0.0.0.0:8000
  1. Set up Systemd service (Linux):
[Unit]
Description=Article Management System
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/app
Environment="PATH=/path/to/venv/bin"
EnvironmentFile=/path/to/.env
ExecStart=/path/to/venv/bin/gunicorn -w 4 "article_management.wsgi:app" -b 127.0.0.1:8000

[Install]
WantedBy=multi-user.target
  1. Nginx Configuration:
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Database Migrations

# Initialize migrations
flask db init

# Create migration
flask db migrate -m "Description"

# Apply migration
flask db upgrade

Testing

Run tests with pytest:

pytest tests/

Security Features

  • Password hashing with werkzeug
  • CSRF protection with Flask-WTF
  • SQL injection prevention with SQLAlchemy
  • XSS protection in templates
  • Authentication required for admin routes
  • Role-based access control (admin/user)
  • Secure session management

Extending the Package

Custom Templates

Override templates by creating a templates/ directory and setting TEMPLATES_PATH in config.

Custom Static Files

Add custom CSS/JS by placing files in static/ directory.

Adding New Routes

Create a new blueprint in routes/ and register it in __init__.py.

Troubleshooting

Common Issues

  1. Database connection error:

    • Check PostgreSQL is running
    • Verify credentials in DATABASE_URL
    • Ensure database exists
  2. Template not found:

    • Check Flask can find the templates directory
    • Verify package installation with pip install -e .
  3. Static files not loading:

    • Ensure static/ folder exists
    • Check file permissions
  4. Migrations fail:

    • Ensure database user has proper privileges
    • Check Flask-Migrate is installed

License

MIT License - see LICENSE file for details

Changelog

v1.1.0 (March 2026)

  • Reading Experience: Completely redesigned article layout with consistent 800px width, serif typography, and professional publishing-quality styling
  • Maintenance Fixes: Manual maintenance now works correctly regardless of auto-maintenance setting
  • Bug Fixes: Fixed missing MaintenanceSettings import in API routes
  • Code Quality: Removed problematic CSRF import, improved error handling

v1.0.0

  • Initial release
  • Full CRUD operations for articles
  • SEO optimization with schema.org
  • HTML import with automatic parsing
  • Admin dashboard
  • User authentication
  • Comments system (rcomments integration)
  • Likes/dislikes
  • Maintenance automation
  • REST API for frontend integration
  • Responsive Bootstrap 5 UI

Usage

Running the Application

# Set Flask app
export FLASK_APP=article_management.wsgi:app
export FLASK_ENV=development

# Run development server
flask run

Or using the WSGI file directly:

python -m article_management.wsgi

Admin Panel

Access the admin panel at /admin after logging in with admin credentials.

Features:

  • Dashboard with statistics
  • Create articles by uploading HTML or pasting content
  • Edit existing articles
  • Manage all articles with search/filter
  • Configure maintenance settings
  • Run maintenance manually
  • SEO analysis tool

Creating Articles

Method 1: HTML Upload

Upload an HTML file with schema.org Article markup:

<article itemscope itemtype="https://schema.org/Article">
    <header>
        <h1 itemprop="headline">Article Title</h1>
        <meta itemprop="datePublished" content="2026-03-24">
        <meta itemprop="dateModified" content="2026-03-24">
    </header>

    <div itemprop="articleBody">
        <h2>Section Title</h2>
        <p>Article content...</p>
    </div>
</article>

Method 2: Manual Entry

Fill in all fields manually through the admin form.

Required HTML Structure:

  • <article itemscope itemtype="https://schema.org/Article">
  • <h1 itemprop="headline"> - Article title
  • <meta itemprop="datePublished"> - Publication date
  • <meta itemprop="dateModified"> - Last modified date
  • <div itemprop="articleBody"> - Main content

The system will automatically:

  • Extract title, dates, and excerpt from HTML
  • Generate SEO-friendly slug from title
  • Create JSON-LD schema
  • Set canonical URL (self-canonicalization by default)

SEO Features

The system provides comprehensive SEO optimization:

  1. Meta Tags: Title, description, keywords
  2. JSON-LD Schema: Automatic generation of schema.org Article markup
  3. Canonical URLs: Self-canonicalization or custom URLs
  4. Descriptive Slugs: Auto-generated from title, unique
  5. SEO Scoring: Real-time analysis with recommendations
  6. Open Graph: Automatic OG tags for social sharing
  7. Twitter Cards: Enhanced Twitter sharing

Maintenance Automation

The system automatically cleans up old articles based on your settings:

  • Daily Schedule: Runs every day at 2 AM
  • Deletion Rules:
    1. Delete articles older than MAINTENANCE_DAYS_THRESHOLD
    2. If total articles still exceed MAINTENANCE_MAX_ARTICLES, delete oldest articles
  • Manual Trigger: Run maintenance anytime from admin panel or CLI

API Integration with React/TypeScript

The system provides a complete REST API for frontend integration:

// Example React component
import React, { useEffect, useState } from 'react';
import { Article } from './types';

const ArticleList: React.FC = () => {
  const [articles, setArticles] = useState<Article[]>([]);
  const [page, setPage] = useState(1);

  useEffect(() => {
    fetch(`/api/articles?page=${page}`)
      .then(res => res.json())
      .then(data => setArticles(data.data.articles));
  }, [page]);

  return (
    <div>
      {articles.map(article => (
        <ArticleCard key={article.id} article={article} />
      ))}
    </div>
  );
};

CLI Commands

The package includes a powerful CLI:

# Initialize database and create admin
ams-cli init-db

# Create admin user
ams-cli create-admin

# List all articles
ams-cli list-articles

# Delete article by ID
ams-cli delete-article 123

# Run maintenance manually
ams-cli run-maintenance

# Export all articles to JSON
ams-cli export-articles -o backup.json

Project Structure

article_management/
├── __init__.py          # Application factory
├── config.py            # Configuration classes
├── models.py            # Database models
├── seo_utils.py         # SEO utilities
├── html_parser.py       # HTML content parser
├── forms.py             # WTForms definitions
├── decorators.py        # Custom decorators
├── cli.py               # CLI commands
├── routes/
│   ├── __init__.py
│   ├── main.py          # Public routes
│   ├── admin.py         # Admin routes
│   ├── auth.py          # Authentication routes
│   └── api.py           # API endpoints
├── templates/           # Jinja2 templates
│   ├── base.html
│   ├── index.html
│   ├── article_detail.html
│   ├── auth/
│   └── admin/
├── static/
│   ├── css/style.css
│   └── js/main.js
└── wsgi.py              # WSGI entry point

Database Schema

Main Tables

  • users: User accounts with authentication
  • articles: Article content with SEO fields
  • comments: Threaded comments (integrated with rcomments)
  • likes: User likes/dislikes tracking
  • maintenance_settings: Maintenance configuration

Relationships

  • User → Comments (one-to-many)
  • User → Likes (one-to-many)
  • Article → Comments (one-to-many, cascade delete)
  • Article → Likes (one-to-many, cascade delete)
  • Comment → Replies (self-referential)

Deployment

Production Configuration

  1. Environment Setup:
export FLASK_ENV=production
export SECRET_KEY=your-very-secure-secret-key
export DATABASE_URL=postgresql://user:pass@host:5432/db
  1. Use a Production WSGI Server:
# Using Gunicorn
pip install gunicorn
gunicorn -w 4 "article_management.wsgi:app" -b 0.0.0.0:8000
  1. Set up Systemd service (Linux):
[Unit]
Description=Article Management System
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/app
Environment="PATH=/path/to/venv/bin"
EnvironmentFile=/path/to/.env
ExecStart=/path/to/venv/bin/gunicorn -w 4 "article_management.wsgi:app" -b 127.0.0.1:8000

[Install]
WantedBy=multi-user.target
  1. Nginx Configuration:
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Database Migrations

# Initialize migrations
flask db init

# Create migration
flask db migrate -m "Description"

# Apply migration
flask db upgrade

Testing

Run tests with pytest:

pytest tests/

Security Features

  • Password hashing with werkzeug
  • CSRF protection with Flask-WTF
  • SQL injection prevention with SQLAlchemy
  • XSS protection in templates
  • Authentication required for admin routes
  • Role-based access control (admin/user)
  • Secure session management

Extending the Package

Custom Templates

Override templates by creating a templates/ directory and setting TEMPLATES_PATH in config.

Custom Static Files

Add custom CSS/JS by placing files in static/ directory.

Adding New Routes

Create a new blueprint in routes/ and register it in __init__.py.

Troubleshooting

Common Issues

  1. Database connection error:

    • Check PostgreSQL is running
    • Verify credentials in DATABASE_URL
    • Ensure database exists
  2. Template not found:

    • Check Flask can find the templates directory
    • Verify package installation with pip install -e .
  3. Static files not loading:

    • Ensure static/ folder exists
    • Check file permissions
  4. Migrations fail:

    • Ensure database user has proper privileges
    • Check Flask-Migrate is installed

License

MIT License - see LICENSE file for details

Changelog

v1.0.0

  • Initial release
  • Full CRUD operations for articles
  • SEO optimization with schema.org
  • HTML import with automatic parsing
  • Admin dashboard
  • User authentication
  • Comments system (rcomments integration)
  • Likes/dislikes
  • Maintenance automation
  • REST API for frontend integration
  • Responsive Bootstrap 5 UI
  • CLI tools

Metadata

Release files for article-management-system 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for article-management-system 1.1.1
File Size Uploaded Provenance
article_management_system-1.1.1.tar.gz 57.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for article-management-system 1.1.1
File Interpreter ABI Platform
article_management_system-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 123.4 kB

Release files / article_management_system-1.1.1.tar.gz

Download URL article_management_system-1.1.1.tar.gz
Size 57.7 kB
Tags Source
SHA-256 checksum
How to use checksums
88a2cf659dae97ac33cfbd836e01e92be68695f63743a572aa51be08fe532164
BLAKE2b-256 checksum
How to use checksums
8dbe6d2e0b44fc66d1350e4ec5ca3cbe6726d864ecb817b21e3a35fa93d29ca4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / article_management_system-1.1.1-py3-none-any.whl

Download URL article_management_system-1.1.1-py3-none-any.whl
Size 65.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1e50d8d233978a30184b9809e3a623507653a3c5ca6c690b16f9aeb1c50dcaf7
BLAKE2b-256 checksum
How to use checksums
5750deca9e4bcd5d4b578fd7c67fc72ae4d5733919a6e6d48cf1ac7ba0826f97
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for article-management-system 1.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page