# Norda Biznes Hub - Instrukcje dla Claude ## Opis projektu Platforma katalogowa i networkingowa dla członków stowarzyszenia Norda Biznes z Wejherowa. - **Produkcja:** https://nordabiznes.pl - **Status:** LIVE (od 2025-11-23) - **Firmy:** 80 członków Norda Biznes (100% pokrycia) ## Struktura projektu ``` nordabiz/ ├── app.py # Główna aplikacja Flask (routes, auth, API) ├── database.py # Modele SQLAlchemy (Company, User, Chat) ├── gemini_service.py # Integracja Google Gemini AI ├── nordabiz_chat.py # Silnik chatu AI z kontekstem firm ├── search_service.py # Unified SearchService (synonimy, FTS, fuzzy) ├── templates/ # Szablony Jinja2 ├── static/ # CSS, JS, obrazy ├── database/ # Schematy SQL, migracje ├── data/ # Dane źródłowe JSON ├── tests/ # Testy jakości AI │ ├── ai_quality_evaluator.py │ ├── ai_quality_test_cases.json │ └── results/ # Wyniki testów (JSON) └── scripts/ # Narzędzia Node.js ``` ## Technologie | Warstwa | Technologia | |---------|-------------| | Backend | Flask 3.0, SQLAlchemy 2.0, Python 3.9+ | | Frontend | HTML5, CSS3, Vanilla JS, Jinja2 | | Baza danych | PostgreSQL (prod), SQLite (dev) | | AI | Google Gemini 2.0 Flash (free tier, 200 req/dzień) | | Security | Flask-Login, Flask-WTF (CSRF), Flask-Limiter | ## Środowiska ### Development (lokalne) - **Baza:** `nordabiz_local.db` (SQLite) - **Port:** 5000 lub 5001 - **Uruchomienie:** `python3 app.py` ### Production - **Serwer:** NORDABIZ-01 (VM 249, IP 10.22.68.249) - **Baza:** PostgreSQL na 10.22.68.249:5432 - **Reverse Proxy:** NPM na R11-REVPROXY-01 (VM 119, IP 10.22.68.250) - **Domena:** nordabiznes.pl (DNS w OVH) - **SSL:** Let's Encrypt (auto-renewal) ### NPM Proxy Configuration (KRYTYCZNE!) **Proxy Host ID:** 27 **Forward Port:** 5000 (NIE 80!) ``` PRAWIDŁOWA KONFIGURACJA: NPM (10.22.68.250) → Backend (10.22.68.249:5000) ✓ BŁĘDNA KONFIGURACJA (powoduje pętlę przekierowań): NPM (10.22.68.250) → Backend (10.22.68.249:80) ✗ ``` **UWAGA:** Na serwerze 10.22.68.249 działa nginx na porcie 80 który przekierowuje na HTTPS. Flask/Gunicorn działa na porcie 5000. Przy edycji proxy hosta ZAWSZE sprawdź czy port = 5000! **Weryfikacja po zmianach NPM:** ```bash curl -I https://nordabiznes.pl/health # Oczekiwany: HTTP 200 ``` **Raport incydentu:** `docs/INCIDENT_REPORT_20260102.md` ## Konwencje danych ### Identyfikatory firm - **Slug:** kebab-case z nazwy, np. `pixlab-sp-z-o-o` - **NIP:** 10 cyfr bez myślników, np. `5882436505` - **REGON:** 9 lub 14 cyfr - **KRS:** 10 cyfr (tylko spółki) ### Kategorie firm - `IT` - IT i Technologie - `Construction` - Budownictwo - `Services` - Usługi (prawne, księgowe, doradcze) - `Production` - Produkcja - `Trade` - Handel - `Other` - Pozostałe ### Poziomy jakości danych - `basic` - Nazwa, NIP, kontakt - `enhanced` - Pełne dane, zweryfikowane - `complete` - Wzbogacone o usługi, kompetencje, certyfikaty ## Ważne zasady ### Bezpieczeństwo - NIE edytuj bezpośrednio bazy produkcyjnej PostgreSQL - Zawsze testuj zmiany na SQLite przed wdrożeniem - Klucze API i hasła tylko w `.env` (nigdy w kodzie) - Rate limiting: 200 req/dzień, 50 req/godzinę ### Import danych - Używaj skryptów `import_*.py` do dodawania firm - Weryfikuj NIP przez API przed importem - Zachowaj spójność slugów (unikalne, lowercase) ### Deployment - Przed wdrożeniem: `python -m py_compile app.py` - SSH do NORDABIZ-01: `ssh maciejpi@10.22.68.249` (ZAWSZE jako maciejpi, NIE root!) - Ścieżka aplikacji: `/var/www/nordabiznes` - Restart: `sudo systemctl restart nordabiznes` - **ZAWSZE** aktualizuj historię zmian (`release_notes` w app.py) po wdrożeniu - Historia zmian: efekt końcowy, bez powtórzeń, prostym językiem ### Szablony Jinja2 - WAŻNE! - Blok `{% block extra_js %}` w `base.html` jest już wewnątrz tagu `{% endblock %}` ### Uprawnienia PostgreSQL - Po utworzeniu nowych tabel: `GRANT ALL ON TABLE ... TO nordabiz_app` - Po utworzeniu sekwencji: `GRANT USAGE, SELECT ON SEQUENCE ... TO nordabiz_app` - Baza: `nordabiz`, użytkownik aplikacji: `nordabiz_app` ### Testowanie na produkcji - **ZAWSZE używaj konta testowego** do weryfikacji funkcjonalności - **Konto testowe:** test@nordabiznes.pl / TestNorda2024! - Konto ma uprawnienia zwykłego użytkownika (nie admin) - Używaj przeglądarki (browser automation) do testów wymagających logowania ## Skrypty danych ### Import (wykonywać kolejno) ```bash python import_norda_companies.py # Batch 1 (56 firm) python import_norda_batch2.py # Batch 2 python import_norda_batch3.py # Batch 3 python import_norda_batch4.py # Batch 4 (9 firm) python import_norda_batch5.py # Batch 5 (8 firm) ``` ### Weryfikacja ```bash python verify_all_companies_data.py # Raport jakości danych python fix_krs_verification.py # Weryfikacja KRS ``` ## API Endpoints | Endpoint | Metoda | Opis | |----------|--------|------| | `/` | GET | Katalog firm | | `/company/` | GET | Profil firmy | | `/search` | GET | Wyszukiwanie | | `/api/companies` | GET | Lista firm (JSON) | | `/api/verify-nip` | GET | Weryfikacja NIP | | `/health` | GET | Health check | | `/chat` | GET | Interfejs chatu AI | | `/admin/news` | GET/POST | Panel moderacji newsów (wymaga admin) | | `/api/notifications` | GET | Powiadomienia użytkownika (JSON) | ## SearchService (search_service.py) Unified search dla chatbota AI i wyszukiwarki `/search`. ### Funkcje: - **NIP/REGON lookup** - bezpośrednie wyszukiwanie po identyfikatorach - **Synonym expansion** - rozszerzenie słów kluczowych (np. "strony" → www, web, portal) - **PostgreSQL FTS** - full-text search z tsvector (produkcja) - **SQLite fallback** - keyword scoring (development) - **Fuzzy matching** - pg_trgm dla literówek (gdy dostępne) ### Scoring: - Nazwa firmy: +10 punktów - Opis: +5 punktów - Usługi: +8 punktów - Kompetencje: +7 punktów - Miasto: +3 punktów ### Użycie: ```python from search_service import search_companies results = search_companies(db, "strony www", limit=10) # Zwraca List[SearchResult] z company, score, match_type ``` ### UWAGA (PostgreSQL): - Gdy FTS się nie powiedzie, wykonywany jest `db.rollback()` przed fallbackiem - Bez tego następuje błąd `InFailedSqlTransaction` ## Chatbot AI (nordabiz_chat.py) ### Konfiguracja: - **Limit firm do AI:** 8 (zmienne w `_build_conversation_context`, linia ~312) - **Historia wiadomości:** 10 ostatnich - **Search:** używa `search_companies()` z SearchService ## Testy jakości AI ### Uruchomienie: ```bash python run_ai_quality_tests.py -v # Verbose output python run_ai_quality_tests.py -v -s # Verbose + save report python run_ai_quality_tests.py -q # Quick (tylko high-priority) ``` ### Przypadki testowe (`tests/ai_quality_test_cases.json`): - 15 przypadków w 8 kategoriach - Próg zaliczenia: 70% - Kategorie: IT/Web, Services/Legal, Services/Accounting, Production/Metal, Construction, HVAC, Energy/Renewable, IT/Security ## Powiązane zasoby - **Źródło danych:** https://norda-biznes.info/czlonkowie - **Monitoring:** Zabbix (do konfiguracji) - **Backup:** Proxmox Backup Server (VM snapshots) - **DNS wewnętrzny:** nordabiznes.inpi.local ## Kontakty - **Projekt:** Norda Biznes Hub - **Infrastruktura:** INPI (skills: proxmox-manager, dns-manager, npm-manager) ## Szablon profilu firmy (company profile) ### Zatwierdzone zmiany do wdrożenia Sekcje do **połączenia** (redukcja duplikatów): 1. **"O firmie" + "Profil działalności"** → jedna sekcja "O firmie" 2. **"Oferta i usługi" + "Słowa kluczowe"** → jedna sekcja "Usługi i kompetencje" 3. **"Wyróżniki" + "Wartości firmy"** → jedna sekcja "Wyróżniki" 4. **Blok "Jakość Danych"** → usunąć (badge przy nazwie wystarczy) ### Sekcje które MUSZĄ pozostać - **Social Media (6 kafelków)** - pokazywać WSZYSTKIE platformy, także te bez profilu ("Brak profilu") - ważne by widzieć czego brakuje - **Dane kontaktowe (sekcja z kartami)** - to docelowe miejsce na WSZYSTKIE dane kontaktowe firmy (adres, telefony, emaile, godziny otwarcia, itp.) ### Docelowa struktura profilu (po optymalizacji) ``` 1. Header (nazwa, kategoria, badge weryfikacji, krótki opis) 2. Pasek kontaktowy (www, email, telefon, lokalizacja) - szybki dostęp 3. O firmie (połączone opisy) 4. Usługi i kompetencje (połączone tagi) 5. Wyróżniki (połączone z wartościami) 6. Dane kontaktowe (pełne karty - główne miejsce na kontakt) 7. Informacje prawne i biznesowe (NIP, REGON, KRS, rok założenia) 8. Social Media (wszystkie 6 platform - widoczne braki) 9. Strona WWW (analiza techniczna) - zawsze na końcu ``` ### Szablon: templates/company_detail.html Plik do modyfikacji przy implementacji zmian. ## Plan rozwoju - Aktualności ### Priorytet 1: Social Media Integration **Status:** Do wdrożenia **Źródła danych:** - Facebook Pages firm członkowskich (posty, wydarzenia) - LinkedIn Company Pages - Google My Business (recenzje, posty) **Wymagania techniczne:** - Facebook Graph API (wymaga App Review dla pages_read_engagement) - LinkedIn Marketing API (wymaga partnera lub OAuth) - Google Business Profile API **Typy zdarzeń do importu:** - `social_post` - posty z social media - `social_event` - wydarzenia z Facebooka - `review` - nowe recenzje Google ### Priorytet 2: News Monitoring (Google/Brave API) **Status:** Wdrożone (2025-12-29) **Źródła danych:** - Wzmianki o firmach w mediach lokalnych/branżowych - Artykuły prasowe - Komunikaty branżowe **Wymagania techniczne:** - Brave Search API (bezpłatny tier) LUB - Google Custom Search API ($5/1000 queries) - Cykliczne wyszukiwanie nazw firm **Typy zdarzeń do importu:** - `news_mention` - wzmianka w mediach - `press_release` - komunikat prasowy - `award` - nagroda/wyróżnienie ### Priorytet 3: Zarząd i Wspólnicy (rejestr.io) **Status:** Planowane **Cel:** Wyświetlanie osób powiązanych z firmą bezpośrednio na stronie profilu **Dane do pobrania z rejestr.io:** - Zarząd (Prezes, Wiceprezes, Członkowie Zarządu) - Prokurenci - Wspólnicy z % udziałów - Beneficjenci rzeczywiści - Linki do profili osób (powiązania z innymi firmami) **Wymagania techniczne:** - Tabela `company_people` (company_id, name, role, shares_percent, person_url) - Scraper Playwright (już mamy bazę w `analyze_connections.py`) - Sekcja w `company_detail.html` po "Informacje prawne i biznesowe" **Przykład wyświetlania:** ``` 👥 ZARZĄD I WSPÓLNICY ┌─────────────────────────────────────────┐ │ 👔 Jan Kowalski - Prezes Zarządu │ │ 👔 Anna Nowak - Członek Zarządu │ │ 💼 Firma XYZ Sp. z o.o. - 60% udziałów │ │ 💼 Jan Kowalski - 40% udziałów │ └─────────────────────────────────────────┘ ``` **Korzyści:** - Widoczne powiązania między firmami Norda Biznes - Ułatwiony networking (kto zna kogo) - Transparentność struktury właścicielskiej ### Notatki implementacyjne - Scraper powinien deduplikować wydarzenia (hash tytułu + daty) - Moderacja: nowe wydarzenia jako "pending" do zatwierdzenia przez admina - Rate limiting: max 100 requestów/dzień do zewnętrznych API ## News Monitoring ### Opis funkcjonalności System automatycznego monitoringu wzmianek o firmach Norda Biznes w mediach lokalnych i branżowych. ### Tabela w bazie danych ```sql company_news ( id SERIAL PRIMARY KEY, company_id INTEGER REFERENCES companies(id), title VARCHAR(500) NOT NULL, description TEXT, url VARCHAR(1000) NOT NULL, source VARCHAR(200), -- nazwa portalu/medium published_at TIMESTAMP, news_type VARCHAR(50), -- news_mention, press_release, award relevance_score FLOAT, -- 0.0-1.0 (AI scoring) status VARCHAR(20) DEFAULT 'pending', -- pending, approved, rejected moderated_by INTEGER, -- user_id admina moderated_at TIMESTAMP, rejection_reason TEXT, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(company_id, url) ) ``` **Statusy newsów:** - `pending` - oczekuje na moderację - `approved` - zatwierdzony, widoczny na profilu firmy - `rejected` - odrzucony (spam, nieistotny, duplikat) ### Brave Search API Integration **Konfiguracja:** - API Key w `.env`: `BRAVE_SEARCH_API_KEY` - Endpoint: `https://api.search.brave.com/res/v1/news/search` - Limit: 2000 req/miesiąc (free tier) **Parametry wyszukiwania:** ```python params = { "q": f'"{company_name}" OR "{nip}"', "count": 10, "freshness": "pw", # past week "country": "pl", "search_lang": "pl" } ``` **Skrypt pobierania:** ```bash cd /var/www/nordabiznes sudo -u www-data /var/www/nordabiznes/venv/bin/python3 fetch_company_news.py ``` ### AI Filtering (Gemini) Filtracja wyników przez Google Gemini: - Ocena relevance_score (0.0-1.0) - Kategoryzacja news_type - Wykrywanie duplikatów/spamu - Automatyczne odrzucanie wyników < 0.3 relevance **Prompt systemu:** ``` Oceń czy artykuł dotyczy działalności firmy {company_name}. Zwróć JSON: {"relevance": 0.0-1.0, "type": "news_mention|press_release|award", "reason": "..."} ``` ### Panel admina /admin/news **URL:** `/admin/news` **Wymaga:** Zalogowany użytkownik z `is_admin=True` **Funkcje:** - Lista newsów pending do moderacji - Filtrowanie po firmie, statusie, dacie - Zatwierdzanie/odrzucanie z powodem - Podgląd oryginalnego artykułu - Bulk actions (zatwierdź wszystkie z relevance > 0.8) ### Sekcja Aktualności na profilu firmy **Lokalizacja:** `templates/company_detail.html` **Warunek:** Tylko newsy ze statusem `approved` **Sortowanie:** Po `published_at` DESC **Limit:** 5 ostatnich newsów **Struktura wyświetlania:** ``` AKTUALNOŚCI ├── [data] Tytuł artykułu (źródło) │ Krótki opis... │ [Czytaj więcej →] └── [data] Kolejny artykuł... ``` ### System powiadomień **Endpoint:** `/api/notifications` **Zwraca:** JSON z listą powiadomień użytkownika **Typy powiadomień:** - `new_news` - nowy news o obserwowanej firmie (dla zalogowanych) - `news_approved` - news firmy użytkownika został zatwierdzony - `news_rejected` - news firmy użytkownika został odrzucony **Struktura odpowiedzi:** ```json { "notifications": [ { "id": 1, "type": "new_news", "message": "Nowa wzmianka o PIXLAB", "url": "/company/pixlab-sp-z-o-o#news", "created_at": "2025-12-29T10:30:00", "read": false } ], "unread_count": 3 } ``` ### Skrypty i cron ```bash # Jednorazowe pobranie newsów dla wszystkich firm python fetch_company_news.py --all # Pobranie dla konkretnej firmy python fetch_company_news.py --company pixlab-sp-z-o-o # Cron job (co 6 godzin) 0 */6 * * * cd /var/www/nordabiznes && /var/www/nordabiznes/venv/bin/python3 fetch_company_news.py --all >> /var/log/nordabiznes/news_fetch.log 2>&1 ``` ## Social Media - Stan aktualny ### Statystyki (2025-12-29) | Platforma | Liczba firm | Pokrycie | |-----------|-------------|----------| | Facebook | 39 | 49% | | Instagram | 26 | 33% | | LinkedIn | 22 | 28% | | YouTube | 17 | 21% | | Twitter/X | 7 | 9% | | TikTok | 4 | 5% | **Łącznie:** 115 profili dla 53 firm (66% pokrycia) **Firmy bez Social Media:** 27 ### Tabela w bazie danych ```sql company_social_media ( id, company_id, platform, url, verified_at, source, is_valid, last_checked_at, check_status, page_name, followers_count, created_at, updated_at ) ``` **Platformy:** facebook, instagram, youtube, linkedin, tiktok, twitter ### Skrypty aktualizacji ```bash # Aktualizacja Social Media z pliku JSON cd /var/www/nordabiznes sudo -u www-data /var/www/nordabiznes/venv/bin/python3 update_social_media.py --dry-run # Test sudo -u www-data /var/www/nordabiznes/venv/bin/python3 update_social_media.py # Produkcja ``` **Pliki:** - `social_media_found.json` - wyniki wyszukiwania (źródło danych) - `update_social_media.py` - skrypt aktualizujący bazę ### Firmy z najlepszym pokryciem Social Media 1. **PORTA KMI** - Facebook, Instagram, YouTube, LinkedIn (4 platformy, 124K FB fans) 2. **Rumia Invest Park** - Facebook, Instagram, YouTube, LinkedIn, Twitter (5 platform) 3. **GRAAL** - Facebook, Instagram, YouTube, LinkedIn (4 platformy) 4. **Chopin Telewizja Kablowa** - Facebook, Instagram, YouTube, Twitter (4 platformy) 5. **Hotel SPA Wieniawa** - Facebook, Instagram, YouTube, TikTok (4 platformy) ### Firmy bez Social Media (do uzupełnienia) SIM Rumia, Rubinsolar, KORNIX, KBMS, Semerling Security, ARD Invest, AMA, Jubiler Agat, P&P, Progress Optima, Ampery, Bibrokers, CoolAir, Joker, KAMMET, Alumech, Litwic&Litwic, Orlex MG, Pro-Invest, Round Two, SCROL, ALMARES, Pucka Gospodarka Komunalna, Hebel Masiak, Lenap Hale, MKonsult, Portal ## Planowane funkcjonalności (Backlog) ### Priorytet 4: System rekomendacji i zdjęć **Status:** Planowane **Cel:** Umożliwienie firmom członkowskim wzajemnego polecania się oraz prezentacji zdjęć **Funkcje:** - Rekomendacje między firmami (kto poleca kogo) - Galeria zdjęć firmy (realizacje, zespół, biuro) - Wyświetlanie na profilu firmy ### Priorytet 5: Status członkostwa i płatności **Status:** Planowane **Cel:** Śledzenie statusu członkostwa i składek miesięcznych **Funkcje:** - Status członka (aktywny, zawieszony, były członek) - Informacja o opłaconych składkach - Historia płatności - Przypomnienia o zaległościach (dla admina) **Tabela `membership_fees`:** ```sql membership_fees ( id SERIAL PRIMARY KEY, company_id INTEGER REFERENCES companies(id), period_start DATE NOT NULL, -- początek okresu (np. 2026-01-01) period_end DATE NOT NULL, -- koniec okresu (np. 2026-01-31) amount DECIMAL(10,2) NOT NULL, -- kwota składki status VARCHAR(20) DEFAULT 'pending', -- pending, paid, overdue paid_at TIMESTAMP, payment_method VARCHAR(50), -- przelew, gotówka notes TEXT, created_at TIMESTAMP DEFAULT NOW() ) ``` ## Forma prawna Norda Biznes ### Stan obecny - **Forma:** OPP (Organizacja Pożytku Publicznego) - **Typ:** Stowarzyszenie non-profit ### Planowana transformacja - **Docelowa forma:** Działalność gospodarcza (przy Izbie) - **Cel:** Możliwość pozyskiwania dofinansowań (granty, projekty UE) - **Korzyści:** - Dostęp do funduszy na rozwój platformy - Możliwość świadczenia płatnych usług - Elastyczność finansowa