mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-03-13 11:16:57 +00:00
Compare commits
5 Commits
cloud-qa
...
feat/insta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6819dbc26b | ||
|
|
29c23e373f | ||
|
|
e09ed5e85c | ||
|
|
17a6ad34d8 | ||
|
|
269175ff51 |
11
README.md
11
README.md
@@ -191,6 +191,7 @@ npm install -g @fleetbase/cli
|
||||
|---------|-------------|
|
||||
| `flb install-fleetbase` | Install Fleetbase using Docker with interactive setup |
|
||||
| `flb set-auth <token>` | Set your registry authentication token for installing extensions |
|
||||
| `flb search [query]` | Search and browse available extensions |
|
||||
| `flb install <extension>` | Install an extension to your Fleetbase instance |
|
||||
| `flb uninstall <extension>` | Uninstall an extension from your instance |
|
||||
| `flb register` | Register a Registry Developer Account |
|
||||
@@ -204,6 +205,16 @@ npm install -g @fleetbase/cli
|
||||
|
||||
Extensions are modular components that enhance the functionality of your Fleetbase instance. They allow you to add new features, customize existing behavior, or integrate with external systems.
|
||||
|
||||
### Browsing Extensions
|
||||
|
||||
```bash
|
||||
flb search # list all extensions
|
||||
flb search fleet # search by keyword
|
||||
flb search --category logistics
|
||||
flb search --free
|
||||
flb search --json # machine-readable output
|
||||
```
|
||||
|
||||
### Installing Extensions
|
||||
|
||||
To install extensions on a self-hosted instance:
|
||||
|
||||
120
RELEASE.md
120
RELEASE.md
@@ -1,114 +1,58 @@
|
||||
# 🚀 Fleetbase v0.7.29 — 2026-02-27
|
||||
# 🚀 Fleetbase v0.7.30 — 2026-02-28
|
||||
|
||||
> "Major security enhancements, analytics tracking, developer tools, and UX improvements"
|
||||
> "Extension discovery, driver vehicle validation, and CLI search"
|
||||
|
||||
---
|
||||
|
||||
## ✨ Highlights
|
||||
|
||||
This release brings **critical security patches**, comprehensive **analytics event tracking** across the platform, enhanced **developer account management** for the extension marketplace, and several **user experience improvements** including accurate geolocation detection.
|
||||
This release includes two bug fixes and one new feature: a corrected public extension discovery endpoint in the Registry Bridge, a driver vehicle validation patch in FleetOps, and a new `flb search` command in the Fleetbase CLI.
|
||||
|
||||
### 🔒 Security Enhancements
|
||||
### 🔌 Registry Bridge — Public Extension Discovery
|
||||
|
||||
Fleetbase v0.7.29 includes critical security fixes that strengthen tenant isolation and prevent unauthorized access. The **core-api** has been patched to address a systemic tenant isolation vulnerability (GHSA-3wj9-hh56-7fw7) with the introduction of a `CompanyScope` global scope that enforces proper tenant boundaries. Additional security improvements include removal of hardcoded authentication bypasses, enforcement of strong password policies across all validators, and prevention of user enumeration in login flows. Cross-tenant IDOR vulnerabilities have been resolved with company-scoped authorization checks throughout the API.
|
||||
The public extensions listing endpoint (`~registry/v1/extensions`) has been corrected and hardened. A dedicated `PublicRegistryExtension` API resource now sanitizes the response, stripping all sensitive fields before they leave the server. The `install_count` aggregation has been fixed to use `withCount('installs')` and the incorrect `author` relationship has been replaced with the proper `company` relationship. The endpoint returns a clean, flat array.
|
||||
|
||||
### 📊 Analytics & Event Tracking
|
||||
### 🚛 FleetOps — Driver Vehicle Validation
|
||||
|
||||
A comprehensive **events service** has been added to **ember-core**, providing centralized analytics tracking across all core services. The system emits both generic events (e.g., `resource.created`) and specific events (e.g., `order.created`) using a standardized dot notation naming convention. Event tracking has been integrated into CRUD operations (create, update, delete, bulk actions, import, export) and resource actions across the platform. In **FleetOps**, 30 controllers now emit analytics events, and import operations return accurate counts of imported records. The dual event system fires on both the events service and universe service, enabling cross-engine communication for analytics integrations like PostHog.
|
||||
A `TypeError` that occurred when creating a driver with a vehicle object sent from the frontend has been resolved. A new `ResolvableVehicle` validation rule accepts a `public_id` string (e.g., `vehicle_abc123`), a UUID string, or an object/array containing an `id`, `public_id`, or `uuid` key. Vehicle normalization has been added to both `createRecord()` and `updateRecord()` in `DriverController` so the correct vehicle UUID is always resolved before persistence.
|
||||
|
||||
### 🛠️ Developer Tools & Marketplace
|
||||
### 🔍 Fleetbase CLI — Extension Search Command
|
||||
|
||||
The **registry-bridge** now supports **Registry Developer Accounts** for self-hosted instances, enabling developers to publish and monetize extensions through a centralized marketplace. The Universal Extension Marketplace backend provides a public extension listing endpoint with 15-minute caching for performance. Stripe Connect account management has been added, allowing developers to update bank account details after initial onboarding. The **fleetbase-cli** has been significantly enhanced with new commands including `flb register` for developer account registration, `flb verify` for email verification, `flb resend-verification` for expired codes, and `flb install-fleetbase` for Docker-based installation with automatic repository cloning.
|
||||
|
||||
### 🌍 Geolocation & UX Improvements
|
||||
|
||||
A critical bug affecting user onboarding has been fixed where the system was displaying the **server's location** instead of the **user's actual location**. The **ember-core** now implements frontend IP lookup using multiple geolocation APIs (geoiplookup.io and ipapi.co) with automatic fallback support and localStorage caching. The **phone-input component** in **ember-ui** has been updated to use this frontend IP lookup, ensuring accurate country code detection for phone number formatting. The **IAM engine** now features tabbed user type sections in the users management interface for better organization.
|
||||
|
||||
### 📈 Reporting & Data Access
|
||||
|
||||
**FleetOps** now exposes the `meta` column and `Transaction` relationships in the Orders report schema, enabling users to query and report on order metadata, custom fields, and financial data including transaction amounts, line items, and aggregates. This resolves a significant limitation where critical financial data was previously inaccessible in reports.
|
||||
|
||||
### 🌐 Internationalization
|
||||
|
||||
Support for **KZT (Kazakhstani Tenge)** currency has been added across both **core-api** and **ember-ui**, expanding Fleetbase's international capabilities.
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security Fixes
|
||||
|
||||
- **[core-api]** Patched critical tenant isolation vulnerability (GHSA-3wj9-hh56-7fw7) with CompanyScope global scope
|
||||
- **[core-api]** Removed hardcoded SMS auth bypass code, replaced with environment-driven bypass for non-production
|
||||
- **[core-api]** Fixed cross-tenant IDOR vulnerabilities with company-scoped authorization
|
||||
- **[core-api]** Enforced strong password policy across all validators
|
||||
- **[core-api]** Prevented user enumeration in login flow
|
||||
- **[core-api]** Restored authToken re-authentication with identity verification
|
||||
A new `flb search [query]` command (alias: `flb list-extensions`) lets developers and administrators browse all available extensions directly from the terminal. Results are displayed in a formatted, colour-coded table showing the extension name, category, publisher, version, price, and supported install formats. Filtering options include `--category`, `--free`, `--json`, `--simple`, and `--host`.
|
||||
|
||||
---
|
||||
|
||||
## ✨ New Features
|
||||
|
||||
### Analytics & Tracking
|
||||
- **[ember-core]** Added centralized events service for analytics tracking across all core services
|
||||
- **[ember-core]** Event tracking in CRUD service (create, update, delete, bulk actions, import, export)
|
||||
- **[ember-core]** Dual event system (fires on both events service and universe service)
|
||||
- **[fleetops]** Added event tracking to 30 FleetOps controllers for event tracking
|
||||
- **[fleetops]** Import operations now return count of imported records in response
|
||||
|
||||
### Developer Tools
|
||||
- **[registry-bridge]** Registry Developer Account support for self-hosted instances
|
||||
- **[registry-bridge]** Universal Extension Marketplace backend with public extension listing endpoint
|
||||
- **[registry-bridge]** Stripe Connect account management for bank account updates
|
||||
- **[registry-bridge]** Email verification for developer accounts using VerificationCode model
|
||||
- **[registry-bridge]** Automatic registry token generation upon email verification
|
||||
- **[fleetbase-cli]** Added `flb register` command for Registry Developer Account registration
|
||||
- **[fleetbase-cli]** Added `flb verify` command for email verification
|
||||
- **[fleetbase-cli]** Added `flb resend-verification` command to request new verification codes
|
||||
- **[fleetbase-cli]** Added `flb install-fleetbase` command for Docker-based installation
|
||||
- **[fleetbase-cli]** Auto-clone Fleetbase repository if not present during installation
|
||||
- **[fleetbase-cli]** Support for `--host` parameter to work with self-hosted instances
|
||||
|
||||
### Reporting & Data
|
||||
- **[fleetops]** Exposed meta column and Transaction relationships in Orders report schema for financial reporting
|
||||
- **[core-api]** User cache now includes updated_at timestamp for automatic cache busting
|
||||
|
||||
### UI/UX
|
||||
- **[iam-engine]** Added tabbed user type sections to users management interface
|
||||
- **[iam-engine]** Enhanced edit user interface with better validation and error handling
|
||||
|
||||
### Internationalization
|
||||
- **[core-api]** Added KZT (Kazakhstani Tenge) currency support
|
||||
- **[ember-ui]** Added support for KZT currency
|
||||
- **[fleetbase-cli]** Added `flb search [query]` command (alias: `flb list-extensions`) for browsing available extensions
|
||||
- **[fleetbase-cli]** `--category` filter to narrow results by extension category
|
||||
- **[fleetbase-cli]** `--free` flag to list only free extensions
|
||||
- **[fleetbase-cli]** `--json` flag for machine-readable JSON output
|
||||
- **[fleetbase-cli]** `--simple` flag for plain-text terminal output
|
||||
- **[fleetbase-cli]** `--host` option to target self-hosted registry instances
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
### Geolocation
|
||||
- **[ember-core]** Implemented frontend IP lookup to get accurate user location (fixes onboarding showing server location)
|
||||
- **[ember-core]** Added lookup-user-ip utility with multi-API fallback support (geoiplookup.io and ipapi.co)
|
||||
- **[ember-core]** localStorage caching for IP lookup results (1 hour TTL)
|
||||
- **[ember-core]** Graceful fallback to browser timezone when geolocation APIs fail
|
||||
- **[ember-ui]** Updated phone-input component to use frontend IP lookup (fixes incorrect country code detection)
|
||||
- **[ember-ui]** Phone input now always initializes with US fallback if geolocation fails
|
||||
### FleetOps
|
||||
- **[fleetops]** Fixed `TypeError` when creating a driver with a vehicle object sent from the frontend
|
||||
- **[fleetops]** Added `ResolvableVehicle` validation rule accepting `public_id`, UUID, or object with `id`/`public_id`/`uuid`
|
||||
- **[fleetops]** Added vehicle normalization in `DriverController::createRecord()` and `updateRecord()`
|
||||
|
||||
### Core Fixes
|
||||
- **[core-api]** Verification codes now default to 'pending' status
|
||||
- **[core-api]** Fixed verification email HTML rendering (button component)
|
||||
- **[core-api]** Prevented empty email/phone on user update
|
||||
- **[core-api]** Resolved camelCase expansion methods from snake_case query params in Filter
|
||||
- **[fleetops]** Prevented duplicate driver creation when user_uuid already has a driver profile
|
||||
- **[registry-bridge]** Made developer account registration routes public (no auth required)
|
||||
- **[registry-bridge]** Polymorphic purchaser relationship for extension purchases (supports both Company and RegistryDeveloperAccount)
|
||||
### Registry Bridge
|
||||
- **[registry-bridge]** Fixed `install_count` column error by switching to `withCount('installs')` eager load
|
||||
- **[registry-bridge]** Removed incorrect `author` relationship; replaced with correct `company` relationship
|
||||
- **[registry-bridge]** Removed sensitive data (internal UUIDs, Stripe IDs, private relationships) from public endpoint response
|
||||
- **[registry-bridge]** Public extensions endpoint now returns a plain array without a wrapping key
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Improvements
|
||||
|
||||
- **[fleetops]** Moved avatar management to FleetOps settings
|
||||
- **[ember-ui]** Faster phone input lookup (1 network hop vs 2, no backend dependency)
|
||||
- **[fleetbase-cli]** Better error handling and debugging for all commands
|
||||
- **[fleetbase-cli]** Skip interactive prompts when command-line options are provided
|
||||
- **[ember-core]** Standardized event naming with dot notation (e.g., resource.created, order.created)
|
||||
- **[fleetbase-cli]** Price display correctly converts cents to dollars in search results
|
||||
- **[fleetbase-cli]** Search results show both install formats: `flb install fleetbase/<slug>` and `flb install <extension_id>`
|
||||
- **[registry-bridge]** Extension listing response is a clean, flat array for easier consumption by CLI and third-party tools
|
||||
|
||||
---
|
||||
|
||||
@@ -136,13 +80,9 @@ docker compose exec application bash -c "./deploy.sh"
|
||||
|
||||
## 📦 Component Versions
|
||||
|
||||
- **core-api**: v1.6.36
|
||||
- **fleetops**: v0.6.36
|
||||
- **registry-bridge**: v0.1.6
|
||||
- **iam-engine**: v0.1.7
|
||||
- **ember-core**: v0.3.11, v0.3.12
|
||||
- **ember-ui**: v0.3.20, v0.3.21
|
||||
- **fleetbase-cli**: v0.0.4
|
||||
- **fleetops**: v0.6.37
|
||||
- **registry-bridge**: v0.1.7
|
||||
- **fleetbase-cli**: v0.0.5
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
"php": ">=8.0 <=8.2.30",
|
||||
"appstract/laravel-opcache": "^4.0",
|
||||
"fleetbase/core-api": "^1.6.37",
|
||||
"fleetbase/fleetops-api": "^0.6.36",
|
||||
"fleetbase/registry-bridge": "^0.1.6",
|
||||
"fleetbase/fleetops-api": "^0.6.37",
|
||||
"fleetbase/registry-bridge": "^0.1.7",
|
||||
"fleetbase/storefront-api": "^0.4.13",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^10.0",
|
||||
|
||||
42
api/composer.lock
generated
42
api/composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "6327bc3172d3e92c060c576df8b57919",
|
||||
"content-hash": "784bd052687a49a240afcf2a8b3a651e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appstract/laravel-opcache",
|
||||
@@ -124,16 +124,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.371.2",
|
||||
"version": "3.371.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "32090a8ac3ec8859cb83bdde800b8f0ecf92d8ec"
|
||||
"reference": "d300ec1c861e52dc8f17ca3d75dc754da949f065"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/32090a8ac3ec8859cb83bdde800b8f0ecf92d8ec",
|
||||
"reference": "32090a8ac3ec8859cb83bdde800b8f0ecf92d8ec",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d300ec1c861e52dc8f17ca3d75dc754da949f065",
|
||||
"reference": "d300ec1c861e52dc8f17ca3d75dc754da949f065",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -197,11 +197,11 @@
|
||||
"authors": [
|
||||
{
|
||||
"name": "Amazon Web Services",
|
||||
"homepage": "http://aws.amazon.com"
|
||||
"homepage": "https://aws.amazon.com"
|
||||
}
|
||||
],
|
||||
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
|
||||
"homepage": "http://aws.amazon.com/sdkforphp",
|
||||
"homepage": "https://aws.amazon.com/sdk-for-php",
|
||||
"keywords": [
|
||||
"amazon",
|
||||
"aws",
|
||||
@@ -215,9 +215,9 @@
|
||||
"support": {
|
||||
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.371.2"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.371.3"
|
||||
},
|
||||
"time": "2026-02-26T19:06:10+00:00"
|
||||
"time": "2026-02-27T19:05:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php-laravel",
|
||||
@@ -2323,16 +2323,16 @@
|
||||
},
|
||||
{
|
||||
"name": "fleetbase/fleetops-api",
|
||||
"version": "0.6.36",
|
||||
"version": "0.6.37",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fleetbase/fleetops.git",
|
||||
"reference": "2a6178e011ed2aad1fe3e5cb67308455c48e1cca"
|
||||
"reference": "071a0f06fbe60b7a98fb84686112cc0cd2c3018c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fleetbase/fleetops/zipball/2a6178e011ed2aad1fe3e5cb67308455c48e1cca",
|
||||
"reference": "2a6178e011ed2aad1fe3e5cb67308455c48e1cca",
|
||||
"url": "https://api.github.com/repos/fleetbase/fleetops/zipball/071a0f06fbe60b7a98fb84686112cc0cd2c3018c",
|
||||
"reference": "071a0f06fbe60b7a98fb84686112cc0cd2c3018c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2407,9 +2407,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/fleetbase/fleetops/issues",
|
||||
"source": "https://github.com/fleetbase/fleetops/tree/v0.6.36"
|
||||
"source": "https://github.com/fleetbase/fleetops/tree/v0.6.37"
|
||||
},
|
||||
"time": "2026-02-27T07:56:16+00:00"
|
||||
"time": "2026-02-28T01:43:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fleetbase/laravel-mysql-spatial",
|
||||
@@ -2479,16 +2479,16 @@
|
||||
},
|
||||
{
|
||||
"name": "fleetbase/registry-bridge",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fleetbase/registry-bridge.git",
|
||||
"reference": "3e6ba698f5015616ec88c336fe66e98701442ad2"
|
||||
"reference": "52441e2b2c56d74afb02a216f962cd712c356efd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fleetbase/registry-bridge/zipball/3e6ba698f5015616ec88c336fe66e98701442ad2",
|
||||
"reference": "3e6ba698f5015616ec88c336fe66e98701442ad2",
|
||||
"url": "https://api.github.com/repos/fleetbase/registry-bridge/zipball/52441e2b2c56d74afb02a216f962cd712c356efd",
|
||||
"reference": "52441e2b2c56d74afb02a216f962cd712c356efd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2555,9 +2555,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/fleetbase/registry-bridge/issues",
|
||||
"source": "https://github.com/fleetbase/registry-bridge/tree/v0.1.6"
|
||||
"source": "https://github.com/fleetbase/registry-bridge/tree/v0.1.7"
|
||||
},
|
||||
"time": "2026-02-27T07:58:45+00:00"
|
||||
"time": "2026-02-28T01:41:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fleetbase/storefront-api",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fleetbase/console",
|
||||
"version": "0.7.29",
|
||||
"version": "0.7.30",
|
||||
"private": true,
|
||||
"description": "Modular logistics and supply chain operating system (LSOS)",
|
||||
"repository": "https://github.com/fleetbase/fleetbase",
|
||||
@@ -37,10 +37,10 @@
|
||||
"@fleetbase/ember-core": "^0.3.12",
|
||||
"@fleetbase/ember-ui": "^0.3.21",
|
||||
"@fleetbase/fleetops-data": "^0.1.25",
|
||||
"@fleetbase/fleetops-engine": "^0.6.36",
|
||||
"@fleetbase/fleetops-engine": "^0.6.37",
|
||||
"@fleetbase/iam-engine": "^0.1.7",
|
||||
"@fleetbase/leaflet-routing-machine": "^3.2.17",
|
||||
"@fleetbase/registry-bridge-engine": "^0.1.6",
|
||||
"@fleetbase/registry-bridge-engine": "^0.1.7",
|
||||
"@fleetbase/storefront-engine": "^0.4.13",
|
||||
"@formatjs/intl-datetimeformat": "^6.18.2",
|
||||
"@formatjs/intl-numberformat": "^8.15.6",
|
||||
|
||||
20
console/pnpm-lock.yaml
generated
20
console/pnpm-lock.yaml
generated
@@ -29,8 +29,8 @@ importers:
|
||||
specifier: ^0.1.25
|
||||
version: 0.1.25(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(webpack@5.105.0)
|
||||
'@fleetbase/fleetops-engine':
|
||||
specifier: ^0.6.36
|
||||
version: 0.6.36(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)
|
||||
specifier: ^0.6.37
|
||||
version: 0.6.37(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)
|
||||
'@fleetbase/iam-engine':
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)
|
||||
@@ -38,8 +38,8 @@ importers:
|
||||
specifier: ^3.2.17
|
||||
version: 3.2.17
|
||||
'@fleetbase/registry-bridge-engine':
|
||||
specifier: ^0.1.6
|
||||
version: 0.1.6(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)
|
||||
specifier: ^0.1.7
|
||||
version: 0.1.7(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)
|
||||
'@fleetbase/storefront-engine':
|
||||
specifier: ^0.4.13
|
||||
version: 0.4.13(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)
|
||||
@@ -1544,8 +1544,8 @@ packages:
|
||||
resolution: {integrity: sha512-uCX/qB4ANDGNN+EM1vdsVc4inprGEwj1dT0G5OTYKsFaHL3CWOeXsOg8qSa5EDClqxIodadx6stB+dSwrhYowg==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@fleetbase/fleetops-engine@0.6.36':
|
||||
resolution: {integrity: sha512-Segq0+W5VHDcjxJ2DL5mbWSsY0Zp6f+jrlE2+Ub6EUJ5BFiqg1vR6NsypiC+uZCSqI8PjHzekIaZSQaJzv/N1g==}
|
||||
'@fleetbase/fleetops-engine@0.6.37':
|
||||
resolution: {integrity: sha512-bmhT26lloVFUJNq8hSzHNL/3C7bONdsCT9qNrD1sFKpKQLA5c7Jsti4pWkb+95sqIuqiYZ7ccfyoOXzGUr7MIA==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
ember-engines: ^0.9.0
|
||||
@@ -1563,8 +1563,8 @@ packages:
|
||||
'@fleetbase/leaflet-routing-machine@3.2.17':
|
||||
resolution: {integrity: sha512-2S/XLPzf25ZKV7cFJwfeu4voYQboF9JiDfpRUTrif4XCfgdrQ2Zim7O5iTpoNv2l8Ne8D+Ed7BGJsKWjJFLcsw==}
|
||||
|
||||
'@fleetbase/registry-bridge-engine@0.1.6':
|
||||
resolution: {integrity: sha512-FmmVQfMMGy1xzmLfVDpLaOg/mf0hfwfL3k+Ae9+QOl+s0GLGzaKX6K/lxviHP/DotzEJEtsuNGZ5jpA+mjzAow==}
|
||||
'@fleetbase/registry-bridge-engine@0.1.7':
|
||||
resolution: {integrity: sha512-z6bA8/DeJ/lTVyjO24W2ltt0C6/GwM9lHO17DwDlyxBh6o6t8htd/PvQap8qcys7tOZXVXu7i4ufkdvb6DwbyQ==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
ember-engines: ^0.9.0
|
||||
@@ -10774,7 +10774,7 @@ snapshots:
|
||||
- utf-8-validate
|
||||
- webpack
|
||||
|
||||
'@fleetbase/fleetops-engine@0.6.36(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)':
|
||||
'@fleetbase/fleetops-engine@0.6.37(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@fleetbase/ember-core': 0.3.12(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(webpack@5.105.0)
|
||||
@@ -10889,7 +10889,7 @@ snapshots:
|
||||
'@mapbox/polyline': 0.2.0
|
||||
osrm-text-instructions: 0.13.4
|
||||
|
||||
'@fleetbase/registry-bridge-engine@0.1.6(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)':
|
||||
'@fleetbase/registry-bridge-engine@0.1.7(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-engines@0.9.0(@ember/legacy-built-in-components@0.4.2(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(postcss@8.5.6)(rollup@2.79.2)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@fleetbase/ember-core': 0.3.12(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(webpack@5.105.0))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.0))(eslint@8.57.1)(webpack@5.105.0)
|
||||
|
||||
@@ -75,7 +75,7 @@ ENV QUEUE_CONNECTION=redis
|
||||
ENV CADDYFILE_PATH=/fleetbase/Caddyfile
|
||||
ENV CONSOLE_PATH=/fleetbase/console
|
||||
ENV OCTANE_SERVER=frankenphp
|
||||
ENV FLEETBASE_VERSION=0.7.29
|
||||
ENV FLEETBASE_VERSION=0.7.30
|
||||
|
||||
# Set environment
|
||||
ARG ENVIRONMENT=production
|
||||
|
||||
Submodule packages/fleetops updated: 2a6178e011...071a0f06fb
Submodule packages/registry-bridge updated: 3e6ba698f5...52441e2b2c
@@ -1,200 +1,562 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/docker-install.sh
|
||||
# Fleetbase Docker installer (dev / prod aware)
|
||||
# --------------------------------------------
|
||||
# Fleetbase Docker installer — interactive setup wizard
|
||||
# -------------------------------------------------------
|
||||
# Usage:
|
||||
# bash scripts/docker-install.sh # interactive (default)
|
||||
# bash scripts/docker-install.sh --non-interactive # CI/CD, all defaults
|
||||
# -------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
###############################################################################
|
||||
# 1. Ask for host (default: localhost)
|
||||
###############################################################################
|
||||
read -rp "Enter host or IP address to bind to [localhost]: " HOST_INPUT
|
||||
HOST=${HOST_INPUT:-localhost}
|
||||
echo "➜ Using host: $HOST"
|
||||
# ─── Colour helpers ──────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'
|
||||
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
|
||||
info() { echo -e "${CYAN}ℹ ${RESET}$*"; }
|
||||
success() { echo -e "${GREEN}✔ ${RESET}$*"; }
|
||||
warn() { echo -e "${YELLOW}⚠ ${RESET}$*"; }
|
||||
error() { echo -e "${RED}✖ ${RESET}$*" >&2; }
|
||||
section() { echo -e "\n${BOLD}── $* $(printf '─%.0s' {1..40})${RESET}"; }
|
||||
|
||||
###############################################################################
|
||||
# 2. Ask for environment (development | production)
|
||||
###############################################################################
|
||||
while true; do
|
||||
read -rp "Choose environment (development / production) [development]: " ENV_INPUT
|
||||
ENV_INPUT=$(echo "$ENV_INPUT" | tr '[:upper:]' '[:lower:]')
|
||||
case "$ENV_INPUT" in
|
||||
""|d|dev|development) ENVIRONMENT=development; break ;;
|
||||
p|prod|production) ENVIRONMENT=production; break ;;
|
||||
*) echo "Please type either 'development' or 'production'." ;;
|
||||
esac
|
||||
# ─── Non-interactive flag ────────────────────────────────────────────────────
|
||||
NON_INTERACTIVE=false
|
||||
for arg in "$@"; do
|
||||
[[ "$arg" == "--non-interactive" ]] && NON_INTERACTIVE=true
|
||||
done
|
||||
echo "➜ Environment: $ENVIRONMENT"
|
||||
$NON_INTERACTIVE && info "Non-interactive mode: all optional steps will use safe defaults."
|
||||
|
||||
USE_HTTPS=false
|
||||
APP_DEBUG=true
|
||||
SC_SECURE=false
|
||||
if [[ "$ENVIRONMENT" == "production" ]]; then
|
||||
USE_HTTPS=true
|
||||
APP_DEBUG=false
|
||||
SC_SECURE=true
|
||||
# ─── Helper: generate a random hex secret ────────────────────────────────────
|
||||
gen_secret() { openssl rand -hex "${1:-20}"; }
|
||||
|
||||
# ─── Helper: append a non-empty env var line to the override builder ─────────
|
||||
# Usage: env_line VAR_NAME "value" → echoes ' VAR_NAME: "value"' if non-empty
|
||||
env_line() {
|
||||
local key="$1" val="$2"
|
||||
[[ -z "$val" ]] && return
|
||||
printf ' %s: "%s"\n' "$key" "$val"
|
||||
}
|
||||
|
||||
echo
|
||||
echo -e "${BOLD}🚀 Fleetbase Installation Wizard${RESET}"
|
||||
echo
|
||||
|
||||
###############################################################################
|
||||
# STEP 0 — Pre-flight checks
|
||||
###############################################################################
|
||||
section "Pre-flight Checks"
|
||||
|
||||
# Required tools
|
||||
for tool in docker git openssl; do
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
error "$tool is required but not found. Install it and retry."
|
||||
exit 1
|
||||
fi
|
||||
success "$tool found"
|
||||
done
|
||||
|
||||
# Docker Compose v2
|
||||
if ! docker compose version >/dev/null 2>&1; then
|
||||
error "'docker compose' (v2) is required. Please upgrade Docker Desktop or install the Compose plugin."
|
||||
exit 1
|
||||
fi
|
||||
success "Docker Compose v2 found"
|
||||
|
||||
# Port availability (warn only — do not block)
|
||||
for port_label in "8000:API" "4200:Console" "3306:MySQL" "38000:SocketCluster"; do
|
||||
port="${port_label%%:*}"
|
||||
label="${port_label##*:}"
|
||||
if ss -tlnp 2>/dev/null | grep -q ":${port} " || \
|
||||
netstat -tlnp 2>/dev/null | grep -q ":${port} "; then
|
||||
warn "Port ${port} (${label}) is already in use — this may cause a conflict."
|
||||
else
|
||||
success "Port ${port} (${label}) is free"
|
||||
fi
|
||||
done
|
||||
|
||||
success "Pre-flight checks complete"
|
||||
|
||||
###############################################################################
|
||||
# STEP 1 — Core parameters
|
||||
###############################################################################
|
||||
section "Core Configuration"
|
||||
|
||||
if $NON_INTERACTIVE; then
|
||||
HOST="localhost"
|
||||
ENVIRONMENT="development"
|
||||
APP_NAME="Fleetbase"
|
||||
else
|
||||
read -rp "Host or IP address to bind to [localhost]: " HOST_INPUT
|
||||
HOST="${HOST_INPUT:-localhost}"
|
||||
|
||||
while true; do
|
||||
read -rp "Environment (development / production) [development]: " ENV_INPUT
|
||||
ENV_INPUT=$(echo "$ENV_INPUT" | tr '[:upper:]' '[:lower:]')
|
||||
case "$ENV_INPUT" in
|
||||
""|d|dev|development) ENVIRONMENT=development; break ;;
|
||||
p|prod|production) ENVIRONMENT=production; break ;;
|
||||
*) warn "Please type either 'development' or 'production'." ;;
|
||||
esac
|
||||
done
|
||||
|
||||
read -rp "Application name [Fleetbase]: " APP_NAME_INPUT
|
||||
APP_NAME="${APP_NAME_INPUT:-Fleetbase}"
|
||||
fi
|
||||
|
||||
# Derive scheme flags
|
||||
USE_HTTPS=false; APP_DEBUG=true; SC_SECURE=false
|
||||
[[ "$ENVIRONMENT" == "production" ]] && { USE_HTTPS=true; APP_DEBUG=false; SC_SECURE=true; }
|
||||
SCHEME_API=$([[ "$USE_HTTPS" == true ]] && echo "https" || echo "http")
|
||||
SCHEME_CONSOLE=$([[ "$USE_HTTPS" == true ]] && echo "https" || echo "http")
|
||||
|
||||
# Detect localhost
|
||||
IS_LOCALHOST=false
|
||||
[[ "$HOST" == "localhost" || "$HOST" == "0.0.0.0" || "$HOST" == "127.0.0.1" ]] && IS_LOCALHOST=true
|
||||
|
||||
info "Host: $HOST | Environment: $ENVIRONMENT | App name: $APP_NAME"
|
||||
|
||||
###############################################################################
|
||||
# 3. Determine project root no matter where script is called from
|
||||
# STEP 2 — Locate project root
|
||||
###############################################################################
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_ROOT="$( cd "$SCRIPT_DIR/.." && pwd )"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
###############################################################################
|
||||
# 4. Generate a fresh Laravel APP_KEY
|
||||
# STEP 3 — Database configuration
|
||||
###############################################################################
|
||||
if ! command -v openssl >/dev/null 2>&1; then
|
||||
echo "✖ openssl is required but not found. Install it and retry." >&2
|
||||
exit 1
|
||||
section "Database Configuration"
|
||||
|
||||
DB_MODE="internal" # default
|
||||
|
||||
if ! $NON_INTERACTIVE; then
|
||||
echo " 1) Bundled Docker MySQL (recommended for development)"
|
||||
echo " 2) External MySQL server (e.g. AWS RDS, PlanetScale)"
|
||||
read -rp "Choose [1]: " DB_CHOICE_INPUT
|
||||
[[ "${DB_CHOICE_INPUT:-1}" == "2" ]] && DB_MODE="external"
|
||||
fi
|
||||
|
||||
if [[ "$DB_MODE" == "external" ]]; then
|
||||
read -rp " Database host [127.0.0.1]: " DB_HOST_INPUT; DB_HOST="${DB_HOST_INPUT:-127.0.0.1}"
|
||||
read -rp " Database port [3306]: " DB_PORT_INPUT; DB_PORT="${DB_PORT_INPUT:-3306}"
|
||||
read -rp " Database name [fleetbase]: " DB_NAME_INPUT; DB_NAME="${DB_NAME_INPUT:-fleetbase}"
|
||||
read -rp " Database username: " DB_USER
|
||||
read -srp " Database password: " DB_PASS; echo
|
||||
# URL-encode the password (basic: replace @ and / which are most problematic)
|
||||
DB_PASS_ENC=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1],safe=''))" "$DB_PASS" 2>/dev/null || echo "$DB_PASS")
|
||||
DATABASE_URL="mysql://${DB_USER}:${DB_PASS_ENC}@${DB_HOST}:${DB_PORT}/${DB_NAME}"
|
||||
DB_ROOT_PASSWORD=""
|
||||
DB_USERNAME="$DB_USER"
|
||||
DB_PASSWORD="$DB_PASS"
|
||||
DB_DATABASE="$DB_NAME"
|
||||
success "External database configured"
|
||||
else
|
||||
DB_ROOT_PASSWORD="$(gen_secret 20)"
|
||||
DB_PASSWORD="$(gen_secret 20)"
|
||||
DB_USERNAME="fleetbase"
|
||||
DB_DATABASE="fleetbase"
|
||||
DATABASE_URL="mysql://${DB_USERNAME}:${DB_PASSWORD}@database/${DB_DATABASE}"
|
||||
success "Secure database credentials auto-generated"
|
||||
fi
|
||||
APP_KEY="base64:$(openssl rand -base64 32 | tr -d '\n')"
|
||||
echo "✔ Generated APP_KEY"
|
||||
|
||||
###############################################################################
|
||||
# 5. Ensure docker‑compose.override.yml is present & updated
|
||||
# STEP 4 — Mail configuration
|
||||
###############################################################################
|
||||
section "Mail Configuration"
|
||||
|
||||
MAIL_MAILER="log"
|
||||
MAIL_HOST=""; MAIL_PORT=""; MAIL_USERNAME=""; MAIL_PASSWORD=""
|
||||
MAIL_FROM_ADDRESS=""; MAIL_FROM_NAME="$APP_NAME"
|
||||
MAILGUN_DOMAIN=""; MAILGUN_SECRET=""
|
||||
POSTMARK_TOKEN=""; SENDGRID_API_KEY=""; RESEND_KEY=""
|
||||
|
||||
CONFIG_MAIL=false
|
||||
if ! $NON_INTERACTIVE; then
|
||||
read -rp "Configure a mail server? Required for password resets & notifications (y/N): " MAIL_YN
|
||||
[[ "${MAIL_YN,,}" == "y" || "${MAIL_YN,,}" == "yes" ]] && CONFIG_MAIL=true
|
||||
fi
|
||||
|
||||
if $CONFIG_MAIL; then
|
||||
echo " Mail drivers: 1) SMTP 2) Mailgun 3) Postmark 4) SendGrid 5) Resend 6) AWS SES 7) Log only"
|
||||
read -rp " Choose driver [1]: " MAIL_DRIVER_INPUT
|
||||
case "${MAIL_DRIVER_INPUT:-1}" in
|
||||
2) MAIL_MAILER="mailgun" ;;
|
||||
3) MAIL_MAILER="postmark" ;;
|
||||
4) MAIL_MAILER="sendgrid" ;;
|
||||
5) MAIL_MAILER="resend" ;;
|
||||
6) MAIL_MAILER="ses" ;;
|
||||
7) MAIL_MAILER="log" ;;
|
||||
*) MAIL_MAILER="smtp" ;;
|
||||
esac
|
||||
|
||||
DEFAULT_FROM="hello@$( $IS_LOCALHOST && echo 'example.com' || echo "$HOST" )"
|
||||
read -rp " From address [$DEFAULT_FROM]: " MAIL_FROM_INPUT
|
||||
MAIL_FROM_ADDRESS="${MAIL_FROM_INPUT:-$DEFAULT_FROM}"
|
||||
read -rp " From name [$APP_NAME]: " MAIL_FROM_NAME_INPUT
|
||||
MAIL_FROM_NAME="${MAIL_FROM_NAME_INPUT:-$APP_NAME}"
|
||||
|
||||
case "$MAIL_MAILER" in
|
||||
smtp)
|
||||
read -rp " SMTP host [smtp.mailgun.org]: " MAIL_HOST_INPUT; MAIL_HOST="${MAIL_HOST_INPUT:-smtp.mailgun.org}"
|
||||
read -rp " SMTP port [587]: " MAIL_PORT_INPUT; MAIL_PORT="${MAIL_PORT_INPUT:-587}"
|
||||
read -rp " SMTP username: " MAIL_USERNAME
|
||||
read -srp " SMTP password: " MAIL_PASSWORD; echo
|
||||
;;
|
||||
mailgun)
|
||||
read -rp " Mailgun domain: " MAILGUN_DOMAIN
|
||||
read -srp " Mailgun API secret: " MAILGUN_SECRET; echo
|
||||
;;
|
||||
postmark)
|
||||
read -srp " Postmark server token: " POSTMARK_TOKEN; echo
|
||||
;;
|
||||
sendgrid)
|
||||
read -srp " SendGrid API key: " SENDGRID_API_KEY; echo
|
||||
;;
|
||||
resend)
|
||||
read -srp " Resend API key: " RESEND_KEY; echo
|
||||
;;
|
||||
ses)
|
||||
info "AWS SES will use the AWS credentials configured in the Storage step."
|
||||
;;
|
||||
esac
|
||||
success "Mail driver set to: $MAIL_MAILER"
|
||||
else
|
||||
info "Skipped — emails will be written to the application log."
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# STEP 5 — File storage
|
||||
###############################################################################
|
||||
section "File Storage Configuration"
|
||||
|
||||
FILESYSTEM_DRIVER="public"
|
||||
AWS_ACCESS_KEY_ID=""; AWS_SECRET_ACCESS_KEY=""; AWS_DEFAULT_REGION=""
|
||||
AWS_BUCKET=""; AWS_URL=""; AWS_USE_PATH_STYLE_ENDPOINT=""
|
||||
GOOGLE_CLOUD_PROJECT_ID=""; GOOGLE_CLOUD_STORAGE_BUCKET=""; GOOGLE_CLOUD_KEY_FILE=""
|
||||
|
||||
if ! $NON_INTERACTIVE; then
|
||||
echo " Storage drivers: 1) Local disk (dev only) 2) AWS S3 3) Google Cloud Storage"
|
||||
read -rp " Choose driver [1]: " STORAGE_INPUT
|
||||
case "${STORAGE_INPUT:-1}" in
|
||||
2) FILESYSTEM_DRIVER="s3" ;;
|
||||
3) FILESYSTEM_DRIVER="gcs" ;;
|
||||
*) FILESYSTEM_DRIVER="public" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [[ "$FILESYSTEM_DRIVER" == "s3" ]]; then
|
||||
read -rp " AWS Access Key ID: " AWS_ACCESS_KEY_ID
|
||||
read -srp " AWS Secret Access Key: " AWS_SECRET_ACCESS_KEY; echo
|
||||
read -rp " AWS Region [us-east-1]: " AWS_REGION_INPUT; AWS_DEFAULT_REGION="${AWS_REGION_INPUT:-us-east-1}"
|
||||
read -rp " S3 Bucket name: " AWS_BUCKET
|
||||
read -rp " S3 Public URL (leave blank for default): " AWS_URL
|
||||
read -rp " Use path-style endpoint? (for MinIO/non-AWS S3) (y/N): " PATH_STYLE_INPUT
|
||||
[[ "${PATH_STYLE_INPUT,,}" == "y" ]] && AWS_USE_PATH_STYLE_ENDPOINT="true"
|
||||
success "S3 storage configured"
|
||||
elif [[ "$FILESYSTEM_DRIVER" == "gcs" ]]; then
|
||||
read -rp " GCS Project ID: " GOOGLE_CLOUD_PROJECT_ID
|
||||
read -rp " GCS Bucket name: " GOOGLE_CLOUD_STORAGE_BUCKET
|
||||
read -rp " Path to GCS key file (JSON): " GOOGLE_CLOUD_KEY_FILE
|
||||
success "Google Cloud Storage configured"
|
||||
else
|
||||
info "Local disk selected — suitable for development only."
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# STEP 6 — Security & CORS
|
||||
###############################################################################
|
||||
section "Security & CORS Configuration"
|
||||
|
||||
# Derive SESSION_DOMAIN
|
||||
SESSION_DOMAIN="$( $IS_LOCALHOST && echo 'localhost' || echo "$HOST" )"
|
||||
|
||||
# Derive SOCKETCLUSTER_OPTIONS origins
|
||||
if $IS_LOCALHOST; then
|
||||
SOCKET_ORIGINS="http://localhost:*,https://localhost:*,ws://localhost:*,wss://localhost:*"
|
||||
else
|
||||
SOCKET_ORIGINS="${SCHEME_CONSOLE}://${HOST}:*,wss://${HOST}:*"
|
||||
fi
|
||||
SOCKETCLUSTER_OPTIONS="{\"origins\":\"${SOCKET_ORIGINS}\"}"
|
||||
|
||||
success "SESSION_DOMAIN set to: $SESSION_DOMAIN"
|
||||
success "WebSocket origins restricted to: $SOCKET_ORIGINS"
|
||||
|
||||
FRONTEND_HOSTS=""
|
||||
if ! $NON_INTERACTIVE; then
|
||||
read -rp "Additional frontend hosts for CORS (comma-separated, leave blank for none): " FRONTEND_HOSTS
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# STEP 7 — Optional third-party API keys
|
||||
###############################################################################
|
||||
section "Optional Third-Party Services"
|
||||
|
||||
IPINFO_API_KEY=""; GOOGLE_MAPS_API_KEY=""; GOOGLE_MAPS_LOCALE="us"
|
||||
TWILIO_SID=""; TWILIO_TOKEN=""; TWILIO_FROM=""
|
||||
|
||||
CONFIG_3P=false
|
||||
if ! $NON_INTERACTIVE; then
|
||||
read -rp "Configure optional third-party API keys now? (Maps, Geolocation, SMS) (y/N): " TP_YN
|
||||
[[ "${TP_YN,,}" == "y" || "${TP_YN,,}" == "yes" ]] && CONFIG_3P=true
|
||||
fi
|
||||
|
||||
if $CONFIG_3P; then
|
||||
read -rp " IPInfo API key (geolocation, leave blank to skip): " IPINFO_API_KEY
|
||||
read -rp " Google Maps API key (leave blank to skip): " GOOGLE_MAPS_API_KEY
|
||||
read -rp " Google Maps locale [us]: " GM_LOCALE_INPUT; GOOGLE_MAPS_LOCALE="${GM_LOCALE_INPUT:-us}"
|
||||
read -rp " Twilio Account SID (SMS, leave blank to skip): " TWILIO_SID
|
||||
read -srp " Twilio Auth Token: " TWILIO_TOKEN; echo
|
||||
read -rp " Twilio From phone number: " TWILIO_FROM
|
||||
success "Third-party services configured"
|
||||
else
|
||||
info "Skipped — these can be added later via docker-compose.override.yml"
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# STEP 8 — Generate APP_KEY
|
||||
###############################################################################
|
||||
section "Generating Application Key"
|
||||
APP_KEY="base64:$(openssl rand -base64 32 | tr -d '\n')"
|
||||
success "APP_KEY generated"
|
||||
|
||||
###############################################################################
|
||||
# STEP 9 — Write docker-compose.override.yml
|
||||
###############################################################################
|
||||
section "Writing docker-compose.override.yml"
|
||||
|
||||
OVERRIDE_FILE="docker-compose.override.yml"
|
||||
|
||||
# url helpers
|
||||
SCHEME_API=$([[ "$USE_HTTPS" == true ]] && echo "https" || echo "http")
|
||||
SCHEME_CONSOLE=$([[ "$USE_HTTPS" == true ]] && echo "https" || echo "http")
|
||||
# Back up any existing override
|
||||
if [[ -f "$OVERRIDE_FILE" ]]; then
|
||||
BACKUP="${OVERRIDE_FILE}.bak.$(date +%Y%m%d%H%M%S)"
|
||||
cp "$OVERRIDE_FILE" "$BACKUP"
|
||||
info "Existing override backed up to $BACKUP"
|
||||
fi
|
||||
|
||||
update_override_with_yq() {
|
||||
yq -i "
|
||||
.services.application.environment.APP_KEY = \"$APP_KEY\" |
|
||||
.services.application.environment.CONSOLE_HOST = \"$SCHEME_CONSOLE://$HOST:4200\" |
|
||||
.services.application.environment.ENVIRONMENT = \"$ENVIRONMENT\" |
|
||||
.services.application.environment.APP_DEBUG = \"$APP_DEBUG\"
|
||||
" "$OVERRIDE_FILE"
|
||||
echo "✔ $OVERRIDE_FILE updated (yq)"
|
||||
}
|
||||
# Build the file using a temp file for atomicity
|
||||
OVERRIDE_TMP="${OVERRIDE_FILE}.tmp.$$"
|
||||
|
||||
create_override() {
|
||||
cat > "$OVERRIDE_FILE" <<YML
|
||||
{
|
||||
cat <<YAML_HEADER
|
||||
services:
|
||||
application:
|
||||
environment:
|
||||
APP_KEY: "$APP_KEY"
|
||||
CONSOLE_HOST: "$SCHEME_CONSOLE://$HOST:4200"
|
||||
ENVIRONMENT: "$ENVIRONMENT"
|
||||
APP_DEBUG: "$APP_DEBUG"
|
||||
YML
|
||||
echo "✔ $OVERRIDE_FILE written"
|
||||
}
|
||||
YAML_HEADER
|
||||
|
||||
if [[ -f "$OVERRIDE_FILE" ]]; then
|
||||
if command -v yq >/dev/null 2>&1; then
|
||||
update_override_with_yq
|
||||
else
|
||||
cp "$OVERRIDE_FILE" "${OVERRIDE_FILE}.bak.$(date +%Y%m%d%H%M%S)"
|
||||
echo "ℹ︎ Existing $OVERRIDE_FILE backed up (no yq found — recreating)"
|
||||
create_override
|
||||
env_line "APP_KEY" "$APP_KEY"
|
||||
env_line "APP_NAME" "$APP_NAME"
|
||||
env_line "APP_URL" "${SCHEME_API}://${HOST}:8000"
|
||||
env_line "CONSOLE_HOST" "${SCHEME_CONSOLE}://${HOST}:4200"
|
||||
env_line "ENVIRONMENT" "$ENVIRONMENT"
|
||||
env_line "APP_DEBUG" "$APP_DEBUG"
|
||||
env_line "DATABASE_URL" "$DATABASE_URL"
|
||||
env_line "SESSION_DOMAIN" "$SESSION_DOMAIN"
|
||||
env_line "FRONTEND_HOSTS" "$FRONTEND_HOSTS"
|
||||
# Mail
|
||||
env_line "MAIL_MAILER" "$MAIL_MAILER"
|
||||
env_line "MAIL_HOST" "$MAIL_HOST"
|
||||
env_line "MAIL_PORT" "$MAIL_PORT"
|
||||
env_line "MAIL_USERNAME" "$MAIL_USERNAME"
|
||||
env_line "MAIL_PASSWORD" "$MAIL_PASSWORD"
|
||||
env_line "MAIL_FROM_ADDRESS" "$MAIL_FROM_ADDRESS"
|
||||
env_line "MAIL_FROM_NAME" "$MAIL_FROM_NAME"
|
||||
env_line "MAILGUN_DOMAIN" "$MAILGUN_DOMAIN"
|
||||
env_line "MAILGUN_SECRET" "$MAILGUN_SECRET"
|
||||
env_line "POSTMARK_TOKEN" "$POSTMARK_TOKEN"
|
||||
env_line "SENDGRID_API_KEY" "$SENDGRID_API_KEY"
|
||||
env_line "RESEND_KEY" "$RESEND_KEY"
|
||||
# Storage
|
||||
[[ "$FILESYSTEM_DRIVER" != "public" ]] && env_line "FILESYSTEM_DRIVER" "$FILESYSTEM_DRIVER"
|
||||
env_line "AWS_ACCESS_KEY_ID" "$AWS_ACCESS_KEY_ID"
|
||||
env_line "AWS_SECRET_ACCESS_KEY" "$AWS_SECRET_ACCESS_KEY"
|
||||
env_line "AWS_DEFAULT_REGION" "$AWS_DEFAULT_REGION"
|
||||
env_line "AWS_BUCKET" "$AWS_BUCKET"
|
||||
env_line "AWS_URL" "$AWS_URL"
|
||||
env_line "AWS_USE_PATH_STYLE_ENDPOINT" "$AWS_USE_PATH_STYLE_ENDPOINT"
|
||||
env_line "GOOGLE_CLOUD_PROJECT_ID" "$GOOGLE_CLOUD_PROJECT_ID"
|
||||
env_line "GOOGLE_CLOUD_STORAGE_BUCKET" "$GOOGLE_CLOUD_STORAGE_BUCKET"
|
||||
env_line "GOOGLE_CLOUD_KEY_FILE" "$GOOGLE_CLOUD_KEY_FILE"
|
||||
# Third-party
|
||||
env_line "IPINFO_API_KEY" "$IPINFO_API_KEY"
|
||||
env_line "GOOGLE_MAPS_API_KEY" "$GOOGLE_MAPS_API_KEY"
|
||||
env_line "GOOGLE_MAPS_LOCALE" "$GOOGLE_MAPS_LOCALE"
|
||||
env_line "TWILIO_SID" "$TWILIO_SID"
|
||||
env_line "TWILIO_TOKEN" "$TWILIO_TOKEN"
|
||||
env_line "TWILIO_FROM" "$TWILIO_FROM"
|
||||
|
||||
cat <<YAML_SOCKET
|
||||
|
||||
socket:
|
||||
environment:
|
||||
SOCKETCLUSTER_OPTIONS: '${SOCKETCLUSTER_OPTIONS}'
|
||||
YAML_SOCKET
|
||||
|
||||
# Add database service block only when using the bundled container
|
||||
if [[ "$DB_MODE" == "internal" ]]; then
|
||||
cat <<YAML_DB
|
||||
|
||||
database:
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
|
||||
MYSQL_DATABASE: "${DB_DATABASE}"
|
||||
MYSQL_USER: "${DB_USERNAME}"
|
||||
MYSQL_PASSWORD: "${DB_PASSWORD}"
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "no"
|
||||
YAML_DB
|
||||
fi
|
||||
else
|
||||
create_override
|
||||
fi
|
||||
} > "$OVERRIDE_TMP"
|
||||
|
||||
mv -f "$OVERRIDE_TMP" "$OVERRIDE_FILE"
|
||||
success "$OVERRIDE_FILE written"
|
||||
|
||||
###############################################################################
|
||||
# 6. Write console/fleetbase.config.json atomically (for development runtime)
|
||||
# STEP 10 — Write console configuration files
|
||||
###############################################################################
|
||||
section "Updating Console Configuration"
|
||||
|
||||
CONFIG_DIR="console"
|
||||
CONFIG_PATH="$CONFIG_DIR/fleetbase.config.json"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
|
||||
cat > "${CONFIG_PATH}.tmp" <<JSON
|
||||
OSRM_HOST="https://router.project-osrm.org"
|
||||
|
||||
cat > "${CONFIG_DIR}/fleetbase.config.json.tmp" <<JSON
|
||||
{
|
||||
"API_HOST": "$SCHEME_API://$HOST:8000",
|
||||
"SOCKETCLUSTER_HOST": "$HOST",
|
||||
"API_HOST": "${SCHEME_API}://${HOST}:8000",
|
||||
"SOCKETCLUSTER_HOST": "${HOST}",
|
||||
"SOCKETCLUSTER_PORT": "38000",
|
||||
"SOCKETCLUSTER_SECURE": "$SC_SECURE"
|
||||
"SOCKETCLUSTER_SECURE": "${SC_SECURE}"
|
||||
}
|
||||
JSON
|
||||
mv -f "${CONFIG_PATH}.tmp" "$CONFIG_PATH"
|
||||
echo "✔ $CONFIG_PATH updated"
|
||||
mv -f "${CONFIG_DIR}/fleetbase.config.json.tmp" "${CONFIG_DIR}/fleetbase.config.json"
|
||||
|
||||
###############################################################################
|
||||
# 6b. Update console environment files (.env.development and .env.production)
|
||||
###############################################################################
|
||||
ENV_DIR="$CONFIG_DIR/environments"
|
||||
ENV_DIR="${CONFIG_DIR}/environments"
|
||||
mkdir -p "$ENV_DIR"
|
||||
|
||||
# Update .env.development
|
||||
cat > "$ENV_DIR/.env.development" <<ENV_DEV
|
||||
API_HOST=http://$HOST:8000
|
||||
cat > "${ENV_DIR}/.env.development" <<ENV_DEV
|
||||
API_HOST=http://${HOST}:8000
|
||||
API_NAMESPACE=int/v1
|
||||
SOCKETCLUSTER_PATH=/socketcluster/
|
||||
SOCKETCLUSTER_HOST=$HOST
|
||||
SOCKETCLUSTER_HOST=${HOST}
|
||||
SOCKETCLUSTER_SECURE=false
|
||||
SOCKETCLUSTER_PORT=38000
|
||||
OSRM_HOST=https://router.project-osrm.org
|
||||
OSRM_HOST=${OSRM_HOST}
|
||||
ENV_DEV
|
||||
|
||||
# Update .env.production
|
||||
cat > "$ENV_DIR/.env.production" <<ENV_PROD
|
||||
API_HOST=https://$HOST:8000
|
||||
cat > "${ENV_DIR}/.env.production" <<ENV_PROD
|
||||
API_HOST=https://${HOST}:8000
|
||||
API_NAMESPACE=int/v1
|
||||
API_SECURE=true
|
||||
SOCKETCLUSTER_PATH=/socketcluster/
|
||||
SOCKETCLUSTER_HOST=$HOST
|
||||
SOCKETCLUSTER_HOST=${HOST}
|
||||
SOCKETCLUSTER_SECURE=true
|
||||
SOCKETCLUSTER_PORT=38000
|
||||
OSRM_HOST=https://router.project-osrm.org
|
||||
OSRM_HOST=${OSRM_HOST}
|
||||
ENV_PROD
|
||||
|
||||
echo "✔ Console environment files updated"
|
||||
success "Console configuration files updated"
|
||||
|
||||
###############################################################################
|
||||
# 7. Start stack, wait for DB, then run deploy
|
||||
# STEP 11 — Start containers
|
||||
###############################################################################
|
||||
echo "⏳ Starting Fleetbase containers..."
|
||||
section "Starting Fleetbase Containers"
|
||||
echo " This may take a few minutes on first run..."
|
||||
docker compose up -d
|
||||
|
||||
###############################################################################
|
||||
# 7a. Wait for the database container to be ready
|
||||
# STEP 12 — Wait for database
|
||||
###############################################################################
|
||||
DB_SERVICE="database" # ← change if your docker‑compose uses a different name
|
||||
DB_WAIT_TIMEOUT=60 # seconds
|
||||
section "Waiting for Database"
|
||||
DB_SERVICE="database"
|
||||
DB_WAIT_TIMEOUT=90
|
||||
|
||||
echo "⏳ Waiting for $DB_SERVICE to become ready (timeout: ${DB_WAIT_TIMEOUT}s)..."
|
||||
DB_CONTAINER=$(docker compose ps -q "$DB_SERVICE")
|
||||
|
||||
if [ -z "$DB_CONTAINER" ]; then
|
||||
echo "✖ Cannot find a running container for service \"$DB_SERVICE\". Check docker‑compose.yml."
|
||||
DB_CONTAINER=$(docker compose ps -q "$DB_SERVICE" 2>/dev/null || true)
|
||||
if [[ -z "$DB_CONTAINER" ]]; then
|
||||
error "Cannot find a running container for service \"$DB_SERVICE\". Check docker-compose.yml."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the service defines a HEALTHCHECK we can rely on it…
|
||||
# Prefer Docker HEALTHCHECK if defined, fall back to mysqladmin ping
|
||||
if docker inspect -f '{{.State.Health.Status}}' "$DB_CONTAINER" &>/dev/null; then
|
||||
SECONDS=0
|
||||
until [ "$(docker inspect -f '{{.State.Health.Status}}' "$DB_CONTAINER")" = "healthy" ]; do
|
||||
if [ "$SECONDS" -ge "$DB_WAIT_TIMEOUT" ]; then
|
||||
echo "✖ Timed out waiting for the database to become healthy."
|
||||
until [[ "$(docker inspect -f '{{.State.Health.Status}}' "$DB_CONTAINER")" == "healthy" ]]; do
|
||||
if (( SECONDS >= DB_WAIT_TIMEOUT )); then
|
||||
error "Timed out waiting for the database to become healthy."
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
sleep 12
|
||||
sleep 5 # brief grace period after healthy
|
||||
else
|
||||
# Fallback: use mysqladmin ping (works for MySQL / MariaDB)
|
||||
SECONDS=0
|
||||
until docker compose exec "$DB_SERVICE" sh -c "mysqladmin --silent --wait=1 -uroot -h127.0.0.1 ping" &>/dev/null; do
|
||||
if [ "$SECONDS" -ge "$DB_WAIT_TIMEOUT" ]; then
|
||||
echo "✖ Timed out waiting for the database to accept connections."
|
||||
until docker compose exec -T "$DB_SERVICE" sh -c "mysqladmin --silent --wait=1 -uroot -h127.0.0.1 ping" &>/dev/null; do
|
||||
if (( SECONDS >= DB_WAIT_TIMEOUT )); then
|
||||
error "Timed out waiting for the database to accept connections."
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
echo "✔ Database is ready."
|
||||
success "Database is ready"
|
||||
|
||||
###############################################################################
|
||||
# 7b. Run the deploy script inside the application container
|
||||
# STEP 13 — Run deploy script
|
||||
###############################################################################
|
||||
echo "⏳ Running deploy script inside the application container..."
|
||||
docker compose exec application bash -c "./deploy.sh"
|
||||
section "Running Deployment Script"
|
||||
docker compose exec -T application bash -c "./deploy.sh"
|
||||
docker compose up -d
|
||||
success "Deployment complete"
|
||||
|
||||
###############################################################################
|
||||
# STEP 14 — Post-install summary
|
||||
###############################################################################
|
||||
CONFIGURED_ITEMS=()
|
||||
SKIPPED_ITEMS=()
|
||||
|
||||
[[ "$DB_MODE" == "external" ]] \
|
||||
&& CONFIGURED_ITEMS+=("External Database") \
|
||||
|| CONFIGURED_ITEMS+=("Bundled MySQL (secure credentials auto-generated)")
|
||||
|
||||
$CONFIG_MAIL \
|
||||
&& CONFIGURED_ITEMS+=("Mail (${MAIL_MAILER})") \
|
||||
|| SKIPPED_ITEMS+=("Mail (using log driver — configure later)")
|
||||
|
||||
[[ "$FILESYSTEM_DRIVER" != "public" ]] \
|
||||
&& CONFIGURED_ITEMS+=("File Storage (${FILESYSTEM_DRIVER^^})") \
|
||||
|| SKIPPED_ITEMS+=("File storage (local disk — not suitable for production)")
|
||||
|
||||
CONFIGURED_ITEMS+=("WebSocket security (origins restricted to ${HOST})")
|
||||
|
||||
$CONFIG_3P \
|
||||
&& CONFIGURED_ITEMS+=("Third-party APIs (Maps, Geolocation, SMS)") \
|
||||
|| SKIPPED_ITEMS+=("Third-party APIs (Maps, Geolocation, SMS)")
|
||||
|
||||
echo
|
||||
echo "🏁 Fleetbase is up!"
|
||||
printf " API → %s://%s:8000\n" "$SCHEME_API" "$HOST"
|
||||
printf " Console → %s://%s:4200\n\n" "$SCHEME_CONSOLE" "$HOST"
|
||||
printf '%0.s═' {1..60}; echo
|
||||
echo -e " ${BOLD}🏁 Fleetbase Installation Complete${RESET}"
|
||||
printf '%0.s═' {1..60}; echo
|
||||
echo
|
||||
echo " 📍 Endpoints"
|
||||
printf " API → %s://%s:8000\n" "$SCHEME_API" "$HOST"
|
||||
printf " Console → %s://%s:4200\n" "$SCHEME_CONSOLE" "$HOST"
|
||||
if [[ ${#CONFIGURED_ITEMS[@]} -gt 0 ]]; then
|
||||
echo
|
||||
echo " ✔ Configured:"
|
||||
for item in "${CONFIGURED_ITEMS[@]}"; do echo " • $item"; done
|
||||
fi
|
||||
if [[ ${#SKIPPED_ITEMS[@]} -gt 0 ]]; then
|
||||
echo
|
||||
echo " ⚠ Skipped (defaults applied):"
|
||||
for item in "${SKIPPED_ITEMS[@]}"; do echo " • $item"; done
|
||||
fi
|
||||
echo
|
||||
echo " 🔐 Next Steps"
|
||||
echo " 1. Open the Console URL in your browser."
|
||||
echo " 2. Complete the onboarding wizard to create your"
|
||||
echo " initial organization and administrator account."
|
||||
if [[ ${#SKIPPED_ITEMS[@]} -gt 0 ]]; then
|
||||
echo " 3. To configure skipped options, edit"
|
||||
echo " docker-compose.override.yml and run:"
|
||||
echo " docker compose up -d"
|
||||
fi
|
||||
echo
|
||||
echo " 📄 Config saved to: docker-compose.override.yml"
|
||||
printf '%0.s═' {1..60}; echo
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user