Developer Guide

Developer Guide 1: Architecture & Structure

Architecture

Chapter 1: Understanding how sparQ works under the hood.

Now that you've built your first app, let's step back and understand how sparQ is structured. This knowledge will help you make better decisions as you build more complex applications.

Design Philosophy

sparQ is built on a foundation that prioritizes modularity and extensibility. The goal is a system that can grow and scale over time while remaining simple, intuitive, and efficient.

Everything in sparQ—including the core system itself—is a module. This means:

A sparQ module is NOT a Python module. When we say "module" in sparQ, we mean a self-contained feature unit—a folder with a specific structure. This is different from Python's concept of a module (any .py file).

  • Consistency - Once you understand one module, you understand them all
  • Isolation - Modules don't interfere with each other
  • Extensibility - Add functionality without touching core code
  • Simplicity - Each module does one thing well

Architectural Principles

Seven key pillars guide sparQ's architecture:

Principle What It Means
Modular Structure Every component functions as an independent module with its own models, views, and controllers
Dynamic Loading Only essential modules are required; additional features load on demand
Lightweight Database SQLite as the primary data store for simplicity and portability
ORM Layer SQLAlchemy handles all database interactions with clean Python code
Server-Side Rendering Jinja2 templates with HTMX for dynamic updates without JavaScript complexity
Containerized Deployment Docker-based deployment for consistent environments
Internationalization JSON-based translation system enables global functionality

The Big Picture

sparQ is a modular business platform built on Flask. Think of it as a foundation that handles all the common stuff—authentication, database, email, payments—so you can focus on building your specific business logic.

Image: High-level architecture diagram showing Flask at the core with modules around it

Here's what makes up a sparQ installation:

+-------------------------------------------------------------+
|                      Flask Application                      |
|                         (app.py)                            |
+-------------------------------------------------------------+
|                                                             |
|  +-----------+  +-----------+  +---------------------+      |
|  |  Module   |  | Database  |  |        i18n         |      |
|  |  Loader   |  |(SQLAlchemy)|  |   (JSON files)     |      |
|  | (pluggy)  |  |  SQLite   |  |                     |      |
|  +-----+-----+  +-----------+  +---------------------+      |
|        |                                                    |
|        v                                                    |
|  +-----------------------------------------------------+    |
|  |                    Modules                          |    |
|  |  +-------+ +-------+ +-------+ +-------+            |    |
|  |  | Core  | | Team  | |Dashbrd| | Apps  |            |    |
|  |  +-------+ +-------+ +-------+ +-------+            |    |
|  +-----------------------------------------------------+    |
|                                                             |
+-------------------------------------------------------------+

Required Modules

Three modules are essential for sparQ to run:

Module Purpose
Core Authentication, user administration, base templates, and foundational services
Dashboard (Home) Business dashboard, pipeline view, and central landing page after login
Team Employee management with roles, departments, and organizational structure

Everything else—Sales, Billing, Service, and your custom apps—is optional and loads only when needed.

Technology Stack

sparQ uses a carefully chosen set of technologies:

Layer Technology Why
Web Framework Flask Lightweight, flexible, extensive ecosystem
Database SQLite Zero configuration, portable, surprisingly powerful
ORM SQLAlchemy Python's most mature database toolkit
Templates Jinja2 Fast, secure, Flask's native templating
Interactivity HTMX + Alpine.js Dynamic UIs without JavaScript complexity
Styling Bootstrap 5 Responsive, well-documented, customizable
Plugin System Pluggy Python's standard for extensibility (used by pytest)
AI Integration OpenAI / Anthropic LLM-powered assistant with tool calling

System Services

sparQ provides a set of system services that any module can use. These live in the system/ directory:

Service What It Does Example Use
db Database connection and ORM from system.db import db
auth Authentication decorators @login_required
email Send emails EmailService.send()
pdf Generate PDF documents PDFService.generate()
i18n Translations _('Hello')
payments Stripe integration PaymentService.charge()
background Background task processing BackgroundTask.run()
marketplace Install/manage apps MarketplaceService.install()
ai AI tools and LLM integration from system.ai import Tool

You'll use these services throughout your apps. For example, to require login on a route:

from system.auth import login_required

@bp.route('/dashboard')
@login_required
def dashboard():
    return render_template('my_app/dashboard.html')

Request Lifecycle

When a user clicks something in your app, here's what happens:

1. Request arrives at Flask
       ↓
2. URL routing matches a controller
       ↓
3. Auth middleware checks permissions
       ↓
4. Your controller runs
       ↓
5. Controller calls models/services
       ↓
6. Template renders HTML
       ↓
7. Response sent to browser

Let's trace a real example. When a user visits /hello/ from your Hello sparQ app:

  1. Flask sees the URL matches @bp.route('/') in your main.py controller
  2. Your index() function runs
  3. It calls render_template('hello/desktop/index.html')
  4. Jinja2 processes the template
  5. HTML is sent back to the browser

The Frontend Stack

sparQ uses a server-rendered approach rather than a Single Page Application (SPA). This means:

  • Jinja2 - Templates render HTML on the server
  • HTMX - Makes pages feel dynamic without writing JavaScript
  • Alpine.js - Handles small UI interactions (dropdowns, modals)
  • Bootstrap 5 - Provides the CSS framework

This stack is simpler than React/Vue and perfect for business applications where SEO matters and you don't need complex client-side state.

Image: Diagram showing Jinja2, HTMX, Alpine.js, and Bootstrap working together

Database Layer

sparQ uses SQLite as its primary database and SQLAlchemy as its ORM (Object-Relational Mapper). This lets you work with Python objects instead of writing raw SQL:

# Instead of: SELECT * FROM tasks WHERE user_id = 1
tasks = Task.query.filter_by(user_id=1).all()

# Instead of: INSERT INTO tasks (title, user_id) VALUES ('Buy milk', 1)
task = Task(title='Buy milk', user_id=1)
db.session.add(task)
db.session.commit()

SQLite might seem simple, but it's incredibly capable. It handles millions of records, supports concurrent reads, and requires zero configuration. For most business applications, it's more than enough.

The SDK

The sdk/ folder contains developer tooling for building apps:

# Create a new app with auto-generated mappid
cd sdk
make app name=myapp

# Package for marketplace
make release name=myapp

The SDK handles scaffolding, generates unique marketplace IDs (mappid), and packages apps for distribution.

The Module System

Everything in sparQ is a module. There are three types:

Type Location Purpose
Base Modules modules/base/ Core functionality shipped with sparQ
Apps data/modules/apps/ Your custom applications
Plugins data/addons/ Extensions that enhance other modules

When sparQ starts, it automatically discovers and loads modules in this order:

  1. Core - Authentication, base templates
  2. Dashboard - Business dashboard (Home)
  3. Team - Employee management
  4. Other base modules - Alphabetically
  5. Your apps - Alphabetically

Modules can define dependencies on other modules, ensuring they load in the correct order.

We'll dive deeper into modules in the next chapter.

Key Takeaways

  • sparQ prioritizes modularity—everything is a self-contained module
  • Core, Dashboard, and Team modules are required; everything else is optional
  • Flask + SQLite + SQLAlchemy provide the foundation
  • Server-rendered HTML with HTMX gives you dynamic UIs without JavaScript complexity
  • System services (auth, db, email, etc.) are available to all modules
  • Modules are automatically discovered and loaded at startup

Modules & Apps

Chapter 2: How sparQ organizes code into modules.

In the previous chapter, you learned that sparQ is built on modules. Now let's understand exactly what modules are, where they live, and how they work together.

What is a Module?

A sparQ module is NOT a Python module. When we say "module" in sparQ, we mean a self-contained feature unit—a folder with a specific structure. This is different from Python's concept of a module (any .py file).

A module is a self-contained piece of functionality with its own models, controllers, views, and translations. Your Hello sparQ app from the tutorial? That's a module.

Every module follows the same structure:

myapp/ ├── __init__.py # Module exports ├── __manifest__.py # App metadata (includes mappid) ├── module.py # Lifecycle hooks ├── controllers/ │ └── main.py # Flask routes ├── models/ │ └── item.py # Database models ├── views/ │ ├── templates/ │ │ └── myapp/ │ │ ├── desktop/ │ │ │ └── index.html # Desktop templates │ │ └── mobile/ │ │ └── index.html # Mobile templates │ └── assets/ │ └── css/ │ └── myapp.css # Styles ├── tools/ # Optional: AI tools │ └── widgets.py # Tool definitions └── lang/ └── en.json # Translations

This consistent structure means once you understand one module, you understand them all.

Module Types

sparQ has two types of modules, determined by where they live:

Image: Diagram showing Base Modules vs Apps with their locations
Type Location Purpose
Base Modules modules/base/ Core sparQ functionality (Sales, Billing, Team, etc.)
Apps data/modules/apps/ Your custom applications and marketplace installs

The folder determines the type. Put your code in data/modules/apps/ and sparQ automatically treats it as an app.

Base Modules vs Apps

The key difference is how they appear in the UI:

Base Modules

  • Part of the main sparQ experience
  • Show up in the left sidebar navigation
  • Examples: Dashboard, Sales, Service, Billing

Apps

  • Launched from the Launch Pad
  • Can be pinned to the main navigation for quick access
  • Can have their own sidebar navigation
  • Examples: Notes, Weather, your custom apps
Image: Screenshot showing the Launch Pad with installed apps

Users can pin frequently-used apps to the main navigation, making them as accessible as base modules.

Where Your Apps Live

When you run the SDK scaffolding command:

cd sdk
make app name=myapp

It creates your app in:

data/modules/apps/myapp/

This location is important because:

  • Persists across updates - Your code won't be overwritten when sparQ updates
  • Auto-discovered - sparQ finds and loads it automatically
  • Portable - You can zip it up and share it on the marketplace

The Directory Structure Explained

Let's look at each part of a module:

__manifest__.py

The identity card of your app. Contains name, version, mappid, and configuration:

# __manifest__.py
manifest = {
    # Required fields
    "name": "MyApp",             # Display name (PascalCase)
    "version": "1.0",            # Semantic version
    "mappid": "x7k2m9",          # Marketplace app ID (auto-generated)
    "main_route": "/myapp",      # URL slug (used in /m/{mappid}/{main_route})
    "type": "App",               # "App" (visible) or "System" (hidden)
    "depends": ["core"],         # Module dependencies
    # Display fields
    "icon_class": "fa-solid fa-cube",  # FontAwesome icon class
    "color": "#7c3aed",                # Theme color (purple)
    "description": "What my app does",
    "long_description": "Detailed description of the app's features.",
}

module.py

Contains lifecycle hooks that run when sparQ starts:

# module.py
def init_app(app):
    """Called when Flask app initializes."""
    pass

def init_database(db):
    """Called after database tables are created."""
    # Good place to seed initial data
    pass

controllers/

Flask blueprints that handle HTTP requests. Each file typically handles one area:

# controllers/main.py
from flask import Blueprint, render_template

bp = Blueprint('main', __name__, url_prefix='/myapp')

@bp.route('/')
def index():
    return render_template('myapp/desktop/index.html')

models/

SQLAlchemy models for your database tables:

# models/item.py
from system.db import db

class Item(db.Model):
    __tablename__ = 'myapp_items'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))

views/

Contains templates and static assets. Templates go in a namespaced subfolder with desktop/ and mobile/ variants:

<!-- views/templates/myapp/desktop/index.html -->
{% extends "core/desktop/base.html" %}
{% block content %}
    <h1>Welcome to My App</h1>
{% endblock %}

CSS files go in views/assets/css/:

/* views/assets/css/myapp.css */
.myapp-app .content-card {
    /* Your custom styles */
}

lang/

JSON files with translations for each language:

// lang/en.json
{
    "welcome": "Welcome to My App",
    "save": "Save",
    "cancel": "Cancel"
}

App Navigation

Apps can define their own sidebar navigation using nav_sections in the manifest:

# __manifest__.py
{
    'name': 'Helpdesk',
    'nav_sections': [
        {
            'title': 'Tickets',
            'icon': 'ticket',
            'items': [
                {'route': 'helpdesk.tickets.list', 'label': 'All Tickets'},
                {'route': 'helpdesk.tickets.unassigned', 'label': 'Unassigned'}
            ]
        }
    ]
}

This creates a custom left sidebar when users are in your app.

Image: Example of an app with custom sidebar navigation

Module Loading Order

When sparQ starts, modules load in this order:

  1. Core - The foundation (authentication, base templates)
  2. Dashboard - Business dashboard (Home)
  3. Team - Employee management
  4. All other base modules - Alphabetically
  5. Apps - From data/modules/apps/, alphabetically

This order matters if your app depends on another module being loaded first.

Key Takeaways

  • Everything in sparQ is a module with a consistent structure
  • The folder location determines if it's a base module or app
  • Your apps go in data/modules/apps/
  • Use cd sdk && make app name=myapp to scaffold a new app
  • Each module has manifest (with mappid), controllers, models, views, and lang files
  • Templates go in views/templates/appname/desktop/
  • Apps can define their own navigation

App Configuration

Chapter 3: Setting up your app's identity and behavior.

Every sparQ app needs configuration files that tell sparQ what your app is called, how it should appear, and what it depends on. Let's explore the manifest files.

The Two Manifest Files

sparQ apps use two manifest files:

File Purpose When Needed
__manifest__.py Tells sparQ how to load your app Always (required)
marketplace.json Marketplace listing information Only when publishing

For development, you only need __manifest__.py. Add marketplace.json when you're ready to publish.

The __manifest__.py File

This is the heart of your app's configuration. Here's a complete example:

# __manifest__.py
manifest = {
    # Required fields
    "name": "TaskManager",       # Display name (PascalCase)
    "version": "1.0",            # Semantic version
    "mappid": "x7k2m9",          # Marketplace app ID (auto-generated)
    "main_route": "/tasks",      # URL slug (used in /m/{mappid}/{main_route})
    "type": "App",               # "App" (visible) or "System" (hidden)
    "depends": ["core"],         # Module dependencies
    # Display fields
    "icon_class": "fa-solid fa-check-square",  # FontAwesome icon class
    "color": "#3B82F6",                         # Theme color (blue)
    "description": "Simple task management for teams",
    "long_description": "Organize tasks, set priorities, and track progress.",
}

Required Fields

Field Description Example
name Display name shown in UI (PascalCase) "TaskManager"
version Version number (MAJOR.MINOR format) "1.0"
mappid Unique 6-char marketplace app ID "x7k2m9"
main_route URL slug for your app "/tasks"
type "App" (visible) or "System" (hidden) "App"
depends List of module dependencies ["core"]

About mappid

The mappid (marketplace app ID) is a unique 6-character identifier for your app. It's used to create collision-free routes in the format /m/{mappid}/{slug}.

You don't need to create this yourself. When you scaffold a new app using the SDK, the mappid is auto-generated:

cd sdk
make app name=myapp

This generates a unique mappid and inserts it into your manifest. Your app will be accessible at /m/{mappid}/myapp.

Why mappid? As the marketplace grows, simple slugs like /notes or /tasks would collide. The mappid ensures every app has a unique namespace while you still control the slug portion of the URL.

Display Fields

Field Description Default
icon_class FontAwesome icon class "fa-solid fa-cube"
color Theme color (hex code) "#7c3aed"
description Short description (1-2 sentences) Empty
long_description Detailed description for marketplace listing Empty

The color field sets your app's accent color throughout the UI:

Image: Side-by-side comparison of apps with different theme colors

Dependencies

The depends field lists modules your app requires:

'depends': ['core', 'team']

Common dependencies:

  • core - Base functionality (almost always needed)
  • team - Employee/user data
  • billing - Invoice and payment features

Navigation

Apps can define their own sidebar navigation with nav_sections:

'nav_sections': [
    {
        'title': 'Dashboard',
        'icon': 'speedometer2',
        'route': 'myapp.main.dashboard'
    },
    {
        'title': 'Settings',
        'icon': 'gear',
        'route': 'myapp.settings.index'
    }
]

Each section needs:

  • title - Text shown in sidebar
  • icon - Bootstrap icon name
  • route - Flask route name (blueprint.function)

The marketplace.json File

When you're ready to publish your app, create a marketplace.json file:

{
    "marketplace_id": "task-manager",
    "name": "Task Manager",
    "type": "app",
    "author": "Your Name",
    "author_email": "you@example.com",
    "description": "Simple task management for teams",
    "category": "productivity",
    "tags": ["tasks", "productivity", "team"],
    "min_sparq_version": "1.0",
    "license": "MIT",
    "screenshots": [
        "screenshots/dashboard.png",
        "screenshots/task-list.png"
    ]
}
No version field needed! The SDK automatically injects the version from __manifest__.py when you run make archive or make release. This ensures your version is always in sync.

Required Marketplace Fields

Field Description
marketplace_id Unique ID (lowercase, hyphens only)
name Display name
type "app", "lang_pack", or "plugin"
author Your name or company
author_email Contact email

Categories

Choose one category for your app:

  • productivity - Task management, notes, organization
  • communication - Chat, messaging, notifications
  • finance - Accounting, invoicing, expenses
  • hr - Human resources, hiring, onboarding
  • sales - CRM, quotes, proposals
  • service - Tickets, support, field service
  • analytics - Reports, dashboards, metrics
  • integrations - Third-party connections
  • utilities - Tools, utilities, helpers

Version Numbers

sparQ uses a simple MAJOR.MINOR versioning format:

  • MAJOR - Breaking changes or major rewrites
  • MINOR - New features, improvements, and bug fixes

Examples:

  • 1.01.1 (new feature or bug fix)
  • 1.11.2 (another update)
  • 1.92.0 (breaking change or major rewrite)
Single source of truth: Always set the version in __manifest__.py. The SDK automatically syncs this to marketplace.json when packaging.

Key Takeaways

  • __manifest__.py is required and tells sparQ about your app
  • mappid is auto-generated by the SDK and creates unique routes
  • marketplace.json is only needed for publishing
  • Use nav_sections to create custom sidebar navigation
  • The color field sets your app's theme
  • Follow semantic versioning for your version numbers