@underundre/undev 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Undre
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # @underundre/undev
2
+
3
+ Reusable dev scripts, configs, and templates for Node.js/TypeScript projects.
4
+
5
+ [Русская версия](README.ru.md)
6
+
7
+ ## What's Inside
8
+
9
+ ```
10
+ configs/ # Shareable tool configs
11
+ eslint.config.js # ESLint flat config (TS strict)
12
+ prettier.config.js # Prettier rules
13
+ tsconfig.base.json # TypeScript strict base
14
+ commitlint.config.js # Conventional Commits
15
+ .editorconfig # IDE settings
16
+
17
+ scripts/ # Bash scripts (parameterized via env vars)
18
+ common.sh # Shared utils (colors, logging, confirm, telegram)
19
+ deploy/
20
+ deploy.sh # Zero-downtime SSH deploy
21
+ rollback.sh # Rollback to previous deploy
22
+ logs.sh # Tail prod logs (pm2/docker/nginx)
23
+ db/
24
+ backup.sh # PostgreSQL backup with retention
25
+ restore.sh # PostgreSQL restore from dump
26
+ server/
27
+ setup-vps.sh # Fresh VPS bootstrap (user, ssh, ufw, node, pm2)
28
+ setup-ssl.sh # Let's Encrypt + auto-renewal
29
+ health-check.sh # Disk/memory/CPU/services check
30
+ docker/
31
+ cleanup.sh # Prune images, containers, volumes
32
+ dev/
33
+ setup.sh # Clone → install → .env → migrate → build
34
+ monitoring/
35
+ security-audit.sh # npm audit + secret scan + outdated deps
36
+
37
+ templates/ # Copy into your project
38
+ .github/workflows/ci.yml # GitHub Actions CI pipeline
39
+ .env.example # Environment variables template
40
+ docker-compose.dev.yml # Dev DB (Postgres + Redis)
41
+ package-scripts.jsonc # Recommended npm scripts reference
42
+ ```
43
+
44
+ ## Usage: Configs
45
+
46
+ Install as dev dependency:
47
+
48
+ ```bash
49
+ npm i -D @underundre/undev
50
+ ```
51
+
52
+ ### ESLint
53
+
54
+ ```js
55
+ // eslint.config.js
56
+ import baseConfig from "@underundre/undev/eslint";
57
+ export default [...baseConfig];
58
+ ```
59
+
60
+ ### TypeScript
61
+
62
+ ```json
63
+ // tsconfig.json
64
+ {
65
+ "extends": "@underundre/undev/tsconfig",
66
+ "compilerOptions": {
67
+ "outDir": "./dist",
68
+ "rootDir": "./src"
69
+ },
70
+ "include": ["src"]
71
+ }
72
+ ```
73
+
74
+ ### Prettier
75
+
76
+ ```json
77
+ // package.json
78
+ { "prettier": "@underundre/undev/prettier" }
79
+ ```
80
+
81
+ ### Commitlint
82
+
83
+ ```js
84
+ // commitlint.config.js
85
+ export default { extends: ["@underundre/undev/commitlint"] };
86
+ ```
87
+
88
+ ## Usage: Scripts
89
+
90
+ Copy the scripts you need into your project:
91
+
92
+ ```bash
93
+ # Copy deploy scripts
94
+ cp -r node_modules/@underundre/undev/scripts/deploy ./scripts/deploy
95
+ cp node_modules/@underundre/undev/scripts/common.sh ./scripts/
96
+
97
+ # Or cherry-pick
98
+ cp node_modules/@underundre/undev/scripts/db/backup.sh ./scripts/
99
+ ```
100
+
101
+ All scripts read config from environment variables. Set them in `.env.production` or pass inline:
102
+
103
+ ```bash
104
+ PROD_SSH_HOST=deploy@myserver.com REMOTE_APP_DIR=/home/deploy/app ./scripts/deploy/deploy.sh
105
+ ```
106
+
107
+ ### Script Config Reference
108
+
109
+ | Variable | Used by | Default |
110
+ |----------|---------|---------|
111
+ | `PROD_SSH_HOST` | deploy, rollback, logs | required |
112
+ | `REMOTE_APP_DIR` | deploy, rollback | required |
113
+ | `POSTGRES_HOST` | db/backup, db/restore | `localhost` |
114
+ | `POSTGRES_PORT` | db/backup, db/restore | `5432` |
115
+ | `POSTGRES_USER` | db/backup, db/restore | `postgres` |
116
+ | `POSTGRES_DB` | db/backup, db/restore | required |
117
+ | `BACKUP_DIR` | db/backup | `./backups` |
118
+ | `RETENTION_DAYS` | db/backup | `14` |
119
+ | `TELEGRAM_BOT_TOKEN` | all (optional notifications) | — |
120
+ | `TELEGRAM_CHAT_ID` | all (optional notifications) | — |
121
+
122
+ ## Usage: Templates
123
+
124
+ ```bash
125
+ # CI workflow
126
+ cp node_modules/@underundre/undev/templates/.github/workflows/ci.yml .github/workflows/
127
+
128
+ # Environment template
129
+ cp node_modules/@underundre/undev/templates/.env.example .
130
+
131
+ # Dev Docker Compose
132
+ cp node_modules/@underundre/undev/templates/docker-compose.dev.yml .
133
+ ```
134
+
135
+ ## npm Scripts Reference
136
+
137
+ See `templates/package-scripts.jsonc` for a complete set of recommended scripts. Key ones:
138
+
139
+ ```json
140
+ {
141
+ "validate": "npm run lint && npm run typecheck && npm run format:check",
142
+ "validate:fix": "npm run lint:fix && npm run typecheck && npm run format"
143
+ }
144
+ ```
145
+
146
+ ## License
147
+
148
+ MIT
package/README.ru.md ADDED
@@ -0,0 +1,148 @@
1
+ # @underundre/undev
2
+
3
+ Переиспользуемые dev-скрипты, конфиги и шаблоны для Node.js/TypeScript проектов.
4
+
5
+ [English version](README.md)
6
+
7
+ ## Что внутри
8
+
9
+ ```
10
+ configs/ # Шарируемые конфиги инструментов
11
+ eslint.config.js # ESLint flat config (строгий TS)
12
+ prettier.config.js # Prettier правила
13
+ tsconfig.base.json # TypeScript strict база
14
+ commitlint.config.js # Conventional Commits
15
+ .editorconfig # Настройки IDE
16
+
17
+ scripts/ # Bash-скрипты (параметризованы через env vars)
18
+ common.sh # Общие утилиты (цвета, логирование, confirm, telegram)
19
+ deploy/
20
+ deploy.sh # Zero-downtime SSH деплой
21
+ rollback.sh # Откат на предыдущий деплой
22
+ logs.sh # Tail логов на проде (pm2/docker/nginx)
23
+ db/
24
+ backup.sh # Бэкап PostgreSQL с ротацией
25
+ restore.sh # Восстановление PostgreSQL из дампа
26
+ server/
27
+ setup-vps.sh # Настройка свежего VPS (юзер, ssh, ufw, node, pm2)
28
+ setup-ssl.sh # Let's Encrypt + автообновление
29
+ health-check.sh # Проверка диска/памяти/CPU/сервисов
30
+ docker/
31
+ cleanup.sh # Очистка images, containers, volumes
32
+ dev/
33
+ setup.sh # Клон → установка → .env → миграции → билд
34
+ monitoring/
35
+ security-audit.sh # npm audit + сканирование секретов + устаревшие зависимости
36
+
37
+ templates/ # Скопировать в свой проект
38
+ .github/workflows/ci.yml # GitHub Actions CI пайплайн
39
+ .env.example # Шаблон переменных окружения
40
+ docker-compose.dev.yml # Dev БД (Postgres + Redis)
41
+ package-scripts.jsonc # Рекомендуемые npm scripts
42
+ ```
43
+
44
+ ## Использование: Конфиги
45
+
46
+ Установить как dev-зависимость:
47
+
48
+ ```bash
49
+ npm i -D @underundre/undev
50
+ ```
51
+
52
+ ### ESLint
53
+
54
+ ```js
55
+ // eslint.config.js
56
+ import baseConfig from "@underundre/undev/eslint";
57
+ export default [...baseConfig];
58
+ ```
59
+
60
+ ### TypeScript
61
+
62
+ ```json
63
+ // tsconfig.json
64
+ {
65
+ "extends": "@underundre/undev/tsconfig",
66
+ "compilerOptions": {
67
+ "outDir": "./dist",
68
+ "rootDir": "./src"
69
+ },
70
+ "include": ["src"]
71
+ }
72
+ ```
73
+
74
+ ### Prettier
75
+
76
+ ```json
77
+ // package.json
78
+ { "prettier": "@underundre/undev/prettier" }
79
+ ```
80
+
81
+ ### Commitlint
82
+
83
+ ```js
84
+ // commitlint.config.js
85
+ export default { extends: ["@underundre/undev/commitlint"] };
86
+ ```
87
+
88
+ ## Использование: Скрипты
89
+
90
+ Скопировать нужные скрипты в проект:
91
+
92
+ ```bash
93
+ # Скопировать скрипты деплоя
94
+ cp -r node_modules/@underundre/undev/scripts/deploy ./scripts/deploy
95
+ cp node_modules/@underundre/undev/scripts/common.sh ./scripts/
96
+
97
+ # Или по одному
98
+ cp node_modules/@underundre/undev/scripts/db/backup.sh ./scripts/
99
+ ```
100
+
101
+ Все скрипты читают конфиг из переменных окружения. Задать в `.env.production` или передать инлайн:
102
+
103
+ ```bash
104
+ PROD_SSH_HOST=deploy@myserver.com REMOTE_APP_DIR=/home/deploy/app ./scripts/deploy/deploy.sh
105
+ ```
106
+
107
+ ### Переменные окружения
108
+
109
+ | Переменная | Используется | По умолчанию |
110
+ |-----------|-------------|-------------|
111
+ | `PROD_SSH_HOST` | deploy, rollback, logs | обязательно |
112
+ | `REMOTE_APP_DIR` | deploy, rollback | обязательно |
113
+ | `POSTGRES_HOST` | db/backup, db/restore | `localhost` |
114
+ | `POSTGRES_PORT` | db/backup, db/restore | `5432` |
115
+ | `POSTGRES_USER` | db/backup, db/restore | `postgres` |
116
+ | `POSTGRES_DB` | db/backup, db/restore | обязательно |
117
+ | `BACKUP_DIR` | db/backup | `./backups` |
118
+ | `RETENTION_DAYS` | db/backup | `14` |
119
+ | `TELEGRAM_BOT_TOKEN` | все (опц. уведомления) | — |
120
+ | `TELEGRAM_CHAT_ID` | все (опц. уведомления) | — |
121
+
122
+ ## Использование: Шаблоны
123
+
124
+ ```bash
125
+ # CI workflow
126
+ cp node_modules/@underundre/undev/templates/.github/workflows/ci.yml .github/workflows/
127
+
128
+ # Шаблон окружения
129
+ cp node_modules/@underundre/undev/templates/.env.example .
130
+
131
+ # Dev Docker Compose
132
+ cp node_modules/@underundre/undev/templates/docker-compose.dev.yml .
133
+ ```
134
+
135
+ ## npm Scripts
136
+
137
+ См. `templates/package-scripts.jsonc`. Ключевые:
138
+
139
+ ```json
140
+ {
141
+ "validate": "npm run lint && npm run typecheck && npm run format:check",
142
+ "validate:fix": "npm run lint:fix && npm run typecheck && npm run format"
143
+ }
144
+ ```
145
+
146
+ ## Лицензия
147
+
148
+ MIT
@@ -0,0 +1,28 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ indent_style = space
6
+ indent_size = 2
7
+ end_of_line = lf
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
13
+
14
+ [Makefile]
15
+ indent_style = tab
16
+
17
+ [*.{sh,bash}]
18
+ indent_size = 2
19
+ end_of_line = lf
20
+
21
+ [*.{yml,yaml}]
22
+ indent_size = 2
23
+
24
+ [*.{json,jsonc}]
25
+ indent_size = 2
26
+
27
+ [*.{sql}]
28
+ indent_size = 4
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shareable commitlint config — Conventional Commits.
3
+ *
4
+ * Usage in your project:
5
+ * export default { extends: ["@underundre/undev/commitlint"] };
6
+ *
7
+ * Or import directly:
8
+ * import config from "@underundre/undev/commitlint";
9
+ * export default config;
10
+ */
11
+
12
+ export default {
13
+ extends: ["@commitlint/config-conventional"],
14
+ rules: {
15
+ "type-enum": [
16
+ 2,
17
+ "always",
18
+ [
19
+ "feat",
20
+ "fix",
21
+ "docs",
22
+ "style",
23
+ "refactor",
24
+ "perf",
25
+ "test",
26
+ "build",
27
+ "ci",
28
+ "chore",
29
+ "revert",
30
+ ],
31
+ ],
32
+ "subject-case": [2, "never", ["start-case", "pascal-case", "upper-case"]],
33
+ "subject-max-length": [2, "always", 100],
34
+ "body-max-line-length": [1, "always", 100],
35
+ },
36
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Shareable ESLint flat config for TypeScript projects.
3
+ *
4
+ * Usage in your project:
5
+ * import baseConfig from "@underundre/undev/eslint";
6
+ * export default [...baseConfig, { /* your overrides * / }];
7
+ */
8
+
9
+ import js from "@eslint/js";
10
+ import tsPlugin from "@typescript-eslint/eslint-plugin";
11
+ import tsParser from "@typescript-eslint/parser";
12
+
13
+ /** @type {import("eslint").Linter.Config[]} */
14
+ export default [
15
+ js.configs.recommended,
16
+ {
17
+ files: ["**/*.ts", "**/*.tsx", "**/*.mts"],
18
+ languageOptions: {
19
+ parser: tsParser,
20
+ parserOptions: {
21
+ projectService: true,
22
+ },
23
+ },
24
+ plugins: {
25
+ "@typescript-eslint": tsPlugin,
26
+ },
27
+ rules: {
28
+ // TypeScript strict
29
+ "@typescript-eslint/no-explicit-any": "error",
30
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
31
+ "@typescript-eslint/consistent-type-imports": ["error", { prefer: "type-imports" }],
32
+ "@typescript-eslint/no-import-type-side-effects": "error",
33
+
34
+ // Safety
35
+ "no-console": ["warn", { allow: ["warn", "error"] }],
36
+ "no-debugger": "error",
37
+ "no-eval": "error",
38
+ "no-implied-eval": "error",
39
+ "prefer-const": "error",
40
+ "no-var": "error",
41
+ eqeqeq: ["error", "always"],
42
+
43
+ // Style (let prettier handle formatting)
44
+ "no-multiple-empty-lines": ["error", { max: 1 }],
45
+ },
46
+ },
47
+ {
48
+ ignores: [
49
+ "node_modules/",
50
+ "dist/",
51
+ "build/",
52
+ "coverage/",
53
+ "*.min.js",
54
+ ".next/",
55
+ ".nuxt/",
56
+ ],
57
+ },
58
+ ];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shareable Prettier config.
3
+ *
4
+ * Usage in your project's package.json:
5
+ * "prettier": "@underundre/undev/prettier"
6
+ *
7
+ * Or in prettier.config.js:
8
+ * import config from "@underundre/undev/prettier";
9
+ * export default { ...config, /* overrides */ };
10
+ */
11
+
12
+ /** @type {import("prettier").Config} */
13
+ export default {
14
+ semi: true,
15
+ singleQuote: false,
16
+ tabWidth: 2,
17
+ trailingComma: "all",
18
+ printWidth: 100,
19
+ bracketSpacing: true,
20
+ arrowParens: "always",
21
+ endOfLine: "lf",
22
+ plugins: [],
23
+ };
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "compilerOptions": {
4
+ "target": "ES2022",
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "lib": ["ES2022"],
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "sourceMap": true,
17
+ "noUncheckedIndexedAccess": true,
18
+ "noUnusedLocals": true,
19
+ "noUnusedParameters": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+ "verbatimModuleSyntax": true
22
+ }
23
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@underundre/undev",
3
+ "version": "0.1.0",
4
+ "description": "Reusable dev scripts, configs, and templates for Node.js/TypeScript projects",
5
+ "type": "module",
6
+ "exports": {
7
+ "./eslint": "./configs/eslint.config.js",
8
+ "./prettier": "./configs/prettier.config.js",
9
+ "./tsconfig": "./configs/tsconfig.base.json",
10
+ "./commitlint": "./configs/commitlint.config.js"
11
+ },
12
+ "files": [
13
+ "configs",
14
+ "scripts",
15
+ "templates"
16
+ ],
17
+ "scripts": {
18
+ "lint": "echo 'No source to lint'",
19
+ "test": "echo 'No tests yet'"
20
+ },
21
+ "keywords": [
22
+ "dev-scripts",
23
+ "configs",
24
+ "eslint",
25
+ "prettier",
26
+ "typescript",
27
+ "deploy",
28
+ "devops"
29
+ ],
30
+ "author": "UnderUndre",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/UnderUndre/undev.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/UnderUndre/undev/issues"
38
+ },
39
+ "homepage": "https://github.com/UnderUndre/undev#readme",
40
+ "engines": {
41
+ "node": ">=20.0.0"
42
+ },
43
+ "peerDependencies": {
44
+ "eslint": ">=9.0.0",
45
+ "prettier": ">=3.0.0",
46
+ "typescript": ">=5.0.0"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "eslint": { "optional": true },
50
+ "prettier": { "optional": true },
51
+ "typescript": { "optional": true }
52
+ }
53
+ }
@@ -0,0 +1,74 @@
1
+ #!/bin/bash
2
+ # ─────────────────────────────────────────────────
3
+ # Common utilities for all undev scripts.
4
+ # Source this at the top of every script:
5
+ # source "$(dirname "$0")/common.sh"
6
+ # ─────────────────────────────────────────────────
7
+
8
+ set -euo pipefail
9
+
10
+ # Colors
11
+ RED='\033[0;31m'
12
+ GREEN='\033[0;32m'
13
+ YELLOW='\033[1;33m'
14
+ BLUE='\033[0;34m'
15
+ CYAN='\033[0;36m'
16
+ NC='\033[0m'
17
+
18
+ # Detect repo root
19
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || dirname "$SCRIPT_DIR")"
21
+
22
+ # Logging
23
+ log() { echo -e "${GREEN}[$(date '+%H:%M:%S')]${NC} $1"; }
24
+ warn() { echo -e "${YELLOW}[$(date '+%H:%M:%S')] WARN:${NC} $1"; }
25
+ error() { echo -e "${RED}[$(date '+%H:%M:%S')] ERROR:${NC} $1" >&2; }
26
+ info() { echo -e "${CYAN}[$(date '+%H:%M:%S')]${NC} $1"; }
27
+ step() { echo -e "${BLUE}▸${NC} $1"; }
28
+
29
+ # Confirm prompt (skip if --yes or CI)
30
+ confirm() {
31
+ local msg="${1:-Continue?}"
32
+ if [[ "${YES:-false}" == "true" ]] || [[ "${CI:-false}" == "true" ]]; then
33
+ return 0
34
+ fi
35
+ read -rp "$(echo -e "${YELLOW}${msg} [y/N]${NC} ")" answer
36
+ [[ "$answer" =~ ^[Yy]$ ]]
37
+ }
38
+
39
+ # Load .env file if it exists
40
+ load_env() {
41
+ local env_file="${1:-.env}"
42
+ if [[ -f "$REPO_ROOT/$env_file" ]]; then
43
+ set -a
44
+ source "$REPO_ROOT/$env_file"
45
+ set +a
46
+ fi
47
+ }
48
+
49
+ # Telegram notification (optional — needs TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID)
50
+ notify_telegram() {
51
+ local message="$1"
52
+ if [[ -n "${TELEGRAM_BOT_TOKEN:-}" ]] && [[ -n "${TELEGRAM_CHAT_ID:-}" ]]; then
53
+ curl -sf -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
54
+ --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \
55
+ --data-urlencode "text=${message}" \
56
+ --data-urlencode "parse_mode=Markdown" > /dev/null 2>&1 &
57
+ fi
58
+ }
59
+
60
+ # Git helpers
61
+ git_branch() { git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD; }
62
+ git_commit() { git -C "$REPO_ROOT" rev-parse --short HEAD; }
63
+ git_version() { node -p "require('$REPO_ROOT/package.json').version" 2>/dev/null || echo "0.0.0"; }
64
+ git_dirty() { [[ -n "$(git -C "$REPO_ROOT" status --porcelain)" ]]; }
65
+
66
+ # Require commands
67
+ require_cmd() {
68
+ for cmd in "$@"; do
69
+ if ! command -v "$cmd" &>/dev/null; then
70
+ error "Required command not found: $cmd"
71
+ exit 1
72
+ fi
73
+ done
74
+ }
@@ -0,0 +1,53 @@
1
+ #!/bin/bash
2
+ # ─────────────────────────────────────────────────
3
+ # PostgreSQL database backup.
4
+ #
5
+ # Config (env vars or .env):
6
+ # POSTGRES_HOST (default: localhost)
7
+ # POSTGRES_PORT (default: 5432)
8
+ # POSTGRES_USER (default: postgres)
9
+ # POSTGRES_DB (required)
10
+ # BACKUP_DIR (default: ./backups)
11
+ # RETENTION_DAYS (default: 14)
12
+ #
13
+ # Usage:
14
+ # ./scripts/db/backup.sh # Backup to local dir
15
+ # BACKUP_DIR=/mnt/s3 ./scripts/db/backup.sh # Custom dir
16
+ # ─────────────────────────────────────────────────
17
+
18
+ source "$(dirname "$0")/../common.sh"
19
+ load_env
20
+
21
+ require_cmd pg_dump
22
+
23
+ : "${POSTGRES_DB:?Set POSTGRES_DB}"
24
+
25
+ DB_HOST="${POSTGRES_HOST:-localhost}"
26
+ DB_PORT="${POSTGRES_PORT:-5432}"
27
+ DB_USER="${POSTGRES_USER:-postgres}"
28
+ BACKUP_DIR="${BACKUP_DIR:-$REPO_ROOT/backups}"
29
+ RETENTION_DAYS="${RETENTION_DAYS:-14}"
30
+
31
+ DATE=$(date +%Y%m%d_%H%M%S)
32
+ BACKUP_FILE="${BACKUP_DIR}/${POSTGRES_DB}_${DATE}.dump"
33
+
34
+ mkdir -p "$BACKUP_DIR"
35
+
36
+ step "Backing up ${POSTGRES_DB}@${DB_HOST}:${DB_PORT}..."
37
+ pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -Fc "$POSTGRES_DB" > "$BACKUP_FILE"
38
+
39
+ SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
40
+ log "Backup complete: $BACKUP_FILE ($SIZE)"
41
+
42
+ # Retention cleanup
43
+ if [[ "$RETENTION_DAYS" -gt 0 ]]; then
44
+ DELETED=$(find "$BACKUP_DIR" -name "*.dump" -mtime "+$RETENTION_DAYS" -delete -print | wc -l)
45
+ if [[ "$DELETED" -gt 0 ]]; then
46
+ info "Cleaned $DELETED old backups (>$RETENTION_DAYS days)"
47
+ fi
48
+ fi
49
+
50
+ notify_telegram "💾 *DB Backup*
51
+ 📦 $POSTGRES_DB
52
+ 📏 $SIZE
53
+ 🗑 Retention: ${RETENTION_DAYS}d"