From 563bc0a0b629f202ea9096d54b04a4d8598eb752 Mon Sep 17 00:00:00 2001 From: MEHMETKECECI Date: Sat, 14 Feb 2026 10:23:57 +0300 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- svc/.env | 2 + svc/db/postgres.go | 28 +++++++++++++- ui/.env.development | 1 + ui/.env.production | 1 + ui/quasar.config.js | 75 ++++++++++++++++++++++++++++++-------- ui/src/boot/axios.js | 21 ----------- ui/src/pages/OrderList.vue | 33 ++++++++--------- ui/src/services/api.js | 13 ++++--- 8 files changed, 112 insertions(+), 62 deletions(-) create mode 100644 ui/.env.development create mode 100644 ui/.env.production delete mode 100644 ui/src/boot/axios.js diff --git a/svc/.env b/svc/.env index d29fb64..2c57027 100644 --- a/svc/.env +++ b/svc/.env @@ -2,6 +2,8 @@ JWT_SECRET=bssapp_super_secret_key_1234567890 PASSWORD_RESET_SECRET=1dc7d6d52fd0459a8b1f288a6590428e760f54339f8e47beb20db36b6df6070b APP_FRONTEND_URL=http://localhost:9000 API_URL=http://localhost:8080 +UI_DIR=/opt/bssapp/ui/dist +POSTGRES_CONN=host=127.0.0.1 port=5432 user=postgres password=tayitkan dbname=baggib2b sslmode=disable diff --git a/svc/db/postgres.go b/svc/db/postgres.go index e7e62c4..c5f6330 100644 --- a/svc/db/postgres.go +++ b/svc/db/postgres.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "os" + "strings" "time" _ "github.com/lib/pq" @@ -37,7 +38,32 @@ func ConnectPostgres() (*sql.DB, error) { // 🔹 Test et if err = db.Ping(); err != nil { - return nil, fmt.Errorf("PostgreSQL erişilemiyor: %w", err) + // Some managed PostgreSQL servers require TLS. If the current DSN uses + // sslmode=disable and server rejects with "no encryption", retry once + // with sslmode=require to avoid startup failure. + if strings.Contains(err.Error(), "no pg_hba.conf entry") && + strings.Contains(err.Error(), "no encryption") && + strings.Contains(strings.ToLower(connStr), "sslmode=disable") { + secureConnStr := strings.Replace(connStr, "sslmode=disable", "sslmode=require", 1) + log.Println("⚠️ PostgreSQL requires TLS, retrying with sslmode=require") + + _ = db.Close() + db, err = sql.Open("postgres", secureConnStr) + if err != nil { + return nil, fmt.Errorf("PostgreSQL TLS retry open failed: %w", err) + } + + db.SetMaxOpenConns(30) + db.SetMaxIdleConns(10) + db.SetConnMaxLifetime(30 * time.Minute) + db.SetConnMaxIdleTime(5 * time.Minute) + + if err = db.Ping(); err != nil { + return nil, fmt.Errorf("PostgreSQL erişilemiyor (TLS retry): %w", err) + } + } else { + return nil, fmt.Errorf("PostgreSQL erişilemiyor: %w", err) + } } log.Println("✅ PostgreSQL bağlantısı başarılı!") diff --git a/ui/.env.development b/ui/.env.development new file mode 100644 index 0000000..a8cf54a --- /dev/null +++ b/ui/.env.development @@ -0,0 +1 @@ +VITE_API_BASE_URL=http://localhost:8080 diff --git a/ui/.env.production b/ui/.env.production new file mode 100644 index 0000000..14ea4ad --- /dev/null +++ b/ui/.env.production @@ -0,0 +1 @@ +VITE_API_BASE_URL=/api diff --git a/ui/quasar.config.js b/ui/quasar.config.js index 520371a..d13bcbb 100644 --- a/ui/quasar.config.js +++ b/ui/quasar.config.js @@ -4,52 +4,89 @@ import { defineConfig } from '#q-app/wrappers' export default defineConfig(() => { return { - // ✅ UYGULAMA KİMLİĞİ (WEB'DE GÖRÜNEN İSİM) + /* ===================================================== + APP INFO + ===================================================== */ productName: 'Baggi BSS', productDescription: 'Baggi Tekstil Business Support System', - // 🔹 Boot dosyaları - boot: ['axios', 'dayjs'], + /* ===================================================== + BOOT FILES + ===================================================== */ + boot: ['dayjs'], - // 🔹 Global CSS + /* ===================================================== + GLOBAL CSS + ===================================================== */ css: ['app.css'], - // 🔹 Ekstra icon/font setleri + /* ===================================================== + ICONS / FONTS + ===================================================== */ extras: [ 'roboto-font', 'material-icons' ], - // 🔹 Derleme Ayarları + /* ===================================================== + BUILD (PRODUCTION) + ===================================================== */ build: { vueRouterMode: 'hash', - env: { - VITE_API_BASE_URL: 'http://localhost:8080/api' - }, + esbuildTarget: { browser: ['es2022', 'firefox115', 'chrome115', 'safari14'], node: 'node20' - } + }, + + // Cache & performance + gzip: true, + preloadChunks: true }, - // 🔹 Geliştirme Sunucusu + /* ===================================================== + DEV SERVER (LOCAL) + ===================================================== */ devServer: { server: { type: 'http' }, port: 9000, - open: true + open: true, + + // DEV proxy (CORS’suz) + proxy: { + '/api': { + target: 'http://localhost:8080', + changeOrigin: true, + secure: false + } + } }, - // 🔹 Quasar Framework ayarları + /* ===================================================== + QUASAR FRAMEWORK + ===================================================== */ framework: { config: { - notify: { position: 'top', timeout: 2500 } + notify: { + position: 'top', + timeout: 2500 + } }, + lang: 'tr', - plugins: ['Loading', 'Dialog', 'Notify'] + + plugins: [ + 'Loading', + 'Dialog', + 'Notify' + ] }, animations: [], + /* ===================================================== + SSR / PWA (DISABLED) + ===================================================== */ ssr: { prodPort: 3000, middlewares: ['render'], @@ -60,6 +97,9 @@ export default defineConfig(() => { workboxMode: 'GenerateSW' }, + /* ===================================================== + MOBILE / DESKTOP + ===================================================== */ capacitor: { hideSplashscreen: true }, @@ -68,7 +108,10 @@ export default defineConfig(() => { preloadScripts: ['electron-preload'], inspectPort: 5858, bundler: 'packager', - builder: { appId: 'baggisowtfaresystem' } + + builder: { + appId: 'baggisowtfaresystem' + } }, bex: { diff --git a/ui/src/boot/axios.js b/ui/src/boot/axios.js deleted file mode 100644 index 400dbfd..0000000 --- a/ui/src/boot/axios.js +++ /dev/null @@ -1,21 +0,0 @@ -import { boot } from 'quasar/wrappers' -import axios from 'axios' - -export const api = axios.create({ - baseURL: 'http://localhost:8080/api', - timeout: 180000, - withCredentials: true // refresh cookie kullanıyorsan kalsın -}) - -export default boot(() => { - api.interceptors.request.use((config) => { - const token = localStorage.getItem('token') // ✅ senin authStore key’in - - if (token) { - config.headers = config.headers || {} - config.headers.Authorization = `Bearer ${token}` - } - - return config - }) -}) diff --git a/ui/src/pages/OrderList.vue b/ui/src/pages/OrderList.vue index 33f6d72..6bffc73 100644 --- a/ui/src/pages/OrderList.vue +++ b/ui/src/pages/OrderList.vue @@ -233,6 +233,7 @@ import { useQuasar } from 'quasar' import { useOrderListStore } from 'src/stores/OrdernewListStore' import { useAuthStore } from 'src/stores/authStore' import { usePermission } from 'src/composables/usePermission' +import api from 'src/services/api' const { canRead } = usePermission() const canReadOrder = canRead('order') @@ -270,22 +271,24 @@ function exportExcel () { OrderDate: store.filters.OrderDate || '' }) - const url = `http://localhost:8080/api/orders/export?${params.toString()}` - - fetch(url, { - headers: { - Authorization: `Bearer ${auth.token}` - } + api.get(`/orders/export?${params.toString()}`, { + responseType: 'blob' }) - .then(res => res.blob()) + .then(res => res.data) .then(blob => { const link = document.createElement('a') link.href = URL.createObjectURL(blob) link.download = 'siparis_listesi.xlsx' link.click() }) + .catch(() => { + $q.notify({ + type: 'negative', + message: 'Excel dosyasi indirilemedi', + position: 'top-right' + }) + }) } - function formatDate (s) { if (!s) return '' const [y, m, d] = String(s).split('-') @@ -383,23 +386,16 @@ function selectOrder (row) { async function printPDF (row) { if (!row?.OrderHeaderID) return - const token = useAuthStore().token - const url = `http://localhost:8080/api/order/pdf/${row.OrderHeaderID}` - try { - const res = await fetch(url, { - headers: { Authorization: `Bearer ${token}` } + const res = await api.get(`/order/pdf/${row.OrderHeaderID}`, { + responseType: 'blob' }) - if (!res.ok) throw new Error() - - const blob = await res.blob() - window.open(URL.createObjectURL(blob), '_blank') + window.open(URL.createObjectURL(res.data), '_blank') } catch { $q.notify({ type: 'negative', message: 'PDF yüklenemedi' }) } } - function clearFilters () { store.filters.search = '' store.filters.CurrAccCode = '' @@ -562,3 +558,4 @@ onMounted(() => { } } + diff --git a/ui/src/services/api.js b/ui/src/services/api.js index 7c85019..c3726a8 100644 --- a/ui/src/services/api.js +++ b/ui/src/services/api.js @@ -3,11 +3,14 @@ import axios from 'axios' import qs from 'qs' import { useAuthStore } from 'stores/authStore' +export const API_BASE_URL = process.env.VITE_API_BASE_URL || '/api' + const api = axios.create({ - baseURL: 'http://localhost:8080/api', + baseURL: API_BASE_URL, timeout: 180000, paramsSerializer: params => - qs.stringify(params, { arrayFormat: 'repeat' }) + qs.stringify(params, { arrayFormat: 'repeat' }), + withCredentials: true }) // REQUEST @@ -21,7 +24,6 @@ api.interceptors.request.use((config) => { url.startsWith('/password/forgot') || url.startsWith('/password/reset') - if (!isPublic && auth?.token) { config.headers ||= {} config.headers.Authorization = `Bearer ${auth.token}` @@ -32,6 +34,7 @@ api.interceptors.request.use((config) => { // RESPONSE let isLoggingOut = false + api.interceptors.response.use( r => r, async (error) => { @@ -47,7 +50,6 @@ api.interceptors.response.use( } ) -// HELPERS export const get = (u, p = {}, c = {}) => api.get(u, { params: p, ...c }).then(r => r.data) @@ -61,7 +63,6 @@ export const del = (u, p = {}, c = {}) => api.delete(u, { params: p, ...c }).then(r => r.data) export const download = (u, p = {}, c = {}) => - api.get(u, { params: p, responseType: 'blob', ...c }) - .then(r => r.data) + api.get(u, { params: p, responseType: 'blob', ...c }).then(r => r.data) export default api