The detail endpoint wraps firm data in a lista under "firma" key.
Without unwrapping, the list of dicts was assigned to legal_name (String),
causing psycopg2 ProgrammingError: can't adapt type 'dict'.
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>
MANAGER/EMPLOYEE/VIEWER are portal permission levels, not job titles.
Rename field to portal_role with labels: administrator profilu, pracownik,
obserwator — so chatbot doesn't misinterpret them as company positions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove is_verified filter so chatbot sees all active users assigned to a
company. Add 'verified' field so AI can inform about account status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extends chatbot to include verified portal users alongside KRS/CEIDG data,
so NordaGPT can answer questions about company representatives who registered
on the portal but aren't listed in official registries.
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>
Direct slug check (e.g. linkedin.com/company/waterm) can match
a different company with the same name. LinkedIn public metadata
is too minimal to verify location/industry without API access.
Rely on Brave Search with title/description validation instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add direct URL check for linkedin.com/company/{slug} before Brave Search
- Prioritize /company/ over /in/ in search result ranking
- Use targeted query "company_name linkedin.com/company" first
- Fall back to personal profile search only if company page not found
- Verify page title matches company name to avoid false positives
Fixes: WATERM showed employee's personal profile instead of existing
company page at linkedin.com/company/waterm
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows "Szukam w Brave Search" as a separate step between website
scanning and individual platform results, reflecting the actual
backend flow now that Brave Search is fully implemented.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Displays badge indicating whether detected LinkedIn is a company page
or personal profile. Shows recommendation to create a Company Page
when only a personal profile is found. Visible only to company
owners/managers and admins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace placeholder _search_brave() with real Brave API integration
- Fix LinkedIn URL construction: /in/ profiles were incorrectly built as /company/
- Add word-boundary matching to validate search results against company name
- Track source (website_scrape vs brave_search) per platform in audit results
- Increase search results from 5 to 10 for better coverage
Fixes: WATERM LinkedIn profile not detected (website has no LinkedIn link,
but Brave Search finds the personal /in/ profile)
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>
Migration 067 copied comma-separated URLs as single records.
067b splits them into individual rows and syncs companies.website.
Banner now uses primary from relationship instead of company.website.
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>
OPNsense bridge + CrowdSec plan saved as future roadmap item.
FortiGate hardening changes from 2026-02-16 session documented.
Design doc status updated to roadmap/future.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detailed step-by-step plan covering CrowdSec deployment on NPM/NordaBiz,
OPNsense VM creation and bridge configuration, Suricata IDS/IPS setup,
console enrollment, bridge insertion procedure, and observation period.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validated design for replacing expired FortiGuard capabilities with
free, open-source security stack: OPNsense VM in transparent bridge
mode with Suricata IPS and CrowdSec distributed agents.
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>
DataTransfer API may fail on some mobile browsers, leaving fileInput
empty. Added form submit interceptor that uses FormData as fallback
to ensure attachments are sent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Notifications dropdown was clipped on mobile phones due to absolute
positioning and min-width: 320px. Changed to fixed bottom sheet on
screens ≤768px for native-like UX.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Seeds its own test user (no dependency on pre-existing accounts),
logs in, and verifies /dashboard returns 200. Would have caught the
missing current_app import from b76d275.
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>
DATABASE_URL and PAGESPEED_API_KEY are read at module level (import
time), so load_dotenv must run before third-party imports that
reference these variables.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add load_dotenv() to seo_audit.py so it reads GOOGLE_PAGESPEED_API_KEY
and DATABASE_URL from .env without requiring manual env var passing.
Fixes PageSpeed 429 errors when running audit via SSH.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent white-space: pre-line from rendering source code newlines
inside <p>, <div> and callout elements in HTML-formatted descriptions.
Plain text descriptions still get line break rendering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensures newlines in plain text event descriptions render as line
breaks, maintaining compatibility with both HTML and plain text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add paragraph spacing, larger font, and styled callout box for
pricing/key info in event detail pages. Better visual hierarchy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add image_url column to NordaEvent model with migration 066.
Display event banner image above description in event detail page.
Include converted WebP image for Lean breakfast event (2026-02-20).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
seo_audit.py was missing SSL columns (has_ssl, ssl_expires_at,
ssl_issuer) in its INSERT/UPDATE query, causing all SEO-audited
companies to show has_ssl=false regardless of actual certificate status.
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>
The scraper was matching facebook.com/tr (Meta Pixel tracking endpoint)
as a valid Facebook profile handle. Added 'tr', 'privacy', 'policies',
'ads', 'business', 'legal', 'flx' to the Facebook exclusion list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>