@feedmepos/mf-media 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,110 @@
1
+ # media-portal
2
+
3
+ Vue 3 microfrontend, published as `@feedmepos/mf-media` and mounted into the portal shell
4
+ (`mf-portal-root`) via import map at `/media`. Two tabs:
5
+
6
+ | Route | View | What it is |
7
+ |---|---|---|
8
+ | `/library` | `views/AssetLibrary.vue` | the asset centre — upload, tag, search, delete |
9
+ | `/studio` | `views/AiStudio.vue` | the AI image studio — compose from a prompt |
10
+
11
+ The tab bar lives in `App.vue` because it is this module's own chrome, and `App.vue` is what
12
+ `app.ts` exports as `FmApp` for the shell to mount. The active tab is derived from the route,
13
+ so a deep link, the back button and a click cannot disagree.
14
+
15
+ ## Running it
16
+
17
+ ```bash
18
+ pnpm dev # standalone dev server on :5190
19
+ pnpm type-check
20
+ pnpm test # node --test over test/*.test.ts
21
+ pnpm build:mf # the published artifact
22
+ ```
23
+
24
+ Standalone dev still requires a real portal sign-in: the studio reads
25
+ `coreStore.currentBusiness`, so without a session there is no businessId and nothing can be
26
+ generated. `src/main.ts` points at the local Go backend per `.env.development`.
27
+
28
+ To exercise the studio you need the backend too, and with no `GEMINI_API_KEY` it uses the
29
+ Stub, which renders proportioned placeholders for free:
30
+
31
+ ```bash
32
+ cd ../media-backend && GOTOOLCHAIN=go1.23.9 go run .
33
+ ```
34
+
35
+ ## What verification here actually covers
36
+
37
+ Three gaps are worth knowing, because each one silently passes work that is wrong:
38
+
39
+ - **`pnpm lint` does not run.** There is no ESLint config anywhere in this repo, so ESLint 8
40
+ parses every file as ES5 and fails on the first `import` — about 20 errors on a clean
41
+ checkout, in files no feature touches. Not a gate; fixing it is separate work.
42
+ - **`pnpm type-check` does not check `Fm*` component props.** `<FmButton size="not-a-real-size">`
43
+ passes clean. Read the component's own `.d.ts` under
44
+ `node_modules/@feedmepos/ui-library/dist/components/` before using a prop. Things a guess
45
+ gets wrong: `FmButton.size` is `'md' | 'lg'` with no `'sm'`, its `icon` prop is deprecated
46
+ in favour of `prependIcon`, `FmCircularProgress.size` starts at `'md'`, and `FmChip`
47
+ selection is `selected` + `selectable`.
48
+ - **`pnpm type-check` does not check anything from `@feedmepos/media-picker` either.** That
49
+ package's `exports.types` points at a `dist/index.d.ts` its build never emits, so the whole
50
+ module resolves as `any`. And because the portal resolves it through the built `dist` rather
51
+ than source, **any change to media-picker needs `pnpm picker:build` from the repo root**
52
+ before the dev server or a build can see it.
53
+
54
+ So `pnpm build:mf` and the browser are the only real checks on a template. Note that
55
+ `build:mf` only compiles *reachable* modules — a component nothing imports yet is not being
56
+ verified by it.
57
+
58
+ ## Spacing numbers are px, and the scale is sparse
59
+
60
+ The design system's Tailwind plugin sets `theme.extend.spacing` to a **px-valued** scale:
61
+
62
+ ```
63
+ 0 4 8 12 16 24 32 40 48 56 64 72 80 88 96 104 112 120
64
+ ```
65
+
66
+ It arrives through `extend`, not as a replacement, so a number **not** on that list silently
67
+ falls through to Tailwind's own **rem** scale and lands about four times too large. `gap-20` is
68
+ not 20px, it is 80px. `h-36` is 144px. `w-44` is 176px.
69
+
70
+ This cost real time: an 80px-padded 320px panel left ~160px of content, split into two columns,
71
+ which wrapped every label to one character per line. Nothing warns — the classes are real
72
+ Tailwind, just not the values the design intends. When translating a mock's pixel values, check
73
+ each number against the list above.
74
+
75
+ Arbitrary values (`w-[320px]`, `bg-[--fm-color-brand-primary,#FF7823]`) **do** work and are the
76
+ established idiom here — see `AssetGrid.vue`. Use them for anything off-scale.
77
+
78
+ ## Studio state survives a tab switch
79
+
80
+ The batches live in `stores/generation.ts`, not in `AiStudio.vue`'s setup, so leaving for the
81
+ asset centre and coming back does not throw away the run. The poll loop is deliberately **not**
82
+ stopped on unmount: a batch generating while the merchant looks at the library should be
83
+ finished when they return, not frozen where they left it.
84
+
85
+ Read it with `storeToRefs`, never plain destructuring — a Pinia store is a reactive proxy, and
86
+ pulling `batches` straight out hands the template a snapshot that never updates.
87
+
88
+ ## Layout
89
+
90
+ ```
91
+ src/
92
+ App.vue the tab bar over <RouterView>
93
+ router/shared.ts both routes, each permission-wrapped
94
+ views/AssetLibrary.vue asset centre
95
+ views/AiStudio.vue studio page — layout only, no logic
96
+ composables/
97
+ generationState.ts pure state transitions (tested)
98
+ useGeneration.ts reactive shell: refs, poll timer, network
99
+ components/studio/ the studio's five components
100
+ api/generation.ts the three studio endpoints
101
+ locales/*.json 7 locales, identical key sets
102
+ test/
103
+ generationState.test.ts node --test, no vitest
104
+ ```
105
+
106
+ `generationState.ts` is split from `useGeneration.ts` so the transitions with edge cases can
107
+ be tested without Vue — the same division `packages/media-picker` draws between `variants.ts`
108
+ and `useAssetVariants.ts`. The `saved`-preserving merge is the reason it earns its keep: a
109
+ poll landing a second after a save would otherwise flip the button back to "save", which
110
+ nobody would reproduce by clicking around.