diff --git a/doc/Getting-Started/Project-Structure.md b/doc/Getting-Started/Project-Structure.md index db983a4..a4aaffa 100644 --- a/doc/Getting-Started/Project-Structure.md +++ b/doc/Getting-Started/Project-Structure.md @@ -45,6 +45,7 @@ my-app/ ├── src/ │ └── app/ │ ├── Config/ +│ │ ├── version.json Application identity (code, name, version) │ │ ├── config.json Environment-independent config │ │ ├── config-dev.json Development config │ │ ├── config-prod.json Production config @@ -89,18 +90,46 @@ my-app/ Configuration is environment-based and uses JSON: +### `version.json` (required) + +Sets your application's identity. The framework loads this automatically at startup before any other config file: + +```json +{ + "application": { + "code": "my-app", + "name": "My Application", + "version": "1.0.0" + } +} +``` + +| Field | Purpose | +|-------|---------| +| `code` | Machine identifier — used as Monolog log channel name and shared-storage path suffix | +| `name` | Human-readable application label | +| `version` | Semver version string | + +Access at runtime: + +```php +app()->getAppCode(); // "my-app" +app()->getAppName(); // "My Application" +app()->getAppVersion(); // "1.0.0" +``` + ### `config.json` (shared) Global settings used across all environments: ```json { - "app": { - "name": "My App", - "timezone": "UTC", - "charset": "UTF-8" - }, - "cache": { - "default": "file" + "application": { + "global": { + "maintenance": false, + "message": "We are in maintenance mode, back shortly", + "timezone": "UTC" + }, + "secret": "${env:APPLICATION_SECRET}" } } ``` @@ -110,24 +139,48 @@ Development overrides and specific config: ```json { - "debug": true, - "logging": { - "level": "DEBUG" + "application": { + "global": { + "maintenance": false, + "message": "We are in maintenance mode, back shortly", + "timezone": "UTC" + }, + "secret": "${env:APPLICATION_SECRET}" }, - "database": { - "default": "mysql", - "connections": { - "mysql": { - "host": "localhost", - "database": "myapp_dev", - "username": "${env:DB_USER}", - "password": "${env:DB_PASS}" + "logger": { + "level": "debug", + "driver": "file", + "drivers": { + "file": { + "file_path": "storage/log", + "file_format": "Y-m-d", + "line_format": "[%datetime%] [%channel%] [%level_name%] %message% %context%\n", + "line_datetime": "Y-m-d H:i:s.v e" + } + } + }, + "connections": { + "mysql": { + "type": "Pdo", + "driver": "mysql", + "schema": "${env:DB_DATABASE}", + "host": "${env:DB_HOST}", + "port": "${env:DB_PORT}", + "username": "${env:DB_USERNAME}", + "password": "${env:DB_PASSWORD}", + "charset": "UTF8", + "options": { + "ATTR_PERSISTENT": false, + "ATTR_ERRMODE": "ERRMODE_EXCEPTION", + "ATTR_AUTOCOMMIT": false } } } } ``` +> **Logger `line_format` and line endings:** On Linux, Docker, and Unix systems the file driver may not append a newline after each entry. Add `\n` at the end of `line_format` to ensure each log entry ends with a newline. On Windows this is not required but harmless. + ### `config-prod.json` Production settings with hardened defaults. diff --git a/doc/Getting-Started/Quick-Start.md b/doc/Getting-Started/Quick-Start.md index 4d93bbf..7074a00 100644 --- a/doc/Getting-Started/Quick-Start.md +++ b/doc/Getting-Started/Quick-Start.md @@ -38,6 +38,30 @@ mkdir -p src/app/Config mkdir public ``` +## Set Your Application Identity + +Create `src/app/Config/version.json`: + +```json +{ + "application": { + "code": "my-first-app", + "name": "My First App", + "version": "0.1.0" + } +} +``` + +The framework loads this file automatically at startup. Access the values at runtime: + +```php +app()->getAppCode(); // "my-first-app" +app()->getAppName(); // "My First App" +app()->getAppVersion(); // "0.1.0" +``` + +> `code` is also used as the Monolog log channel name and storage path identifier. + ## Create Your First Controller Create `src/app/Controllers/WelcomeController.php`: diff --git a/doc/Getting-Started/Your-First-App.md b/doc/Getting-Started/Your-First-App.md index 7557465..679e03a 100644 --- a/doc/Getting-Started/Your-First-App.md +++ b/doc/Getting-Started/Your-First-App.md @@ -30,6 +30,22 @@ mkdir -p public mkdir -p storage/logs ``` +## Step 0: Set Your Application Identity + +Create `src/app/Config/version.json`: + +```json +{ + "application": { + "code": "task-api", + "name": "Task Management API", + "version": "1.0.0" + } +} +``` + +The framework loads this file automatically at startup. `code` is used as the Monolog log channel name and storage path identifier. Access the values at runtime via `app()->getAppCode()`, `app()->getAppName()`, and `app()->getAppVersion()`. + ## Step 1: Create Your First Controller Create `src/app/Controllers/TaskController.php`: @@ -359,33 +375,38 @@ namespace App; ## Step 5: Create Configuration -Create `src/app/Config/config.json`: +Create `src/app/Config/config-dev.json`: ```json { - "app": { - "name": "Task API", - "version": "1.0.0", - "timezone": "UTC" + "application": { + "global": { + "maintenance": false, + "message": "We are in maintenance mode, back shortly", + "timezone": "UTC" + }, + "secret": "${env:APPLICATION_SECRET}" }, - "logging": { - "default": "monolog", - "level": "INFO" + "logger": { + "level": "debug", + "driver": "file", + "drivers": { + "php": { + "line_format": "[%channel%] [%level_name%] %message% %context%\n", + "line_datetime": "Y-m-d H:i:s.v e" + }, + "file": { + "file_path": "storage/log", + "file_format": "Y-m-d", + "line_format": "[%datetime%] [%channel%] [%level_name%] %message% %context%\n", + "line_datetime": "Y-m-d H:i:s.v e" + } + } } } ``` -Create `src/app/Config/config-dev.json`: - -```json -{ - "debug": true, - "logging": { - "level": "DEBUG", - "path": "storage/logs/app.log" - } -} -``` +> **`line_format` and line endings:** Append `\n` to `line_format` in the `file` driver to ensure each log entry ends with a newline on Linux, Docker, and Unix systems. On Windows this is not required but harmless. ## Step 6: Start the Development Server diff --git a/doc/User-Guide/Configuration.md b/doc/User-Guide/Configuration.md index 530f68e..ddcb99e 100644 --- a/doc/User-Guide/Configuration.md +++ b/doc/User-Guide/Configuration.md @@ -2,6 +2,32 @@ SPIN Framework uses a JSON-based configuration system that's loaded at runtime and provides easy access through helper functions. +## Application Identity (`version.json`) + +Every Spin application must have `src/app/Config/version.json`. The framework loads it automatically at startup — before any `config-{env}.json` — and exposes the values through the `app()` helper: + +```json +{ + "application": { + "code": "my-app", + "name": "My Application", + "version": "1.0.0" + } +} +``` + +| Field | Purpose | +|-------|---------| +| `code` | Machine identifier — used as Monolog log channel name and shared-storage path suffix | +| `name` | Human-readable application label | +| `version` | Semver version string | + +```php +app()->getAppCode(); // "my-app" +app()->getAppName(); // "My Application" +app()->getAppVersion(); // "1.0.0" +``` + ## Configuration Structure SPIN applications use JSON configuration files organized by environment (e.g., `config-dev.json`, `config-prod.json`). The configuration is structured hierarchically and supports environment variables. @@ -36,13 +62,13 @@ _Configuration files support `${env:}` macros for environment variables "driver": "php", "drivers": { "php": { - "line_format": "[%channel%] [%level_name%] %message% %context%", + "line_format": "[%channel%] [%level_name%] %message% %context%\n", "line_datetime": "Y-m-d H:i:s.v e" }, "file": { "file_path": "storage/log", "file_format": "Y-m-d", - "line_format": "[%datetime%] [%channel%] [%level_name%] %message% %context%", + "line_format": "[%datetime%] [%channel%] [%level_name%] %message% %context%\n", "line_datetime": "Y-m-d H:i:s.v e" } } @@ -239,13 +265,13 @@ Missing variables with no inline default resolve to an empty string. "driver": "php", // Driver name "drivers": { "php": { - "line_format": "[%channel%] [%level_name%] %message% %context%", + "line_format": "[%channel%] [%level_name%] %message% %context%\n", "line_datetime": "Y-m-d H:i:s.v e" }, "file": { "file_path": "storage/log", "file_format": "Y-m-d", - "line_format": "[%datetime%] [%channel%] [%level_name%] %message% %context%", + "line_format": "[%datetime%] [%channel%] [%level_name%] %message% %context%\n", "line_datetime": "Y-m-d H:i:s.v e" } } @@ -253,6 +279,8 @@ Missing variables with no inline default resolve to an empty string. } ``` +> **`line_format` and line endings:** The `\n` at the end of `line_format` ensures each log entry is terminated with a newline. On Linux, Docker, and Unix systems this is required for the file driver to produce readable log files. On Windows the newline is written automatically, but the `\n` is harmless. + ### Cache Configuration ```json