--- name: web-application-spec version: 1.0.0 description: Standardized specification for web applications built with bricks frontend, ahserver backend framework, and apppublic/sqlor foundation modules. trigger_conditions: - User requests to create a new web application following the specified architecture - Task involves setting up application structure with ahserver, bricks, apppublic, sqlor - Development follows the documented directory structure and dependency requirements --- # Web Application Specification ## Overview This specification defines the standard architecture for web applications built using: - **Frontend**: bricks framework - **Backend**: ahserver application framework - **Foundation**: apppublic and sqlor modules - **Optional Modules**: appbase, rbac, and other developed modules All web applications must follow this exact structure and configuration pattern. ## Required Dependencies ### Core Dependencies (Mandatory) ```bash pip install git+https://git.opencomputing.cn/yumoqing/apppublic pip install git+https://git.opencomputing.cn/yumoqing/sqlor pip install git+https://git.opencomputing.cn/yumoqing/ahserver ``` ### Database Web Application Dependencies (If using database) ```bash pip install git+https://git.opencomputing.cn/yumoqing/appbase pip install git+https://git.opencomputing.cn/yumoqing/rbac ``` ## Application Directory Structure ``` ${appname}/ ├── app/ │ └── ${appname}.py # Main application entry point ├── conf/ │ └── config.json # Application configuration ├── files/ # File storage directory ├── logs/ # Log files directory ├── wwwroot/ │ ├── imgs/ # SVG and image files │ └── bricks/ # Bricks framework distribution ├── build.sh # Initialization and deployment script └── .env # Environment variables ``` ## File Specifications ### app/${appname}.py (Main Application) ```python from ahserver.webapp import webapp from ahserver.serverenv import ServerEnv import bricks_for_python # registers bui processor from bricks_for_python.init import load_pybricks # registers UiWindow etc. from appbase.init import load_appbase from rbac.init import load_rbac def get_module_dbname(m): return 'dbname' def password_encode(s): if s is None: return '' from ahserver.globalEnv import password_encode as _orig return _orig(s) def init(): env = ServerEnv() # ← MUST be before load_rbac env.get_module_dbname = get_module_dbname env.password_encode = password_encode load_appbase() load_rbac() load_pybricks() if __name__ == '__main__': webapp(init) ``` ### conf/config.json (Configuration) Must include the following sections: - `password_key`: System encryption key - `logger`: Logging configuration with name, level, and file path - `filesroot`: File storage root path using `$[workdir]$` placeholder - `databases`: Database connection configurations with driver and kwargs - `website`: Web server configuration including paths, processors, session settings **Key Configuration Patterns:** - Use `$[workdir]$` placeholder for work directory references - Database names in `databases` section must match `get_module_name()` return values - **Critical: processors must include `.tmpl` → `tmpl`**. The BricksUIProcessor (handler for `.ui` files) internally loads `/bricks/header.tmpl` and other templates. Without `[".tmpl", "tmpl"]`, the app returns 500 `'NoneType' has no attribute 'be_call'` on `/` and `/index.ui`: ```json "processors": [ [".tmpl", "tmpl"], [".ui", "bui"], [".dspy", "dspy"] ] ``` - Website processors must include `.ui` → `bui` and `.dspy` → `dspy` mappings - **Website indexes**: Must include `"index.ui"` for bricks-based apps. Without it, visiting `/` or `/module/` returns 500 "invalid path" because ahserver cannot resolve directory URLs: ```json "indexes": ["index.ui", "index.html"] ``` - **WebSocket support**: Must include `[".wss", "ws"]` in processors list, otherwise `.wss` files are served as static files and WebSocket connections fail. Nginx `/wss/` block strips the prefix via `proxy_pass`, so the backend receives the path without `/wss` (e.g., `/module/file.wss`). ### WebSocket Configuration Details When adding WebSocket (`.wss`) endpoints to a module: 1. **Backend config.json**: Add `[".wss", "ws"]` to `website.processors`: ```json "processors": [ [".wss", "ws"], [".ws", "ws"], [".ui", "bui"], [".dspy", "dspy"] ] ``` 2. **Nginx**: The `/wss/` location block handles WebSocket upgrade and strips the prefix: ```nginx location /wss/ { proxy_pass http://localhost:9180/; # strips /wss prefix proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } ``` 3. **Frontend**: Connect to `/wss/module/file.wss` (with `/wss` prefix): ```javascript var url = protocol + '//' + host + '/wss/module/file.wss'; var ws = new WebSocket(url); // browser auto-sends cookie ``` 4. **RBAC permissions**: Register paths **without** `/wss` prefix (nginx strips it): ```bash python set_role_perm.py "logined" "/module/file.wss" ``` 5. **Common pitfall**: If ahserver logs `handle as a normal file` for a `.wss` request, the `[".wss","ws"]` processor mapping is missing from `config.json`. ahserver only recognizes extensions explicitly listed in `processors`. ### build.sh (Deployment Script) The build script must perform these operations in order: #### A) Module Dependencies Setup 1. **Install xls2ddl tool**: After creating virtual environment, install xls2ddl first: ```bash pip install xls2ddl ``` 2. **Module Installation**: Clone and pip install all required modules 3. **Database DDL Generation**: For modules with `models/` directory: - If models contain `.xlsx` files: ```bash cd models/ xls2ddl mysql . > mysql.ddl.sql mysql -h db -u[user] -p[password] [dbname] < mysql.ddl.sql ``` - If models contain `.json` files: ```bash cd models/ json2ddl mysql . > mysql.ddl.sql mysql -h db -u[user] -p[password] [dbname] < mysql.ddl.sql ``` 4. **Initial Data Import**: For modules with `data/` directory: ```bash dbloader $cdir [dbname] data.xlsx ``` 5. **CRUD Generation**: For modules with `json/` directory: ```bash cd json/ xls2ui -m ../models -o ../wwwroot ${modulename} *.json ``` 6. **wwwroot Symlinking**: Create symbolic links for each module: ```bash ln -s $cdir/pkgs/$m/wwwroot $cdir/wwwroot/$m ``` #### B) Bricks Framework Setup - Execute bricks build.sh and symlink dist directory: ```bash ln -s $cdir/pkgs/bricks/dist $cdir/wwwroot/bricks ``` #### C) System Service Configuration - Create systemd service file with proper user/group context - Generate start.sh and stop.sh scripts with environment loading - Enable and start the service on system boot #### D) Cron Job Management - Add application-specific cron jobs without duplication ### .env (Environment Variables) - Export all runtime environment variables required by the application - Include database credentials, API keys, and system paths ## Build Script Requirements ### Directory Creation - Create `pkgs/` directory for module clones - Create `logs/` directory for application logging ### Module Processing Order 1. Install foundation modules (apppublic, sqlor, ahserver, bricks) 2. **Clone and process database modules** (appbase, rbac): - Clone from Git repositories to pkgs/ directory - Install via pip - Generate DDL from models/ directory (.xlsx or .json files) - Generate CRUD UI from json/ directory using xls2ui 3. Install business modules (accounting, pricing, contract_management, etc.) following the same pattern as database modules ### Database Operations - Process **all modules** that have `models/`, `json/`, or `data/` directories (including appbase and rbac) - Use proper error handling for database operations - Maintain database isolation per module when configured ### Symbolic Links - All module wwwroot directories must be symlinked to application wwwroot - Bricks dist directory must be symlinked to wwwroot/bricks ### Service Management - Create proper systemd service with logging redirection - Implement graceful start/stop scripts - Set appropriate file permissions (chmod +x for scripts) ## Bricks UI Development Pitfalls See `references/ragserver-pitfalls.md` for complete debugging recipes. See `references/sage-module-pitfalls.md` for SQL column names, `params_kw=None`, deployment, and error investigation rules. - Widget `id` at top level (NOT in `options`) - DOM order for `app.` resolution - `.tmpl` processor required in config - `bricks_for_python` import + `load_pybricks()` call - DataViewer response format (`{status, data:{rows,total}}`) - Menu widget target pattern - Float model fields needing `length` + `dec` ### Widget `id` at Top Level (Not in `options`) ```json // CORRECT {"widgettype":"VBox","id":"main_content","options":{"css":"filler"}} // WRONG — id inside options is ignored {"widgettype":"VBox","options":{"id":"main_content","css":"filler"}} ``` ### DOM Order Affects `app.` Resolution Put the content area BEFORE the sidebar in `subwidgets`. Bricks initializes widgets left-to-right. ## Configuration Best Practices ### Security - Store sensitive data (passwords, keys) in encrypted form in config.json - Use environment variables for runtime secrets via .env file - Implement proper file permissions for logs and files directories ### Performance - Configure appropriate client_max_size for file uploads - Set optimal session timeout values (session_max_time, session_issue_time) - Use Redis for session storage in production ### Maintainability - Use consistent naming patterns across all configuration sections - Document custom processor mappings in website.processors - Maintain clear separation between development and production configurations ## Verification Checklist - [ ] `.tmpl` → `tmpl` processor in `website.processors` (required for bricks UI, or `/` returns 500) - [ ] `bricks_for_python` imported and `load_pybricks()` called in `init()` - [ ] `ServerEnv` initialized BEFORE `load_rbac()` / `load_appbase()` - [ ] Website `indexes` config includes `"index.ui"` (required for directory URL resolution) - `session_max_time` and `session_issue_time` in config for Redis session persistence (restart won't lose login) - [ ] All required dependencies are installed from correct Git repositories - [ ] Application directory structure matches specification exactly - [ ] Main application file includes proper module loading pattern - [ ] Configuration file uses correct placeholders and structure - [ ] Build script handles all module types (foundation, database, business) - [ ] Database DDL generation works for all modules with models/ - [ ] CRUD generation executes for all modules with json/ - [ ] Initial data loads correctly for modules with data/ - [ ] All wwwroot symlinks are created properly - [ ] Bricks framework is built and linked correctly - [ ] System service starts and stops gracefully - [ ] Environment variables are loaded from .env file - [ ] Application runs with proper logging and error handling