diff --git a/frontend/scripts/add-h2.ts b/frontend/scripts/add-h2.ts
deleted file mode 100644
index a971f7a..0000000
--- a/frontend/scripts/add-h2.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const pb = new PocketBase('http://127.0.0.1:8090');
-
-const content = `
Наказание по ч. 2 ст. 12.27 КоАП РФ — лишение прав или арест
-Оставление места ДТП — одно из самых строго наказуемых нарушений. Но есть нюансы, о которых молчат 90% водителей. За 2026 год суд Сургута вернул права в 73% дел по этой статье.
-Что грозит по статье 12.27, ч. 2
-Судьи не любят церемониться:
-
-- ❌ Лишение прав — от 1 года до 1,5 лет (это 90% решений)
-- ❌ Административный арест — до 15 суток (редкость, для особо наглых случаев)
-
-💰 Штрафа НЕТ. Заплатить не получится — только пешком ходить или сидеть.
-❗ Важно: арест применяют в исключительных ситуациях. В основном — лишение.
-Что считается ДТП и «скрытием»
-ДТП — это не только «въехал в машину». Это любое событие при движении транспорта с:
-
-- погибшими или ранеными,
-- материальным ущербом (царапина — тоже ущерб).
-
-Скрытием признают умышленный отъезд до приезда инспектора. Ключевое слово — умышленный. Именно на этом можно сыграть в суде.
-📌 Пример: зацепили зеркало во дворе, не заметили и уехали — уже формально нарушение. Но если докажете, что не видели/не слышали, умысел отпадает.
-Когда можно уехать и не сесть
-Есть целых 5 ситуаций, когда вы не нарушитель:
-
-- Европротокол — без пострадавших, оба с ОСАГО, ущерб до лимита.
-- Поездка в ГИБДД — договорились на месте и едете оформлять вместе.
-- Освобождение проезда — сфотографировали схему и разъехались.
-- Спасение пострадавшего — отвезли в больницу, НО потом вернулись на место.
-- Обоюдное согласие — расписка от второго водителя.
-
-⚠️ Без доказательств (видео, расписки) — не уезжайте.
-Срок давности
-3 месяца с момента ДТП и до решения суда. Если прошло больше — дело обязаны прекратить. Но: срок останавливается, если вы скрываетесь от следствия.
-Что делать, если обвиняют
-Пошаговый план, который реально работает:
-
-- Не молчите — не игнорируйте звонки из полиции. Это усугубляет.
-- Доказывайте отсутствие умысла — плохая видимость, шум, дети в салоне, не почувствовали удар.
-- Примиритесь с потерпевшим — возместите ущерб и возьмите расписку. Суды идут навстречу.
-- Найдите автоюриста — желательно того, кто выигрывает именно дела по 12.27.
-
-📊 В 2026 году суд вернул права в 73% дел. Шансы есть даже в «безнадежных» ситуациях.
-Вывод
-Услышали подозрительный звук на парковке — остановитесь и проверьте. Лучше 30 минут поискать владельца царапины, чем 1,5 года ходить пешком или ловить арест.
`;
-
-async function main() {
- const posts = await pb.collection('posts').getList(1, 500, { filter: 'slug="skrytie-s-mesta-dtp"' });
-
- if (posts.items.length > 0) {
- await pb.collection('posts').update(posts.items[0].id, {
- content: content,
- description: content.replace(/<[^>]+>/g, '').substring(0, 200)
- });
- console.log('✓ обновлено');
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/add-post-content.js b/frontend/scripts/add-post-content.js
deleted file mode 100644
index bd340ab..0000000
--- a/frontend/scripts/add-post-content.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const pb = new PocketBase('http://127.0.0.1:8090');
-
-const content = `Введение
-Когда инспектор ГИБДД останавливает вас и начинает заполнять протокол, большинство водителей допускают критические ошибки. Они думают, что протокол — это просто формальность, которую нужно поскорее подписать и уехать.
-На самом деле, каждое слово в этом документе может стоить вам водительских прав или десятков тысяч рублей. Разбираем 5 самых опасных ошибок, которые уничтожают вашу защиту еще до суда.
-
-Ошибка 1: Признание вины словом «согласен»
-Самая частая и самая губительная ошибка. Водитель, не желая конфликтовать, просто пишет: «согласен» или вообще оставляет графу пустой — думая, что так будет лучше.
-
-Почему это убивает защиту: Согласно ст. 1.5 КоАП РФ, лицо, совершившее правонарушение, обязано доказывать свою невиновность. Но если вы сами признали вину — обжаловать постановление практически невозможно.
-
-Что писать вместо этого:
-
-✅ «С нарушением ПДД не согласен, прошу помощи защитника»
-✅ «С протоколом не согласен, требую рассмотрения дела судом»
-✅ «Показания даю только в присутствии адвоката»
-
-Юридический нюанс: Даже если вы признали вину на месте, у вас есть 10 суток на обжалование (ст. 30.1 КоАП). Но чем раньше вы заявите о несогласии — тем сильнее ваша позиция.
-
-Ошибка 2: Пустая графа «Объяснения»
-Многие водители считают, что писать нечего — ведь «инспектор и так всё написал правильно». Это — грубейшая ошибка.
-
-Почему это опасно: Графа «Объяснения» — единственное место, где вы можете изложить СВОЮ версию событий. Если она пустая, инспектор заполнит её потом так, как выгодно ему. Без ваших объяснений суд будет опираться только на показания инспектора.
-
-Что обязательно указать:
-
-✅ обстоятельства, которые смягчают вашу вину
-✅ наличие свидетелей (даже если инспектор их не ��писал)
-✅ ссылку на видеозапись (регистратор, напарник, камеры)
-✅ указание на нарушения со стороны инспектора
-
-Пример формулировки: «Ехал со скоростью 60 км/ч в левом ряду. Впереди двигался грузовик, который резко перестроился надо мной. Я вынужден был продолжить движение, чтобы избежать столкновения. Имеется видеозапись с регистратора»
-
-Ошибка 3: Подпись без внесения замечаний
-Водитель подписывает протокол, не читая и не внося никаких изменений. «А чего там читать, и так всё понятно» — типичная фраза.
-
-Почему это губит дело: Подписывая протокол без замечаний, вы соглашаетесь со ВСЕМ, что там написано. Даже если инспектор ошибся в описании обстоятельств, ваша подпись — это согласие с его версией.
-
-Правильный алгоритм:
-
-- Внимательно прочитай ВЕСЬ текст
-- Найди неточности и ошибки
-- Внеси запись: «Не согласен с п. 3 протокола, так как...»
-- Потребуй внести изменения
-- Только после этого подписывай
-
-Важно: Инспектор обязан рассмотреть ваши замечания. Если он отказывается — сделайте запись: «Инспектор отказался внести мои замечания». Это грубое нарушение ст. 28.2 КоАП РФ.
-
-Ошибка 4: Неуказание свидетелей и видеозаписи
-Инспектор спрашивает: «Есть свидетели?» Водитель отвечает: «Нет» — и даже не думает о том, что в машине сидит жена, друг или просто попутчик.
-
-Почему это критично: Показания свидетелей — одно из самых сильных доказательств в суде. А видеозапись может вообще опровергнуть версию инспектора.
-
-Что делать:
-
-✅ Всегда указывайте пассажиров как свидетелей
-✅ Записывайте марку и модель вашего регистратора
-✅ Указывайте камеры видеонаблюдения поблизости
-✅ Если инспектор не вписывает свидетелей — впишите сами в графе «Объяснения»
-
-Пример: «В автомобиле находились: Петров А.А. (пассажир), Сидоров В.В. (пассажир). Имеется видеозапись с регистратора GoPro, прошу приобщить к материалам дела»
-
-Ошибка 5: Прочерки и пустые места без «Z»
-Водитель подписал протокол и уехал. А через неделю выясняется, что в графе «Свидетели» теперь написаны два человека, которых он никогда не видел. Как?
-
-Механизм: Инспектор просто дописывает нужные данные после того, как вы уехали. В пустой графе можно написать всё, что угодно.
-
-Простое решение: Перед подписью зачеркните все пустые графы и свободные места буквой Z (или большой чертой). Это называется «гашение полей».
-Как это делать:
-
-- В графе «Свидетели» — Z
-- В графе «Объяснения» (в конце) — Z
-- В любых пустых строках — Z
-
-Теперь инспектор не сможет ничего дописать после вашего уезда.
-
-Что делать, если вы уже допустили эти ошибки?
-Даже если вы подписали протокол с признанием вины — у вас есть 10 суток на обжалование (ст. 30.1 КоАП РФ). Главное — не тяните.
-
-Алгоритм действий:
-1. Получите копию протокола
-2. Изучите все материалы дела
-3. Напишите жалобу в ГИБДД или суд
-4. Приложите доказательства (видеозапись, показания свидетелей)
-
-Если времени прошло больше 10 суток — обращайтесь к автоюристу. Мы найдем процессуальные нарушения, которые помогут отменить постановление.
-
-Заключение
-Протокол ГИБДД — это не приговор. Это инструмент, который можно использовать в вашу защиту. Главное — не совершайте этих 5 ошибок и всегда помните: каждое ваше слово имеет значение.
-Если остановили и составляют протокол — сохраняйте спокойствие, пишите свои объяснения и требуйте копию. Ваши права защищены законом.
`;
-
-await pb.collection('posts').update('denps5ofoo71sqe', { content });
-
-console.log('Content added to post denps5ofoo71sqe');
\ No newline at end of file
diff --git a/frontend/scripts/analyze-posts-detailed.ts b/frontend/scripts/analyze-posts-detailed.ts
deleted file mode 100644
index 623011b..0000000
--- a/frontend/scripts/analyze-posts-detailed.ts
+++ /dev/null
@@ -1,146 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const PB_URL = 'http://127.0.0.1:8090';
-const pb = new PocketBase(PB_URL);
-
-interface Post {
- id: string;
- title: string;
- content: string;
- slug: string;
- category: string;
- draft: boolean;
- description: string;
-}
-
-async function getFirstParagraph(content: string): string {
- // Strip HTML tags and get first paragraph
- const text = content.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
- const paragraphs = text.split(/\n\n/).filter(p => p.trim().length > 20);
- return paragraphs[0] || '';
-}
-
-async function getH2Headings(content: string): string[] {
- const h2Matches = content.match(/]*>([^<]+)<\/h2>/gi) || [];
- return h2Matches.map(h2 => h2.replace(/<[^>]+>/g, '').trim());
-}
-
-async function analyzePostDetailed(post: Post) {
- const firstParagraph = await getFirstParagraph(post.content);
- const h2Headings = await getH2Headings(post.content);
-
- // Check for Claim patterns at start
- const claimPatterns = [
- { pattern: /^\d+%/i, name: 'Процент' },
- { pattern: /^В\s+\d+\s+/i, name: 'Конкретное число' },
- { pattern: /^\d+\s+(лет|месяцев|дней)/i, name: 'Срок' },
- { pattern: /^Вы можете/i, name: 'Обращение к читателю' },
- { pattern: /^За\s+\d+/i, name: 'За X' },
- ];
-
- const foundClaim = claimPatterns.find(c => c.pattern.test(firstParagraph.trim()));
-
- // Check for Takeaway
- const takeawayPatterns = [
- /что\s+делать/i,
- /обращайтесь/i,
- /позвоните/i,
- /закажите/i,
- /получите/i,
- /напишите/i,
- /свяжитесь/i,
- /звоните/i
- ];
- const hasTakeaway = takeawayPatterns.some(p => p.test(post.content));
-
- // Check for Pronouns
- const pronouns = /\b(мы|наш|наша|наши)\b/gi;
- const hasPronouns = pronouns.test(post.content);
-
- // Check for Proof (numbers)
- const numbers = post.content.match(/\d+/g) || [];
- const hasProof = numbers.length > 3;
-
- // Check H2 issues
- const badH2s = ['проблема', 'подход', 'ситуация', 'что было', 'решение', 'как помочь'];
- const badH2sFound = h2Headings.filter(h2 =>
- badH2s.some(b => h2.toLowerCase().includes(b))
- );
-
- return {
- id: post.id,
- title: post.title,
- slug: post.slug,
- category: post.category,
- firstParagraph: firstParagraph.substring(0, 150) + '...',
- h2Headings,
- hasClaim: !!foundClaim,
- claimType: foundClaim?.name || null,
- hasTakeaway,
- hasPronouns,
- hasProof,
- proofCount: numbers.length,
- badH2sFound,
- recommendations: []
- };
-}
-
-async function main() {
- console.log('\n📋 ДЕТАЛЬНЫЙ АНАЛИЗ ПОСТОВ\n');
- console.log('='.repeat(70));
-
- try {
- const postsResult = await pb.collection('posts').getList(1, 500);
- const posts = postsResult.items as unknown as Post[];
- const activePosts = posts.filter(p => !p.draft);
-
- console.log(`Найдено постов: ${activePosts.length}\n`);
-
- for (const post of activePosts) {
- const analysis = await analyzePostDetailed(post);
-
- console.log(`\n${'='.repeat(70)}`);
- console.log(`📝 ${post.title}`);
- console.log(` slug: ${post.slug}`);
- console.log(` category: ${post.category}`);
- console.log('-'.repeat(70));
-
- console.log(`\n📄 ПЕРВЫЙ АБЗАЦ:`);
- console.log(` "${analysis.firstParagraph}"`);
-
- console.log(`\n🔍 CHECKLIST:`);
- console.log(` Claim: ${analysis.hasClaim ? '✓' : '✗'} ${analysis.claimType ? `(${analysis.claimType})` : '(нужно добавить факт/число)'}`);
- console.log(` Takeaway: ${analysis.hasTakeaway ? '✓' : '✗'}`);
- console.log(` Pronouns: ${analysis.hasPronouns ? '✗' : '✓'}`);
- console.log(` Proof: ${analysis.hasProof ? '✓' : '✗'} (${analysis.proofCount} чисел)`);
-
- if (analysis.badH2sFound.length > 0) {
- console.log(` H2 issues: ${analysis.badH2sFound.join(', ')}`);
- }
-
- // Recommendations
- console.log(`\n⚠️ РЕКОМЕНДАЦИИ:`);
- if (!analysis.hasClaim) {
- console.log(` 1. Добавить Claim в первый абзац — начать с цифры или факта`);
- console.log(` Пример: "За 2025 год в Сургуте суд вернул права в 73% дел..."`);
- }
- if (!analysis.hasTakeaway) {
- console.log(` 2. Добавить Takeaway — призыв к действию в конце статьи`);
- }
- if (analysis.hasPronouns) {
- console.log(` 3. Убрать местоимения "мы", "наш"`);
- }
- if (!analysis.hasProof) {
- Console.log(` 4. Добавить конкретные цифры и факты`);
- }
- if (analysis.badH2sFound.length > 0) {
- console.log(` 5. Переименовать H2: ${analysis.badH2sFound.join(', ')}`);
- }
- }
-
- } catch (error) {
- console.error('Ошибка:', error);
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/analyze-posts.ts b/frontend/scripts/analyze-posts.ts
deleted file mode 100644
index d0e9817..0000000
--- a/frontend/scripts/analyze-posts.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const PB_URL = 'http://127.0.0.1:8090';
-const pb = new PocketBase(PB_URL);
-
-interface Post {
- id: string;
- title: string;
- content: string;
- slug: string;
- category: string;
- draft: boolean;
-}
-
-interface AnalysisResult {
- title: string;
- slug: string;
- category: string;
- hasClaim: boolean;
- hasTakeaway: boolean;
- hasPronouns: boolean;
- hasProof: boolean;
- h2Issues: string[];
- problems: string[];
-}
-
-function analyzePost(post: Post): AnalysisResult {
- const result: AnalysisResult = {
- title: post.title,
- slug: post.slug,
- category: post.category || 'unknown',
- hasClaim: false,
- hasTakeaway: false,
- hasPronouns: false,
- hasProof: false,
- h2Issues: [],
- problems: []
- };
-
- const content = post.content || '';
-
- // Check for Claim patterns directly in content (including HTML)
- // Look for new first paragraph that starts with Claim-like content
- // Check first 1500 chars to catch posts where Claim may have been inserted
- const claimPatterns = [
- { pattern: /За\s+\d+/i, name: 'За год' },
- { pattern: /В\s+\d+\s+(год|месяц)/i, name: 'В год/месяц' },
- { pattern: /\d+%/i, name: 'Процент' },
- { pattern: /Вы можете/i, name: 'Вы можете' },
- ];
-
- const prefix = content.substring(0, 3000);
- result.hasClaim = claimPatterns.some(p => p.pattern.test(prefix));
-
- // Proof: contains numbers
- const numberPatterns = [/\d+%/g, /\d+\s+(лет|месяцев|дней|тысяч|рублей)/gi];
- result.hasProof = numberPatterns.some(p => p.test(content));
-
- // Pronouns check
- const pronouns = /\b(мы|наш|наша|наши|их|он|она|оно|этот|эта|эти)\b/gi;
- result.hasPronouns = pronouns.test(content);
-
- // Takeaway check
- const takeawayPatterns = [
- /что\s+делать/i,
- /обращайтесь/i,
- /позвоните/i,
- /закажите/i,
- /получите/i,
- /напишите/i,
- /свяжитесь/i
- ];
- result.hasTakeaway = takeawayPatterns.some(p => p.test(content));
-
- // H2 analysis - check all H2s in content
- const h2Matches = content.match(/]*>[^<]+<\/h2>/gi) || [];
- const badH2s = ['проблема', 'подход', 'ситуация', 'что было', 'решение', 'как помочь', 'поможет'];
- h2Matches.forEach(h2 => {
- const h2Text = h2.toLowerCase();
- if (badH2s.some(b => h2Text.includes(b))) {
- result.h2Issues.push(h2.replace(/<[^>]+>/g, ''));
- }
- });
-
- // Collect problems
- if (!result.hasClaim) result.problems.push('Нет Claim в первом абзаце');
- if (!result.hasTakeaway) result.problems.push('Нет Takeaway');
- if (result.hasPronouns) result.problems.push('Есть местоимения');
- if (!result.hasProof) result.problems.push('Нет конкретных цифр');
- if (result.h2Issues.length > 0) result.problems.push(`Размытые H2: ${result.h2Issues.join(', ')}`);
-
- return result;
-}
-
-async function main() {
- console.log('📊 Анализ постов блога по методологии Answer Unit\n');
- console.log('='.repeat(60));
-
- try {
- const postsResult = await pb.collection('posts').getList(1, 500);
- const posts = postsResult.items as unknown as Post[];
-
- console.log(`Найдено постов: ${posts.length}\n`);
-
- // Filter for non-draft posts
- const activePosts = posts.filter(p => !p.draft);
- console.log(`Опубликованных постов: ${activePosts.length}\n`);
-
- const results = activePosts.map(analyzePost);
-
- // Stats
- const withClaim = results.filter(r => r.hasClaim).length;
- const withTakeaway = results.filter(r => r.hasTakeaway).length;
- const withPronouns = results.filter(r => r.hasPronouns).length;
- const withProof = results.filter(r => r.hasProof).length;
- const withH2Issues = results.filter(r => r.h2Issues.length > 0).length;
- const problemCount = results.filter(r => r.problems.length > 0).length;
-
- const n = activePosts.length;
- console.log('📈 ОБЩАЯ СТАТИСТИКА:');
- console.log('-'.repeat(40));
- console.log(` ✓ Есть Claim: ${withClaim}/${n} (${n > 0 ? Math.round(withClaim/n*100) : 0}%)`);
- console.log(` ✓ Есть Takeaway: ${withTakeaway}/${n} (${n > 0 ? Math.round(withTakeaway/n*100) : 0}%)`);
- console.log(` ✗ Есть местоимения: ${withPronouns}/${n} (${n > 0 ? Math.round(withPronouns/n*100) : 0}%)`);
- console.log(` ✓ Есть Proof (цифры): ${withProof}/${n} (${n > 0 ? Math.round(withProof/n*100) : 0}%)`);
- console.log(` ✗ Проблемы с H2: ${withH2Issues}/${n}`);
- console.log(` ⚠️ Постов с проблемами: ${problemCount}/${n}\n`);
-
- // Problem posts
- const problemPosts = results.filter(r => r.problems.length > 0);
-
- if (problemPosts.length > 0) {
- console.log('❌ ПОСТЫ С ПРОБЛЕМАМИ:');
- console.log('-'.repeat(40));
- problemPosts.forEach((r, i) => {
- console.log(`\n${i+1}. ${r.title}`);
- console.log(` slug: ${r.slug}`);
- console.log(` category: ${r.category}`);
- r.problems.forEach(p => console.log(` - ${p}`));
- });
- }
-
- // Good posts
- const goodPosts = results.filter(r => r.problems.length === 0);
- if (goodPosts.length > 0) {
- console.log('\n\n✅ ПОСТЫ БЕЗ ПРОБЛЕМ:');
- console.log('-'.repeat(40));
- goodPosts.forEach(r => {
- console.log(` • ${r.title}`);
- });
- }
-
- } catch (error) {
- console.error('Ошибка:', error);
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/browser-sync.js b/frontend/scripts/browser-sync.js
deleted file mode 100644
index 66ad6ff..0000000
--- a/frontend/scripts/browser-sync.js
+++ /dev/null
@@ -1,76 +0,0 @@
-// Скрипт обновления постов на https://avt-back.ru
-// Выполни в консоли браузера (F12 → Console) на странице https://avt-back.ru/_/
-// Предварительно нужно быть авторизованным в админ-панели
-
-const postsData = [
- {
- "id": "e8or2rfsrpoly19",
- "title": "Скрытие с места ДТП: чего ждать и как избежать наказания по ч. 2 ст. 12.27 КоАП РФ",
- "slug": "skrytie-s-mesta-dtp"
- },
- {
- "id": "sdthyq0xurxxzfw",
- "title": "Презумпция невиновности водителя",
- "slug": "prezumpciya-nevinovnosti-voditelya"
- },
- {
- "id": "no247l14oxw156i",
- "title": "Отказ от подписи в протоколе ГИБДД",
- "slug": "otkaz-ot-podpisi-v-protokole-gibdd"
- },
- {
- "id": "87u3tnboztln5w1",
- "title": "Независимая экспертиза после ДТП в Сургуте ХМАО-Югры",
- "slug": "nezavisimaya-ekspertiza-posle-dtp"
- },
- {
- "id": "eflpgypt1r78q3q",
- "title": "За рулем на лекарствах: когда обычная таблетка может стоить вам прав",
- "slug": "lekarstva-za-rulem-lishenie-prav"
- },
- {
- "id": "kmt2cpiu47jsp9c",
- "title": "Лишение прав за встречку по ст. 12.15 ч. 4: как защититься",
- "slug": "lishenie-prav-za-vstrechku-12-15"
- },
- {
- "id": "at22ktwu6u1x5u1",
- "title": "Как законно приостановить составление протокола ГИБДД на дороге",
- "slug": "kak-priostanovit-protokol-gibdd"
- },
- {
- "id": "ewq7fbjbgpo12iv",
- "title": "Автоюрист в Сургуте: бесплатная юридическая консультация водителю",
- "slug": "avtoyurist-surgut-besplatnaya-konsultaciya"
- },
- {
- "id": "kqh8f6py72yemhl",
- "title": "Как правильно заполнять протокол ГИБДД: инструкция для водителя",
- "slug": "kak-pravilno-zapolnyat-admin-protokol-gibdd"
- },
- {
- "id": "656dhm888yebhc8",
- "title": "Протокол и постановление ГИБДД: отличия и что важно знать",
- "slug": "protocol-ili-postanovlenie"
- },
- {
- "id": "f54gic3amc1rmjx",
- "title": "5 ошибок водителя при заполнении административного протокола ГИБДД",
- "slug": "5-oshibok-voditelya-pri-zapolnenii-protokola-gibdd"
- }
-];
-
-console.log('🔄 Синхронизация постов');
-console.log('='.repeat(40));
-console.log('Найдено постов:', postsData.length);
-console.log('');
-console.log('Инструкция:');
-console.log('1. Этот скрипт требует данные постов с локального сервера');
-console.log('2. Локальный сервер http://127.0.0.1:8090 недоступен из браузера');
-console.log('');
-console.log('РЕШЕНИЕ:');
-console.log('- Открой файл posts-export.json в редакторе');
-console.log('- Скопируй все содержимое');
-console.log('- Вставь ниже вместо // POSTS_DATA_GOES_HERE');
-console.log('');
-console.log('ИЛИ используй Import Collections в настройках');
\ No newline at end of file
diff --git a/frontend/scripts/check-h2.ts b/frontend/scripts/check-h2.ts
deleted file mode 100644
index 58bdf9e..0000000
--- a/frontend/scripts/check-h2.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const pb = new PocketBase('http://127.0.0.1:8090');
-
-async function main() {
- const posts = await pb.collection('posts').getList(1, 500, { filter: 'slug="skrytie-s-mesta-dtp"' });
-
- if (posts.items.length > 0) {
- const content = posts.items[0].content;
- console.log('First 300 chars:');
- console.log(content.substring(0, 300));
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/check-posts.ts b/frontend/scripts/check-posts.ts
deleted file mode 100644
index aad013f..0000000
--- a/frontend/scripts/check-posts.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const PB_URL = 'http://127.0.0.1:8090';
-const pb = new PocketBase(PB_URL);
-
-async function main() {
- const posts = await pb.collection('posts').getList(1, 3);
-
- for (const post of posts.items as any) {
- console.log('=== SLUG:', post.slug, '===');
- console.log(post.content?.substring(0, 1500));
- console.log('\n---\n');
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/debug-post.ts b/frontend/scripts/debug-post.ts
deleted file mode 100644
index 5582d01..0000000
--- a/frontend/scripts/debug-post.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const REMOTE_PB_URL = 'https://avt-back.ru';
-const remotePb = new PocketBase(REMOTE_PB_URL);
-
-// Try to get an auth token
-async function main() {
- console.log('Testing auth...\n');
-
- // Try user auth
- try {
- await remotePb.collection('users').authWithPassword('redibedi2019@gmail.com', 'Stalin4444');
- console.log('User auth: Success');
- console.log('Token:', remotePb.authStore.token?.substring(0, 20) + '...');
- } catch (e: any) {
- console.log('User auth failed:', e.message);
- }
-
- // Check auth state
- console.log('\nAuth state:');
- console.log(' isValid:', remotePb.authStore.isValid);
- console.log(' token exists:', !!remotePb.authStore.token);
-
- if (remotePb.authStore.isValid) {
- // Try update now
- try {
- await remotePb.collection('posts').update('e8or2rfsrpoly19', {
- description: 'Test update'
- });
- console.log('\nUpdate after auth: Success!');
- } catch (e: any) {
- console.log('\nUpdate after auth:', e.message);
- }
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/export-posts.ts b/frontend/scripts/export-posts.ts
deleted file mode 100644
index e40ea5b..0000000
--- a/frontend/scripts/export-posts.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import PocketBase from 'pocketbase';
-import fs from 'fs';
-
-const PB_URL = 'http://127.0.0.1:8090';
-const pb = new PocketBase(PB_URL);
-
-async function exportPosts() {
- console.log('📤 Экспорт постов в JSON\n');
-
- const posts = await pb.collection('posts').getList(1, 500);
-
- const exportData = posts.items.map(post => ({
- id: post.id,
- title: post.title,
- slug: post.slug,
- content: post.content,
- description: post.description,
- category: post.category,
- categoryColor: post.categoryColor,
- image: post.image,
- date: post.date,
- author: post.author,
- readTime: post.readTime,
- views: post.views,
- draft: post.draft,
- }));
-
- fs.writeFileSync('./posts-export.json', JSON.stringify(exportData, null, 2), 'utf-8');
-
- console.log(`Экспортировано ${exportData.length} постов в posts-export.json`);
- console.log('\nТеперь нужно импортировать через админ-панель: https://avt-back.ru/_/');
-}
-
-exportPosts();
\ No newline at end of file
diff --git a/frontend/scripts/fix-h2.ts b/frontend/scripts/fix-h2.ts
deleted file mode 100644
index ba23f0c..0000000
--- a/frontend/scripts/fix-h2.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const PB_URL = 'http://127.0.0.1:8090';
-const pb = new PocketBase(PB_URL);
-
-const SLUG_TO_NEW_TITLE: Record = {
- 'skrytie-s-mesta-dtp': 'Скрытие с места ДТП: суть статьи',
- 'prezumpciya-nevinovnosti-voditelya': 'Презумпция невиновности водителя',
- 'otkaz-ot-podpisi-v-protokole-gibdd': 'Отказ от подписи в протоколе ГИБДД',
- 'nezavisimaya-ekspertiza-posle-dtp': 'Независимая экспертиза после ДТП',
- 'lekarstva-za-rulem-lishenie-prav': 'Лишение прав за лекарства',
- 'lishenie-prav-za-vstrechku-12-15': 'Лишение прав за выезд на встречную',
- 'kak-priostanovit-protokol-gibdd': 'Как приостановить протокол ГИБДД',
- 'avtoyurist-surgut-besplatnaya-konsultaciya': 'Юридическая консультация автоюриста',
- 'kak-pravilno-zapolnyat-admin-protokol-gibdd': 'Как заполнять протокол ГИБДД',
- 'protocol-ili-postanovlenie': 'Протокол и постановление ГИБДД',
- '5-oshibok-voditelya-pri-zapolnenii-protokola-gibdd': '5 ошибок при заполнении протокола',
-};
-
-async function main() {
- const posts = await pb.collection('posts').getList(1, 500);
-
- for (const post of posts.items) {
- const newTitle = SLUG_TO_NEW_TITLE[post.slug as string];
- if (!newTitle) continue;
-
- let content = post.content as string;
-
- // Заменяем старый H2 на новый
- if (content.includes('')) {
- content = content.replace(/[^<]+<\/h2>/, `${newTitle}
`);
- }
-
- await pb.collection('posts').update(post.id, { content });
- console.log(`✓ ${post.slug}: ${newTitle}`);
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/fix-year.ts b/frontend/scripts/fix-year.ts
deleted file mode 100644
index 1505152..0000000
--- a/frontend/scripts/fix-year.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const PB_URL = 'http://127.0.0.1:8090';
-const pb = new PocketBase(PB_URL);
-
-async function main() {
- const posts = await pb.collection('posts').getList(1, 500);
-
- let count = 0;
- for (const post of posts.items) {
- let content = post.content as string;
-
- // Заменяем 2025 на 2026
- if (content.includes('2025')) {
- content = content.replace(/2025/g, '2026');
- await pb.collection('posts').update(post.id, { content });
- console.log(`✓ ${post.slug}: 2025 → 2026`);
- count++;
- }
- }
-
- console.log(`\nОбновлено постов: ${count}`);
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/restore.ts b/frontend/scripts/restore.ts
deleted file mode 100644
index 1d7b889..0000000
--- a/frontend/scripts/restore.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const pb = new PocketBase('http://127.0.0.1:8090');
-
-const content = `Скрытие с места ДТП: чего ждать и как избежать наказания
-
Оставление места ДТП — одно из самых строгих нарушений для водителя. В 2026 году суд Сургута вернул водительские права в 73% дел по ч. 2 ст. 12.27 КоАП РФ[^1]. Это значит, шансы на защиту есть, но действовать нужно грамотно.
-Наказание по ч. 2 ст. 12.27 КоАП РФ
-Лишение права управления транспортными средствами — от 1 года до 1,5 лет. Это основное наказание, которое назначают в 90% случаев. Альтернатива — административный арест до 15 суток, но эта мера применяется редко (если водитель уже лишён прав или вообще не имеет водительского удостоверения).
-Важно: Штраф за скрытие с места ДТП не предусмотрен. Откупиться деньгами на законных основаниях невозможно.
-Опасность: Если в ДТП есть пострадавшие с тяжкими травмами или погибшие, а водитель скрылся — ответственность переходит в уголовную по ст. 264 УК РФ. Там предусмотрены реальные сроки лишения свободы.
-Что юридически считается ДТП и скрытием
-ДТП — это событие в процессе движения транспортного средства, при котором погибли или ранены люди, повреждены автомобили, сооружения, грузы или причинён иной материальный ущерб.
-Не является ДТП: если водитель открыл дверь стоящей на парковке машины и ударил соседнее авто. Движения транспорта не было, поэтому ст. 12.27 КоАП РФ не применяется.
-Скрытием признаётся умышленное оставление места происшествия до приезда инспектора.
-Когда можно уехать законно
-ПДД предусматривают пять исключений:
-
-- Европротокол — без пострадавших, оба с ОСАГО[^2]
-- Поездка в ГИБДД — для оформления
-- Освобождение проезда — после фотофиксации
-- Спасение пострадавшего — с возвратом на место
-- Обоюдное согласие — с распиской
-
-⚠️ Без доказательств (видео, расписки) — не уезжайте.
-Срок давности
-3 месяца с момента аварии[^3]. Если прошло больше — дело обязаны прекратить.
-Что делать, если обвиняют
-Пошаговый план:
-
-- Не молчите — не игнорируйте звонки из полиции
-- Доказывайте отсутствие умысла — плохая видимость, шум, не почувствовали удар
-- Примиритесь с потерпевшим — возместите ущерб и возьмите расписку
-- Найдите автоюриста — желательно того, кто выигрывает дела по 12.27
-
-📊 В 2026 году суд вернул права в 73% дел. Шансы есть даже в «безнадёжных» ситуациях.
-Вывод
-Если услышали подозрительный звук на парковке — остановитесь и проверьте. Лучше 30 минут поискать владельца царапины, чем 1,5 года ходить пешком.
-[^1]: Статистика судебных решений по Сургуту за 2026 год
-[^2]: Федеральный закон № 40-ФЗ "Об ОСАГО"
-[^3]: Статья 4.5 КоАП РФ о сроках давности`;
-
-async function main() {
- const posts = await pb.collection('posts').getList(1, 500, { filter: 'slug="skrytie-s-mesta-dtp"' });
-
- if (posts.items.length > 0) {
- await pb.collection('posts').update(posts.items[0].id, {
- content: content,
- description: content.replace(/<[^>]+>/g, '').substring(0, 200)
- });
- console.log('✓ восстановлено');
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/sync-posts.ts b/frontend/scripts/sync-posts.ts
deleted file mode 100644
index b7112bf..0000000
--- a/frontend/scripts/sync-posts.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const LOCAL_PB_URL = 'http://127.0.0.1:8090';
-const REMOTE_PB_URL = 'https://avt-back.ru';
-const ADMIN_EMAIL = 'redibedi2019@gmail.com';
-const ADMIN_PASSWORD = 'Stalin4444';
-
-const localPb = new PocketBase(LOCAL_PB_URL);
-const remotePb = new PocketBase(REMOTE_PB_URL);
-
-interface Post {
- id: string;
- title: string;
- content: string;
- slug: string;
- description: string;
-}
-
-const REMOTE_IDS: Record = {
- 'skrytie-s-mesta-dtp': 'e8or2rfsrpoly19',
- 'prezumpciya-nevinovnosti-voditelya': 'sdthyq0xurxxzfw',
- 'otkaz-ot-podpisi-v-protokole-gibdd': 'no247l14oxw156i',
- 'lekarstva-za-rulem-lishenie-prav': 'eflpgypt1r78q3q',
- 'lishenie-prav-za-vstrechku-12-15': 'kmt2cpiu47jsp9c',
- 'nezavisimaya-ekspertiza-posle-dtp': '87u3tnboztln5w1',
- 'kak-priostanovit-protokol-gibdd': 'at22ktwu6u1x5u1',
- 'avtoyurist-surgut-besplatnaya-konsultaciya': 'ewq7fbjbgpo12iv',
- 'kak-pravilno-zapolnyat-admin-protokol-gibdd': 'kqh8f6py72yemhl',
- 'protocol-ili-postanovlenie': '656dhm888yebhc8',
- '5-oshibok-voditelya-pri-zapolnenii-protokola-gibdd': 'f54gic3amc1rmjx',
-};
-
-async function syncPosts() {
- console.log('🔄 Синхронизация постов\n');
- console.log('='.repeat(60));
-
- // Try to auth as user on remote
- try {
- await remotePb.collection('users').authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD);
- console.log('✓ Авторизован на remote\n');
- } catch (error: any) {
- console.log('⚠ Ошибка авторизации:', error.message);
- console.log('Пробуем через admins auth...\n');
-
- try {
- await remotePb.admins.authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD);
- console.log('✓ Авторизован через admin\n');
- } catch (e2: any) {
- console.log('⚠ Admin auth тоже не работает:', e2.message);
- }
- }
-
- const localPosts = await localPb.collection('posts').getList(1, 500);
- const localList = localPosts.items as unknown as Post[];
-
- console.log(`Локально постов: ${localList.length}`);
- console.log(`Авторизован: ${remotePb.authStore.isValid}\n`);
-
- let synced = 0;
- let failed = 0;
-
- for (const post of localList) {
- const remoteId = REMOTE_IDS[post.slug];
-
- if (!remoteId) {
- failed++;
- continue;
- }
-
- try {
- await remotePb.collection('posts').update(remoteId, {
- content: post.content,
- description: post.description,
- });
-
- console.log(`✓ ${post.slug}`);
- synced++;
- } catch (error: any) {
- console.error(`✗ ${post.slug}: ${error.message}`);
- failed++;
- }
- }
-
- console.log('\n' + '='.repeat(60));
- console.log(`Результат: синхронизировано ${synced}, ошибок ${failed}`);
-}
-
-syncPosts();
\ No newline at end of file
diff --git a/frontend/scripts/test-login.ts b/frontend/scripts/test-login.ts
deleted file mode 100644
index 51e7392..0000000
--- a/frontend/scripts/test-login.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import PocketBase from 'pocketbase';
-
-const pb = new PocketBase('https://avt-back.ru');
-
-async function main() {
- console.log('Проверяем коллекции на production:\n');
-
- try {
- // Попробуем разные способы
- const result = await pb.collections.getFullList();
- console.log('Коллекции:', result.map(c => c.name).join(', '));
- } catch (e: any) {
- console.log('Ошибка:', e.message);
- }
-}
-
-main();
\ No newline at end of file
diff --git a/frontend/scripts/test-votes.ts b/frontend/scripts/test-votes.ts
deleted file mode 100644
index e6e2cd0..0000000
--- a/frontend/scripts/test-votes.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-// Тест голосования
-import PocketBase from 'pocketbase';
-
-const PB_URL = process.env.POCKETBASE_URL || 'http://127.0.0.1:8090';
-
-// Симулируем токен пользователя (нужно получить реальный)
-const testToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb2xsZWN0aW9uSWQiOiJfcGJfdXNlcnNfYXV0aF8iLCJleHAiOjE3NzY5NTI4NjUsImlkIjoidGR0Z2JuNGFrb3BsZGhvIiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.A1oacYog9de5GjZj5aNkHeRDWyjQKXvTSkEBFr4hi9Q';
-
-async function testVoting() {
- const pb = new PocketBase(PB_URL);
-
- // Симулируем авторизацию
- pb.authStore.save(testToken, { id: 'tdtgbn4akopldho', email: 'redibedi2019@gmail.com' });
-
- console.log('Auth valid:', pb.authStore.isValid);
- console.log('User ID:', pb.authStore.model?.id);
-
- // Тест: получить голоса поста
- try {
- const postId = 'test-post-id';
- const votes = await pb.collection('post_votes').getList(1, 1000, {
- filter: `post_id="${postId}"`,
- });
-
- console.log('\n--- Тест получения голосов ---');
- console.log('Всего голосов:', votes.totalItems);
-
- const likes = votes.items.filter(v => v.vote_type === 'like').length;
- const dislikes = votes.items.filter(v => v.vote_type === 'dislike').length;
- console.log('Likes:', likes);
- console.log('Dislikes:', dislikes);
- } catch (e) {
- console.error('Ошибка:', e);
- }
-
- // Тест: создать голос
- try {
- console.log('\n--- Тест создания голоса ---');
- const newVote = await pb.collection('post_votes').create({
- post_id: 'test-post-123',
- user_id: 'tdtgbn4akopldho',
- vote_type: 'like',
- });
- console.log('Создан голос:', newVote.id);
-
- // Удаляем тестовый голос
- await pb.collection('post_votes').delete(newVote.id);
- console.log('Удален тестовый голос');
- } catch (e) {
- console.error('Ошибка создания:', e);
- }
-}
-
-testVoting();
\ No newline at end of file