From 11069dcf43397670c75315c7f7670bbb063fa065 Mon Sep 17 00:00:00 2001
From: ErikTitan <102426162+ErikTitan@users.noreply.github.com>
Date: Fri, 26 Jun 2026 01:19:12 +0200
Subject: [PATCH 1/3] Update webinar links for Lesson #4 and Lesson #5
---
.../certification/level-1/webinars-dates-topics-and-links.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md b/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md
index 8d6f534..ab59fe8 100644
--- a/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md
+++ b/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md
@@ -7,8 +7,8 @@
| Wednesday, May 13, 2026 | 1:30 PM (UTC+0) | [Lesson #1: Introduction to Hubleto](lesson-1) | [YouTube recording](https://www.youtube.com/watch?v=_hJSIheo0sA) |
| Wednesday, May 27, 2026 | 1:30 PM (UTC+0) | [Lesson #2: Overview of Hubleto features](lesson-2) | [Youtube recording](https://www.youtube.com/watch?v=Qv7vmQXFYrE) |
| Wednesday, Jun 10, 2026 | 1:30 PM (UTC+0) | [Lesson #3: Business Apps Development - backend](lesson-3) | [YouTube recording](https://www.youtube.com/watch?v=vZYjOEDjupc) |
-| Wednesday, Jun 24, 2026 | 1:30 PM (UTC+0) | [Lesson #4: Business Apps Development - frontend](lesson-4) | [LinkedIn event](https://www.linkedin.com/events/7470792935916105729/?viewAsMember=true) |
-| Wednesday, Jul 8, 2026 | 1:30 PM (UTC+0) | [Lesson #5: Business Apps Development - CarRental app](lesson-5) | |
+| Wednesday, Jun 24, 2026 | 1:30 PM (UTC+0) | [Lesson #4: Business Apps Development - frontend](lesson-4) | [YouTube recording](https://www.youtube.com/watch?v=1LeP0r5-JLo) |
+| Wednesday, Jul 8, 2026 | 1:30 PM (UTC+0) | [Lesson #5: Business Apps Development - CarRental app](lesson-5) | [LinkedIn event](https://www.linkedin.com/events/7475866044474122240?viewAsMember=true) |
| Wednesday, Jul 22, 2026 | 1:30 PM (UTC+0) | [Lesson #6: Business Apps Development - IpInfoTest app](lesson-6) | |
| Wednesday, Aug 5, 2026 | 1:30 PM (UTC+0) | [Lesson #7: Hubleto ReactUi basics](lesson-7) | |
| Wednesday, Aug 19, 2026 | 1:30 PM (UTC+0) | [Lesson #8: Models, RecordManagers and Migrations, part 1](lesson-8) | |
From 354c67b5d5de7d64adb92badaed75d635d1bf4ce Mon Sep 17 00:00:00 2001
From: ErikTitan <102426162+ErikTitan@users.noreply.github.com>
Date: Wed, 1 Jul 2026 22:22:34 +0200
Subject: [PATCH 2/3] Add Lesson 8 to Level 1 certification
---
v0/book/config.yaml | 1 +
.../pages/certification/level-1/lesson-8.md | 562 ++++++++++++++++++
2 files changed, 563 insertions(+)
create mode 100644 v0/book/content/pages/certification/level-1/lesson-8.md
diff --git a/v0/book/config.yaml b/v0/book/config.yaml
index f3140b7..8f44e84 100644
--- a/v0/book/config.yaml
+++ b/v0/book/config.yaml
@@ -232,6 +232,7 @@ tableOfContents:
- page: certification/level-1/lesson-5
- page: certification/level-1/lesson-6
- page: certification/level-1/lesson-7
+ - page: certification/level-1/lesson-8
- page: certification/level-2
- page: certification/level-3
diff --git a/v0/book/content/pages/certification/level-1/lesson-8.md b/v0/book/content/pages/certification/level-1/lesson-8.md
new file mode 100644
index 0000000..ce793f3
--- /dev/null
+++ b/v0/book/content/pages/certification/level-1/lesson-8.md
@@ -0,0 +1,562 @@
+# Lesson 8: Models, RecordManagers and Migrations, part 1
+
+ Developer Certification Level 1
+
+## Introduction
+
+In this lesson, you will revisit the most important backend building blocks of Hubleto: `Model`, `RecordManager`, and `Migration`. Lessons 3 through 7 already used these concepts in practice. Here, we will look at them in a more structured way.
+
+The examples in this lesson come mainly from the Contacts app, Workflow app, and Worksheets app.
+
+The main questions are:
+
+* what belongs in the model,
+* what belongs in the record manager,
+* how relations are declared,
+* how records are created, updated, and deleted,
+* and how migrations translate model structure into SQL tables and foreign keys.
+
+> **What you will learn:**
+>
+> * What the responsibilities of `Model` and `RecordManager` are in Hubleto.
+> * How relations are defined in the model and mirrored in the record manager.
+> * How `belongsTo` and `hasMany` are used in real Hubleto apps.
+> * Which built-in record APIs Hubleto uses for create, update, save, and delete.
+> * How `prepareReadQuery()` is customized in real applications.
+> * How migrations are organized and why tables and foreign keys are installed separately.
+
+## 1. Model vs. RecordManager
+
+In Hubleto, the **description of a model** is separated from the **engine that reads and writes records**.
+
+The model class usually defines:
+
+* SQL table name,
+* record manager class,
+* relation metadata,
+* column definitions,
+* DescriptionAPI configuration,
+* callbacks such as `onBeforeCreate()` or `onAfterUpdate()`.
+
+The record manager usually defines:
+
+* the actual Eloquent relations such as `belongsTo()` and `hasMany()`,
+* query customization in methods such as `prepareReadQuery()`,
+* optional lookup and sorting customization,
+* lower-level data loading behavior.
+
+In practice, this means:
+
+* the model stores metadata such as `$table`, `$recordManagerClass`, and `$relations`,
+* the default Eloquent record manager handles query preparation, relation loading, and record save/delete logic,
+* the ERP record manager adds standard visibility filtering such as owner, manager, team, and sharing rules.
+
+In other words:
+
+* **Model** = what the business object is.
+* **RecordManager** = how records of that business object are loaded and manipulated.
+
+## 2. Anatomy of a real model
+
+A good simple example is the `Contact` model from the Contacts app.
+
+Its core properties look like this:
+
+```php
+class Contact extends \Hubleto\Erp\Model
+{
+ public string $table = 'contacts';
+ public string $recordManagerClass = RecordManagers\Contact::class;
+
+ public array $relations = [
+ 'CUSTOMER' => [ self::BELONGS_TO, Customer::class, 'id_customer' ],
+ 'VALUES' => [ self::HAS_MANY, Value::class, 'id_contact', 'id' ],
+ 'TAGS' => [ self::HAS_MANY, ContactTag::class, 'id_contact', 'id' ],
+ ];
+}
+```
+
+This tells Hubleto three important things:
+
+1. Records are stored in the `contacts` table.
+2. Database work is handled by `RecordManagers\Contact`.
+3. The contact has one parent customer and multiple child records such as values and tags.
+
+The same model also defines its columns in `describeColumns()`. For example, `first_name`, `last_name`, `id_customer`, `virt_email`, and `virt_tags` are all described there. This is why the model is not only a database definition. It is also the central description of how the record should be understood and presented.
+
+## 3. Relations are defined in two places
+
+This is one of the most important Level 1 rules.
+
+When you use the standard Eloquent-based record manager, a relation is declared:
+
+1. in the model's `$relations` array, and
+2. again in the record manager as an Eloquent relation method.
+
+### Why the model needs `$relations`
+
+The `$relations` array gives Hubleto structured metadata that is later used by features such as:
+
+* relation-aware reading,
+* nested save and validation,
+* form and table data preparation,
+* recursive relation loading with controlled depth.
+
+The basic structure is:
+
+```php
+'RELATION_NAME' => [ relationType, relatedModelClass, foreignKey, localKey ]
+```
+
+A typical relation declaration looks like this:
+
+```php
+public array $relations = [
+ 'CUSTOMER' => [ self::BELONGS_TO, Customer::class, 'id_customer' ],
+ 'VALUES' => [ self::HAS_MANY, Value::class, 'id_contact', 'id' ],
+ 'TAGS' => [ self::HAS_MANY, ContactTag::class, 'id_contact', 'id' ],
+];
+```
+
+### Why the record manager needs relation methods
+
+The record manager still needs actual Eloquent relations so that calls such as `with('VALUES')`, `with('TAGS')`, or `with('STEPS')` work correctly.
+
+Example from the Contacts app:
+
+```php
+public function CUSTOMER(): BelongsTo
+{
+ return $this->belongsTo(Customer::class, 'id_customer');
+}
+
+public function VALUES(): HasMany
+{
+ return $this->hasMany(Value::class, 'id_contact', 'id');
+}
+
+public function TAGS(): HasMany
+{
+ return $this->hasMany(ContactTag::class, 'id_contact', 'id');
+}
+```
+
+Notice an important detail:
+
+* in the **model**, the relation points to the **model class**,
+* in the **record manager**, the Eloquent relation points to the **record manager class**.
+
+This duplication is intentional. The model describes the relation, and the record manager implements it.
+
+## 4. Practical relation examples
+
+### `belongsTo`: Contact -> Customer
+
+This is the standard "many contacts belong to one customer" pattern.
+
+Model definition:
+
+```php
+'CUSTOMER' => [ self::BELONGS_TO, Customer::class, 'id_customer' ]
+```
+
+Record manager definition:
+
+```php
+public function CUSTOMER(): BelongsTo
+{
+ return $this->belongsTo(Customer::class, 'id_customer');
+}
+```
+
+Meaning:
+
+* the `contacts` table stores `id_customer`,
+* each contact points to one customer,
+* Hubleto can load the related customer as `CUSTOMER`.
+
+### `hasMany`: Workflow -> WorkflowStep
+
+This is the standard parent-child pattern.
+
+From the Workflow app:
+
+```php
+public array $relations = [
+ 'STEPS' => [ self::HAS_MANY, WorkflowStep::class, 'id_workflow', 'id' ]
+];
+```
+
+And in the Workflow record manager:
+
+```php
+public function STEPS(): HasMany
+{
+ return $this->hasMany(WorkflowStep::class, 'id_workflow', 'id')
+ ->orderBy('order', 'asc');
+}
+```
+
+Meaning:
+
+* one workflow has many workflow steps,
+* the child table stores `id_workflow`,
+* steps are returned in business order, not just insertion order.
+
+### `hasMany`: Contact -> Value
+
+This is another useful real-world example because the child records are not only decorative. They are part of the contact's real data model.
+
+```php
+'VALUES' => [ self::HAS_MANY, Value::class, 'id_contact', 'id' ]
+```
+
+and:
+
+```php
+public function VALUES(): HasMany
+{
+ return $this->hasMany(Value::class, 'id_contact', 'id');
+}
+```
+
+This pattern is used when one master record owns a list of subrecords.
+
+## 5. Built-in record manipulation API
+
+Hubleto does not rely only on raw Eloquent calls. It has its own record-oriented API layer on top of Eloquent.
+
+Hubleto provides standard record API endpoints such as:
+
+* `api/record/get`
+* `api/record/load-table-data`
+* `api/record/lookup`
+* `api/record/save`
+* `api/record/delete`
+
+These are part of the standard records API.
+
+### `recordSave()` is the main save entry point
+
+In the standard save flow, the backend calls:
+
+```php
+$savedRecord = $this->model->record->recordSave(
+ $record,
+ 0,
+ $saveRelations
+);
+```
+
+This is the important part. Standard table and form saving does not directly call `create()` or `update()`. It goes through Hubleto's `recordSave()` API.
+
+The `recordSave()` method handles:
+
+* create vs. update decision,
+* permission checks,
+* validation,
+* callbacks,
+* normalization,
+* saving selected child relations.
+
+That is why `recordSave()` is more than a thin wrapper around Eloquent.
+
+### `recordCreate()` and `recordDelete()`
+
+The same record manager also provides:
+
+* `recordCreate(array $record): array`
+* `recordDelete(int|string $id): int`
+* `recordUpdate(array $record, array $originalRecord = []): array`
+
+These are useful in internal application code.
+
+For example, the Workflow app seeds default workflow data during installation using:
+
+```php
+$idWorkflow = $mWorkflow->record->recordCreate([
+ "name" => $this->translate('Deals'),
+ "show_in_kanban" => 1,
+ "order" => 3,
+ "group" => "deals",
+])['id'];
+
+$mWorkflowStep->record->recordCreate([
+ 'name' => $this->translate('Prospecting'),
+ 'order' => 1,
+ 'color' => '#838383',
+ 'id_workflow' => $idWorkflow,
+ 'tag' => 'deal-prospecting',
+]);
+```
+
+This is a good example of when `recordCreate()` is appropriate:
+
+* the app is inserting known bootstrap data,
+* it already knows the values to store,
+* it is not saving a nested UI form payload.
+
+Unlike `recordSave()`, `recordCreate()` is a more direct helper. It is useful for controlled inserts, but it is not the full relation-aware form-save pipeline.
+
+For delete operations, the standard delete flow calls `recordDelete($id)`, and `recordDelete()` performs permission checks before removing the row.
+
+### Practical rule for Level 1
+
+Use this mental model:
+
+* `recordSave()` = the standard Hubleto save pipeline for UI and relation-aware saves.
+* `recordCreate()` = useful for controlled inserts such as app installation, seed data, or focused internal code.
+* raw Eloquent methods such as `create()`, `update()`, `delete()` still exist, but they bypass some Hubleto-specific lifecycle logic.
+
+## 6. Customizing `prepareReadQuery()`
+
+`prepareReadQuery()` is one of the most important customization points in a record manager.
+
+At the beginning, `prepareReadQuery()` prepares:
+
+* base selects,
+* joins,
+* included relations.
+
+Then the ERP layer adds standard restrictions such as:
+
+* owner filtering,
+* manager filtering,
+* team filtering,
+* shared-with filtering,
+* junction-table filtering from URL parameters.
+
+Your app-level record manager then extends that behavior with business-specific filtering.
+
+### Example 1: Contacts filtered by customer
+
+From the Contacts app:
+
+```php
+public function prepareReadQuery(mixed $query = null, int $level = 0, array|null $includeRelations = null): mixed
+{
+ $query = parent::prepareReadQuery($query, $level, $includeRelations);
+ $query = $query->orderBy('is_primary', 'desc');
+
+ $hubleto = \Hubleto\Erp\Loader::getGlobalApp();
+ if ($hubleto->router()->urlParamAsInteger("idCustomer") > 0) {
+ $query = $query->where($this->table . '.id_customer', $hubleto->router()->urlParamAsInteger("idCustomer"));
+ }
+
+ return $query;
+}
+```
+
+This is a very common pattern:
+
+1. call `parent::prepareReadQuery()` first,
+2. read URL parameters,
+3. add business filters,
+4. return the modified query.
+
+### Example 2: Worksheets filtered by task, project, and period
+
+The Worksheets app shows a more advanced version.
+
+It filters by:
+
+* `idTask`,
+* `idProject`,
+* selected period,
+* selected workers,
+* grouping filters.
+
+One particularly useful part is this:
+
+```php
+if ($idProject > 0) {
+ $mProjectTask = $hubleto->getService(ProjectTask::class);
+
+ $projectTasksIds = $mProjectTask->record->prepareReadQuery()
+ ->where($mProjectTask->table . '.id_project', $idProject)
+ ->pluck('id_task')
+ ?->toArray();
+
+ if (count($projectTasksIds) == 0) $projectTasksIds = [0];
+
+ $query = $query->whereIn($this->table . '.id_task', $projectTasksIds);
+}
+```
+
+This shows that `prepareReadQuery()` is not only for one extra `where()`. It is also the place for real business reading rules.
+
+### Good practices for `prepareReadQuery()`
+
+* Always start with `parent::prepareReadQuery(...)` unless you have a very special reason not to.
+* Keep the method focused on read behavior.
+* Use URL parameters and filters deliberately.
+* Avoid placing unrelated write logic here.
+* If the method becomes too large, extract helper methods.
+
+## 7. Migrations: how models become SQL tables
+
+In Hubleto, migrations are discovered from the model's `Migrations` folder and executed through the model's own upgrade methods.
+
+The model loads migration classes from:
+
+* the same namespace as the model,
+* the `Models/Migrations` subfolder,
+* files whose names start with the model's short name.
+
+The current migration method names are:
+
+* `upgradeSchema()`
+* `downgradeSchema()`
+* `upgradeForeignKeys()`
+* `downgradeForeignKeys()`
+
+You may sometimes see other method names in older examples. In the examples used here, the method names above are the ones in use.
+
+### Why tables and foreign keys are separated
+
+The upgrade process runs pending table migrations first.
+
+Then it runs pending foreign-key migrations afterward.
+
+This separation prevents dependency-order problems. If model A references model B, both tables must exist before the foreign key is added.
+
+### Practical example: Workflow and WorkflowStep
+
+From the Workflow app migration:
+
+```php
+public function upgradeSchema(): void
+{
+ $this->db->execute("SET foreign_key_checks = 0;
+create table `workflows` (
+ `id` int(8) primary key auto_increment,
+ `name` varchar(255),
+ `order` int(255),
+ `description` varchar(255),
+ `show_in_kanban` int(1),
+ `group` varchar(255),
+ index `id` (`id`),
+ index `order` (`order`),
+ index `show_in_kanban` (`show_in_kanban`),
+ INDEX `group` (`group`)) ENGINE = InnoDB;
+SET foreign_key_checks = 1;");
+}
+```
+
+And from the migration for workflow steps:
+
+```php
+public function upgradeSchema(): void
+{
+ $this->db->execute("SET foreign_key_checks = 0;
+create table `workflow_steps` (
+ `id` int(8) primary key auto_increment,
+ `id_workflow` int(8) NULL default NULL,
+ `name` varchar(255),
+ `order` int(255),
+ `color` char(10),
+ `tag` varchar(255),
+ `probability` int(255),
+ index `id` (`id`),
+ index `id_workflow` (`id_workflow`),
+ index `order` (`order`),
+ index `probability` (`probability`)) ENGINE = InnoDB;
+SET foreign_key_checks = 1;");
+}
+
+public function upgradeForeignKeys(): void
+{
+ $this->db->execute("ALTER TABLE `workflow_steps`
+ ADD CONSTRAINT `fk_fabc826acfa6488d209bc1f03431b9ef`
+ FOREIGN KEY (`id_workflow`)
+ REFERENCES `workflows` (`id`)
+ ON DELETE RESTRICT
+ ON UPDATE RESTRICT;");
+}
+```
+
+This is the direct SQL counterpart of the relation:
+
+```php
+'STEPS' => [ self::HAS_MANY, WorkflowStep::class, 'id_workflow', 'id' ]
+```
+
+The model relation explains the PHP-level meaning. The migration makes it physically true in the database.
+
+## 8. What to study next
+
+If you want to turn this lesson into hands-on practice, review these parts in this order:
+
+1. The base `Model` class.
+2. The default Eloquent record manager.
+3. The ERP record manager extension.
+4. The `Contact` model and its record manager in the Contacts app.
+5. The `Workflow` model and its record manager in the Workflow app.
+6. The workflow migrations in the Workflow app.
+7. The `Activity` record manager in the Worksheets app.
+
+When you read them, answer these questions:
+
+* Which parts are metadata and which parts are executable query logic?
+* Which relations are declared in the model?
+* Which relations are implemented as Eloquent methods?
+* Which read rules come from the base layer, which from the ERP layer, and which from the app?
+* Which migration creates the table and which migration adds the foreign key?
+
+## 9. Common mistakes
+
+Developers usually make these mistakes at this stage:
+
+### Mistake 1: Defining a relation only in the model
+
+If you define a relation in `$relations` but forget the matching Eloquent relation method in the record manager, relation loading will not behave correctly.
+
+### Mistake 2: Putting read filtering into controllers instead of `prepareReadQuery()`
+
+Controllers should stay thin. Query restrictions belong in the record manager.
+
+### Mistake 3: Using raw Eloquent writes everywhere
+
+Raw `create()` and `update()` are valid tools, but standard Hubleto save flows are built around `recordSave()`, `recordCreate()`, and `recordDelete()`.
+
+### Mistake 4: Treating migrations as optional
+
+If the model changed but the migration did not, your code and database schema are no longer describing the same system.
+
+### Mistake 5: Forgetting that ERP record managers already filter visibility
+
+When you extend the ERP record manager, some read restrictions are already included. Do not accidentally duplicate them in every app.
+
+## Best practices
+
+* Keep the model as the authoritative description of the business object.
+* Keep the record manager as the authoritative place for relation methods and read-query customization.
+* Use relation names consistently between `$relations` and record manager methods.
+* Call `parent::prepareReadQuery()` first.
+* Prefer `recordSave()` for normal form-driven save flows.
+* Use migrations to keep schema evolution explicit and repeatable.
+
+## Study material
+
+| Resource | Description |
+| --- | --- |
+| [Lesson 3](lesson-3) | First introduction to backend app development. |
+| [Lesson 4](lesson-4) | How controllers, views, and React tables/forms consume backend data. |
+| [Lesson 7](lesson-7) | How ReactUi tables and forms depend on model descriptions and record APIs. |
+| [Models](../../docs/framework/models) | Overview of model structure and responsibilities. |
+| [Record manager](../../docs/framework/models/record-manager) | Explanation of record managers and Eloquent-backed data access. |
+| [Records API](../../docs/framework/models/records-api) | Framework CRUD endpoints and save/delete flow. |
+| [Migrations](../../docs/framework/models/migrations) | Overview of migration-based schema versioning. |
+| [Description API](../../docs/erp/advanced-development/description-api) | UI description layer that sits on top of models. |
+
+## Videos
+
+The webinar recording for this lesson will be added after the live session.
+
+## Do you have any questions?
+
+Do you have any questions or comments? Leave us a message in the community portal.
+
+Go to community.hubleto.eu
+
+If you are new here, learn more about the [developer certification course](../../certification).
From d9b082978f1df1c5a29210cc3d8bc8c56f6bff0c Mon Sep 17 00:00:00 2001
From: ErikTitan <102426162+ErikTitan@users.noreply.github.com>
Date: Wed, 8 Jul 2026 22:38:47 +0200
Subject: [PATCH 3/3] Add archived livestream links
---
v0/book/content/pages/certification/level-1/lesson-4.md | 4 ++++
v0/book/content/pages/certification/level-1/lesson-5.md | 4 +++-
.../certification/level-1/webinars-dates-topics-and-links.md | 2 +-
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/v0/book/content/pages/certification/level-1/lesson-4.md b/v0/book/content/pages/certification/level-1/lesson-4.md
index 827a49a..4d31372 100644
--- a/v0/book/content/pages/certification/level-1/lesson-4.md
+++ b/v0/book/content/pages/certification/level-1/lesson-4.md
@@ -127,6 +127,10 @@ If you open `Views/Cars.twig`, you will see how seamlessly the React data grid i
| [React UI Components](../../docs/framework/views/react-ui) | How to use Hubleto's built-in React components in your views. |
| [Sample `CarRental` app](https://github.com/mrgopes/hubleto-car-rental) | Source code of the completed CarRental app. |
+## Archived livestream
+
+
+
## Do you have any questions?
Do you have any questions or comments? Leave us a message in the community portal.
diff --git a/v0/book/content/pages/certification/level-1/lesson-5.md b/v0/book/content/pages/certification/level-1/lesson-5.md
index 4f84e6e..1543679 100644
--- a/v0/book/content/pages/certification/level-1/lesson-5.md
+++ b/v0/book/content/pages/certification/level-1/lesson-5.md
@@ -223,7 +223,9 @@ The CLI generator is useful, but it often creates placeholders that should be cl
| [React UI Components](../../docs/framework/views/react-ui) | Reference for Hubleto React UI usage. |
| [Sample `CarRental` app](https://github.com/mrgopes/hubleto-car-rental) | Source code of a sample custom app. |
-The webinar recording for this lesson will be added after the live session.
+## Archived livestream
+
+
## Do you have any questions?
diff --git a/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md b/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md
index ab59fe8..0050555 100644
--- a/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md
+++ b/v0/book/content/pages/certification/level-1/webinars-dates-topics-and-links.md
@@ -8,7 +8,7 @@
| Wednesday, May 27, 2026 | 1:30 PM (UTC+0) | [Lesson #2: Overview of Hubleto features](lesson-2) | [Youtube recording](https://www.youtube.com/watch?v=Qv7vmQXFYrE) |
| Wednesday, Jun 10, 2026 | 1:30 PM (UTC+0) | [Lesson #3: Business Apps Development - backend](lesson-3) | [YouTube recording](https://www.youtube.com/watch?v=vZYjOEDjupc) |
| Wednesday, Jun 24, 2026 | 1:30 PM (UTC+0) | [Lesson #4: Business Apps Development - frontend](lesson-4) | [YouTube recording](https://www.youtube.com/watch?v=1LeP0r5-JLo) |
-| Wednesday, Jul 8, 2026 | 1:30 PM (UTC+0) | [Lesson #5: Business Apps Development - CarRental app](lesson-5) | [LinkedIn event](https://www.linkedin.com/events/7475866044474122240?viewAsMember=true) |
+| Wednesday, Jul 8, 2026 | 1:30 PM (UTC+0) | [Lesson #5: Business Apps Development - CarRental app](lesson-5) | [YouTube recording](https://www.youtube.com/watch?v=APYWRZ6r3l8) |
| Wednesday, Jul 22, 2026 | 1:30 PM (UTC+0) | [Lesson #6: Business Apps Development - IpInfoTest app](lesson-6) | |
| Wednesday, Aug 5, 2026 | 1:30 PM (UTC+0) | [Lesson #7: Hubleto ReactUi basics](lesson-7) | |
| Wednesday, Aug 19, 2026 | 1:30 PM (UTC+0) | [Lesson #8: Models, RecordManagers and Migrations, part 1](lesson-8) | |