- YouTubeService now fetches: subscribers, views, video count, description,
avatar, banner, country, creation date, recent 5 videos
- Enricher uses API first, falls back to scraping
- Extra YouTube data stored in content_types JSONB
- Audit detail shows view count, country, creation date, recent videos
- Requires enabling YouTube Data API v3 in Google Cloud Console
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can now select which platforms to scan (Facebook, Instagram,
LinkedIn, YouTube, Twitter/X, TikTok) via checkboxes in the
confirmation dialog. Backend filters both company list and profiles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3 attempts with 2-5s random delay between retries. Detects authwall
and rate limit (429/999) responses. Updated status message to explain
LinkedIn's inconsistent availability to users.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
og:description from LinkedIn/Facebook embeds dynamic follower counts
and varies by language, causing false "changes" on every scan.
The field is still saved to DB, just not tracked for review.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of checking profile.source (which was never 'facebook_api'),
now checks SocialMediaConfig for companies with OAuth page_id.
Added progress indicator with spinner and percentage during scan.
After API sync, page auto-refreshes to show new data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of skipping OAuth-connected Facebook profiles, the enrichment
scan now calls sync_facebook_to_social_media() to fetch fresh data
via Graph API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Events with plain text (no <p>, <br>, <div>, <ul> tags) now get
newlines converted to <p>/<br> for proper formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- /profil/<user_id>: simple profile for users without person_id,
redirects to /osoba/ if person_id exists
- event.html: all attendees are now clickable links (green)
- Auto-link User→Person by name match on every login (no manual scripts)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse HTML into tags and text nodes, only process text nodes outside
<a> tags. Uses \b word boundary instead of broken lookbehind.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Member names in event description link to person profiles
- URLs auto-linked (nordabiznes.pl, https://... etc)
- Calendar add section: blue gradient card with Google/Outlook buttons
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- POST /konto/avatar: upload, center-crop to square, resize 300x300
- POST /konto/avatar/delete: remove file and clear DB
- dane.html: interactive avatar editor with hover overlay
- person_detail.html: show photo if available, fallback to initials
- Migration 070: avatar_path column on users table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rada Izby badge next to name
- Last active label (e.g. "Aktywny 2 dni temu")
- Forum stats (topics + replies count)
- Recent events attended (up to 5, linked)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Norda Biznes logo on featured events
- Speaker name links to person profile
- Google Calendar and ICS/Outlook export buttons
- Update dev banner: official launch April 9, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Facebook, Instagram, LinkedIn block public access - messages now explain
this and suggest OAuth API connection instead of generic "no data".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all _enrichment_status in-memory dict references with
file-based shared state (/tmp/nordabiz_enrichment_state.json).
Fixes enrichment appearing instantly complete in multi-worker env.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Live panel with spinner, progress bar, company counter
- Each company appears as a row with platform badges showing status
(changes/no_changes/skipped/error/no_data)
- Incremental polling (since= param) for efficient updates
- After completion: link to review page if changes found
- Blue highlighted rows for companies with new data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Scraper now collects data to staging area (in-memory), NOT to database
- New review page (/admin/social-audit/enrichment-review) with:
- Summary stats (scanned, changes, skipped, errors)
- Per-company expandable sections with before→after diff per field
- Pending approval banner with change count
- Sticky bottom bar with Approve/Discard buttons
- Approve endpoint writes staged data to DB
- Discard endpoint clears staging without touching DB
- After scan completes, auto-redirect to review page
- Companies without changes shown in collapsed list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Scraper no longer overwrites API data (source priority hierarchy)
- Per-platform data provenance badges (API OAuth/Scraping/Manual/Unknown)
- Expandable field-level source breakdown (which fields from API vs scraping)
- OAuth status per platform with connect/renew/sync links
- "Run audit" button on dashboard (background enrichment for all companies)
- "Run audit" button on detail view (single company enrichment)
- Enrichment progress polling with real-time status updates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Social Health Score (0-100) composite: activity 30%, engagement 25%,
completeness 20%, growth 15%, cross-platform 10%. Add followers growth
rate from JSONB history, activity status classification (active/moderate/
slow/dormant/abandoned). Display health score in dashboard table and
detail view with color-coded ring, growth indicators per platform,
and cross-platform coverage score.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows latest version, date, one highlight feature, and count of other
changes. Links to /release-notes. Extracted _get_releases() helper
for reuse between index and release_notes routes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New route /admin/social-audit/<company_id> showing detailed social media
audit per company: platform cards with metrics, profile checklist,
completeness bar, recommendations, invalid profiles section.
Added audit detail icon in dashboard table alongside profile link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows full conversation thread when replies exist, with per-message
status (sent/read with timestamps), sender→recipient flow, and
current message highlighted. Single messages show status bar at bottom.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UserCompanyPermissions has no 'position' column, causing 500 error on
/wiadomosci/nowa. Use User.company_role as fallback for position display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add attachment display section in view.html with inline image thumbnails and document download links
- Add eager loading of attachments in inbox, sent, and view queries
- Add paperclip emoji indicator in inbox and sent message lists
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Required for Google OAuth verification to remove "unverified app" warning.
Adds /polityka-prywatnosci and /regulamin routes with Polish legal content,
footer links, and sitemap entries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After token exchange, fetches Google userinfo to save the email and
name of the Google account used for authorization. Displays this info
on the GBP audit page so users know which account to reconnect with.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows whether the company has an active Google Business Profile
console connection, with clear status indicators (connected/expired/
not connected) and guidance on how to reconnect via Konto → Integracje.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix google_reviews_data bug: data is dict with 'reviews' key, not a list
(was always hidden by 'is not mapping' guard)
- Add rating distribution bar chart from Places API review data
- Display google_photos_metadata table (author, dimensions, owner photos)
- Add audit diagnostics footer (source, version, errors)
- Show owner_response_time and keywords on individual GBP reviews
- Add Polish translations for Google Places business types (40+ types)
- Use primary_type_display for human-readable category names
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add opening hours, business status, Google types, website URL, Place ID,
rating/reviews/photos summary, website tracking indicators, Google attributes,
Places API reviews, smart recommendations engine, and benchmarks comparison
with other Norda Biznes members.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Speed Index, Time to Interactive, Total Blocking Time from PageSpeed
- Benchmark table: company vs category avg vs all-members avg with arrows
- WHOIS via RDAP: domain registration, expiry, last change, registrar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses ip-api.com to look up ISP name, organization, city, region,
country and AS number for the hosting IP address.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New /admin/seo/<id> detail page with full audit breakdown
- 4 score cards with visual rings and Polish descriptions
- Recommendations section: critical/warning/info issues with actionable text
- SEO checklist: meta tags, sitemap, robots, structured data, OG tags
- Technical details: SSL, mobile, CWV metrics, security headers
- Google Business Profile section when available
- Add "Szczegoly" button in company table (replaces profile link)
- Add visible column descriptions above table (not hidden tooltips)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove in-memory log viewer (DebugLogHandler, 5 routes, template,
menu links, endpoint aliases). Logs available via journalctl on server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace complex dashboard (11 stat cards, token stats, model breakdown,
recent logs, advanced filters) with clean 3-card PLN cost view,
usage by type, user ranking, company ranking, and daily history.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace anonymized metadata ("45 chars") with real topic categories
(O firmach, Szukanie kontaktu, O wydarzeniach, etc). Remove empty
conversion stats, UTM sources, avg message length. Keep feedback
with ratings in compact two-column layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace complex Problem Score tables and remediation metrics with
two clear sections: "Members needing help" (actionable alerts with
buttons) and "Technical problems" (collapsed, for developer).
Removes ~200 lines of unused scoring/remediation code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Paths tab (entry/exit pages, transitions, drop-off) provided little
actionable value for association admin. Session length distribution
moved to Overview as compact card layout. Menu: 6 tabs -> 5.
Old /paths URL redirects to /overview.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zombie sessions (browser tab left open for days) were inflating
duration-based scores. LEAST(duration_seconds, 3600) per session
ensures only active time counts toward engagement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hovering over the activity bar shows breakdown: sessions, pages,
clicks, time, conversions, searches with weights and final score.
Column header explains what the metric measures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 3-section active/at-risk/dormant design with one clear table
showing all members sorted by activity level. Green/yellow/gray bars,
human-readable last login dates, inactive users dimmed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single 50-row table with Active/At Risk/Dormant sections.
Remove noisy WoW% column and sparklines, add human-readable last activity.
Score displayed as colored bar instead of abstract number.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alert improvements:
- "Send welcome email" button on never-logged-in alerts (sends activation
email with 72h reset token)
- "Reset password" button on reset-no-effect and repeat-resets alerts
- Buttons show status: sending → sent/error, prevent double-clicks
- New POST /admin/analytics/send-welcome/<user_id> endpoint
Companies needing attention:
- New section on Overview tab listing active companies with incomplete
profiles (missing description, contact, website, address, logo)
- Sorted by number of issues, shows quality badge and edit link
- Checks logo file existence on disk for webp/svg/png/jpg
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass search_query_id to search results template
- Add POST /api/analytics/search-click endpoint to update SearchQuery
with clicked_result_position, clicked_company_id, time_to_click_ms
- Add data-position and data-company-id attributes to company cards
- Add JS using navigator.sendBeacon for non-blocking click tracking
- Fix content engagement labels: "nowych (30 dni)" instead of "opublikowanych"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open rate now shows percentage of active members who read at least one
piece of content, capped at 100%. Previously showed inflated numbers
because it counted reads of older content against only recent publications.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Company pages use /company/<id> paths (not slugs). Updated _humanize_path
to try numeric ID lookup first, and fixed company popularity query to
match only /company/<digits> paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Dashboard admin widget: compact KPI cards (active/total members with
progress bar, sessions, security alerts, never-logged users)
2. Overview KPI: first card shows X/Y members with progress bar and %
3. Feature adoption chart: which portal modules are used by what % of
members (NordaGPT, Forum, Search, Calendar, B2B, News, Companies)
4. Event comparison table: views, unique viewers, RSVP count per event
in the last 60 days - helps plan better events
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Event paths like /kalendarz/29 were matched by the /kalendarz/
prefix before reaching the dynamic event title lookup. Reorder
to check dynamic patterns (event ID, company slug) first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The refactor to _kpi_for_period() removed the local variables but
the return dict still referenced them. Replace with the kpi dict.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. KPI cards show trend arrows (▲▼ X%) comparing current vs previous period
2. Raw paths replaced with human-readable names throughout Pages and Paths tabs:
- /company/pixlab-sp-z-o-o → PixLab sp. z o.o.
- /kalendarz/45 → Spotkanie z posłami (event title from DB)
- /login → Logowanie, /dashboard → Panel użytkownika etc.
3. Bounce rate threshold adjusted (85%+ warning instead of 70%)
with tooltip explaining 70-85% is normal for membership portals
4. Column headers changed from technical (Ścieżka, Exit rate) to
user-friendly (Strona, Wsp. wyjścia)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add EXCLUDED_PATH_CONTAINS patterns to catch security scanners using
varied paths (.php, .env, wp-includes, aws-config, phpinfo etc.)
that bypass the prefix-based filter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add KPI stat cards to Overview tab (active users, sessions, pageviews, bounce rate)
- Filter technical paths from Pages and Paths tabs (/sw.js, /robots.txt, /.git/, /.env, etc.)
- Cap time_on_page at 30min to exclude outlier tabs left open
- Format time as human-readable (Xm Ys) instead of raw seconds
- Mask security tokens in unused pages list (/reset-password/*** etc.)
- Fix Polish labels (period display: "7 dni" instead of "week")
- Add percentages to logged/anonymous donut chart legend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merged analytics_dashboard, user_insights, and chat_analytics into a
single consolidated view at /admin/analytics with 6 tabs: Overview,
Engagement, Pages, Paths, Problems, Chat & Conversions.
- Menu reduced from 5 to 3 items (Analityka, Monitoring AI, Debug)
- All queries now use bot filtering consistently
- Old URLs redirect to new consolidated view
- Removed 1,380 lines of duplicate templates
- Net reduction: -1,328 lines
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Release notes for Gemini 3.1 migration, rate limiter fix, calendar fix,
lxml parser, and announcements section.
Fix external link button in announcement detail - force white text on
primary background for readability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace gemini-3-pro-preview with gemini-3.1-pro-preview (old deprecated March 9)
- Add gemini-3.1-flash-lite-preview as quality fallback in chain
- Remove last google.generativeai import from zopk_knowledge_service.py
- Update pricing, thinking models, and preview models sets
- Keep '3-pro' alias for backward compatibility across codebase
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add year range validation (2020-2100) on /kalendarz/ to prevent ValueError crash
- Exempt notification/message unread-count endpoints from rate limiting (shared IP via NAT)
- Replace deprecated google.generativeai SDK with google-genai in nordabiz_chat.py
- Remove dead news_service import that logged warnings on every worker startup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds minimal service worker for PWA installability. On Android Chrome,
the smart banner and install page now trigger the native install dialog
directly instead of showing manual instructions. iOS still shows
step-by-step guide (Apple provides no install API).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile-only install instructions at /zainstaluj-aplikacje with
auto-detected iPhone/Android tabs, CSS UI mockups, and step-by-step
guide. Smart banner appears after 3s on mobile (dismissible via
localStorage), hidden in standalone mode. Footer link and login
page hint also mobile-only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sends email to admin when a user with last_login=NULL successfully
sets their password via reset link (first-time activation).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add frontend button disable on submit and backend duplicate detection
(same user, same content, within 30 seconds).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New column: users.notify_email_messages (default true)
- Send email via MS Graph when someone receives a private message
- Toggle in /konto/prywatnosc to enable/disable email notifications
- Email includes message preview, sender name, and direct link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merged three separate v1.36-38 entries for Feb 20 into single v1.36.0.
Renumbered: Feb 21 = v1.37.0, Feb 22 = v1.38.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hovering over a reaction button (👍, ❤️) now shows who reacted.
Names are loaded server-side and updated dynamically after toggling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
User model has 'name', not 'full_name'. The incorrect attribute caused
every hover tooltip on forum usernames to show an error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Set is_norda_member=True when admin assigns active company to user
- Clear is_norda_member=False when last active company is removed
- Covers admin edit route and admin API add/remove company routes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create UserNotification when sending private message (bell icon)
- Add "Wiadomości" link in main nav between Social and Aktualności
- Unread badge syncs across nav, user menu, and bell via polling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- "Powrót do firmy" link when composing from company profile
- "Wyślij e-mail" button opens default mail client (mailto:)
- "E-mail" button on company contact cards for direct mailto
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows portal users linked to a company with their contact details,
role badges, Norda membership status, and direct messaging link.
Respects individual privacy settings (show_phone, show_email).
Addresses forum feedback from Jakub Bornowski (topic #18).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a "Send reset" action button in the Problems tab and user profile page,
allowing admins to send password reset emails directly from User Insights
dashboard. Each reset requires manual confirmation via dialog.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users who had auth problems (failed logins, password resets, security
alerts) but have since logged in successfully are now shown in a
collapsed "Rozwiązane problemy" section. Active problems remain
prominently displayed at the top.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows whether password resets and welcome emails led to successful logins:
- Summary cards: success rate, resolved/pending/failed counts, avg time to login
- Detailed table: each action with user, type, date sent, and outcome
- Resolved = user logged in after email, Pending = <48h, Failed = no login
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- _tab_problems: 750 queries → ~10 batch queries with GROUP BY
- _tab_engagement: 2550 queries → ~12 batch queries, sparkline in 1 query
- user_insights_profile: 60+ queries → batch trend (2 queries), bot filtering on all metrics
- Stat cards exclude UNAFFILIATED, dormant excludes never-logged-in users
- Engagement status: never-logged=dormant, login<=7d+score>=10=active, 8-30d=at_risk
- Badge CSS: support both at-risk and at_risk class names
- Problems table: added Alerts and Locked columns
- Security alerts stat card in Problems tab
- Back link preserves tab/period context
- Trend chart Y-axis dynamic instead of hardcoded max:30
- Timeline truncation info when >= 150 events
- Migration 080: composite indexes on audit_logs and email_logs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add is_bot column to user_sessions with backfill from user_agent patterns
- Update analytics_daily trigger to skip bot sessions
- Recalculate 90 days of analytics_daily without bot contamination
- Replace cumulative failed_login_attempts with time-based audit_logs queries
- Switch engagement score from linear (capped at 100) to log2 scale
- Expand section_map from 9 to 17 categories (~95% traffic coverage)
- Exclude robots.txt, sitemap.xml etc from page view tracking
- Add bot filter to all overview, pages, paths, and engagement queries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Proactive alerts in Problems tab: never_logged_in, locked, reset_no_effect, repeat_resets
- 5th stat card showing never-logged-in users count
- Full problem chronology in user profile: audit_logs, emails, sessions, security alerts
- Resolution status card: resolved/pending/blocked/unresolved with time-to-resolution
- Timeline enhanced with detail field, CSS severity classes, and new icon types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
email_logs.user_id is never populated for password_reset emails.
Match by recipient_email instead. Also fix failed_logins stat card
to use users.failed_login_attempts sum instead of security_alerts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Updated Facebook link from /nordabiznes to /profile.php?id=100057396041901
across all 4 locations (email templates, JSON-LD schema)
- Added Facebook link to site footer (Contact section)
- Added "Follow us on Facebook" to landing page CTA
- Redesigned upcoming events: side-by-side layout instead of stacked
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous logo-circle.png was 404, favicon-192 was wrong icon.
Generated logo-email.png from favicon.svg compass via sharp.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Email: dark header with compass, company card, green checkmarks, Polish
date format, full footer with address, phone and tech support contact.
Actions: 4-column grid layout instead of vertical stack.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds envelope icon in AKCJE column that sends an email to the user
with their current company role and permissions summary.
Uses approved v3 email template with Norda Business branding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add missing SEO elements to improve audit score from 89 to 95+:
- Canonical URL and dynamic meta description blocks in base.html
- Open Graph tags (og:title, og:description, og:image, og:url, og:locale)
- JSON-LD structured data (Organization + WebSite schemas)
- robots.txt route with proper Disallow rules
- sitemap.xml route with homepage and release-notes
- LocalBusiness JSON-LD schema on landing page for Local SEO
- Last-Modified header for freshness signals
- Preload critical image for LCP optimization
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. seo_analyzer.py: Consider aria-label, title, img AND svg as valid
link text (SVG icon links were falsely counted as "without text")
2. routes_portal_seo.py: Calculate overall_seo score using
SEOAuditor._calculate_overall_score() before saving to DB
(was always None because stream route bypasses audit_company())
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Extract HSTS, CSP, X-Frame-Options, X-Content-Type-Options from
HTTP response headers during portal SEO audit (were always None
because SEOAuditor doesn't check security headers natively)
2. Add aria-label to all social media and website icon links on
landing page tiles (300 of 317 links had no text content,
only SVG icons)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OnPageSEOResult uses nested objects (meta_tags.title, images.total_images,
structured_data.has_structured_data). TechnicalSEOResult uses robots_txt.exists,
sitemap.exists, canonical.has_canonical. Fixed all field access paths.
Extracted DB save logic to _save_audit_to_db() for clarity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Audit now runs step-by-step with real-time progress via Server-Sent Events.
Each of 9 steps (fetch, on-page, technical, PageSpeed, local SEO, citations,
freshness, save) shows status with spinner, checkmark, or error icon.
Removed old POST form in favor of SSE-based streaming approach.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SEOAuditor result dict contains datetime objects that can't be serialized
to JSONB. Added _make_json_safe() to recursively convert them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Model had columns (overall_score, on_page_score, etc.) that didn't exist
in the migration. Updated model and templates to match the actual table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The audit_owner_required decorator was never defined in utils/decorators.py,
causing ImportError that prevented the entire admin blueprint from loading.
Uses the same is_audit_owner() pattern as routes_audits.py and routes_social.py.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add /admin/portal-seo to run SEO audits on nordabiznes.pl
using the same SEOAuditor used for company websites.
Tracks results over time for before/after comparison.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show company logos with website and social media links
to unauthenticated visitors below the existing landing
page content, improving local content indexability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show social media cards, SEO PageSpeed scores, and GBP stats
directly in admin view. Add "Profil publiczny" link to header.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Bulk discovery skips companies with any candidate (including rejected)
- Single discovery skips URLs from previously rejected domains
- Dashboard shows list of companies rejected by admin with note
that they won't be re-searched in bulk mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
In-memory _bulk_jobs dict was per-worker in gunicorn (4 workers),
causing poll requests to miss job state. Now uses /tmp JSON files
visible to all workers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Evaluate top 3 Brave results instead of just taking the first one.
Add domain name matching signal (+2 pts when domain contains company name).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show Brave search description under company name and scraped page
text snippet (first 500 chars) as expandable row below each
candidate, helping admin verify if the URL matches the company.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bulk query now excludes companies that already have pending/accepted
candidates, so only truly new companies are processed via Brave API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Brave free tier rate limits aggressively (429 after ~1 req/s).
Added retry logic (3 attempts: 3s, 6s, 9s waits) and increased
inter-company delay from 2s to 5s. Error candidates are now
cleaned up before retry to allow re-discovery.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single latest_result field with cumulative log array and
offset-based polling to prevent missed entries and race conditions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automated discovery using Brave Search API to find company websites,
scrape verification data (NIP/REGON/KRS/email/phone), and present
candidates with match badges in the data quality dashboard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace substring matching with word-boundary tokenized matching
- Short names (1-2 words): require ALL significant words to match
- Longer names (3+): require at least 50% word overlap
- Pick best-scoring result instead of first match
- Add company_name validation to competitor_monitoring_service
- Show Google profile name in dashboard hints for admin verification
- Display mismatch warning when Google name differs from company name
Prevents cases like "IT Space" matching "Body Space" (score 0.50 < 1.00 threshold).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add clickable field coverage bars to filter companies missing specific data
- Add quick-action buttons (Registry/SEO/GBP) per company in dashboard table
- Add stale data detection (>6 months) with yellow badges
- Implement weighted priority score (contacts 34%, audits 17%)
- Add data hints in admin company detail showing where to find missing data
- Add "Available data" section showing Google Business data ready to apply
- Add POST /api/company/<id>/apply-hint endpoint for one-click data fill
- Extend website content updater with phone/email extraction (AI + regex)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract 12-field completeness scoring to utils/data_quality.py service
- Auto-update data_quality_score and data_quality label on company data changes
- Add /admin/data-quality dashboard with field coverage stats, quality distribution, and sortable company table
- Add bulk enrichment with background processing, step selection, and progress tracking
- Flow GBP phone/website to Company record when company fields are empty
- Display Google opening hours on public company profile
- Add BulkEnrichmentJob model and migration 075
- Refactor arm_company.py to support selective steps and progress callbacks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove the dark/light background toggle from logo selection modal,
company detail pages (admin and public), and the toggle-logo-bg API
endpoint. The feature didn't meet UX requirements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When choosing a logo, admins can now switch between light and dark
backgrounds to see which works better for transparent logos. The
selected background preference is automatically saved when confirming.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a per-company setting to display logos on dark background,
useful for logos with white text or light-colored elements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The logo path was hardcoded to .webp even when the actual file was .svg,
causing broken image display for SVG logos like Orlex Design.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logo check only looked for .webp files, missing SVG logos like
Orlex Design. Now checks both extensions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CEIDG enrichment now creates individual CompanyPKD records from the PKD
list, matching the pattern used by KRS enrichment for consistency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KRS API returns two date formats for za_okres field:
"01.01.2011 - 31.12.2011" (older) and "OD 01.01.2013 DO 31.12.2013" (newer).
Use regex to extract all date patterns instead of splitting on ' - '.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Map remaining KRS API fields: registration date, company agreement date,
duration, capital currency, OPP status, representation rules, shareholders
(wspólnicy), and financial reports (sprawozdania finansowe).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KRS API returns kontakt_krs with www and email fields. These were not
being mapped to Company.website and Company.email. Now enrichment
extracts these and normalizes the URL (adds https:// prefix, lowercase).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The KRS enrichment function was only mapping forma_prawna, legal_name
and capital. Now maps REGON, address (ulica + nr_domu), city, postal,
primary PKD code on Company model, and NIP if missing. Fixed field
name mismatches: nr_domu (not numer), opis (not nazwa), glowna (not
glowny). City names are title-cased from KRS uppercase format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New admin page at /admin/companies/{id}/detail showing company data,
completeness score, and action buttons for registry data (CEIDG/KRS),
logo fetch, SEO audit, social media audit, and GBP audit.
Includes "Uzbrój firmę" master button for sequential execution.
Company list now links to detail page with "NOWA" badge for recent entries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PDF files: "Otwórz" (inline in browser) + "Pobierz" (download)
DOCX files: "Pobierz" only (browsers can't display DOCX inline)
Removes LibreOffice on-the-fly conversion - simpler and more reliable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use /usr/bin/libreoffice (Gunicorn has limited PATH)
- Set HOME=/tmp (LibreOffice needs writable home dir)
- Handle FileNotFoundError with user-friendly message
- Improve error flash messages in Polish
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DOCX/DOC documents are now converted to PDF using LibreOffice headless
when the user clicks "Otwórz". The converted PDF is cached next to the
original file so subsequent views are instant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PDF documents now have an "Otwórz" button that opens
the file in the browser's built-in PDF viewer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add document management routes (upload, download, soft-delete) to board blueprint,
link BoardDocument to BoardMeeting via meeting_id FK, add documents section to
meeting view template, and include import scripts for meeting 2/2026 data and PDFs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Charts now render automatically on page load via AJAX from DB cache
(no click needed). Info bar above charts shows post count, cache date,
and hint to refresh. GET cache endpoint now returns cached_at date.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes slow page load for non-admin users (919KB inline JSON).
Route now sends max 10 posts inline with total_count metadata.
New GET endpoint serves full cache via AJAX for Analityka button.
loadAllFbPosts tries DB cache first (instant), falls back to FB API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin's _get_user_company_ids returns None meaning all companies,
but iterating over None gave empty list. Now falls back to fb_stats keys.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Migration 071: Add cached_posts (JSONB) and posts_cached_at to social_media_config
- Service: get_cached_posts() and save_all_posts_to_cache() methods
- Route: New POST endpoint to save posts cache, pass cached data to template
- Template: Render cached posts+charts instantly on page load from DB,
save to DB after "Load all" or "Refresh", remove AJAX auto-load
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously get_page_posts returned a flat list with no pagination support.
Now returns dict with posts and next_cursor, enabling infinite scrolling
through all Facebook page posts via the after query parameter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display last 10 posts from connected Facebook page with engagement
data (likes, comments, shares, reactions). On-demand insights button
loads impressions, reach, engaged users, and clicks per post.
In-memory cache with 5-min TTL prevents API rate limit issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- select-page now saves page token to SocialMediaConfig.access_token
- _get_publish_token prefers config page token over OAuthToken
- Prevents breakage when OAuth reconnect overwrites OAuthToken with USER token
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Social Publisher: blue gradient panel with followers, engagement,
completeness, contact pills, and refresh button.
Integracje: "Synchronizuj dane" button next to Disconnect for Facebook.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Batch-query confirmed attendee counts per event and display as
subtle cyan number with people icon in event meta line.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After connecting a FB page via OAuth, automatically fetch page stats
(followers, engagement, bio) from Graph API and persist to
CompanySocialMedia table. Adds manual refresh endpoint and UI badge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same bug as discover-pages: select-page was using page token to call
me/accounts, which returns empty. Now uses user_access_token from
metadata_json.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OAuth integrations page was hardcoded to maciej.pienczyn@inpi.pl.
Now accessible to any user with MANAGER role or higher.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After selecting a FB page, the user token was overwritten with page
token. me/accounts requires user token to list pages, so page discovery
returned empty. Now stores user_access_token in oauth metadata_json.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Facebook Graph API returns error 100 when setting is_published=false on
already-published posts. Replaced "Zmień na debug" with "Usuń z Facebooka"
which deletes the post from FB and resets status to draft for re-publishing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds bidirectional visibility control: published posts can be switched
between public (live) and draft (debug/admin-only) mode via Facebook
Graph API. Includes is_live column, status indicator, and toggle buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New force_live parameter in publish_post() overrides config.debug_mode
- Red "Publikuj na żywo" button with confirmation dialog
- Visible when company has debug_mode enabled
- Works for new posts, drafts, and re-publishing debug-published posts
- "Publikuj teraz" shows "(debug)" label when in debug mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Query company_social_media table for valid profiles (Facebook, Instagram,
LinkedIn, YouTube, etc.) and pass them as context to AI prompts.
Member spotlight posts now include social media links at the end.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass user_id, company_id, and feature name to generate_text() calls:
- 'social_publisher_content' for post content generation
- 'social_publisher_hashtags' for hashtag generation
All costs logged to AIUsageLog and AIAPICostLog with user/company context.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two render_template calls were missing ai_models/default_ai_model
causing UndefinedError on template render (500 error).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3 models available: Gemini 3 Flash (default, cheap), Gemini 3 Pro
(best quality, 4x cost), Gemini 2.5 Flash (stable previous gen).
Model selection applies to both content and hashtag generation.
Shows which model was used after generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove hashtag instructions from AI prompts (content-only generation)
- Add _split_hashtags() to extract any hashtags AI still includes
- generate_content() now returns (content, hashtags, model) tuple
- Prevents duplicate hashtags when publishing (content + hashtags field)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6 tones: Profesjonalny (default), Przyjazny, Oficjalny, Entuzjastyczny,
Informacyjny, Inspirujący. Tone instruction is appended to the AI prompt.
Dropdown appears next to "Generuj AI" button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New generate_hashtags() method in SocialPublisherService
- New /social-publisher/generate-hashtags AJAX endpoint
- "Generuj hashtagi AI" button next to hashtags field
- Small print info about AI engine (Gemini 3 Flash) with note
about future model selection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix AttributeError: Company.city -> Company.address_city in get_company_context
- Default publishing_company_id to first available company when not selected
- Replace alert() with inline error message for AI generation failures
- Return user-friendly error messages instead of internal exceptions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Managers can now access Social Publisher to create posts and configure
Facebook only for their assigned company. Admins see all companies.
Added nav menu link visible for MANAGER+ role.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Social Publisher now supports multi-company FB publishing via OAuth.
Each company can connect its own Facebook page through the existing
OAuth framework. Includes discover-pages/select-page endpoints,
per-company settings UI, and publishing_company_id on posts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Check content-type before parsing JSON in runAudit() to show
helpful message when NPM proxy times out (returns HTML)
- Replace abort(404) with jsonify in audit trigger endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously all new permission records had contacts/social/analytics
disabled by default regardless of role. Now MANAGER+ users get
full permissions automatically.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds editable admin notes to company edit modal in admin panel,
with visual indicator (pencil icon) in companies table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of auto-selecting one logo candidate, the service now downloads
up to 6 candidates and displays them in a gallery. User sees all options
(including their current logo if exists) and picks the best one.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a company already has a logo, the fetch shows both old and new
logos side-by-side so the user can choose to keep or replace. Uses
preview file mechanism (slug_preview.webp) with confirm/cancel actions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New "Pobierz logo" button on company detail page that automatically
downloads and converts company logos from their websites. Uses 4-strategy
approach (DOM scan, meta tags, favicon, Google API fallback) with
animated progress overlay showing 6 steps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CEIDG enrichment was broken due to key mismatches (expected adres_ulica but API
returns adresDzialalnosci.ulica), writes to non-existent columns (address_building,
address_postal_code), and missing saves for ceidg_id/status/owner/PKD fields.
Now fetches full details via /firma/{id} endpoint (Phase 2) for complete data
including PKD list, correspondence address, and succession manager.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Registration now assigns company_role=NONE instead of VIEWER - users
with a company NIP must be approved by admin/office manager before
getting any company dashboard access. Admin panel shows yellow alert
banner and "Oczekujący" filter tab when users are pending approval.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds independent company_role management (NONE/VIEWER/EMPLOYEE/MANAGER)
visible next to company column. Decouples company_role from system role
so admins can control portal permissions for company profiles separately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New accounts should have minimal permissions (VIEWER = view company
dashboard only). Admins, office managers, or company managers promote
users to higher roles manually.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users could register with just a first name, causing incomplete data
in participant lists. Added backend validation (min 2 words) and
HTML pattern attribute. Also fixed Polish characters in flash message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin panel module for publishing posts on NORDA chamber Facebook page.
Includes AI content generation (Gemini), post workflow (draft/approved/
scheduled/published), Facebook Graph API publishing, and engagement tracking.
New: migration 070, SocialPost/SocialMediaConfig models, publisher service,
admin routes with AJAX, 3 templates (list/form/settings).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
19 sub-sections (7 CEIDG + 12 KRS) can now be individually hidden
within the Official Registry Data section. Sub-section toggles use
indented styling with lighter colors in the edit UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow company owners, managers, and admins to hide specific profile
sections from visitors. Hidden sections remain visible to authorized
users with a "Ukryta" badge. Includes migration, API endpoint,
edit UI tab, and conditional rendering for all 15 profile sections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add company_website_id FK to CompanyWebsiteAnalysis, extract audit cards
to Jinja macro, render per-website under each banner with fallback for
sites without audit data. Google Rating stays at company level.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Six types: website (blue), store (green), booking (purple), blog (orange),
portfolio (pink), other (gray). Each type has unique icon, color in contact
bar and banner section, and tooltip with site description.
Form edit adds type selector dropdown per website row.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CompanyWebsite model with label, is_primary flag, and backward
compatibility sync to company.website. Dynamic form in company edit,
separate buttons in contact bar, additional banners in detail view.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Explicitly delete reply reads, attachments, reports and edit history
before deleting the reply to avoid NotNullViolation on forum_reply_reads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The onboarding widget added in b76d275 uses current_app.root_path but
current_app was not imported from flask. This caused NameError for all
logged-in users visiting /dashboard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Visual timeline showing company profile completion status:
- 6 steps computed from existing DB data (no new tables)
- Color-coded badges: member/office/auto responsibility
- Collapsible with localStorage persistence
- Green "complete" state when all steps done
- Action links for incomplete member-owned steps
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously only validated format (10 digits). Now also validates
the NIP checksum (weights 6,5,7,2,3,4,5,6,7, mod 11) to catch
typos like the one that left a user unlinked from their company.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Child companies (with parent_company_id) now show parent's NIP and can
fetch data from KRS/CEIDG using inherited NIP. Fixes Alter Energy showing
no NIP despite sharing one with Fiume Studio.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Display up to 3 next events with RSVP status instead of just one
- Add import script for WhatsApp Norda group data (Feb 2026):
events, company updates, Alter Energy, Croatia announcement
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Employees clicking "Edytuj profil" now see a modal with their company's
management team contacts instead of being sent to an edit form they can't use.
Managers and admins continue to access the edit form directly. Direct URL
access to /firma/edytuj is also guarded with redirect + flash message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New analyze_roadmap_with_ai() function sends existing milestones and recent
knowledge facts to Gemini for comprehensive analysis. Returns new milestone
suggestions, status update recommendations, and identified roadmap gaps.
Adds PATCH endpoint for milestone status updates and tabbed UI modal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Role field stores uppercase 'ADMIN' (from SystemRole enum). Use
is_admin boolean property which is synced by set_role() for reliable checks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4 new features visible only to admin (role=='admin'):
- Homepage: "Czy wiesz, że?" widget with 3 random high-confidence facts
- /zopk: Knowledge stats, top entities, key numeric facts, fact type distribution
- /zopk: Dated facts timeline (CSS-only vertical timeline)
- /zopk: D3.js entity co-occurrence graph with slider control
No migrations needed - read-only SELECT queries only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Long-running Gemini extractions (30-120s per article) caused SSE
connection timeout. Now runs extraction in a thread and sends
heartbeat updates every 10s to keep the connection alive.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin was confused by red "Błędy: 2" when scraping/extraction had
expected issues (403, content too short). Changes:
- All scraper/extractor messages translated to Polish
- HTTP 403/404/429 get specific descriptive messages
- Expected failures shown as yellow "Pominięte" instead of red "Błędy"
- "No chunks created" → "Treść za krótka do ekstrakcji"
- Summary label "Błędy" → "Pominięte"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The scrape stream used 'type' field and lacked 'percent', 'message',
'details' - format incompatible with the shared SSE modal handler.
Aligned to match knowledge stream format: status/percent/message/details.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SSE scrape stream was filtering on ZOPKNews.content_scraped which
doesn't exist in the model. The correct field is scrape_status with
values 'pending', 'failed', 'scraped', 'skipped'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flask-Login's current_user proxy loses context inside generator
functions. Same fix as applied to search stream endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Brave free tier was returning 429 for ~50% of queries due to back-to-back
requests. Added 1.1s delay between queries and retry with exponential
backoff (1.5s, 3s). Heartbeat endpoint exempted from Flask-Limiter and
interval increased from 30s to 60s to reduce log noise.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create separate SessionLocal() in run_search() thread instead of sharing
main thread's session (SQLAlchemy sessions are not thread-safe). Increase
connection pool_size to 10 with pool_pre_ping for gthread worker support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flask-Login's current_user proxy loses context inside generator
functions, causing 'NoneType' has no attribute 'id' error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace simulated progress animation with Server-Sent Events streaming
that shows actual backend progress in real-time during ZOPK news search.
Prevents timeout errors by keeping the connection alive with heartbeat
events. Old POST endpoint preserved as automatic fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After refactoring to blueprints, templates still used bare endpoint names
(e.g., url_for('admin_zopk')) instead of prefixed names (e.g.,
url_for('admin.admin_zopk')). While most worked via backward-compat aliases,
api_zopk_search_news was missing from the alias list causing 500 on /admin/zopk.
Fixed 19 template files and added missing alias for api_zopk_search_news.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hide Integracje link in user menu for non-owner users
- Add server-side access check on /konto/integracje route
- Add owner-only visual indicator on the link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin can now set passwords directly via modal with generator (crypto.getRandomValues),
replacing the confirm-dialog flow with a tabbed modal (set password / reset link).
Custom CSS tooltips replace native title="" for instant hover display.
New "Ostatnie logowanie" column shows last_login timestamps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive rewrite of access control dashboard: role hierarchy table,
full function-by-role access matrix (7 columns incl. unauthenticated users),
Rada Izby members section, and all active accounts with Excel-like
collapsible grouping by role. Expand/collapse all controls included.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Audits (SEO, IT, GBP, Social Media) are now visible only to the
designated audit owner (maciej.pienczyn@inpi.pl). All other users,
including admins, see 404 for audit routes and no audit links in
navigation. KRS Audit and Digital Maturity remain unchanged.
Adds /admin/access-overview panel showing the access matrix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GBP Performance API integration for visibility metrics (Maps/Search
impressions, call/website clicks, direction requests, search keywords).
Extend Search Console with URL Inspection, Sitemaps, device/country/type
breakdowns, and period-over-period trend comparison. Change OAuth scope
from webmasters.readonly to webmasters for URL Inspection support.
Migration 064 adds 24 new columns to company_website_analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SEO dashboard: show step-by-step guide when GSC connected but site
not found in Search Console (instead of generic "connect" CTA)
- Integrations page: add info note about GSC site verification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SEO audit from admin panel uses seo_audit.py (SEOAuditor), not
audit_ai_service.py. Added GSC OAuth enrichment step after audit save.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GSC columns to DB, persist OAuth data during audits, and render
clicks/impressions/CTR/position with top queries table on the dashboard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Company users should connect their own Google/Meta accounts, not admins.
- Add /konto/integracje route for company users (auth blueprint)
- OAuth callbacks now redirect to /konto/integracje
- Template breadcrumb adapts to user vs admin view
- Admin route /admin/companies/<id>/settings kept for admin access
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Company settings page with 4 OAuth cards (GBP, Search Console, Facebook, Instagram)
- 3 API service clients: GBP Management, Search Console, Facebook Graph
- OAuth enrichment in GBP audit (owner responses, posts), social media (FB/IG Graph API),
and SEO prompt (Search Console data)
- Fix OAuth callback redirects to point to company settings page
- All integrations have graceful fallback when no OAuth credentials configured
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 4 quick-win features to GBP dashboard:
- "Poproś o opinię" button with writeAReviewUri from Places API
- "Pokaż trasę" button with directionsUri
- Open/Closed badge showing business status at audit time
- NAP comparison table (Name, Address, Phone) vs Google data
New DB columns: google_maps_links (JSONB), google_open_now (BOOLEAN)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GBP: Places API data section, audit errors banner, special hours display
Social: Platform comparison table, refresh timestamp, 5-level activity status
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Google replaced First Input Delay (FID) with Interaction to Next Paint
(INP) as a Core Web Vital in March 2024. This renames the DB column
from first_input_delay_ms to interaction_to_next_paint_ms, updates the
PageSpeed client to prefer the INP audit key, and fixes all references
across routes, services, scripts, and report generators. Updated INP
thresholds: good ≤200ms, needs improvement ≤500ms.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Route passes 16 new fields from DB (technical SEO, meta tags, structured
data, performance) plus CrUX/security/image metrics. Template shows new
sections: Meta Tags & Content, CrUX Field Data, Security Headers (score
X/4), Image Optimization (% modern formats), and 9 new Technical SEO
checklist items. Migration 059 adds 16 columns for persisting live data.
AI service now saves CrUX/security/image data to DB during analysis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Template was updated to use inp_ms (INP replaced FID in March 2024) but
the route dict still passed the old fid_ms key, causing UndefinedError.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New files:
- oauth_service.py: Shared OAuth 2.0 service supporting Google and Meta
providers with token exchange, refresh, and storage
- database/migrations/058_oauth_tokens.sql: oauth_tokens table with
company/provider/service unique constraint
- blueprints/api/routes_oauth.py: OAuth API endpoints for connect,
callback, status, and disconnect flows
Supports:
- Google OAuth (GBP Business Profile, Search Console)
- Meta OAuth (Facebook Pages, Instagram)
- CSRF state validation, token refresh, expiry tracking
- Per-company token storage with active/inactive status
Requires .env config:
- GOOGLE_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_SECRET (Google APIs)
- META_APP_ID, META_APP_SECRET (Facebook/Instagram)
- OAUTH_REDIRECT_BASE_URL (default: https://nordabiznes.pl)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The API route was explicitly mapping fields and omitting the 'previous'
key from the service result.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Users" button and modal in companies table to view/assign/unassign users
- New endpoint POST /admin/companies/<id>/unassign-user to detach user from company
- New endpoint GET /admin/users/list-all for user dropdown in assignment modal
- Modal shows assigned users with "Unpin" button and dropdown for adding new ones
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move percentage text from inside bars to separate column (always visible)
- Add cost (USD) column to "Wykorzystanie wg typu" section
- Add tokens+cost to type query in backend
- Fix same issues in company detail template
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add user/company/model/custom date range filters to AI usage dashboard
- Add model breakdown section showing per-model usage and costs
- Add company detail page (/admin/ai-usage/company/<id>) with per-user stats
- Add CSV export endpoint respecting all active filters
- Remove unused model-comparison page from navigation and imports
- Remove 20-item limit on user/company rankings (show all)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users can now choose between Flash Lite (fastest, 1000 RPD), Flash
(thinking mode, 20 RPD) and Pro (premium). Default changed to Flash Lite.
Badge shows actual model used for full transparency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Gemini AI integration to SEO, GBP, and Social Media audits that
generates contextual analysis summaries and prioritized action items
with ready-to-use content (Schema.org, meta descriptions, social posts,
GBP descriptions, review responses, content calendars).
New files:
- audit_ai_service.py: Central AI service with caching (7-day TTL)
- blueprints/api/routes_audit_actions.py: 4 API endpoints
- database/migrations/056_audit_actions.sql: 3 new tables
- templates/partials/audit_ai_actions.html: Reusable UI component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- google_places_service.py: Google Places API integration
- competitor_monitoring_service.py: Competitor tracking service
- scripts/competitor_monitor_cron.py, scripts/generate_audit_report.py
- blueprints/admin/routes_competitors.py, templates/admin/competitor_dashboard.html
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The admin social audit dashboard (/admin/social-audit) now shows:
- Yellow stat card with count of profiles needing verification
- Dedicated 'Profile do recznej weryfikacji' section listing all items
- Warning icon in recommendations column for verification-needed profiles
- Route now fetches profiles with check_status='needs_verification' alongside valid ones
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>