fix(scan): Fix-mode scanner + dialog suppression + cancel/timer + importer revive
Build backend images / build content-svc (push) Failing after 1m25s
Build backend images / build file-svc (push) Failing after 1m10s
Build backend images / build gateway (push) Failing after 56s
Build backend images / build identity-svc (push) Failing after 53s
Build backend images / build notification-svc (push) Failing after 57s
Build backend images / build render-svc (push) Failing after 48s
Build backend images / build studio-svc (push) Failing after 1m5s

- scan.jsx: app.beginSuppressDialogs() + clean quit (no AE hang on font/footage
  dialogs); FIX-mode branch parses frl_c(x)t/m(y) layer names → scenes by c(x);
  flexible/mockup keep comp-based walk; FR_SCAN_MODE selects.
- render-svc: scan job carries project mode; cancel endpoint + node watchdog that
  kills AE on cancel; parseObjectURL handles minio:// (bucket in host); scan with
  no template fails cleanly; status guards so late results can't un-cancel.
- content importer: revive soft-deleted scenes instead of duplicate-inserting
  (fixes scenes_project_id_key unique violation); orphan diff ignores deleted.
- admin: scan dialog gets project-type picker + elapsed timer + Cancel button.
- node-agent: AE-2026 wiring (host port 5010, host-reachable presign endpoint),
  FR_SCAN_MODE plumbing. docs/aep-template-convention.md: per-type naming + bundles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-04 19:06:08 +03:30
parent ee670552a8
commit 6661f53734
17 changed files with 498 additions and 45 deletions
+53
View File
@@ -38,6 +38,24 @@
- `FRLMaker(key)` → if it already contains `frl`/`frd`, keep; else `frl_<key>`.
- `FRDMaker(key)` → strip `frl_`, ensure `frd``frd_<key>`.
### Naming differs by PROJECT TYPE ⚠️ (scanner must be told the type)
**Only two layer kinds:** `t` = text · `m` = media. In AE image / video / audio are the **same** footage (AVLayer), so all three are `m`.
**FIX / MusicVisualizer** — no per-scene `frc_` comps. AE project-panel folders:
| Folder | Holds |
|---|---|
| `Final/` | `frfinal` — the mother render comp |
| `Edit/` | editable comps (any name); layers `frl_c(x)t(y)` (text) / `frl_c(x)m(y)` (media). `c(x)` = scene no., `(y)` = element index |
| `Share/` | `frshare` comp — `frd_<name>` layers: **colours** (RGBA, 4 numbers) + **design-selector** layers (a number **03** that shows/hides layers via expression). All user-editable. |
| `Other/` | footage (video/image) files |
→ scanner derives scenes from the distinct `c<x>` in `frl_c(x)t/m(y)` layer names; element key = the full layer name; type `t`→Text, `m`→Media.
**FLEXIBLE / Mockup** — each scene **is a comp**; editable layers `frl_<key>` inside; story duplicates rename `<scene>_d{N}`.
→ The **scan takes a project-type argument** (defaults to the project's `ChooseMode`) and branches its parsing rule (`FR_SCAN_MODE``fix` parses layer names, `flexible` parses comps).
### 🔑 The uniqueness invariant
> **No two layers ever share a name.** Every editable field maps to exactly **one** independent value.
- This is why duplication **renames** (see §4): a shallow duplicate would collide names → values *mirror*; renaming keeps names unique → values *independent*.
@@ -219,6 +237,41 @@ Expressions are the #1 thing that complicate Master Properties (expression-drive
---
## 11.5 Project import bundles (admin upload)
Adding a project uses **two zips** with strict conventions:
### Zip 1 — render bundle (AE project)
```
final.aep ← at the zip root
(Footage)/... ← footage folder (name may be "(Footage)" with parens), SIBLING of final.aep
(Footage)/LONG VERSION/Items/SFX1..n.mp3 ← SFX are footage the AEP references (NOT separate assets)
```
- `final.aep` + the footage folder **must be siblings** so AE resolves relative paths. Footage-folder name match is case-insensitive and accepts `Footage` or `(Footage)`.
- Stored at `templates/{project_id}/bundle.zip`; the node extracts it keeping the tree intact and runs `aerender` **from the `.aep`'s folder** → footage is beside it → no "missing footage".
- **Validation on upload:** the zip must contain `final.aep` (prefer this name) with a sibling footage folder. Reject otherwise.
- The scanner reads `final.aep` from this same bundle.
- **SFX** ship *inside* this footage; they are not in the assets bundle.
### Zip 2 — assets bundle (demos / placeholders / colour SVGs / music)
May be wrapped in a top folder (e.g. `New folder/`) → **match by basename**, strip leading dirs.
`s{i}` = the i-th scene by sort order.
| File | Meaning | Target |
|---|---|---|
| `p.jpg` | project image / thumbnail | Project image |
| `p.mp4` | full project demo (audio, 1080) | Project full demo |
| `p.svg` | project colour SVG | Project colour SVG |
| `demo.mp4` | hover preview loop (on the card) | Project hover/mini demo |
| `<name>.mp3` | **the single non-`sfx` mp3** = default **music** (arbitrary name, e.g. `Playful Ink Reveal.mp3`) | Project default music |
| `s1.mp4 … s(n).mp4` | per-scene loop demos | `Scene[i].Demo` |
| `s1.jpg … s(n).jpg` | per-scene placeholder images | `Scene[i].Image` |
| `s1.svg … s(n).svg` | per-scene colour SVG (optional) | `Scene[i].SceneColorSvg` |
**Music rule:** the project's default music is the one `.mp3` in the assets bundle whose name is **not** `sfx`. (SFX itself comes from the render footage.)
**Flow:** render bundle → scan → scenes created → assets bundle ingested → each asset uploaded to storage and its field set, mapping `s{i}` to the i-th scene by sort. (Assets-bundle ingestion is a separate admin feature — TODO.)
## 11. Open items to confirm / validate
- [ ] VoiceOver mode mechanics (separate mode vs flavor of Fix/Flexible).
- [ ] Exact `flatrender` timeline offset formula (cumulative `Duration overlap`).