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.
The application is designed around modularity, security, and separation of concerns.
src/component/). Even core features like the template engine or themes are components.RequestHandler class mediates between Flask (HTTP handling) and NTPL (View rendering), ensuring consistent security and context setup.Model abstraction..ntpl).UTOKEN, LTOKEN), robust Session management, CSP.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)
└── ...
Components are loaded alphabetically based on their folder name (cmp_NNNN_name).
manifest.json: Registration info (UUID, Name, Route).schema.json: Configuration data (menus, constants, translations).custom.json: Local-only overrides (never committed to git).config/config.db (table custom): Optional centralized per-component overrides keyed by UUID (comp_uuid) with JSON payload in value_json.route/: Python backend logic (Blueprints, RequestHandlers).neutral/: Frontend templates (.ntpl).Override merge order:
manifest.json / schema.json)custom.json (if present)config.db -> custom.value_json (if present and enabled=1)Schema, Session, Userg.pr (Flask g object)@bp.route("/")
def index():
handler = HelloRequestHandler(g.pr, "", bp.neutral_route)
return handler.render_route()
g.pr (PreparedRequest context)CURRENT_COMP_ROUTETemplate class renders the index.ntpl (usually from cmp_0200_template).index.ntpl dynamically includes the component’s content-snippets.ntpl.SQL is defined in JSON files in src/model/.
src/model/user.jsonself.model.exec("user", "get-by-login", {"login": "..."})Goal: Create a “Dashboard” component mapped to /dashboard.
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.
manifest.json:
{
"uuid": "dashboard_8x90s",
"name": "Dashboard",
"route": "/dashboard",
...
}
schema.json to remove old component data.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})
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()
neutral/route/root/content-snippets.ntpl.current:template:body-main-content.
{:snip; current:template:body-main-content >>
<h1>Dashboard</h1>
<p>Users: {:;dashboard_stats->users:}</p>
:}
{:^;:}
Inherit from FormRequestHandler (see src/core/request_handler_form.py and cmp_5100_sign).
class MyFormHandler(FormRequestHandler):
def form_post(self) -> bool:
if not self.validate_post("ref:my_form_error"): return False
# Process data...
return True
{:snip; form-start :}, {:snip; form-end :} and input snippets provided by the theme or form component.To add a new query:
src/model/dashboard.json.
{
"get-stats": {
"@portable": "SELECT COUNT(*) as count FROM user"
}
}
stats = self.model.exec("dashboard", "get-stats", {})
{:snip; name >> content :} to define, {:snip; name :} to call.{:filled; var >> show :}.{:;varname:}: Output variable.{:;local::varname:}: Output from local (inheritable) scope.{:trans; key :}: Translate string.{:include; file.ntpl :}.Refer to docs/templates-neutrats.md for full syntax.
src/model/*.json.self.schema_data['CONTEXT']. Do not access Flask’s request object directly for data processing in templates if possible.cmp_NNNN_name.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).Set and review these variables in config/.env before production deployment:
ALLOWED_HOSTS: Comma-separated host allow-list (localhost,*.example.com). Requests with non-allowed Host are rejected (400).TRUSTED_PROXY_CIDRS: Comma-separated CIDRs for trusted reverse proxies. Forwarded headers are only honored from these sources.WSGI_DEBUG_ALLOWED: Additional debug gate for WSGI entrypoints. Keep as false in production.DEBUG_EXPIRE: Debug flag lifetime in seconds. 0 disables debug guard activation.DEBUG_FILE: Guard file path used by debug activation checks. Keep unset in production unless debugging intentionally.Run tests with pytest. Each component should carry its own tests.
# Test specific component
pytest src/component/cmp_7000_hellocomp/tests