Files
lucent-laravel/docs/Website Setup.md
T
2026-05-06 23:42:32 +03:00

211 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Website Setup
This is an opinionated website setup. It's irrelevant to both Lucent and Laravel. It is just the way I like to organize everything.
## Summary
- Create a Lucent folder with Schemas, Image Filters and Pages
- Pages are similar to controllers, but will also get used to statically generate the website
- A Context singleton class that acts as a container for global state
- A middleware to initiate the Context class and set the application state for the request
- Some helper functions to make our life easier
## Context Class
```php
<?php namespace App\Lucent;
class Context
{
public string $website = "";
public string $title;
public string $description = "";
public string $url = "";
public string $mode = "static";
public string $locale = "el";
public array $data = [];
public array $locales = ["el","en"];
protected array $pages = [
"homepage" => Homepage::class,
];
public function __construct(
public Application $app,
public Query $query
){}
public function render(string $pageName, ...$args): string
{
$page = $this->app->make($this->pages[$pageName]);
return $page->render(...$args);
}
public function getTitle()
{
return empty($this->title) ? $this->website : $this->title . " | " . $this->website;
}
public function getFullUrl(string $path = "")
{
return config("app.url") . $this->generateLocaleUrl($path, $this->locale);
}
public function localeUrl(string $path = ""): string
{
return $this->generateLocaleUrl($path, $this->locale);
}
public function switchLocale(string $locale, $path = ""): string
{
return $this->generateLocaleUrl($path, $locale);
}
private function generateLocaleUrl(string $path, string $locale): string
{
if ($this->mode == "preview") {
return config("app.url") . "/preview/" . $locale . "/" . trim($path, "/");
}
return config("app.url") . "/" . $locale . "/" . trim($path, "/");
}
}
```
Add this class to `AppServiceProvider` as a singleton
```php
$this->app->singleton(Context::class);
```
## Context Middleware
```php
<?php namespace App\Http\Middleware;
class Context
{
public function __construct(public Context $context){}
public function handle(Request $request, Closure $next, string $mode = "static"): Response
{
$this->context->locale = $request->route("locale");
App::setLocale($this->meta->locale);
$this->context->mode = $mode;
$this->context->loadData();
return $next($request);
}
}
```
Add the middleware inside the HTTP Kernel file.
## Configuration
After publishing the config (`php artisan vendor:publish --tag=lucent-config`), configure `config/lucent.php` via `.env`:
| Key | Env var | Default | Description |
|---|---|---|---|
| `env` | `LUCENT_ENV` | `production` | `production` or `development` |
| `auth` | `LUCENT_AUTH` | `lucent` | Auth driver: `lucent` or `lunar` |
| `disk` | `LUCENT_DISK` | `public` | Laravel filesystem disk for uploads |
| `schemas_path` | `LUCENT_SCHEMAS_PATH` | `resources/lucent/schemas` | Where schema JSON files live |
| `database` | `LUCENT_DB_CONNECTION` | `DB_CONNECTION` | Database connection name |
| `name` | `LUCENT_NAME` | `Lucent` | CMS display name |
| `url` | `LUCENT_URL` | `APP_URL` | Base URL of the CMS |
| `previewTarget` | `LUCENT_PREVIEW_TARGET` | `previewTarget` | Preview route parameter |
| `commands` | — | `[]` | Artisan commands exposed to admin users (see [Static Generator](Static%20Generator.md)) |
| `imageFilters` | — | `[]` | Image filter presets applied to uploads (see below) |
| `canInvite` | — | `["admin"]` | Roles that can invite new users |
| `canBuild` | — | `["admin"]` | Roles that can trigger static builds |
| `systemUserId` | — | `""` | User ID used for console-initiated record writes |
## Image Filters
Image filters are Intervention Image filter classes applied to every uploaded image, producing additional versions (e.g. a cropped or watermarked variant). Each preset is stored at `templates/{name}/{original-path}` on the configured disk.
Define filters in `config/lucent.php`:
```php
"imageFilters" => [
"hero" => \App\ImageFilters\HeroFilter::class,
"thumb" => \App\ImageFilters\ThumbFilter::class,
],
```
A filter class must implement `Intervention\Image\Filters\FilterInterface`:
```php
namespace App\ImageFilters;
use Intervention\Image\Filters\FilterInterface;
use Intervention\Image\Image;
class HeroFilter implements FilterInterface
{
public function applyFilter(Image $image): Image
{
return $image->fit(1200, 600)->encode('webp', 80);
}
}
```
Every uploaded image automatically gets a 300×300 WebP thumbnail at `thumbs/{path}` in addition to any configured presets.
## Authentication
Lucent uses **email-link (magic link) login** — no passwords. Users receive a time-limited link by email.
### Auth modes
Set `LUCENT_AUTH` to choose how users are stored:
| Value | Description |
|---|---|
| `lucent` | Users stored in the `lucent_users` table. Supports roles. |
| `lunar` | Delegates to Lunar's `lunar_staff` table. Roles not supported. |
### Login flow
1. User submits their email at `/lucent/login`
2. A 32-character token is stored against the user with a timestamp
3. Lucent emails a login link containing the token
4. User clicks the link → token is validated (must be used within **1 hour**)
5. Session is established; token is cleared
### First-time setup
The `/lucent/register` route is only available when **no users exist** in the system. Once the first admin registers, the route returns a redirect to `/lucent/login`. Registration automatically assigns the `admin` role and sends a login link.
### Middleware
Two middleware aliases are available for your routes:
| Alias | Description |
|---|---|
| `lucent.auth` | Requires an active Lucent session |
| `lucent.guest` | Redirects authenticated users away |
### Roles
Roles are defined in your channel config. Only roles listed there are valid — anything else is silently stripped on assignment. The `canInvite` and `canBuild` config keys control which roles can invite users and trigger builds respectively.
On console commands and non-`/lucent` routes, `currentUserId()` returns `config("lucent.systemUserId")` instead of the session user.
## Database Tables
All Lucent-managed tables use the `lucent_` prefix:
| Table | Description |
|---|---|
| `lucent_records` | All collection and file schema records |
| `lucent_files` | Uploaded file metadata |
| `lucent_edges` | Relationships between records |
| `lucent_revisions` | Record revision history |
| `lucent_users` | Users (when using `lucent` auth mode) |
| `lucent_command_logs` | Background command execution logs |
These are created automatically by running `php artisan lucent:setup`.