greenfieldintermediate4-6 hours

Building a Custom Project Management Tool to Replace Jira

A workflow for creating a lightweight, customized project management system using a 600-line Python script with SQLite database. This approach replaces complex tools like Jira with a simple, tailored solution that fits specific team needs.

Thomas Landgraf
Thomas Landgraf
38 views0 saves

Tools & Prerequisites

Required Tools

Flask(Web Framework)
HTML/CSS(Frontend Technologies)
Jinja2(Template Engine)
Python(Programming Language)
SQLite(Database)

Optional Tools

Git(Version Control)

Step-by-Step Guide

1

Set Up Project Structure

Create the basic project structure with necessary directories and files

Code Example

mkdir project-tracker
cd project-tracker
mkdir templates static
touch app.py requirements.txt

Pro Tip

Use a virtual environment to isolate dependencies: python -m venv venv && source venv/bin/activate

2

Install Dependencies

Set up Flask and other required Python packages

Code Example

pip install flask sqlite3
echo 'flask==2.0.1' > requirements.txt

Pro Tip

Consider adding flask-login for user authentication and flask-mail for email notifications

3

Create Database Schema

Design and implement the SQLite database structure for tasks and users

Code Example

CREATE TABLE tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    description TEXT,
    status TEXT DEFAULT 'todo',
    assignee TEXT,
    priority INTEGER DEFAULT 3,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL
);

Pro Tip

Use SQLite's built-in timestamp functions for automatic date tracking

4

Build Flask Application Core

Create the main Flask application with basic routes and database connection

Code Example

from flask import Flask, render_template, request, redirect
import sqlite3

app = Flask(__name__)

def get_db():
    conn = sqlite3.connect('tasks.db')
    conn.row_factory = sqlite3.Row
    return conn

@app.route('/')
def index():
    db = get_db()
    tasks = db.execute('SELECT * FROM tasks ORDER BY created_at DESC').fetchall()
    db.close()
    return render_template('index.html', tasks=tasks)

Pro Tip

Use Flask's g object for better database connection management in production

5

Create HTML Templates

Build simple, functional HTML templates for the user interface

Code Example

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Task Tracker</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

Pro Tip

Keep the UI simple and focused on functionality over aesthetics initially

6

Implement CRUD Operations

Add routes for creating, reading, updating, and deleting tasks

Code Example

@app.route('/task/new', methods=['GET', 'POST'])
def new_task():
    if request.method == 'POST':
        db = get_db()
        db.execute('INSERT INTO tasks (title, description, assignee) VALUES (?, ?, ?)',
                   [request.form['title'], request.form['description'], request.form['assignee']])
        db.commit()
        db.close()
        return redirect('/')
    return render_template('new_task.html')

Pro Tip

Add input validation and error handling for production use

7

Add Search and Filtering

Implement basic search functionality and status filters

Code Example

@app.route('/search')
def search():
    query = request.args.get('q', '')
    status = request.args.get('status', '')
    db = get_db()
    sql = 'SELECT * FROM tasks WHERE 1=1'
    params = []
    if query:
        sql += ' AND (title LIKE ? OR description LIKE ?)'
        params.extend([f'%{query}%', f'%{query}%'])
    if status:
        sql += ' AND status = ?'
        params.append(status)
    tasks = db.execute(sql, params).fetchall()
    db.close()
    return render_template('index.html', tasks=tasks)

Pro Tip

Consider adding full-text search with SQLite's FTS5 extension for better performance

8

Style the Application

Add basic CSS styling for a clean, usable interface

Code Example

/* static/style.css */
body {
    font-family: Arial, sans-serif;
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

.task-card {
    border: 1px solid #ddd;
    padding: 15px;
    margin-bottom: 10px;
    border-radius: 5px;
}

.status-todo { background-color: #f0f0f0; }
.status-in-progress { background-color: #fff3cd; }
.status-done { background-color: #d4edda; }

Pro Tip

Use CSS Grid or Flexbox for responsive layouts

9

Add Activity Logging

Implement an audit trail to track changes to tasks

Code Example

def log_activity(task_id, user_id, action):
    db = get_db()
    db.execute('INSERT INTO activity_log (task_id, user_id, action) VALUES (?, ?, ?)',
               [task_id, user_id, action])
    db.commit()
    db.close()

Pro Tip

Use triggers in SQLite to automatically log updates for better performance

10

Deploy and Test

Deploy the application and test with your team

Code Example

# For development
python app.py

# For production with gunicorn
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 app:app

Pro Tip

Start with a small pilot group before rolling out to the entire team

This workflow guides you through building a custom project management tool that replaces Jira with a simple Python script. The author successfully replaced their team's Jira instance with a 600-line Python application that uses SQLite for data storage and provides a web interface for task management.

Overview

The solution consists of:

  • A Python Flask web application
  • SQLite database for data persistence
  • Simple HTML/CSS interface
  • Basic task management features (create, update, assign, track)
  • Custom workflows tailored to team needs

Key Benefits

  1. Simplicity: No complex configuration or administration
  2. Customization: Easily modify to fit exact team needs
  3. Performance: Fast and lightweight
  4. Cost: Free and self-hosted
  5. Control: Full ownership of data and functionality

Architecture

The system uses:

  • Flask for the web framework
  • SQLite for database (single file, no server needed)
  • Jinja2 for templating
  • Basic CSS for styling
  • Optional: JavaScript for enhanced interactivity

Core Features Implemented

  • Task creation and editing
  • Status tracking (To Do, In Progress, Done)
  • User assignment
  • Priority levels
  • Basic search and filtering
  • Simple reporting
  • Email notifications (optional)

Database Schema

The SQLite database includes tables for:

  • Tasks (id, title, description, status, assignee, priority, created_at, updated_at)
  • Users (id, name, email)
  • Comments (id, task_id, user_id, content, created_at)
  • Activity logs (id, task_id, user_id, action, timestamp)

Deployment Options

  1. Local development server
  2. Internal company server
  3. Cloud VPS (DigitalOcean, Linode, etc.)
  4. Docker container
  5. Heroku or similar PaaS

Discussion (0)

Comments coming soon!