@live-change/frontend-template 0.9.198 → 0.9.200
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/.claude/rules/live-change-backend-actions-views-triggers.md +246 -0
- package/.claude/rules/live-change-backend-architecture.md +126 -0
- package/.claude/rules/live-change-backend-event-sourcing.md +186 -0
- package/.claude/rules/live-change-backend-models-and-relations.md +260 -0
- package/.claude/rules/live-change-frontend-vue-primevue.md +317 -0
- package/.claude/rules/live-change-service-structure.md +89 -0
- package/.claude/settings.json +32 -0
- package/.claude/skills/create-skills-and-rules/SKILL.md +248 -0
- package/.claude/skills/create-skills-and-rules.md +196 -0
- package/.claude/skills/live-change-backend-change-triggers/SKILL.md +186 -0
- package/.claude/skills/live-change-design-actions-views-triggers/SKILL.md +462 -0
- package/.claude/skills/live-change-design-actions-views-triggers.md +190 -0
- package/.claude/skills/live-change-design-models-relations/SKILL.md +230 -0
- package/.claude/skills/live-change-design-models-relations.md +173 -0
- package/.claude/skills/live-change-design-service/SKILL.md +133 -0
- package/.claude/skills/live-change-design-service.md +132 -0
- package/.claude/skills/live-change-frontend-accessible-objects/SKILL.md +384 -0
- package/.claude/skills/live-change-frontend-accessible-objects.md +383 -0
- package/.claude/skills/live-change-frontend-action-buttons/SKILL.md +129 -0
- package/.claude/skills/live-change-frontend-action-buttons.md +128 -0
- package/.claude/skills/live-change-frontend-action-form/SKILL.md +149 -0
- package/.claude/skills/live-change-frontend-action-form.md +143 -0
- package/.claude/skills/live-change-frontend-analytics/SKILL.md +147 -0
- package/.claude/skills/live-change-frontend-analytics.md +146 -0
- package/.claude/skills/live-change-frontend-command-forms/SKILL.md +216 -0
- package/.claude/skills/live-change-frontend-command-forms.md +215 -0
- package/.claude/skills/live-change-frontend-data-views/SKILL.md +183 -0
- package/.claude/skills/live-change-frontend-data-views.md +182 -0
- package/.claude/skills/live-change-frontend-editor-form/SKILL.md +240 -0
- package/.claude/skills/live-change-frontend-editor-form.md +177 -0
- package/.claude/skills/live-change-frontend-locale-time/SKILL.md +172 -0
- package/.claude/skills/live-change-frontend-locale-time.md +171 -0
- package/.claude/skills/live-change-frontend-page-list-detail/SKILL.md +201 -0
- package/.claude/skills/live-change-frontend-page-list-detail.md +200 -0
- package/.claude/skills/live-change-frontend-range-list/SKILL.md +129 -0
- package/.claude/skills/live-change-frontend-range-list.md +128 -0
- package/.claude/skills/live-change-frontend-ssr-setup/SKILL.md +119 -0
- package/.claude/skills/live-change-frontend-ssr-setup.md +118 -0
- package/.cursor/rules/live-change-backend-actions-views-triggers.mdc +290 -0
- package/.cursor/rules/live-change-backend-architecture.mdc +131 -0
- package/.cursor/rules/live-change-backend-event-sourcing.mdc +185 -0
- package/.cursor/rules/live-change-backend-models-and-relations.mdc +256 -0
- package/.cursor/rules/live-change-frontend-vue-primevue.mdc +290 -0
- package/.cursor/rules/live-change-service-structure.mdc +107 -0
- package/.cursor/skills/create-skills-and-rules.md +248 -0
- package/.cursor/skills/live-change-backend-change-triggers.md +186 -0
- package/.cursor/skills/live-change-design-actions-views-triggers.md +296 -0
- package/.cursor/skills/live-change-design-models-relations.md +230 -0
- package/.cursor/skills/live-change-design-service.md +76 -0
- package/.cursor/skills/live-change-frontend-accessible-objects.md +384 -0
- package/.cursor/skills/live-change-frontend-action-buttons.md +129 -0
- package/.cursor/skills/live-change-frontend-action-form.md +149 -0
- package/.cursor/skills/live-change-frontend-analytics.md +147 -0
- package/.cursor/skills/live-change-frontend-command-forms.md +216 -0
- package/.cursor/skills/live-change-frontend-data-views.md +183 -0
- package/.cursor/skills/live-change-frontend-editor-form.md +240 -0
- package/.cursor/skills/live-change-frontend-locale-time.md +172 -0
- package/.cursor/skills/live-change-frontend-page-list-detail.md +201 -0
- package/.cursor/skills/live-change-frontend-range-list.md +129 -0
- package/.cursor/skills/live-change-frontend-ssr-setup.md +120 -0
- package/README.md +71 -0
- package/front/src/router.js +2 -1
- package/opencode.json +10 -0
- package/package.json +52 -50
- package/server/app.config.js +35 -0
- package/server/services.list.js +2 -0
- package/.nx/workspace-data/file-map.json +0 -195
- package/.nx/workspace-data/nx_files.nxt +0 -0
- package/.nx/workspace-data/project-graph.json +0 -8
- package/.nx/workspace-data/project-graph.lock +0 -0
- package/.nx/workspace-data/source-maps.json +0 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: live-change-frontend-range-list
|
|
3
|
+
description: Build paginated scrollable lists with RangeViewer, rangeBuckets and .with()
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: live-change-frontend-range-list (Claude Code)
|
|
7
|
+
|
|
8
|
+
Use this skill when you build **paginated, scrollable lists** backed by DAO ranges in a LiveChange frontend.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
- You need a list that loads items in pages (infinite scroll).
|
|
13
|
+
- The list is backed by a DAO range view (e.g. `articlesByCreatedAt`).
|
|
14
|
+
- You want to attach related objects to each item via `.with()`.
|
|
15
|
+
|
|
16
|
+
## Step 1 – Define the path function
|
|
17
|
+
|
|
18
|
+
The path function receives a `range` object (with `gt`, `gte`, `lt`, `lte`, `limit`, `reverse`) and returns a DAO path.
|
|
19
|
+
|
|
20
|
+
Use `reverseRange()` to display items newest-first:
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
import { reverseRange } from '@live-change/vue3-ssr'
|
|
24
|
+
|
|
25
|
+
function articlesPathRange(range) {
|
|
26
|
+
return path.blog.articlesByCreatedAt({ ...reverseRange(range) })
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Step 2 – Attach related objects with `.with()`
|
|
31
|
+
|
|
32
|
+
Chain `.with()` calls to load related data for each item:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
function articlesPathRange(range) {
|
|
36
|
+
return path.blog.articlesByCreatedAt({ ...reverseRange(range) })
|
|
37
|
+
.with(article => path.userIdentification.identification({
|
|
38
|
+
sessionOrUserType: article.authorType,
|
|
39
|
+
sessionOrUser: article.author
|
|
40
|
+
}).bind('authorProfile'))
|
|
41
|
+
.with(article => path.blog.articleStats({ article: article.id }).bind('stats'))
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Each `.with()` call:
|
|
46
|
+
- receives a proxy of the item,
|
|
47
|
+
- builds a path to the related data,
|
|
48
|
+
- calls `.bind('fieldName')` to attach the result under that field name.
|
|
49
|
+
|
|
50
|
+
Nested `.with()` is also supported:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
function eventsPathRange(range) {
|
|
54
|
+
return path.myService.allEvents({ ...reverseRange(range) })
|
|
55
|
+
.with(event => path.myService.eventState({ event: event.id }).bind('state')
|
|
56
|
+
.with(state => path.myService.roundPairs({ event: event.id, round: state.round }).bind('roundPairs'))
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Step 3 – Use `<RangeViewer>` in the template
|
|
62
|
+
|
|
63
|
+
```vue
|
|
64
|
+
<template>
|
|
65
|
+
<RangeViewer
|
|
66
|
+
:pathFunction="articlesPathRange"
|
|
67
|
+
:canLoadTop="false"
|
|
68
|
+
canDropBottom
|
|
69
|
+
loadBottomSensorSize="3000px"
|
|
70
|
+
dropBottomSensorSize="5000px"
|
|
71
|
+
>
|
|
72
|
+
<template #empty>
|
|
73
|
+
<p class="text-center text-surface-500 my-4">No articles yet.</p>
|
|
74
|
+
</template>
|
|
75
|
+
<template #default="{ item: article }">
|
|
76
|
+
<Card class="mb-2">
|
|
77
|
+
<template #content>
|
|
78
|
+
<h3>{{ article.title }}</h3>
|
|
79
|
+
<p class="text-sm text-surface-500">By {{ article.authorProfile?.firstName }}</p>
|
|
80
|
+
</template>
|
|
81
|
+
</Card>
|
|
82
|
+
</template>
|
|
83
|
+
</RangeViewer>
|
|
84
|
+
</template>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Key props:
|
|
88
|
+
|
|
89
|
+
| Prop | Default | Description |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `pathFunction` | required | `(range) => path` – builds the DAO path for a given range |
|
|
92
|
+
| `bucketSize` | `20` | Items per page |
|
|
93
|
+
| `canLoadTop` / `canLoadBottom` | `true` | Whether loading in each direction is allowed |
|
|
94
|
+
| `canDropTop` / `canDropBottom` | `false` | Whether to drop pages that scrolled far out of view |
|
|
95
|
+
| `loadBottomSensorSize` | `'500px'` | How far before the bottom to trigger loading (increase for smoother UX) |
|
|
96
|
+
| `dropBottomSensorSize` | `'5000px'` | How far to keep before dropping |
|
|
97
|
+
| `frozen` | `false` | Pause live updates |
|
|
98
|
+
|
|
99
|
+
Slots:
|
|
100
|
+
|
|
101
|
+
| Slot | Props | Description |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `default` | `{ item, bucket, itemIndex, bucketIndex }` | Render each item |
|
|
104
|
+
| `empty` | – | Shown when there are no items |
|
|
105
|
+
| `loadingTop` / `loadingBottom` | – | Loading spinners |
|
|
106
|
+
| `changedTop` / `changedBottom` | – | Indicators when data changed while frozen |
|
|
107
|
+
|
|
108
|
+
## Step 4 – Low-level `rangeBuckets` (optional)
|
|
109
|
+
|
|
110
|
+
For advanced control, use `rangeBuckets` directly:
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
import { rangeBuckets, reverseRange } from '@live-change/vue3-ssr'
|
|
114
|
+
|
|
115
|
+
const { buckets, loadBottom, dropTop, freeze, unfreeze } = await rangeBuckets(
|
|
116
|
+
(range) => path.blog.articlesByCreatedAt({ ...reverseRange(range) }),
|
|
117
|
+
{ bucketSize: 20 }
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Iterate in the template:
|
|
122
|
+
|
|
123
|
+
```vue
|
|
124
|
+
<template v-for="(bucket, bi) in buckets.value" :key="bi">
|
|
125
|
+
<div v-for="(item, ii) in bucket.data.value" :key="item.id">
|
|
126
|
+
<!-- render item -->
|
|
127
|
+
</div>
|
|
128
|
+
</template>
|
|
129
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: live-change-frontend-ssr-setup
|
|
3
|
+
description: Set up SSR entry points, router, PrimeVue theme and Suspense data loading
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skill: live-change-frontend-ssr-setup
|
|
7
|
+
|
|
8
|
+
Ten skill opisuje **konfigurację frontendu** opartego o live-change-stack:
|
|
9
|
+
|
|
10
|
+
- entry-client / entry-server,
|
|
11
|
+
- router i meta `signedIn`,
|
|
12
|
+
- konfigurację PrimeVue / motywu.
|
|
13
|
+
|
|
14
|
+
## 1. Entry points – klient i serwer
|
|
15
|
+
|
|
16
|
+
1. W projekcie frontendowym upewnij się, że masz dwa entry points:
|
|
17
|
+
- `entry-client.js` (lub `.ts`),
|
|
18
|
+
- `entry-server.js` (lub `.ts`).
|
|
19
|
+
|
|
20
|
+
2. Skorzystaj z helperów z `@live-change/frontend-base`:
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
// entry-client.js
|
|
24
|
+
import { clientEntry } from '@live-change/frontend-base/client-entry.js'
|
|
25
|
+
import App from './App.vue'
|
|
26
|
+
import { createRouter } from './router.js'
|
|
27
|
+
import { config } from './config.js'
|
|
28
|
+
|
|
29
|
+
export default clientEntry(App, createRouter, config)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// entry-server.js
|
|
34
|
+
import { serverEntry, sitemapEntry } from '@live-change/frontend-base/server-entry.js'
|
|
35
|
+
import App from './App.vue'
|
|
36
|
+
import { createRouter, routerSitemap } from './router.js'
|
|
37
|
+
import { config } from './config.js'
|
|
38
|
+
|
|
39
|
+
export const render = serverEntry(App, createRouter, config)
|
|
40
|
+
export const sitemap = sitemapEntry(App, createRouter, routerSitemap, config)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 2. Router – `vite-plugin-pages` + meta `signedIn`
|
|
44
|
+
|
|
45
|
+
1. Użyj `vite-plugin-pages` do generowania tras z `src/pages/`.
|
|
46
|
+
2. Dodaj blok `<route>` w plikach stron, np.:
|
|
47
|
+
|
|
48
|
+
```vue
|
|
49
|
+
<route>
|
|
50
|
+
{ "name": "devices", "meta": { "signedIn": true } }
|
|
51
|
+
</route>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. W routerze dodaj guard logowania (jeśli go nie ma):
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
router.beforeEach((to) => {
|
|
58
|
+
if(to.meta.signedIn && !isLoggedIn()) {
|
|
59
|
+
localStorage.setItem('redirectAfterLogin', to.fullPath)
|
|
60
|
+
return { name: 'user:signIn' }
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Funkcja `isLoggedIn()` może opierać się na stanie sesji/usera w store lub prostym sprawdzeniu tokena/ciasteczek.
|
|
66
|
+
|
|
67
|
+
## 3. Konfiguracja PrimeVue – motyw i opcje
|
|
68
|
+
|
|
69
|
+
1. W pliku `config.js` skonfiguruj PrimeVue:
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { definePreset } from '@primevue/themes'
|
|
73
|
+
import Aura from '@primevue/themes/aura'
|
|
74
|
+
|
|
75
|
+
const MyPreset = definePreset(Aura, {
|
|
76
|
+
semantic: {
|
|
77
|
+
primary: {
|
|
78
|
+
50: '{indigo.50}',
|
|
79
|
+
100: '{indigo.100}',
|
|
80
|
+
200: '{indigo.200}',
|
|
81
|
+
300: '{indigo.300}',
|
|
82
|
+
400: '{indigo.400}',
|
|
83
|
+
500: '{indigo.500}',
|
|
84
|
+
600: '{indigo.600}',
|
|
85
|
+
700: '{indigo.700}',
|
|
86
|
+
800: '{indigo.800}',
|
|
87
|
+
900: '{indigo.900}',
|
|
88
|
+
950: '{indigo.950}'
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
export const config = {
|
|
94
|
+
theme: {
|
|
95
|
+
preset: MyPreset,
|
|
96
|
+
options: {
|
|
97
|
+
darkModeSelector: '.app-dark-mode'
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
2. Upewnij się, że App.vue używa tego configu przez globalną konfigurację PrimeVue (zgodnie z template’em live-change-stack).
|
|
104
|
+
|
|
105
|
+
## 4. Globalne komponenty i formularze
|
|
106
|
+
|
|
107
|
+
1. W `App.vue` zarejestruj globalne komponenty używane często w projekcie:
|
|
108
|
+
- auto-form components,
|
|
109
|
+
- globalne layouty, jeśli są.
|
|
110
|
+
|
|
111
|
+
2. Dzięki temu na stronach używasz np. `<command-form>` bez lokalnego importu.
|
|
112
|
+
|
|
113
|
+
## 5. SSR i `live/path` + Suspense
|
|
114
|
+
|
|
115
|
+
1. Upewnij się, że root aplikacji (np. `ViewRoot`) opakowuje strony w `<Suspense>`.
|
|
116
|
+
2. Strony powinny:
|
|
117
|
+
- używać `await Promise.all([live(path()....)])` w `script setup`,
|
|
118
|
+
- korzystać z `.value` w template,
|
|
119
|
+
- nie wykonywać pobierania danych w `onMounted`.
|
|
120
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: @live-change/frontend-template
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## @live-change/frontend-template
|
|
6
|
+
|
|
7
|
+
`@live-change/frontend-template` to **szablon kompletnej aplikacji frontendowej** Live Change:
|
|
8
|
+
|
|
9
|
+
- gotowy SSR + SPA oparty o `@live-change/frontend-base` i `@live-change/vue3-ssr`
|
|
10
|
+
- zintegrowane moduły: `user-frontend`, `security`, `content`, `blog`, `task`, `upload`, `url`, `video-call`, `peer-connection`, `auto-form` i inne
|
|
11
|
+
- standardowa struktura katalogów i skrypty `package.json`
|
|
12
|
+
|
|
13
|
+
Szablon jest punktem startowym dla nowych projektów (np. `family-tree`, `speed-dating` zostały na nim oparte).
|
|
14
|
+
|
|
15
|
+
### Najważniejsze zależności
|
|
16
|
+
|
|
17
|
+
W `package.json` szablonu znajdziesz m.in.:
|
|
18
|
+
|
|
19
|
+
- `@live-change/frontend-base`
|
|
20
|
+
- `@live-change/frontend-auto-form`
|
|
21
|
+
- `@live-change/vue3-components`
|
|
22
|
+
- `@live-change/vue3-ssr`
|
|
23
|
+
- frontendy: `user-frontend`, `access-control-frontend`, `content-frontend`, `image-frontend`, `task-frontend`, `upload-frontend`, `url-frontend`, `wysiwyg-frontend`, `blog-frontend`, `video-call-frontend`, `peer-connection-frontend`
|
|
24
|
+
|
|
25
|
+
### Skrypty uruchomieniowe
|
|
26
|
+
|
|
27
|
+
Typowe skrypty (uproszczony przegląd):
|
|
28
|
+
|
|
29
|
+
- `memDev` / `localDev` / `dev` – tryby deweloperskie z różną konfiguracją DB
|
|
30
|
+
- `ssrDev` – dev SSR
|
|
31
|
+
- `serveAll` / `serveAllMem` – produkcyjny SSR z API i usługami
|
|
32
|
+
- `apiServer`, `devApiServer`, `memApiServer` – warianty samego API
|
|
33
|
+
- `build`, `build:client`, `build:ssr`, `build:server`, `build:spa` – budowanie frontu i serwera
|
|
34
|
+
- `prerender*` – generowanie statycznych stron
|
|
35
|
+
|
|
36
|
+
Są one spójne z opisem w dokumentacji serwera (`server/01-getting-started.md`).
|
|
37
|
+
|
|
38
|
+
### Struktura projektu na bazie szablonu
|
|
39
|
+
|
|
40
|
+
Typowy projekt zaczynający z `frontend-template` ma:
|
|
41
|
+
|
|
42
|
+
- `server/app.config.js` – lista usług i konfiguracja klienta
|
|
43
|
+
- `server/services.list.js` – eksport definicji usług
|
|
44
|
+
- `server/start.js` – start CLI (opisany w dokumentacji serwera)
|
|
45
|
+
- `front/src` – kod frontendu:
|
|
46
|
+
- `App.vue`
|
|
47
|
+
- `router.js`
|
|
48
|
+
- `config.js` (i18n, tematy, integracje)
|
|
49
|
+
- `pages/*` – strony routingu (`vite-plugin-pages`)
|
|
50
|
+
- `components/*` – komponenty wspólne
|
|
51
|
+
|
|
52
|
+
W `front/src/config.js` łączysz lokalizacje `frontend-base`, `frontend-auto-form` i innych modułów, podobnie jak w:
|
|
53
|
+
|
|
54
|
+
- `family-tree/front/src/config.js`
|
|
55
|
+
- `speed-dating/front/src/config.js`
|
|
56
|
+
|
|
57
|
+
### Praca z szablonem
|
|
58
|
+
|
|
59
|
+
Typowy flow tworzenia nowej aplikacji:
|
|
60
|
+
|
|
61
|
+
1. Tworzysz nowy pakiet oparty o `@live-change/frontend-template` (lub kopiujesz repo).
|
|
62
|
+
2. Aktualizujesz `server/app.config.js` i `server/services.list.js`, aby włączyć tylko potrzebne usługi.
|
|
63
|
+
3. Dostosowujesz `front/src/config.js` (temat, i18n, integracje analityki).
|
|
64
|
+
4. Tworzysz nowe strony w `front/src/pages` oraz komponenty w `front/src/components`.
|
|
65
|
+
5. Korzystasz z:
|
|
66
|
+
- `@live-change/vue3-ssr` do pracy z DAO,
|
|
67
|
+
- `@live-change/vue3-components` do logiki i formularzy,
|
|
68
|
+
- `@live-change/frontend-auto-form` do CRUD-ów.
|
|
69
|
+
|
|
70
|
+
Dokładny „manual” tego flow znajdzie się w sekcji `frontend/01-getting-started.md` dokumentacji.
|
|
71
|
+
|
package/front/src/router.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
|
|
11
11
|
import { dbAdminRoutes } from "@live-change/db-admin"
|
|
12
12
|
import { autoFormRoutes } from "@live-change/frontend-auto-form"
|
|
13
|
-
import { taskAdminRoutes } from "@live-change/task-frontend"
|
|
13
|
+
import { taskAdminRoutes, cronAdminRoutes } from "@live-change/task-frontend"
|
|
14
14
|
import { userRoutes } from "@live-change/user-frontend"
|
|
15
15
|
import { catchAllPagesRoute, contentEditRoutes, pagesSitemap } from "@live-change/content-frontend"
|
|
16
16
|
|
|
@@ -27,6 +27,7 @@ export function routes(config = {}) {
|
|
|
27
27
|
...contentEditRoutes({ ...config }),
|
|
28
28
|
|
|
29
29
|
...taskAdminRoutes({ ...config, prefix: '/_task' }),
|
|
30
|
+
...cronAdminRoutes({ ...config, prefix: '/_cron' }),
|
|
30
31
|
...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) }),
|
|
31
32
|
...catchAllPagesRoute({ ...config }),
|
|
32
33
|
]
|
package/opencode.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://opencode.ai/config.json",
|
|
3
|
+
"instructions": [
|
|
4
|
+
".claude/rules/live-change-backend-architecture.md",
|
|
5
|
+
".claude/rules/live-change-backend-actions-views-triggers.md",
|
|
6
|
+
".claude/rules/live-change-backend-models-and-relations.md",
|
|
7
|
+
".claude/rules/live-change-service-structure.md",
|
|
8
|
+
".claude/rules/live-change-frontend-vue-primevue.md"
|
|
9
|
+
]
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@live-change/frontend-template",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.200",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"memDev": "tsx --inspect --expose-gc server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
|
|
6
6
|
"localDevInit": "tsx server/start.js localDev --enableSessions --initScript ./init.js --dbAccess",
|
|
@@ -45,54 +45,56 @@
|
|
|
45
45
|
"@codemirror/language": "6.10.1",
|
|
46
46
|
"@dotenvx/dotenvx": "0.27.0",
|
|
47
47
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
|
48
|
-
"@live-change/access-control-frontend": "^0.9.
|
|
49
|
-
"@live-change/access-control-service": "^0.9.
|
|
50
|
-
"@live-change/agreement-service": "^0.9.
|
|
51
|
-
"@live-change/backup-service": "^0.9.
|
|
52
|
-
"@live-change/blog-frontend": "^0.9.
|
|
53
|
-
"@live-change/blog-service": "^0.9.
|
|
54
|
-
"@live-change/cli": "^0.9.
|
|
55
|
-
"@live-change/content-frontend": "^0.9.
|
|
56
|
-
"@live-change/content-service": "^0.9.
|
|
57
|
-
"@live-change/
|
|
58
|
-
"@live-change/dao
|
|
59
|
-
"@live-change/dao-
|
|
60
|
-
"@live-change/
|
|
61
|
-
"@live-change/
|
|
62
|
-
"@live-change/
|
|
63
|
-
"@live-change/
|
|
64
|
-
"@live-change/
|
|
65
|
-
"@live-change/frontend-
|
|
66
|
-
"@live-change/
|
|
67
|
-
"@live-change/
|
|
68
|
-
"@live-change/
|
|
69
|
-
"@live-change/
|
|
70
|
-
"@live-change/
|
|
71
|
-
"@live-change/
|
|
72
|
-
"@live-change/
|
|
73
|
-
"@live-change/
|
|
74
|
-
"@live-change/peer-connection-
|
|
75
|
-
"@live-change/
|
|
76
|
-
"@live-change/
|
|
77
|
-
"@live-change/
|
|
78
|
-
"@live-change/
|
|
79
|
-
"@live-change/
|
|
80
|
-
"@live-change/
|
|
81
|
-
"@live-change/
|
|
82
|
-
"@live-change/
|
|
83
|
-
"@live-change/
|
|
84
|
-
"@live-change/
|
|
85
|
-
"@live-change/
|
|
86
|
-
"@live-change/
|
|
87
|
-
"@live-change/
|
|
88
|
-
"@live-change/
|
|
89
|
-
"@live-change/user-
|
|
90
|
-
"@live-change/
|
|
91
|
-
"@live-change/
|
|
92
|
-
"@live-change/
|
|
93
|
-
"@live-change/
|
|
94
|
-
"@live-change/
|
|
95
|
-
"@live-change/
|
|
48
|
+
"@live-change/access-control-frontend": "^0.9.200",
|
|
49
|
+
"@live-change/access-control-service": "^0.9.200",
|
|
50
|
+
"@live-change/agreement-service": "^0.9.200",
|
|
51
|
+
"@live-change/backup-service": "^0.9.200",
|
|
52
|
+
"@live-change/blog-frontend": "^0.9.200",
|
|
53
|
+
"@live-change/blog-service": "^0.9.200",
|
|
54
|
+
"@live-change/cli": "^0.9.200",
|
|
55
|
+
"@live-change/content-frontend": "^0.9.200",
|
|
56
|
+
"@live-change/content-service": "^0.9.200",
|
|
57
|
+
"@live-change/cron-service": "^0.9.200",
|
|
58
|
+
"@live-change/dao": "^0.9.200",
|
|
59
|
+
"@live-change/dao-vue3": "^0.9.200",
|
|
60
|
+
"@live-change/dao-websocket": "^0.9.200",
|
|
61
|
+
"@live-change/db-client": "^0.9.200",
|
|
62
|
+
"@live-change/draft-service": "^0.9.200",
|
|
63
|
+
"@live-change/email-service": "^0.9.200",
|
|
64
|
+
"@live-change/framework": "^0.9.200",
|
|
65
|
+
"@live-change/frontend-auto-form": "^0.9.200",
|
|
66
|
+
"@live-change/frontend-base": "^0.9.200",
|
|
67
|
+
"@live-change/geoip-service": "^0.9.200",
|
|
68
|
+
"@live-change/google-authentication-service": "^0.9.200",
|
|
69
|
+
"@live-change/image-frontend": "^0.9.200",
|
|
70
|
+
"@live-change/linkedin-authentication-service": "^0.9.200",
|
|
71
|
+
"@live-change/locale-settings-service": "^0.9.200",
|
|
72
|
+
"@live-change/notification-service": "^0.9.200",
|
|
73
|
+
"@live-change/password-authentication-service": "^0.9.200",
|
|
74
|
+
"@live-change/peer-connection-frontend": "^0.9.200",
|
|
75
|
+
"@live-change/peer-connection-service": "^0.9.200",
|
|
76
|
+
"@live-change/prosemirror-service": "^0.9.200",
|
|
77
|
+
"@live-change/scope-service": "^0.9.200",
|
|
78
|
+
"@live-change/secret-code-service": "^0.9.200",
|
|
79
|
+
"@live-change/secret-link-service": "^0.9.200",
|
|
80
|
+
"@live-change/security-service": "^0.9.200",
|
|
81
|
+
"@live-change/session-service": "^0.9.200",
|
|
82
|
+
"@live-change/task-frontend": "^0.9.200",
|
|
83
|
+
"@live-change/task-service": "^0.9.200",
|
|
84
|
+
"@live-change/timer-service": "^0.9.200",
|
|
85
|
+
"@live-change/upload-frontend": "^0.9.200",
|
|
86
|
+
"@live-change/upload-service": "^0.9.200",
|
|
87
|
+
"@live-change/url-frontend": "^0.9.200",
|
|
88
|
+
"@live-change/url-service": "^0.9.200",
|
|
89
|
+
"@live-change/user-frontend": "^0.9.200",
|
|
90
|
+
"@live-change/user-identification-service": "^0.9.200",
|
|
91
|
+
"@live-change/user-service": "^0.9.200",
|
|
92
|
+
"@live-change/video-call-frontend": "^0.9.200",
|
|
93
|
+
"@live-change/video-call-service": "^0.9.200",
|
|
94
|
+
"@live-change/vote-service": "^0.9.200",
|
|
95
|
+
"@live-change/vue3-components": "^0.9.200",
|
|
96
|
+
"@live-change/vue3-ssr": "^0.9.200",
|
|
97
|
+
"@live-change/wysiwyg-frontend": "^0.9.200",
|
|
96
98
|
"@vueuse/core": "^12.3.0",
|
|
97
99
|
"codeceptjs-assert": "^0.0.5",
|
|
98
100
|
"compression": "^1.7.5",
|
|
@@ -125,5 +127,5 @@
|
|
|
125
127
|
"author": "Michał Łaszczewski <michal@laszczewski.pl>",
|
|
126
128
|
"license": "ISC",
|
|
127
129
|
"description": "",
|
|
128
|
-
"gitHead": "
|
|
130
|
+
"gitHead": "a509834e600a546297faa7d1534b6f52e66d2e66"
|
|
129
131
|
}
|
package/server/app.config.js
CHANGED
|
@@ -4,12 +4,43 @@ dotenv.config()
|
|
|
4
4
|
import App from "@live-change/framework"
|
|
5
5
|
const app = App.app()
|
|
6
6
|
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
8
|
+
import { dirname, join } from 'path'
|
|
9
|
+
import { accessSync, readFileSync } from 'fs'
|
|
10
|
+
|
|
11
|
+
const packageJsonPath = dirname(fileURLToPath(import.meta.url))
|
|
12
|
+
.split('/').map((part, i, arr) =>
|
|
13
|
+
join(arr.slice(0, arr.length - i).join('/'), 'package.json')
|
|
14
|
+
).find(p => { try { accessSync(p); return true } catch(e) { return false }})
|
|
15
|
+
const packageJson = packageJsonPath ? JSON.parse(readFileSync(packageJsonPath, 'utf-8')) : {}
|
|
16
|
+
|
|
17
|
+
const name = packageJson.name ?? "Example"
|
|
18
|
+
const brandName = process.env.BRAND_NAME || (name[0].toUpperCase() + name.slice(1))
|
|
19
|
+
const homepage = process.env.BASE_HREF ?? packageJson.homepage
|
|
20
|
+
const brandDomain = process.env.BRAND_DOMAIN ||
|
|
21
|
+
(homepage && homepage.match(/https\:\/\/([^\/]+)/)?.[1]) || 'example.com'
|
|
22
|
+
const baseHref = process.env.BASE_HREF || homepage || 'http://localhost:8001'
|
|
23
|
+
const version = process.env.VERSION || packageJson.version
|
|
24
|
+
|
|
25
|
+
const clientConfig = {
|
|
26
|
+
version,
|
|
27
|
+
name, brandName, brandDomain, homepage, baseHref
|
|
28
|
+
}
|
|
29
|
+
const baseAppConfig = {
|
|
30
|
+
...clientConfig,
|
|
31
|
+
clientConfig: { ...clientConfig },
|
|
32
|
+
}
|
|
33
|
+
|
|
7
34
|
const contactTypes = ['email']
|
|
8
35
|
|
|
9
36
|
import securityConfig from './security.config.js'
|
|
10
37
|
import documentTypePage from './page.documentType.js'
|
|
11
38
|
|
|
12
39
|
app.config = {
|
|
40
|
+
...baseAppConfig,
|
|
41
|
+
clientConfig: {
|
|
42
|
+
...baseAppConfig.clientConfig,
|
|
43
|
+
},
|
|
13
44
|
services: [
|
|
14
45
|
{
|
|
15
46
|
name: 'timer',
|
|
@@ -42,6 +73,10 @@ app.config = {
|
|
|
42
73
|
name: 'accessControl',
|
|
43
74
|
createSessionOnUpdate: true,
|
|
44
75
|
contactTypes,
|
|
76
|
+
indexed: true,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'scope'
|
|
45
80
|
},
|
|
46
81
|
{
|
|
47
82
|
name: 'security',
|
package/server/services.list.js
CHANGED
|
@@ -7,6 +7,7 @@ import userIdentification from '@live-change/user-identification-service'
|
|
|
7
7
|
import identicon from '@live-change/identicon-service'
|
|
8
8
|
import localeSettings from '@live-change/locale-settings-service'
|
|
9
9
|
import accessControl from '@live-change/access-control-service'
|
|
10
|
+
import scope from '@live-change/scope-service'
|
|
10
11
|
import security from '@live-change/security-service'
|
|
11
12
|
import notification from '@live-change/notification-service'
|
|
12
13
|
import upload from '@live-change/upload-service'
|
|
@@ -37,6 +38,7 @@ export {
|
|
|
37
38
|
identicon,
|
|
38
39
|
localeSettings,
|
|
39
40
|
accessControl,
|
|
41
|
+
scope,
|
|
40
42
|
security,
|
|
41
43
|
notification,
|
|
42
44
|
upload,
|