doc update

This commit is contained in:
2026-05-06 23:42:32 +03:00
parent 1e2f941f47
commit fcadc8d7a1
4 changed files with 223 additions and 30 deletions
+10 -2
View File
@@ -165,9 +165,17 @@ Date and time selector. Stores as an ISO 8601 string.
---
### uuid
UUID text field. Stores an arbitrary UUID string. Typically used as a read-only external reference ID.
**Required:** `name`, `label`
---
### json
Raw JSON data field.
Raw JSON data field. Accepts either a JSON string or a plain array — both are stored as JSON.
**Required:** `name`, `label`
@@ -175,7 +183,7 @@ Raw JSON data field.
### file
Upload or select files from a files schema.
Upload or select files from a files schema. Files can be uploaded directly or browsed from previously uploaded files. Image files (jpeg, png, webp, gif, tiff) automatically get a 300×300 thumbnail generated on upload.
**Required:** `name`, `label`, `collections`
+18 -2
View File
@@ -40,8 +40,6 @@ There are 2 types of schemas:
| `label` | yes | Friendly display name |
| `type` | yes | Must be `"files"` |
| `fields` | yes | Array of field definitions. See [Fields](Fields.md) |
| `disk` | no | Laravel disk name. Default: `"lucent"` |
| `path` | no | Subdirectory for uploads. Default: schema name |
| `groups` | no | Group IDs to split fields into tabs |
| `isEntry` | no | Show in sidebar. Default: `false` |
| `sortBy` | no | Default sort in browser |
@@ -51,6 +49,24 @@ There are 2 types of schemas:
| `read` | no | Roles with read access |
| `write` | no | Roles with write access |
### File Metadata
Every uploaded file is automatically stored with the following metadata (stored in `lucent_files`):
| Field | Description |
|---|---|
| `id` | Unique file ID |
| `recordId` | ID of the record this file belongs to |
| `originalName` | Original filename as uploaded |
| `mime` | MIME type e.g. `image/webp` |
| `path` | Storage path e.g. `files/{recordId}/{filename}` |
| `size` | File size in bytes |
| `width` | Image width in pixels (0 for non-images) |
| `height` | Image height in pixels (0 for non-images) |
| `checksum` | SHA-1 hash of the file contents |
Image files (jpeg, png, webp, gif, tiff) also get a 300×300 thumbnail generated automatically at `thumbs/{path}`, plus any image filter presets configured in `lucent.imageFilters`.
## System Fields
+84 -25
View File
@@ -5,51 +5,94 @@ To generate the static content of the website, lucent provides a helper class.
## Laravel Command
Just create a command and name it as you like. Make sure to inject the StaticGenerator class.
Create an Artisan command and inject `StaticGenerator`:
```php
public function __construct(
public StaticGenerator $staticGenerator,
) {
parent::__construct();
class GenerateStatic extends Command
{
protected $signature = 'generate:static';
public function __construct(
public StaticGenerator $staticGenerator,
public Context $ctx,
) {
parent::__construct();
}
public function handle(): void
{
$this->staticGenerator->run('generate:static', function ($writer) {
$writer->save("/", $this->ctx->render("homepage"));
$writer->save("/about", $this->ctx->render("about"));
});
}
}
```
## Redirect command
`run(string $signature, callable $callback)` — the first argument must match the command's artisan signature. This is used to stream live build logs in the Lucent UI. The callback receives a `Writer` instance.
There are cases which is useful to create a redirect like when you have a multilingual website:
## Writer: save
Writes an HTML file at the given path:
```php
$this->staticGenerator->run(function ($writer) {
$writer->createRedirect("/", "/el");
});
$writer->save("/blog/my-post", $html);
// writes to: storage/lucent/build/blog/my-post/index.html
```
## The Writer save command
An optional third argument changes the file extension (default `"html"`).
In order to create an html file, you have to use the writer's save command
The first argument is the url and the second is the rendered HTML. That's where the page classes do come handy.
## Writer: createRedirect
Generates an HTML meta-refresh redirect. Useful for root-level locale redirects:
```php
$this->staticGenerator->run(function ($writer) {
$writer->save("/", $this->ctx->render("homepage"));
$writer->save("/about", $this->ctx->render("about"));
});
$writer->createRedirect("/", "/el");
$writer->createRedirect("/", "/el", "Redirecting", "Please wait...");
```
Arguments: `from`, `to`, `title` (default `"Redirecting"`), `message` (default `"Redirecting Soon..."`).
## Writer: recordIterator
Iterates over all records in paginated batches — useful when there are too many records to load at once:
```php
$writer->recordIterator(
query: fn(int $limit, int $skip) => $query
->filter(["schema" => "blogPosts"])
->onlyPublished()
->limit($limit)
->skip($skip)
->tree(),
parser: function ($records) use ($writer) {
foreach ($records as $record) {
$writer->save(
"/blog/" . $record->data->slug,
$this->ctx->render("blogPost", $record),
);
}
},
);
```
Signature: `recordIterator(callable $query, callable $parser, int $skip = 0, int $limit = 100): int`
The `$query` callable receives `($limit, $skip)` and must return a collection. Iteration stops automatically when a batch returns zero records.
## Storage and Permissions
All the generated html is stored on `storage/lucent/live`
In order to make it accessible you have to create symlink:
All generated HTML is written to `storage/lucent/build` during the run, then atomically swapped to `storage/lucent/live` on completion. Create the public symlink with:
```bash
php artisan lucent:livelink
```
Now your static website is accessible at `http://localhost:8000/live`
But it would not be nice to have the **live** prefix everywhere. That's why you need to make the following tweak in the nginx vhost
The static site is then accessible at `http://localhost:8000/live`. To serve it without the `/live` prefix, add this to your nginx vhost:
```nginxconf
location / {
@@ -57,14 +100,30 @@ location / {
}
```
## Artisan Commands
| Command | Description |
|---|---|
| `lucent:setup-db` | Create all Lucent database tables |
| `lucent:schemas` | Compile schema JSON files |
| `lucent:livelink` | Create the `public/live` symlink |
| `lucent:rebuild:thumbnails` | Regenerate thumbnails for all uploaded images |
| `lucent:removeOrphanEdges` | Remove edges pointing to deleted records |
| `lucent:generate:collection {name}` | Scaffold a new collection schema JSON file |
## Build from the Lucent UI
In your lucent.php config file you can define your command that is used to generate the static files:
Register your generate command in `config/lucent.php` so admin users can trigger it from the UI:
```php
"generateCommand" => "generate:static"
"commands" => [
"generate:static" => "Generate Static Site",
],
```
That way, the users will be able to initiate the build command through the user interface.
Only roles listed in `canBuild` can trigger commands from the UI.
+110
View File
@@ -99,3 +99,113 @@ class Context
```
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`.