Fix R15: require prod hardening in docs; drop N+1 in warnings
- Document that production must set APP_ENV=production + APP_DEBUG=false (else exceptions leak and the demo household seeds); note it in .env.example too. - HomeStatus::warnings now iterates devices → entities using the already-loaded device, instead of $entity->device, removing an N+1 on dashboard render. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/phase-1-bootstrap
parent
52af82115d
commit
2a39f1cc4e
|
|
@ -1,4 +1,6 @@
|
|||
APP_NAME=HomeOS
|
||||
# Development defaults. For production set APP_ENV=production and APP_DEBUG=false
|
||||
# (otherwise exceptions are exposed and the demo household is seeded).
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -22,8 +22,17 @@ Then open **http://localhost** and sign in with the seeded dev admin:
|
|||
|
||||
- **admin@homeos.local** / **homeos-dev** ← change this for anything but local dev.
|
||||
|
||||
For production, set strong values in `.env` for `DB_PASSWORD`, the `REVERB_APP_*`
|
||||
keys and `HOMEOS_ADMIN_PASSWORD`, and run `php artisan key:generate`.
|
||||
### Production
|
||||
|
||||
`.env.example` ships **development** defaults. For a real deployment you **must**:
|
||||
|
||||
- set `APP_ENV=production` and `APP_DEBUG=false` (otherwise exceptions are exposed
|
||||
and the demo household is seeded into your real database);
|
||||
- set strong values for `DB_PASSWORD`, the `REVERB_APP_*` keys and
|
||||
`HOMEOS_ADMIN_PASSWORD` (seeding aborts if the admin password is unset outside
|
||||
local/testing), and run `php artisan key:generate`.
|
||||
|
||||
The demo seeder (`DemoHomeSeeder`) only runs in local/testing.
|
||||
|
||||
## Everyday commands (in-container, R8)
|
||||
|
||||
|
|
|
|||
|
|
@ -40,33 +40,35 @@ class HomeStatus
|
|||
/** @return array<int, array{level:string,icon:string,title:string,meta:?string,link:?string}> */
|
||||
public function warnings(Collection $devices): array
|
||||
{
|
||||
$entities = $devices->flatMap->entities;
|
||||
$warnings = [];
|
||||
|
||||
foreach ($devices->reject->isOnline() as $device) {
|
||||
$warnings[] = [
|
||||
'level' => 'offline', 'icon' => 'devices',
|
||||
'title' => $device->name, 'meta' => __('devices.offline'), 'link' => null,
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($entities as $entity) {
|
||||
if ($entity->type === 'contact' && data_get($entity->state, 'state.open') === true) {
|
||||
// Iterate devices (already loaded) → entities so we never lazy-load $entity->device (no N+1).
|
||||
foreach ($devices as $device) {
|
||||
if (! $device->isOnline()) {
|
||||
$warnings[] = [
|
||||
'level' => 'warning', 'icon' => 'window',
|
||||
'title' => $entity->device->name, 'meta' => __('devices.open'), 'link' => null,
|
||||
'level' => 'offline', 'icon' => 'devices',
|
||||
'title' => $device->name, 'meta' => __('devices.offline'), 'link' => null,
|
||||
];
|
||||
}
|
||||
|
||||
if ($entity->type === 'battery') {
|
||||
$percent = (int) data_get($entity->state, 'state.percent', 100);
|
||||
if ($percent < self::LOW_BATTERY) {
|
||||
foreach ($device->entities as $entity) {
|
||||
if ($entity->type === 'contact' && data_get($entity->state, 'state.open') === true) {
|
||||
$warnings[] = [
|
||||
'level' => 'warning', 'icon' => 'alert',
|
||||
'title' => $entity->device->name,
|
||||
'meta' => __('devices.battery').': '.$percent.'%', 'link' => null,
|
||||
'level' => 'warning', 'icon' => 'window',
|
||||
'title' => $device->name, 'meta' => __('devices.open'), 'link' => null,
|
||||
];
|
||||
}
|
||||
|
||||
if ($entity->type === 'battery') {
|
||||
$percent = (int) data_get($entity->state, 'state.percent', 100);
|
||||
if ($percent < self::LOW_BATTERY) {
|
||||
$warnings[] = [
|
||||
'level' => 'warning', 'icon' => 'alert',
|
||||
'title' => $device->name,
|
||||
'meta' => __('devices.battery').': '.$percent.'%', 'link' => null,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue