Auf dem Testserver lief die App beim Scrollen langer Timelines in ein 429: nach jeder Scroll-Pause ging sofort ein PUT /settings raus, und jedes sichtbare Vorschaubild zählte auf dasselbe Limit von 300/min. Danach blieben Bilder leer und "Einstellungen konnten nicht gespeichert werden" erschien. Backend: Medien-Reads bekommen einen eigenen Limiter (media, 1200/min), POST /client-logs nimmt Warnungen und Fehler der App an (client-logs, 30/min) und schreibt sie in den täglichen Kanal `client`; Exceptions tragen user_id, path und method im Kontext. Frontend: Einstellungen gehen frühestens 1,5 s nach der letzten Änderung und nur bei geändertem Inhalt zum Server, 429/Netzfehler werden still mit Backoff wiederholt, nur eine Ablehnung wird gemeldet. Bilder laufen durch ein Gate (6 parallel, Retry-After, 3 Versuche) und fallen auf einen Platzhalter statt auf einen kaputten Pfad zurück. Neuer clientLog-Service mit IndexedDB-Puffer, Dedupe und Batch-Versand, globaler Fehlerfang im Boot, Protokoll im Entwickler-Tab. Drei pulsierende Punkte statt weißer Fläche in Timeline-Punkt, Key Image und Medienkacheln. Dokumentation in documentation/logging.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
259 lines
9.1 KiB
JavaScript
259 lines
9.1 KiB
JavaScript
// Configuration for your app
|
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file
|
|
|
|
import { defineConfig } from '#q-app/wrappers'
|
|
|
|
export default defineConfig((ctx) => {
|
|
return {
|
|
// https://v2.quasar.dev/quasar-cli-vite/prefetch-feature
|
|
// preFetch: true,
|
|
|
|
// app boot file (/src/boot)
|
|
// --> boot files are part of "main.js"
|
|
// https://v2.quasar.dev/quasar-cli-vite/boot-files
|
|
boot: ['errorLog'],
|
|
|
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#css
|
|
css: ['app.scss'],
|
|
|
|
// https://github.com/quasarframework/quasar/tree/dev/extras
|
|
extras: [
|
|
// 'ionicons-v4',
|
|
// 'mdi-v7',
|
|
// 'fontawesome-v6',
|
|
// 'eva-icons',
|
|
// 'themify',
|
|
// 'line-awesome',
|
|
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
|
|
|
'roboto-font', // optional, you are not bound to it
|
|
'material-icons', // optional, you are not bound to it
|
|
],
|
|
|
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#build
|
|
build: {
|
|
target: {
|
|
browser: ['es2022', 'firefox115', 'chrome115', 'safari14'],
|
|
node: 'node20',
|
|
},
|
|
|
|
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
|
// vueRouterBase,
|
|
// vueDevtools,
|
|
// vueOptionsAPI: false,
|
|
|
|
// rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
|
|
|
|
// publicPath: '/',
|
|
// analyze: true,
|
|
// env: {},
|
|
// rawDefine: {}
|
|
// ignorePublicFolder: true,
|
|
// minify: false,
|
|
// polyfillModulePreload: true,
|
|
// distDir
|
|
|
|
extendViteConf(viteConf) {
|
|
const srcDir = new URL('./src/composables', import.meta.url).pathname
|
|
viteConf.resolve.alias['composables'] = srcDir
|
|
},
|
|
// viteVuePluginOptions: {},
|
|
|
|
vitePlugins:
|
|
ctx.prod && ctx.modeName !== 'capacitor'
|
|
? [
|
|
[
|
|
'vite-plugin-checker',
|
|
{
|
|
eslint: {
|
|
lintCommand: 'eslint -c ./eslint.config.js "./src/**/*.{js,mjs,cjs,vue}"',
|
|
useFlatConfig: true,
|
|
},
|
|
},
|
|
{ server: false },
|
|
],
|
|
]
|
|
: [],
|
|
},
|
|
|
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#devserver
|
|
devServer: {
|
|
// https: true,
|
|
open: true, // opens browser window automatically
|
|
allowedHosts: ['app.thats-me.test'],
|
|
// When the app is opened via http://localhost:9000 the API client falls
|
|
// back to the relative base "/api" (see src/services/apiClient.js).
|
|
// Forward those requests to the Laravel container so the login works
|
|
// without VITE_API_BASE. "laravel.test" resolves inside the Docker
|
|
// network (dev container and quasar.app). When running the dev server
|
|
// on the host, point DEV_API_PROXY_TARGET at https://api.thats-me.test.
|
|
proxy: {
|
|
'/api': {
|
|
target: process.env.DEV_API_PROXY_TARGET || 'http://laravel.test',
|
|
changeOrigin: true,
|
|
// Traefik serves a self-signed certificate in local development.
|
|
secure: false,
|
|
},
|
|
},
|
|
},
|
|
|
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#framework
|
|
framework: {
|
|
config: {},
|
|
|
|
// iconSet: 'material-icons', // Quasar icon set
|
|
// lang: 'en-US', // Quasar language pack
|
|
|
|
// For special cases outside of where the auto-import strategy can have an impact
|
|
// (like functional components as one of the examples),
|
|
// you can manually specify Quasar components/directives to be available everywhere:
|
|
//
|
|
// components: [],
|
|
// directives: [],
|
|
|
|
// Quasar plugins
|
|
// Notify is used by the event panel and settings for upload/save
|
|
// errors; without it registered those calls silently did nothing.
|
|
plugins: ['Dark', 'Notify'],
|
|
},
|
|
|
|
htmlVariables: {
|
|
fonts: '<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap" rel="stylesheet">'
|
|
},
|
|
|
|
// animations: 'all', // --- includes all animations
|
|
// https://v2.quasar.dev/options/animations
|
|
animations: [],
|
|
|
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-file#sourcefiles
|
|
// sourceFiles: {
|
|
// rootComponent: 'src/App.vue',
|
|
// router: 'src/router/index',
|
|
// store: 'src/store/index',
|
|
// pwaRegisterServiceWorker: 'src-pwa/register-service-worker',
|
|
// pwaServiceWorker: 'src-pwa/custom-service-worker',
|
|
// pwaManifestFile: 'src-pwa/manifest.json',
|
|
// electronMain: 'src-electron/electron-main',
|
|
// electronPreload: 'src-electron/electron-preload'
|
|
// bexManifestFile: 'src-bex/manifest.json
|
|
// },
|
|
|
|
// https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr
|
|
ssr: {
|
|
prodPort: 3000, // The default port that the production server should use
|
|
// (gets superseded if process.env.PORT is specified at runtime)
|
|
|
|
middlewares: [
|
|
'render', // keep this as last one
|
|
],
|
|
|
|
// extendPackageJson (json) {},
|
|
// extendSSRWebserverConf (esbuildConf) {},
|
|
|
|
// manualStoreSerialization: true,
|
|
// manualStoreSsrContextInjection: true,
|
|
// manualStoreHydration: true,
|
|
// manualPostHydrationTrigger: true,
|
|
|
|
pwa: false,
|
|
// pwaOfflineHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
|
|
|
// pwaExtendGenerateSWOptions (cfg) {},
|
|
// pwaExtendInjectManifestOptions (cfg) {}
|
|
},
|
|
|
|
// https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa
|
|
pwa: {
|
|
workboxMode: 'GenerateSW',
|
|
// What the service worker keeps for offline use is the app shell only.
|
|
// The API is never cached (the sync queue owns offline writes, the
|
|
// stores own offline reads), and the large bundled photos are fetched
|
|
// on first use rather than precached on install.
|
|
extendGenerateSWOptions (cfg) {
|
|
cfg.skipWaiting = true
|
|
cfg.clientsClaim = true
|
|
cfg.cleanupOutdatedCaches = true
|
|
cfg.globPatterns = [
|
|
'**/*.{js,css,html,ico,svg,woff,woff2,json,webmanifest}',
|
|
'icons/*.png',
|
|
'images/backgrounds/thumbs/*.jpg'
|
|
]
|
|
cfg.globIgnores = [ ...(cfg.globIgnores || []), 'images/backgrounds/*.jpg', 'images/gallery/**', 'videos/**', 'audio/**', 'demo/**', 'js/**' ]
|
|
cfg.navigateFallbackDenylist = [ ...(cfg.navigateFallbackDenylist || []), /^\/api\//, /^\/event-media\// ]
|
|
cfg.runtimeCaching = [
|
|
{
|
|
urlPattern: /\/images\/.*\.(?:jpg|jpeg|png|webp)$/,
|
|
handler: 'CacheFirst',
|
|
options: {
|
|
cacheName: 'tm-backgrounds',
|
|
expiration: { maxEntries: 30, maxAgeSeconds: 60 * 60 * 24 * 60 }
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\/api\//,
|
|
handler: 'NetworkOnly'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
|
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova
|
|
cordova: {
|
|
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
|
|
},
|
|
|
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor
|
|
capacitor: {
|
|
hideSplashscreen: true,
|
|
},
|
|
|
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron
|
|
electron: {
|
|
// extendElectronMainConf (esbuildConf) {},
|
|
// extendElectronPreloadConf (esbuildConf) {},
|
|
|
|
// extendPackageJson (json) {},
|
|
|
|
// Electron preload scripts (if any) from /src-electron, WITHOUT file extension
|
|
preloadScripts: ['electron-preload'],
|
|
|
|
// specify the debugging port to use for the Electron app when running in development mode
|
|
inspectPort: 5858,
|
|
|
|
bundler: 'packager', // 'packager' or 'builder'
|
|
|
|
packager: {
|
|
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
|
|
// OS X / Mac App Store
|
|
// appBundleId: '',
|
|
// appCategoryType: '',
|
|
// osxSign: '',
|
|
// protocol: 'myapp://path',
|
|
// Windows only
|
|
// win32metadata: { ... }
|
|
},
|
|
|
|
builder: {
|
|
// https://www.electron.build/configuration/configuration
|
|
|
|
appId: 'thatsme-quasar',
|
|
},
|
|
},
|
|
|
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
|
|
bex: {
|
|
// extendBexScriptsConf (esbuildConf) {},
|
|
// extendBexManifestJson (json) {},
|
|
|
|
/**
|
|
* The list of extra scripts (js/ts) not in your bex manifest that you want to
|
|
* compile and use in your browser extension. Maybe dynamic use them?
|
|
*
|
|
* Each entry in the list should be a relative filename to /src-bex/
|
|
*
|
|
* @example [ 'my-script.ts', 'sub-folder/my-other-script.js' ]
|
|
*/
|
|
extraScripts: [],
|
|
},
|
|
}
|
|
})
|