Add database migration to support opening hours and photos fields.
Update GBP audit service to properly fetch and validate these fields
from Google Business Profile API. Add comprehensive test coverage.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Verified production health endpoint is running
- Confirmed code implementation is correct:
- gbp_audit_service.py uses google_opening_hours for hours field
- gbp_audit_service.py uses google_photos_count for photos field
- gbp_audit_service.py uses google_rating/google_reviews_count for reviews
- Manual browser verification required (page requires authentication)
- Instructions documented in build-progress.txt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migration code complete:
- database/migrations/add_gbp_hours_photos_columns.sql
- run_migration.py helper script
SSH access to production (10.22.68.249) is blocked from sandbox.
User must run the documented command to complete migration.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added a Python migration script that can be run on the production server
to add the google_opening_hours and google_photos_count columns.
Script connects to localhost (127.0.0.1) as required by PostgreSQL config.
Usage on production server:
cd /var/www/nordabiznes && python3 run_migration.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created tests/test_gbp_audit_field_checks.py with comprehensive tests
- Tests verify _check_hours() correctly uses google_opening_hours field
- Tests verify _check_photos() correctly uses google_photos_count field
- Tests cover edge cases: null values, missing analysis, partial data
- All field check logic validated: complete/partial/missing status
- Field weights verified: hours=8, photos=15, total=100
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>
Add database migration script to add google_opening_hours (JSONB) and
google_photos_count (INTEGER) columns to company_website_analysis table.
These columns are needed for storing GBP data from Google Places API:
- google_opening_hours: stores weekday_text, open_now, and periods data
- google_photos_count: stores count of photos from Google Business profile
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed _check_photos method to read from analysis.google_photos_count
instead of total_images. This provides actual GBP photo count rather
than estimated website images.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed _check_hours() in GBP Audit Service to read opening hours from
google_opening_hours field instead of google_business_status. The method
now properly returns the actual hours value when available.
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>
Added 'photos' field to the fields list in get_place_details() method
to enable fetching business photos from Google Places API.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added google_opening_hours Column(JSONB) for storing GBP opening hours
- Added google_photos_count Column(Integer) for storing GBP photos count
- Both columns added to GOOGLE BUSINESS section alongside existing google_* columns
BLOCKED: Cannot verify - dependencies not met:
- Local SQLite database empty (no tables initialized)
- Google Places API not enabled for current API key
- Previous subtask (4-2) was blocked, no audit ran
Documented blockers and options to unblock in build-progress.txt.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add --company-slug argument to social_media_audit.py for easier testing
- Add get_company_id_by_slug() method to SocialMediaAuditor class
- Add python-dotenv support to load .env file from project root
- Create verify_google_places.py script for direct API testing
Note: Full verification blocked - current API key (PageSpeed) doesn't have
Places API enabled. Requires enabling Places API in Google Cloud Console
for project NORDABIZNES (gen-lang-client-0540794446).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixed bug in social media exclusion logic that was too aggressive.
The substring check `any(ex in match.lower() for ex in excludes)`
was incorrectly excluding valid usernames containing exclusion
strings (e.g., 'testcompany' was excluded because it contained 'p').
Changed to exact match only to properly handle Instagram post URLs
(`instagram.com/p/...`) without false positives on valid usernames.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added test for search_google_reviews method to handle API errors gracefully.
The test mocks GooglePlacesSearcher to simulate a RequestException during
get_place_details and verifies that the method returns None values instead
of crashing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added test_search_google_reviews test in TestBraveSearcherGoogleReviews class
that verifies successful Google reviews retrieval via Google Places API:
- Mocks complete place lookup with realistic place_id
- Mocks full place details response including rating, reviews count,
opening hours, and business status
- Verifies all expected fields are correctly returned
- Validates correct API calls are made with expected parameters
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive unit tests for social_media_audit.py:
- WebsiteAuditor tests: SSL checks, hosting detection, HTML parsing, social media extraction
- GooglePlacesSearcher tests: find_place, get_place_details, API error handling
- BraveSearcher tests: Google reviews search, fallback mechanisms
- SocialMediaAuditor tests: company auditing, result saving, integration tests
- Pattern tests: hosting providers, social media URL patterns, exclusion rules
Tests follow the same structure and patterns as test_seo_audit.py.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add google_places_searcher attribute to SocialMediaAuditor
- Initialize GooglePlacesSearcher if GOOGLE_PLACES_API_KEY env var is set
- Update audit_company() to use Places API directly when available
- Fallback to Brave Search when API key not configured
- Log which data source is being used for reviews
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implemented actual Google reviews data collection in BraveSearcher class:
- Uses GooglePlacesSearcher to find company and get place details
- Returns google_rating, google_reviews_count, opening_hours, business_status
- Falls back to Brave Search API parsing when Google API key not available
- Added _search_brave_for_reviews() helper for fallback implementation
- Proper error handling and logging throughout
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements GooglePlacesSearcher class with:
- find_place() method: searches for business by name and city
using Google Places findplacefromtext API
- get_place_details() method: retrieves rating, review count,
opening hours, business status, phone, and website
Features:
- Uses GOOGLE_PLACES_API_KEY environment variable
- Comprehensive error handling (timeout, request errors)
- Polish language locale support
- Follows existing BraveSearcher class pattern
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes:
- Added GBP audit link to company profile contact bar
- Link visible to admins on all profiles
- Link visible to regular users only on their own company profile
- Styled consistently with contact bar design (Google blue)
Verified:
- Template syntax balanced (blocks, if, for)
- Route gbp_audit_dashboard exists in app.py
QA Fix Session: 1
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added AI-powered recommendation generation to GBP audit service:
- Import gemini_service module for AI integration
- generate_ai_recommendations(): Main method to generate personalized
recommendations using Gemini with proper cost tracking
- _build_ai_recommendation_prompt(): Builds context-aware prompt with
company info, audit results, and field statuses in Polish
- _parse_ai_recommendations(): Parses JSON response from Gemini with
robust error handling and fallback to static recommendations
- audit_with_ai(): Convenience method for running audit with AI
- audit_company_with_ai(): Module-level convenience function
Features:
- Recommendations are personalized to company industry/category
- Includes action_steps and expected_impact for each recommendation
- Graceful fallback to static recommendations if AI unavailable
- Cost tracking via 'gbp_audit_ai' feature tag
- Updated test runner with --ai flag for testing AI mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add user-facing GBP audit dashboard route at /audit/gbp/<company_slug>:
- Requires login (@login_required)
- Admin users can view audit for any company
- Regular users can only view audit for their own company
- Passes can_audit flag to template for run audit button visibility
- Gracefully handles missing audit data (template shows "no audit" state)
- Logs audit dashboard views for monitoring
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Creates templates/gbp_audit.html for GBP completeness audit display:
- Score circle with visual conic gradient showing completion percentage
- Field status cards (10 fields) with icons, badges, and progress bars
- Recommendations list sorted by priority (high/medium/low)
- Breadcrumb navigation and responsive mobile layout
- Loading overlay and info modal for audit operations
- Polish UI text matching existing platform conventions
Template follows patterns from admin_seo_dashboard.html and integrates
with the GBP audit API endpoints created in subtask-3-1.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added GBP (Google Business Profile) audit API endpoints:
- GET /api/gbp/audit/health - Health check for GBP audit service
- GET /api/gbp/audit - Fetch latest audit results by company_id or slug
- GET /api/gbp/audit/<slug> - Fetch audit results by slug path
- POST /api/gbp/audit - Run GBP audit for a company
Features:
- Health endpoint returns service status and version
- GET endpoints return completeness score, field status, and recommendations
- POST endpoint runs audit and saves results (configurable)
- Access control: members can audit own company, admins can audit any
- Rate limited to 20 requests per hour
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create gbp_audits table with all required fields:
- completeness_score (0-100)
- fields_status and recommendations (JSONB)
- Individual field flags (has_name, has_phone, etc.)
- Photo and review metrics
- Google Place integration fields
- Audit metadata (source, version, errors)
- Add indexes for company_id, audit_date, and score
- Add update trigger for updated_at timestamp
- Create views: v_company_gbp_overview, v_gbp_audit_history
- Include GRANT statements for nordabiz_app user
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add GBPAudit SQLAlchemy model for Google Business Profile audit tracking:
- Completeness score (0-100) with score category property
- Field-by-field status tracking (JSONB)
- AI-generated recommendations storage (JSONB)
- Individual field boolean flags (name, address, phone, etc.)
- Photo/review metrics
- Google Place ID integration
- Audit metadata and timestamps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Widoczny link do Google PageSpeed Insights (Lighthouse) w nagłówku panelu.
Użytkownik/admin wie skąd pochodzą metryki.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Konfiguracja Google PageSpeed Insights API
- Metryki i interpretacja wyników
- Skrypty uruchamiania audytów
- WAŻNE: połączenie z bazą przez localhost
- Tabela seo_metrics
- UI stylizowanych modali
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Zamieniono natywne confirm/alert na ładne modale CSS
- Dodano link "Audyt SEO" w menu administracyjnym
- Modal z animacją slide-in, ikony ostrzeżenia/info
- Obsługa zamykania przez backdrop
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Problem: /admin/seo zwracał błąd 500 z AttributeError: category
Przyczyna: Company.category jest relacją SQLAlchemy (obiektem), nie stringiem.
Rozwiązanie: Użycie Category.name.label('category_name') z właściwym JOIN.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Naprawione błędy wprowadzone podczas synchronizacji:
- Przywrócono sekcję company-logo z obrazkiem w karcie firmy
- Przywrócono style CSS dla logo (100% szerokość, 80px wysokość)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Naprawione błędy wprowadzone podczas synchronizacji:
- Przywrócono sekcję company-logo-header z obrazkiem
- Przywrócono style CSS dla logo (240x240px, shadow, border-radius)
- Przywrócono przyciski Social Media (Facebook, Instagram, LinkedIn, YouTube, X, TikTok)
- Przywrócono style kolorów dla platform social media
- Naprawiono pole website_url → website
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Created comprehensive test suite for SEO admin dashboard functionality:
- tests/test_admin_seo_dashboard.py with 8 test functions
- Dashboard data query verification (SQLAlchemy joins)
- Statistics calculation (good/medium/poor/not_audited counts)
- Score color coding (green/yellow/red thresholds)
- Sorting logic (name, score, date)
- Filtering logic (category, score range, text search)
- Drill-down links validation
- API response structure verification
- Template data requirements verification
All 8 dashboard tests pass. All 64 existing SEO unit tests pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Changed PostgreSQL-specific ANY(:ids) to use IN clause with
dynamic placeholders for SQLite/PostgreSQL compatibility
- Verified SEO audit dry-run extracts all metrics correctly:
- HTTP status, load time, final URL
- Meta title, H1 count, image analysis
- Structured data detection
- robots.txt, sitemap.xml, indexability
- Overall SEO score calculation (95 for pixlab.pl)
Note: Company ID 26 has no website configured, tested with ID 1 instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>