.contains() generates LIKE which fails on PG arrays.
Use .op('@>')(pg_array(...)) pattern matching existing codebase.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The codebase uses SessionLocal() with try/finally pattern,
not db_session. Import error broke all blueprint registration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Main NAV: replace Kaszubia/Więcej with "Projekty" dropdown (Kaszubia, PEJ).
Remove Social (beta) and Korzyści from main NAV (already in admin bar).
Add "Narzędzia" dropdown to admin bar (Kontakty, Raporty, Mapa Powiązań).
Admin nav reduced from 13 to 10 items.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10 tasks across 4 chunks: backend routes, templates, nav
reorganization, and verification/deploy. Includes fixes from
spec and plan reviews (field names, endpoint aliases, diacritics).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hybrid "lens" approach — PEJ section filters existing ZOPK data
by nuclear project IDs, adding dedicated routes, templates, and
CSV export without new database tables.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Email clients (Gmail, Outlook, Apple Mail) don't support CSS
linear-gradient(), causing white text on white background — company
name, header title, and CTA button were invisible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep AI-generated descriptions visible but remove clickability until
project detail pages have real content (news tagged to projects).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Companies matched to ZOPK projects (score >= 40) now see a green
"Zielony Okrąg Przemysłowy Kaszubia" section on their profile with:
- Project name, type icon, and link type badge
- AI-generated collaboration description explaining relevance
- Relevance score percentage
- Links to project detail pages
- Hover effects for interactivity
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add /api/zopk-facts endpoint returning paginated facts from distinct
source articles, ordered by recency
- Add "Pokaż więcej" button with AJAX loading and fade-in animation
- New cards are clickable with same hover effect as initial ones
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace broken distinct() call with group_by() and add db.rollback()
in except handler to prevent failed transaction from cascading.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pick one fact from each of the 3 most recent distinct articles
instead of 3 facts from the same article.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cards now link to source article, show hover highlight and
"Czytaj →" indicator. Cursor changes to pointer on hover.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uses Gemini AI to analyze each company's profile (PKD codes, services,
descriptions, AI insights) against 5 ZOPK projects and generate
relevance scores with collaboration descriptions in Polish.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Change from random() to published_at DESC — show newest, most
relevant facts instead of random old ones
- Translate fact type labels to Polish (investment→inwestycja,
decision→decyzja, event→wydarzenie, etc.)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Enable "Czy wiesz, że..." ZOPK facts widget on homepage for all
logged-in users (was admin-only and disabled with {% if False %})
- Add "Oś czasu" button to ZOPK admin dashboard navigation (was
only accessible from public /zopk page edit links)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Source servers return 503 (Cloudflare) for cross-origin image requests
from browsers. Solution: download and cache images server-side during
scraping, serve from /static/uploads/zopk/.
- Scraper now downloads og:image and stores locally during article
scraping (max 2MB, supports jpg/png/webp)
- Backfill script downloads images for all existing articles server-side
- Template fallback shows domain initial letter when image unavailable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add referrerpolicy="no-referrer" to img tags to bypass hotlink
protection on source servers
- Replace Google Favicons fallback (blocked) with inline domain
initial letter in green placeholder
- Consistent styling across index and news_list templates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix broken news thumbnails by adding og:image extraction during content
scraping (replaces Brave proxy URLs that block hotlinking)
- Add image onerror fallback in templates showing domain favicon when
original image fails to load
- Decode Brave proxy image URLs to original source URLs before saving
- Enforce English-only entity types in AI extraction prompt to prevent
mixed Polish/English type names
- Add migration 083 to normalize 14 existing Polish entity types and
clean up 5 stale fetch jobs stuck in 'running' status
- Add backfill script for existing articles with broken image URLs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
External monitoring via UptimeRobot (free tier) with internal health
logger to differentiate ISP outages from server issues. Includes:
- 4 new DB models (UptimeMonitor, UptimeCheck, UptimeIncident, InternalHealthLog)
- Migration 082 with tables, indexes, and permissions
- Internal health logger script (cron */5 min)
- UptimeRobot sync script (cron hourly) with automatic cause correlation
- Admin dashboard /admin/uptime with uptime %, response time charts,
incident log with editable notes/causes, pattern analysis, monthly report
- SLA comparison table (99.9%/99.5%/99%)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Short user sessions (<5min) never triggered the flush, leaving
page_views_count at 0 for most users despite actual browsing activity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevents confusing "link invalid" error when verification link is
clicked twice (or prefetched by email clients like Outlook). The token
now expires naturally instead of being cleared on first use.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The periods data from Google Places API (New) uses {hour, minute} instead
of {time}. The JS check now handles both formats so business hours status
displays correctly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New page /admin/gbp-audit/match-places shows companies without
google_place_id. Admin searches Google Maps, reviews results, and
confirms the correct match. Adds search_places_raw() to return all
results without name filtering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Companies with an existing google_place_id now skip the name-matching
search and use the verified Place ID directly. This fixes companies like
ALMARES ("PSB Profi Almares" in Google) whose single-word name failed
strict matching. Also removes invalid 'source' kwarg from GBPAudit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Batch audit now collects changes without saving to DB. Admin must
review before/after differences and approve or discard. Mirrors the
existing social audit enrichment review pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reviews and business type names were returned in English because
the get_place_details endpoint lacked the languageCode parameter,
unlike searchText and searchNearby which already had it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Run audit for all active companies with background thread, live progress
panel, and optional Google Places API data refresh. Pattern mirrors
existing social audit batch implementation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Personalized guide with GBP links (write review, view profile, photos)
for each member's company. Includes tips on collecting reviews,
responding to feedback, Local Guides program, and Google policies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded email check for audit panels with role-based
SUPERADMIN check. ADMIN retains all management capabilities but
SUPERADMIN adds access to technical audits (SEO, IT, GBP, Social,
Access Control).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin-sent reset emails now say "Administrator portalu wygenerował
link do ustawienia hasła" instead of generic "zażądano resetowania".
Validity period shown correctly: 24h for admin, 1h for self-service.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The admin reset-password endpoint used datetime.utcnow() while the
validation used datetime.now(), causing tokens to appear expired
immediately on CET servers. Changed to datetime.now() and extended
admin-initiated resets to 24 hours validity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>