Email notifications limited to test address during development.
Fixed missing Polish characters in notification titles and body.
Commented out production email loop (TODO marker for re-enable).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Meeting 2 had 5 companies in one agenda item with separate decisions.
Old code only extracted from title. Now also parses each decision for
"Przyjęto firmę X jako" pattern. Raised similarity threshold from 0.3
to 0.5 to avoid false positives (e.g. "Konkol Sp. z o.o." matching "INPI Sp. z o.o.").
Co-Authored-By: Claude Opus 4.6 (1M context) <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>
Previous regex only matched 3-3-2-2 format. New universal pattern
catches any 10-digit NIP with dashes/spaces in any position.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase candidate pool from 3 to 5. Stop evaluating once a
candidate matches NIP/REGON/KRS (100% certainty).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root page often lacks NIP/REGON. Now scrapes /kontakt/, /contact,
/o-nas, /o-firmie to find strong verification signals. Stops early
when NIP/REGON/KRS found.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip paths from candidate URLs (e.g. /kontakt/, /about/) to always
save root domain. Deduplicates results pointing to same domain.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
"Jubiler Agat" now matches "agat-jubiler.pl" by checking individual
words in any order, not just concatenated substring.
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>
- Added norda-biznes.info, bizraport.pl, aplikuj.pl, lexspace.pl,
drewnianeabc.pl, f-trust.pl, itspace.llc to directory blacklist
- Delay first poll by 3s so thread has time to populate total
- Better completion messages (show count, handle 0 remaining)
- Increase poll interval to 3s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added imsig.pl, monitorfirm.pb.pl, zwiazekpracodawcow.pl,
transfermarkt.pl, mapcarta.com and other directories/portals
that returned false positives in first production run.
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>
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>
- 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>
- Add 'failed' to allowed statuses in publish_post() and update_post()
- Show "Spróbuj ponownie" button for failed posts in form template
- Root cause: select-page endpoint stored USER token instead of PAGE token
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>
Replace 6 generic tones with 10 research-backed options optimized for
chamber of commerce Facebook content. New default: "Opowieść" (Storytelling).
New tones: Duma i wspólnota, Rozmowa, Świętowanie, Za kulisami,
Z przymrużeniem oka. Based on Buffer/Hootsuite/Jasper best practices
and 2026 social media trends favoring authenticity over polish.
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>
Use category relationship (company.category.name) instead of non-existent
direct attribute, and description_full/description_short instead of
non-existent description/short_description fields.
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>
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>
- Add @rada_member_required decorator for access control
- Add BoardDocument model for storing protocols and documents
- Create document upload service (PDF, DOCX, DOC up to 50MB)
- Add /rada/ blueprint with list, upload, download endpoints
- Add "Rada" link in navigation (visible only for board members)
- Add "Rada" badge and toggle button in admin user management
- Create SQL migration to set up board_documents table and assign
is_rada_member=True to 16 board members by email
Storage: /data/board-docs/ (outside webroot for security)
Access: is_rada_member=True OR role >= OFFICE_MANAGER
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>