neutral-starter-py

Neutral TS Starter Py - Developer Guide

This document is a comprehensive guide for developers looking to understand, extend, and maintain the Neutral TS Starter Py application. It covers high-level architecture, core concepts, and detailed implementation workflows.


1. Architectural Overview

The application is designed around modularity, security, and separation of concerns.

Core Philosophy

  1. Everything is a Component: The feature set is built entirely from components (src/component/). Even core features like the template engine or themes are components.
  2. Neutral Template Library (NTPL): A language-agnostic, secure-by-default logic-less templating engine handles the frontend.
  3. Declarative SQL: Database interactions are defined in JSON files, keeping Python code free of hardcoded SQL strings and allowing for database portability.
  4. RequestHandler Pattern: A central RequestHandler class mediates between Flask (HTTP handling) and NTPL (View rendering), ensuring consistent security and context setup.

The Stack


2. Project Structure

root/
├── docs/                   # Documentation
├── src/
│   ├── app/                # Application Factory & Configuration
│   │   ├── components.py   # Component Loader Logic
│   │   ├── config.py       # Global Config (Paths, Secrets)
│   │   └── ...
│   ├── component/          # MODULES LIVE HERE
│   │   ├── cmp_0200_template/ # The base layout/theme engine
│   │   ├── cmp_5100_sign/     # Example: Auth system (Login/Register)
│   │   └── cmp_7000_hellocomp/# Example: Minimal component
│   ├── core/               # Framework Core Logic
│   │   ├── prepared_request.py  # Request bootstrap (security, auth)
│   │   ├── request_handler.py   # Component route handler
│   │   ├── model.py             # Database Executor
│   │   ├── template.py          # NTPL Integration
│   │   └── session.py           # Session Handler
│   ├── model/              # SQL Definitions (JSON)
│   └── neutral/            # Global Templates (if any)
└── ...

3. Core Concepts

3.1 Component System

Components are loaded alphabetically based on their folder name (cmp_NNNN_name).

Override merge order:

  1. Base files (manifest.json / schema.json)
  2. custom.json (if present)
  3. config.db -> custom.value_json (if present and enabled=1)

3.2 The Request Pipeline

  1. Global before_request (PreparedRequest):
    • Validates Host
    • Initializes Schema, Session, User
    • Evaluates security policies (auth, status, roles)
    • Stores result in g.pr (Flask g object)
  2. Flask Route: Receives HTTP request (only executes if security passed).
    @bp.route("/")
    def index():
        handler = HelloRequestHandler(g.pr, "", bp.neutral_route)
        return handler.render_route()
    
  3. RequestHandler:
    • Receives g.pr (PreparedRequest context)
    • Sets CURRENT_COMP_ROUTE
    • Executes business logic
    • Prepares template data
  4. Template Rendering:
    • Template class renders the index.ntpl (usually from cmp_0200_template).
    • index.ntpl dynamically includes the component’s content-snippets.ntpl.

3.3 Data Layer (Model)

SQL is defined in JSON files in src/model/.


4. Developer Workflow

4.1 Creating a New Component

Goal: Create a “Dashboard” component mapped to /dashboard.

  1. Copy Template: Start from cmp_7000_hellocomp or cmp_5100_sign.
    cp -r src/component/cmp_7000_hellocomp src/component/cmp_8000_dashboard
    

    cmp_7000_hellocomp is an illustrative example component. In production, disable or remove it if you do not explicitly need it.

  2. Configuration:
    • Edit manifest.json:
      {
          "uuid": "dashboard_8x90s",
          "name": "Dashboard",
          "route": "/dashboard",
          ...
      }
      
    • Clean up schema.json to remove old component data.
  3. Backend Implementation:
    • Rename/Edit route/handler_dashboard.py:
      from core.request_handler import RequestHandler
      class RequestHandlerDashboard(RequestHandler):
          def _pre_process(self):
              # Add custom logic here
              self.view.set_data("dashboard_stats", {"users": 100})
      
    • Update route/routes.py:
      from flask import g
      
      @bp.route("/")
      def index():
          # "root" folder in neutral/route/
          handler = RequestHandlerDashboard(g.pr, "", bp.neutral_route)
          return handler.render_route()
      
  4. Frontend Implementation:
    • Edit neutral/route/root/content-snippets.ntpl.
    • Crucial: You must define current:template:body-main-content.
      {:snip; current:template:body-main-content >>
          <h1>Dashboard</h1>
          <p>Users: {:;dashboard_stats->users:}</p>
      :}
      {:^;:}
      

4.2 Handling Forms

Inherit from FormRequestHandler (see src/core/request_handler_form.py and cmp_5100_sign).

  1. Form Handler:
    class MyFormHandler(FormRequestHandler):
        def form_post(self) -> bool:
            if not self.validate_post("ref:my_form_error"): return False
            # Process data...
            return True
    
  2. Template: Use {:snip; form-start :}, {:snip; form-end :} and input snippets provided by the theme or form component.

4.3 Database Interactions

To add a new query:

  1. Create src/model/dashboard.json.
    {
        "get-stats": {
            "@portable": "SELECT COUNT(*) as count FROM user"
        }
    }
    
  2. Call it in Python:
    stats = self.model.exec("dashboard", "get-stats", {})
    

4.4 Using Neutral Templates (NTPL)

Refer to docs/templates-neutrats.md for full syntax.


5. Security & Best Practices

  1. Do NOT write SQL in Python. Always use src/model/*.json.
  2. Use Context: All user input (POST, GET) is available in self.schema_data['CONTEXT']. Do not access Flask’s request object directly for data processing in templates if possible.
  3. Naming:
    • Components: cmp_NNNN_name.
    • UUIDs: specific format (alphanumeric + underscore).
  4. Tokens: The system automatically handles UTOKEN (User identity token) and LTOKEN (Link/Form token) to prevent CSRF. Ensure your forms include the necessary token fields (usually handled by form-start snippet).

5.1 Operational Security Configuration

Set and review these variables in config/.env before production deployment:


6. Testing

Run tests with pytest. Each component should carry its own tests.

# Test specific component
pytest src/component/cmp_7000_hellocomp/tests