- pytest framework with fixtures for auth (auth_client, admin_client)
- Unit tests for SearchService
- Integration tests for auth flow
- Security tests (OWASP Top 10: SQL injection, XSS, CSRF)
- Smoke tests for production health and backup monitoring
- E2E tests with Playwright (basic structure)
- DR tests for backup/restore procedures
- GitHub Actions CI/CD workflow (.github/workflows/test.yml)
- Coverage configuration (.coveragerc) with 80% minimum
- DR documentation and restore script
Staging environment: VM 248, staging.nordabiznes.pl
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Removed limits on services (was 10) and keywords (was 8)
- Added new extraction categories:
- products: physical/digital products
- brands: partners, certifications (VMware, Veeam, etc.)
- specializations: specific competencies
- target_customers: customer types (SMB, enterprise, etc.)
- regions: geographic coverage
- Merged all data into services_extracted and main_keywords
- Increased content limit to 20000 chars for AI
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New script: scripts/website_content_updater.py
- Uses Gemini 3 Flash (free tier) for AI extraction
- Extracts: services_extracted, main_keywords, content_summary
- Supports: single company, batch, stale-days filtering, dry-run
- Rate limiting: 2s between API calls
- Documented cron setup in CLAUDE.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add krs_raw_data, krs_fetched_at, krs_registration_date,
krs_representation, krs_activities columns to Company model
- Save complete KRS API response for full data access
- Display in company profile:
- Board members (zarząd) with functions and avatars
- Shareholders (wspólnicy) with share amounts
- Representation method (sposób reprezentacji)
- Business activities (PKD codes)
- Registration date with years active
- KRS address with region info
- OPP (public benefit) status
- Metadata (stan_z_dnia, data_odpisu)
- Add migration 037_krs_extended_data.sql
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add enrich_companies_from_registries() that tries KRS first for companies
with KRS number, then falls back to CEIDG
- Add update_company_from_krs() to save KRS data to Company model
- Fix CEIDG search to use 'nip' parameter directly
- Keep enrich_companies_from_ceidg() as alias for compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add new Company fields: ceidg_id, ceidg_status, pkd_codes (JSONB),
correspondence address, owner_citizenships, ceidg_raw_data
- Add enrich_companies_from_ceidg() to fetch full CEIDG details
- Add fetch_full_ceidg_details() for detailed API calls
- Add update_company_from_ceidg() to save all CEIDG fields
- Add --enrich and --apply flags for batch enrichment
- Add migration 036_ceidg_extended_data.sql
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add search_ceidg_by_name() for API v3 name-based queries
- Add search_missing_nip_companies() to find NIP for companies without NIP
- Add --missing-nip flag to search for all companies missing NIP
- Add --apply-nip flag to save found NIPs to database
- Fix API endpoint: /api/ceidg/v3/firmy (not /firma)
- Correctly extract NIP from wlasciciel object in response
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes:
- Remove position: sticky from konto sidebar (dane, prywatnosc, bezpieczenstwo, blokady)
- Add "Firmy" link to admin dropdown menu (before "Użytkownicy")
- Add scan_websites_for_nip.py script for data quality
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Zmiana nazwy: "Norda Biznes Hub" → "Norda Biznes Partner"
- Aktualizacja modelu AI: Gemini 2.0 Flash → Gemini 3 Flash
- Zachowano historyczne odniesienia w timeline i dokumentacji
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New admin page /admin/model-comparison for comparing AI responses
- Side-by-side comparison: old model (2.5 Flash-Lite) vs new (3 Flash)
- Questions from real conversations (Artur Wiertel, Maciej Pienczyn)
- Run simulation button to generate new responses
- Added link in admin menu under "Porównanie modeli"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dodanie parent_id do tabeli categories
- Model Category z relacją parent/subcategories
- 4 główne grupy: Usługi, Budownictwo, Handel, Produkcja
- Skrypt assign_category_parents.py do przypisania podkategorii
- Migracja 030_add_category_hierarchy.sql
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Landing page: przycisk "Norda Partner" + kontakt Izby (email, WhatsApp)
- Landing page: link "Strefa Gościa" → norda-biznes.info
- Menu "Więcej": dodano "Strefa Gościa (Izba)" dla zalogowanych
- Forum: ukryto filtry kategorii/statusów (uproszczenie UX)
- README: zmiana "AI Assistant" → "NordaGPT"
- Skrypt import firmy testowej "Kaszubia 2030"
- .gitignore: wykluczenie notatek ze spotkań (MEETING_*.md)
Zmiany na podstawie spotkania 2026-01-28 i uwag Artura Wiertla.
Wzór nawigacji: Vaillant.pl (Klienci indywidualni / Profesjonaliści)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Skrypt importu miał błędną godzinę 18:00. Faktyczne spotkania
"Chwila dla Biznesu" odbywają się o 19:00.
Zaktualizowano:
- Komentarz w linii 50
- Opis wydarzenia (description)
- time_start: time(19, 0)
Istniejące wydarzenia w bazie zostały zaktualizowane ręcznie (UPDATE SQL).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dodano skrypt cron do automatycznej ekstrakcji wiedzy (scripts/cron_extract_knowledge.py)
- Dodano panel deduplikacji faktów (/admin/zopk/knowledge/fact-duplicates)
- Dodano API i funkcje auto-weryfikacji encji i faktów
- Dodano panel Timeline ZOPK (/admin/zopk/timeline) z CRUD
- Rozszerzono dashboard bazy wiedzy o statystyki weryfikacji i przyciski auto-weryfikacji
- Dodano migrację 016_zopk_milestones.sql dla tabeli kamieni milowych
- Naprawiono duplikat modelu ZOPKMilestone w database.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Zmieniono 'processed' -> 'success' i 'generated' -> 'success' aby
pasowały do wartości zwracanych przez batch_extract() i
generate_chunk_embeddings().
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Uruchamia po kolei: scraping treści, ekstrakcję AI, generowanie embeddingów.
Do użycia w cron job co godzinę.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem: Newsy z Google News RSS miały source_domain='news.google.com'
i favicon Google zamiast prawdziwego źródła.
Rozwiązanie: Nowy skrypt fix_google_news_sources.py który:
- Wyciąga nazwę źródła z tytułu (po " - ")
- Mapuje 59 źródeł na ich prawdziwe domeny
- Aktualizuje source_domain i image_url (favicon)
Wynik: 143/143 newsów zaktualizowanych z poprawnymi źródłami.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Zamieniono requests.Session() na bezpośredni requests.get()
- Dodano max_depth=3 jako zabezpieczenie przed nieskończoną rekurencją
- Jawne zamykanie response.close() po każdym request
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Dodano context manager (with) dla sesji requests
- Jawne zamykanie odpowiedzi HTTP (response.close())
- Dodano flush=True do print dla natychmiastowego outputu
- Rozwiązuje problem 725+ otwartych połączeń
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Strategia pobierania obrazków:
1. Rozwiń URL Google News do oryginalnego źródła
2. Pobierz og:image z meta tagów strony
3. Fallback: logo domeny (Clearbit API)
4. Fallback: favicon (Google Favicon API)
Użycie: python scripts/fetch_news_images.py [--dry-run] [--limit N]
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Nowa kolumna member_since w tabeli companies
- Karta "Członek Izby NORDA od" na profilu firmy (niebieski kolor #3b82f6)
- Wyświetlanie liczby lat w Izbie
- Import 57 dat przystąpienia z pliku Excel od Artura
- Skrypt import_member_since.py do importu dat
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug: When page fetch fails (SSL error), result['onpage'] is None.
Using dict.get('key', {}) returns None when key exists with None value.
Fix: Use 'or {}' pattern to handle both missing keys and None values.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add person_id column to users table
- Template shows person profile link when person_id exists
- Add script to match and link users to persons by name
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add is_test field to Classified model
- Add test-item styling (opacity + gray border + badge)
- Add yellow toggle button with localStorage persistence
- Add script to mark existing classifieds as test
- Add 'test' to ForumTopic.CATEGORIES with Polish label 'Testowy'
- Add gray styling for test topics (badge + card opacity)
- Add scripts to list and mark test topics
- Add source and source_note fields to NordaEvent model
- Create import_calendar_2026.py for NORDA calendar events
- Create import_excel_members_2026_01_13.py for new members
- Add .private/ to .gitignore (confidential materials)
Imported 26 events from Kalendarz Izby NORDA 2026 (Artur Wiertel)
Imported 31 new member companies from Excel
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add normalize_social_url() function to database.py to prevent
www vs non-www duplicates in social media records
- Update update_social_media.py to normalize URLs before insert
- Update social_media_audit.py to normalize URLs before insert
- Add inline GBP Audit section to company profile
- Add inline Social Media Audit section to company profile
- Add inline IT Audit section to company profile
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add company logo display in search results cards
- Make logo clickable (links to company profile)
- Temporarily hide "Aktualności i wydarzenia" section on company profiles
- Add scripts for KRS PDF download/parsing and CEIDG API
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Created comprehensive test suite for IT audit collaboration matching:
1. Unit tests (tests/test_it_audit_collaboration.py):
- 12 tests verifying all 6 match types
- Backup replication, shared licensing, Teams federation
- Shared monitoring, collective purchasing, knowledge sharing
- Edge cases for size parsing and similarity
2. Integration test script (scripts/test_collaboration_matching.py):
- Creates test audits with matching criteria
- Runs collaboration matching algorithm
- Verifies matches saved to database
All unit tests pass (12/12).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 'channel', 'c', 'user', '@' etc. to YouTube exclusion list
- Add 'bold_themes', 'boldthemes' to Twitter/Facebook exclusions (theme creators)
- Fix pattern matching loop to stop after first valid match per platform
- Prevents fallback pattern from overwriting correct channel ID with 'channel'
Fixes issue where youtube.com/channel/ID was being overwritten with
youtube.com/channel/channel by the second fallback pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add detailed logging to SocialMediaAuditor (website scan, Brave search, results)
- Slow down progress bar animation (400ms instead of 200ms) for better readability
- Bold "ZNALEZIONO" text for found platforms
- Display Google rating and review count in progress
- Increase wait time before modal close (4 seconds)
- Add console.log for debugging audit response
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed a bug where google_opening_hours and google_photos_count were being
fetched from the Google Places API but not passed through to the result
dictionary correctly:
- Changed 'opening_hours' key to 'google_opening_hours' to match what
save_audit_result() expects
- Added 'google_photos_count' to the result dictionary
Verified with dry-run: INPI company now shows opening hours schedule
and 10 photos count from Google Business Profile.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added google_opening_hours and google_photos_count to INSERT column list
- Added corresponding placeholders to VALUES list
- Added to ON CONFLICT UPDATE SET clause
- Added to parameter dictionary reading from google_reviews result
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add google_photos_count to result dictionary initialization
- Extract photos count from API response using len(place['photos'])
- Update logging to include photos count in output
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>