Files
email-organizer/plans/milestone-1.md
2025-08-03 10:09:53 -07:00

8.7 KiB

Milestone 1: Prototype Implementation Plan

Objective

Deliver a functional prototype demonstrating the core infrastructure, basic UI for rule configuration, a mock email processing pipeline, and database schema implementation as outlined in the project roadmap.

Scope

This milestone focuses on establishing the foundational elements required for the Email Organizer. It will not include actual email fetching, complex AI processing, or user authentication. The goal is to have a working skeleton that proves the core concepts.

File and Folder Structure

email-organizer/
├── app/                    # Main application package
│   ├── __init__.py         # Flask app factory
│   ├── models.py           # SQLAlchemy models (User, Folder)
│   ├── routes.py           # Flask routes (UI endpoints)
│   ├── static/             # Static files (CSS, JS, images)
│   │   └── ...             # HTMX, AlpineJS, Tailwind CSS files
│   └── templates/          # Jinja2 HTML templates
│       └── index.html      # Main UI page
├── migrations/             # Alembic migrations
├── tests/                  # Unit and integration tests
│   ├── __init__.py
│   ├── conftest.py         # Pytest configuration and fixtures
│   ├── test_models.py      # Tests for database models
│   └── test_routes.py      # Tests for UI routes
├── config.py               # Application configuration
├── manage.py               # CLI commands (e.g., db setup, mock process)
├── requirements.txt        # Python dependencies
├── .env                    # Environment variables (not in VCS)
├── .env.example            # Example environment variables
├── README.md
└── plans/
    └── milestone-1.md      # This plan

Sample Code

1. Flask App Factory (app/__init__.py)

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

def create_app(config_name='default'):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    
    db.init_app(app)
    
    from app.routes import main
    app.register_blueprint(main)
    
    return app

2. SQLAlchemy Models (app/models.py)

from app import db
from sqlalchemy.dialects.postgresql import UUID
import uuid

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    email = db.Column(db.String(255), unique=True, nullable=False)
    # Placeholders for Milestone 1
    password_hash = db.Column(db.LargeBinary) 
    imap_config = db.Column(db.JSONB)

class Folder(db.Model):
    __tablename__ = 'folders'
    id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    user_id = db.Column(UUID(as_uuid=True), db.ForeignKey('users.id'), nullable=False)
    name = db.Column(db.String(255), nullable=False)
    rule_text = db.Column(db.Text)
    priority = db.Column(db.Integer)
    
    user = db.relationship('User', backref=db.backref('folders', lazy=True))

3. Basic UI Route (app/routes.py)

from flask import Blueprint, render_template, request, jsonify
from app.models import Folder

main = Blueprint('main', __name__)

@main.route('/')
def index():
    # For prototype, use a mock user ID
    mock_user_id = '123e4567-e89b-12d3-a456-426614174000'
    folders = Folder.query.filter_by(user_id=mock_user_id).all()
    return render_template('index.html', folders=folders)

@main.route('/api/folders', methods=['POST'])
def add_folder():
    # Mock implementation for prototype
    data = request.get_json()
    # In a real implementation, this would save to the database
    # For now, just echo back the data
    return jsonify({'message': 'Folder added (mock)', 'folder': data}), 201

4. Simple HTML Template (app/templates/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Email Organizer - Prototype</title>
    <script src="https://unpkg.com/htmx.org@1.9.12"></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Include AlpineJS if needed -->
</head>
<body class="bg-base-100">
    <div class="container mx-auto p-4">
        <h1 class="text-2xl font-bold mb-4">Email Organizer - Prototype</h1>
        
        <div id="folders-list">
            <h2 class="text-xl font-semibold mb-2">Folders</h2>
            <ul>
                {% for folder in folders %}
                <li class="mb-2 p-2 bg-base-200 rounded">{{ folder.name }}: {{ folder.rule_text }}</li>
                {% endfor %
            </ul>
        </div>

        <div id="add-folder-form" class="mt-6">
            <h2 class="text-xl font-semibold mb-2">Add Folder</h2>
            <form hx-post="/api/folders" hx-target="#folders-list" hx-swap="beforeend">
                <div class="mb-2">
                    <label for="folder-name" class="block">Name:</label>
                    <input type="text" id="folder-name" name="name" class="input input-bordered w-full max-w-xs" required>
                </div>
                <div class="mb-2">
                    <label for="folder-rule" class="block">Rule (Natural Language):</label>
                    <textarea id="folder-rule" name="rule_text" class="textarea textarea-bordered w-full" required></textarea>
                </div>
                <button type="submit" class="btn btn-primary">Add Folder</button>
            </form>
        </div>
    </div>
</body>
</html>

5. Mock Email Processing Script (manage.py)

import sys
from app import create_app, db
from app.models import Folder

def mock_process_emails():
    """Simulate processing emails with defined rules."""
    app = create_app()
    with app.app_context():
        # Mock user ID
        mock_user_id = '123e4567-e89b-12d3-a456-426614174000'
        folders = Folder.query.filter_by(user_id=mock_user_id).all()
        
        # Mock emails
        emails = [
            {'subject': 'Your Amazon Order', 'from': 'no-reply@amazon.com', 'body': 'Your order has shipped.'},
            {'subject': 'Meeting Reminder', 'from': 'boss@company.com', 'body': 'Don\'t forget the meeting at 3 PM.'},
            {'subject': 'Special Offer!', 'from': 'deals@shop.com', 'body': 'Exclusive discounts inside!'}
        ]
        
        print("Starting mock email processing...")
        for email in emails:
            print(f"\nProcessing email: {email['subject']}")
            matched = False
            for folder in folders:
                # Simple mock rule matching (in real app, this would be more complex)
                if folder.rule_text.lower() in email['subject'].lower() or folder.rule_text.lower() in email['from'].lower():
                    print(f"  -> Matched rule '{folder.rule_text}' -> Folder '{folder.name}'")
                    matched = True
                    break
            if not matched:
                print("  -> No matching rule found.")

if __name__ == '__main__':
    if len(sys.argv) > 1 and sys.argv[1] == 'mock-process':
        mock_process_emails()
    else:
        print("Usage: python manage.py mock-process")

Testing Plan

Unit Tests (tests/test_models.py)

  • Test User model instantiation and basic properties.
  • Test Folder model instantiation, properties, and relationship with User.
  • Test database constraints (e.g., unique email for User).

Integration Tests (tests/test_routes.py)

  • Test the / route loads successfully and renders the template.
  • Test the /api/folders POST endpoint accepts data and returns a JSON response (mock behavior).

Setup (tests/conftest.py)

  • Use pytest fixtures to create an app instance and a temporary database for testing.
  • Provide a fixture to create a mock user and folders for tests.

Acceptance Criteria

  1. Infrastructure: The Flask application initializes correctly, connects to the PostgreSQL database, and the development server starts without errors.
  2. Database Schema: The users and folders tables are created in the database with the correct columns, data types, and relationships as defined in models.py.
  3. UI Functionality:
    • The root URL (/) loads the index.html template.
    • The page displays a list of folders (initially empty or seeded).
    • The "Add Folder" form is present and can be submitted.
    • Submitting the form sends a request to the /api/folders endpoint.
  4. Mock Processing:
    • The python manage.py mock-process command runs without errors.
    • The script correctly fetches folder rules from the database.
    • The script demonstrates matching mock emails to rules and prints the results to the console.
  5. Code Quality: Code follows Python best practices, is well-structured, and includes basic documentation/comments where necessary.