nordabiz/docs/architecture/04-flask-components.md
Maciej Pienczyn 23493f0b61 docs: Aktualizacja dokumentacji do Gemini 3 Flash
Zmiana domyślnego modelu w dokumentacji i kodzie:
- gemini-2.5-flash → gemini-3-flash-preview
- gemini-2.5-pro → gemini-3-pro-preview

Zaktualizowane pliki:
- README.md - opis technologii
- docs/architecture/*.md - diagramy i przepływy
- nordabiz_chat.py - fallback model name
- zopk_news_service.py - model dla AI evaluation
- templates/admin/zopk_dashboard.html - wyświetlany model

Zachowano mapowania legacy modeli dla kompatybilności wstecznej.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 14:19:05 +01:00

54 KiB
Raw Blame History

Flask Application Component Diagram (C4 Level 3)

Document Version: 1.0 Last Updated: 2026-01-10 Status: Production LIVE Diagram Type: C4 Model - Level 3 (Components)


Overview

This diagram shows the internal component structure of the Flask web application. It illustrates:

  • What components exist within the Flask application (routes, services, models)
  • How components interact with each other
  • Responsibilities of each component layer
  • Code organization and module structure

Abstraction Level: Component (C4 Level 3) Audience: Developers, Technical Leads Purpose: Understanding internal application architecture for development and maintenance

Application Size: ~13,144 lines of Python code Total Routes: 90+ HTTP endpoints Database Models: 36 SQLAlchemy models Service Components: 7 service layer modules


Flask Component Architecture Diagram

graph TB
    %% External input
    HTTP["📨 HTTP Requests<br/>(from NPM Proxy)"]

    %% Flask App boundary
    subgraph "Flask Application (app.py - 13,144 lines)"

        %% Request handling layer
        subgraph "Request Handling Layer"
            Router["🔀 Flask Router<br/>(URL routing)"]
            Auth["🔐 Authentication<br/>(Flask-Login)<br/>User loader, session mgmt"]
            CSRF["🛡️ CSRF Protection<br/>(Flask-WTF)<br/>Token validation"]
            RateLimit["⏱️ Rate Limiter<br/>(Flask-Limiter)<br/>200/day, 50/hour"]
        end

        %% Route categories
        subgraph "Route Controllers (90+ endpoints)"
            PublicRoutes["🌐 Public Routes (8)<br/>/, /search, /company/slug<br/>/aktualnosci, /health"]
            AuthRoutes["🔑 Auth Routes (7)<br/>/register, /login, /logout<br/>/verify-email, /reset-password"]
            UserRoutes["👤 User Routes (21)<br/>/dashboard, /chat, /forum<br/>/wiadomosci, /kalendarz, /tablica"]
            AdminRoutes["👨‍💼 Admin Routes (28)<br/>/admin/seo, /admin/forum<br/>/admin/users, /admin/fees"]
            APIRoutes["🔌 API Routes (26)<br/>/api/chat, /api/seo, /api/companies<br/>/api/notifications, /api/recommendations"]
            AuditRoutes["📊 Audit Routes (4)<br/>/audit/seo, /audit/social<br/>/audit/gbp, /audit/it"]
        end

        %% Service layer
        subgraph "Service Layer (7 modules)"
            SearchService["🔍 SearchService<br/>search_service.py<br/>~400 lines<br/><br/>• Company search<br/>• NIP/REGON lookup<br/>• PostgreSQL FTS<br/>• Synonym expansion<br/>• Fuzzy matching<br/>• Result scoring"]

            ChatService["💬 ChatService<br/>nordabiz_chat.py<br/>~800 lines<br/><br/>• AI conversation<br/>• Context building<br/>• Session management<br/>• Token tracking<br/>• Message history"]

            GeminiService["🤖 GeminiService<br/>gemini_service.py<br/>~500 lines<br/><br/>• AI text generation<br/>• Image analysis<br/>• Streaming responses<br/>• Cost tracking<br/>• Error handling"]

            EmailService["📧 EmailService<br/>email_service.py<br/>~200 lines<br/><br/>• MS Graph OAuth<br/>• Email sending<br/>• Template rendering<br/>• Error handling"]

            KRSService["🏛️ KRSService<br/>krs_api_service.py<br/>~300 lines<br/><br/>• Company verification<br/>• Registry data fetch<br/>• Data validation<br/>• Caching"]

            GBPService["📊 GBPService<br/>gbp_audit_service.py<br/>~600 lines<br/><br/>• Places API search<br/>• Profile analysis<br/>• AI recommendations<br/>• Audit reporting"]

            ITService["🖥️ ITService<br/>it_audit_service.py<br/>~500 lines<br/><br/>• IT maturity assess<br/>• Question scoring<br/>• Report generation<br/>• Recommendations"]
        end

        %% Database layer
        subgraph "Database Layer (database.py - ~1,500 lines)"
            ORM["🗄️ SQLAlchemy ORM<br/>Session management<br/>Query building"]

            subgraph "Domain Models (36 total)"
                CoreModels["📂 Core Domain (5)<br/>Company, User, Category<br/>CompanyOwner, SearchHistory"]

                ContentModels["📝 Content Domain (6)<br/>CompanyNews, NewsVerification<br/>ForumTopic, ForumReply, ClassifiedAd<br/>CompanyPhoto"]

                SocialModels["👥 Social Domain (5)<br/>CompanySocialMedia<br/>SocialMediaAudit<br/>SocialMediaProfile<br/>Recommendation, Like"]

                AuditModels["📊 Audit Domain (4)<br/>SEOMetrics, GBPAudit<br/>ITInfrastructureAudit<br/>DigitalMaturityScore"]

                ChatModels["💬 Chat Domain (3)<br/>ChatSession, ChatMessage<br/>GeminiUsage"]

                CommunityModels["🤝 Community Domain (5)<br/>Event, EventAttendee<br/>MembershipFee, Message<br/>Notification"]

                SystemModels["⚙️ System Domain (8)<br/>EmailVerification, PasswordReset<br/>APIQuota, APILog, DataQualityCheck<br/>ActivityLog, AuditLog, SystemSetting"]
            end
        end

        %% Template rendering
        Templates["📄 Template Engine<br/>(Jinja2)<br/>HTML rendering<br/>Template inheritance"]

        %% Static files
        Static["🎨 Static Assets<br/>CSS, JavaScript, Images"]
    end

    %% External dependencies
    Database[("💾 PostgreSQL<br/>Database<br/>36 tables")]
    GeminiAPI["🤖 Gemini API<br/>(external)"]
    BraveAPI["🔍 Brave API<br/>(external)"]
    PageSpeedAPI["📊 PageSpeed API<br/>(external)"]
    PlacesAPI["📍 Places API<br/>(external)"]
    KRSAPI["🏛️ KRS API<br/>(external)"]
    MSGraphAPI["📧 MS Graph API<br/>(external)"]

    %% Request flow
    HTTP --> Router
    Router --> Auth
    Router --> CSRF
    Router --> RateLimit

    Auth --> PublicRoutes
    Auth --> AuthRoutes
    Auth --> UserRoutes
    Auth --> AdminRoutes
    Auth --> APIRoutes
    Auth --> AuditRoutes

    %% Route to service connections
    PublicRoutes --> SearchService
    PublicRoutes --> Templates

    UserRoutes --> ChatService
    UserRoutes --> SearchService
    UserRoutes --> Templates

    AdminRoutes --> GBPService
    AdminRoutes --> ITService
    AdminRoutes --> Templates

    APIRoutes --> ChatService
    APIRoutes --> SearchService
    APIRoutes --> GBPService

    AuditRoutes --> Templates

    %% Service to service connections
    ChatService --> SearchService
    ChatService --> GeminiService
    GBPService --> GeminiService

    %% Service to external API connections
    GeminiService --> GeminiAPI
    ChatService --> GeminiAPI
    SearchService --> Database
    EmailService --> MSGraphAPI
    KRSService --> KRSAPI
    GBPService --> PlacesAPI

    %% Database access
    PublicRoutes --> ORM
    UserRoutes --> ORM
    AdminRoutes --> ORM
    APIRoutes --> ORM

    ORM --> CoreModels
    ORM --> ContentModels
    ORM --> SocialModels
    ORM --> AuditModels
    ORM --> ChatModels
    ORM --> CommunityModels
    ORM --> SystemModels

    CoreModels --> Database
    ContentModels --> Database
    SocialModels --> Database
    AuditModels --> Database
    ChatModels --> Database
    CommunityModels --> Database
    SystemModels --> Database

    %% Template rendering
    Templates --> Static

    %% Styling
    classDef routeStyle fill:#1168bd,stroke:#0b4884,color:#ffffff,stroke-width:2px
    classDef serviceStyle fill:#85bbf0,stroke:#5d92c7,color:#000000,stroke-width:2px
    classDef modelStyle fill:#50c878,stroke:#3da35f,color:#000000,stroke-width:2px
    classDef infraStyle fill:#ff9f1c,stroke:#cc7f16,color:#000000,stroke-width:2px
    classDef externalStyle fill:#999999,stroke:#666666,color:#ffffff,stroke-width:2px
    classDef databaseStyle fill:#438dd5,stroke:#2e6295,color:#ffffff,stroke-width:3px

    class PublicRoutes,AuthRoutes,UserRoutes,AdminRoutes,APIRoutes,AuditRoutes routeStyle
    class SearchService,ChatService,GeminiService,EmailService,KRSService,GBPService,ITService serviceStyle
    class CoreModels,ContentModels,SocialModels,AuditModels,ChatModels,CommunityModels,SystemModels modelStyle
    class Router,Auth,CSRF,RateLimit,ORM,Templates,Static infraStyle
    class GeminiAPI,BraveAPI,PageSpeedAPI,PlacesAPI,KRSAPI,MSGraphAPI externalStyle
    class Database databaseStyle

Component Descriptions

1. Request Handling Layer

🔀 Flask Router

Location: app.py (Flask core) Responsibility: URL pattern matching and request routing Technology: Flask routing decorators (@app.route())

Key Features:

  • 90+ registered routes across 6 categories
  • RESTful API endpoints (/api/*)
  • Dynamic URL parameters (<slug>, <id>)
  • Multiple HTTP methods (GET, POST, PUT, DELETE)

Example Routes:

@app.route('/')                          # Homepage
@app.route('/company/<slug>')            # Company profile
@app.route('/api/chat/<id>/message')     # API endpoint
@app.route('/admin/seo')                 # Admin panel

🔐 Authentication (Flask-Login)

Location: app.py (lines ~200-400) Responsibility: User authentication and session management Technology: Flask-Login extension

Key Features:

  • Session-based authentication (cookies)
  • User loader callback (@login_manager.user_loader)
  • Login required decorator (@login_required)
  • Remember me functionality
  • Session persistence

Authentication Levels:

  • Public: Anonymous access allowed
  • User: Requires login (current_user.is_authenticated)
  • Admin: Requires admin flag (current_user.is_admin)

Session Storage: Server-side sessions in PostgreSQL (or cookies for simple data)

🛡️ CSRF Protection (Flask-WTF)

Location: app.py (Flask-WTF integration) Responsibility: Cross-Site Request Forgery protection Technology: Flask-WTF CSRFProtect

Key Features:

  • Automatic CSRF token generation
  • Form validation with CSRF tokens
  • AJAX request protection (X-CSRFToken header)
  • Token rotation on authentication changes

Protected Routes: All POST, PUT, DELETE requests Exempt Routes: /health, /api/webhooks (if needed)

⏱️ Rate Limiter (Flask-Limiter)

Location: app.py (Flask-Limiter integration) Responsibility: API rate limiting and abuse prevention Technology: Flask-Limiter

Rate Limits:

  • Global Default: 200 requests/day, 50 requests/hour
  • Chat API: 100 requests/day (AI cost control)
  • Search API: 200 requests/hour
  • Admin API: Unlimited (trusted users)

Storage: Redis (production) or in-memory (development) Key Function: get_remote_address() for IP-based limiting


2. Route Controllers (90+ endpoints)

🌐 Public Routes (8 endpoints)

Authentication: None required Purpose: Publicly accessible pages

Route Method Description Template
/ GET Homepage - company directory index.html
/search GET Search companies search_results.html
/company/<slug> GET Company profile page company_detail.html
/aktualnosci GET News feed news.html
/health GET Health check (JSON) -
/release-notes GET Release notes release_notes.html
/api/companies GET JSON export of companies -
/api/verify-nip GET NIP verification API -

Key Features:

  • No authentication required
  • Cacheable responses
  • SEO-optimized (meta tags, structured data)
  • Rate limited to prevent scraping

🔑 Auth Routes (7 endpoints)

Authentication: Mixed (public registration, authenticated logout) Purpose: User authentication lifecycle

Route Method Description Authentication
/register GET, POST User registration Public
/login GET, POST User login Public
/logout GET User logout Required
/verify-email/<token> GET Email verification Public
/resend-verification POST Resend verification email Public
/reset-password GET, POST Password reset request Public
/reset-password/<token> GET, POST Password reset form Public

Security Features:

  • Password hashing (bcrypt)
  • Email verification required
  • Password strength validation
  • Rate limiting on registration (5/hour)
  • CSRF protection on all forms

👤 User Routes (21 endpoints)

Authentication: Required (@login_required) Purpose: Authenticated user features

Categories:

  • Dashboard: /dashboard - User overview
  • Chat: /chat - AI assistant interface
  • Forum: /forum, /forum/nowy, /forum/<id>, /forum/<id>/odpowiedz (7 routes)
  • Messages: /wiadomosci, /wiadomosci/nowa, /wiadomosci/<id> (5 routes)
  • Calendar: /kalendarz, /kalendarz/<id>, /kalendarz/<id>/rsvp (3 routes)
  • Classifieds: /tablica, /tablica/nowe, /tablica/<id> (3 routes)
  • IT Audit: /it-audit/form - IT maturity self-assessment

Key Features:

  • Personal dashboard with activity feed
  • AI chat with conversation history
  • Forum participation (topics, replies, moderation)
  • Private messaging between members
  • Event calendar with RSVP
  • Classifieds board for member offers
  • IT infrastructure self-audit

👨‍💼 Admin Routes (28 endpoints)

Authentication: Required + Admin flag (current_user.is_admin) Purpose: Administrative functions

Categories:

SEO Management (1 route):

  • /admin/seo - SEO audit dashboard

Social Media Management (2 routes):

  • /admin/social-media - Social media profiles overview
  • /admin/social-audit - Social media audit results

GBP Management (1 route):

  • /admin/gbp-audit - Google Business Profile audit dashboard

IT Audit Management (1 route):

  • /admin/it-audit - IT audit results dashboard

Forum Moderation (5 routes):

  • /admin/forum - Forum overview
  • /admin/forum/topic/<id>/pin - Pin topic
  • /admin/forum/topic/<id>/delete - Delete topic
  • /admin/forum/reply/<id>/delete - Delete reply
  • /admin/forum/user/<id>/ban - Ban user from forum

Recommendations Management (3 routes):

  • /admin/recommendations - Pending recommendations
  • /admin/recommendations/<id>/approve - Approve recommendation
  • /admin/recommendations/<id>/reject - Reject recommendation

User Management (8 routes):

  • /admin/users - User list
  • /admin/users/<id>/toggle-admin - Toggle admin status
  • /admin/users/<id>/toggle-active - Activate/deactivate user
  • /admin/users/<id>/reset-password - Admin password reset
  • /admin/users/<id>/delete - Delete user account
  • /admin/users/<id>/impersonate - Login as user (debug)
  • /admin/users/export - Export user data (CSV)
  • /admin/users/bulk-action - Bulk operations

Fees Management (5 routes):

  • /admin/fees - Membership fees overview
  • /admin/fees/generate - Generate monthly fees
  • /admin/fees/<id>/mark-paid - Mark fee as paid
  • /admin/fees/<id>/send-reminder - Send payment reminder
  • /admin/fees/export - Export fees data

Events Management (3 routes):

  • /admin/kalendarz - Event management
  • /admin/kalendarz/nowy - Create new event
  • /admin/kalendarz/<id>/edit - Edit event

Analytics (3 routes):

  • /admin/chat-analytics - AI chat usage analytics
  • /admin/debug - Debug information panel
  • /admin/digital-maturity - Digital maturity overview

Security:

  • All routes check current_user.is_admin
  • Action logging to audit_log table
  • Confirmation dialogs for destructive actions
  • CSRF protection on all POST requests

🔌 API Routes (26 endpoints)

Authentication: Mixed (some require login, some admin-only) Purpose: JSON API for AJAX requests and external integrations Response Format: JSON

Chat API (4 endpoints):

  • POST /api/chat/start - Start new chat session (user auth)
  • POST /api/chat/<id>/message - Send chat message (user auth)
  • GET /api/chat/<id>/history - Get chat history (user auth)
  • DELETE /api/chat/<id> - Delete chat session (user auth)

SEO API (3 endpoints):

  • POST /api/seo/audit - Trigger SEO audit (admin only)
  • GET /api/seo/audit/<slug> - Get audit results (public)
  • GET /api/seo/dashboard - Dashboard data (admin only)

GBP API (3 endpoints):

  • POST /api/gbp/audit - Trigger GBP audit (admin only)
  • GET /api/gbp/audit/<slug> - Get audit results (public)
  • GET /api/gbp/dashboard - Dashboard data (admin only)

Social Media API (1 endpoint):

  • POST /api/social/audit - Trigger social audit (admin only)

Notifications API (4 endpoints):

  • GET /api/notifications - Get user notifications (user auth)
  • PUT /api/notifications/<id>/read - Mark as read (user auth)
  • PUT /api/notifications/read-all - Mark all as read (user auth)
  • DELETE /api/notifications/<id> - Delete notification (user auth)

Recommendations API (3 endpoints):

  • GET /api/recommendations/<id> - Get recommendation details (user auth)
  • POST /api/recommendations/create - Create recommendation (user auth)
  • DELETE /api/recommendations/<id> - Delete recommendation (user auth)

Messages API (1 endpoint):

  • GET /api/messages/unread-count - Get unread count (user auth)

Utility API (5 endpoints):

  • GET /api/verify-nip - Verify NIP number (public)
  • GET /api/check-email - Check email availability (public)
  • GET /api/model-info - Get AI model info (public)
  • GET /api/companies - Export companies JSON (public)
  • GET /api/search-suggestions - Search autocomplete (public)

Common Patterns:

  • JSON request/response
  • HTTP status codes (200, 201, 400, 401, 403, 404, 500)
  • Error messages in {"error": "message"} format
  • Success messages in {"success": true, "data": {...}} format
  • Rate limiting applied
  • CORS headers when needed

📊 Audit Routes (4 endpoints)

Authentication: Public (read-only audit reports) Purpose: Display audit results for companies

Route Description Template
/audit/seo/<slug> SEO audit report audit_seo.html
/audit/social/<slug> Social media audit report audit_social.html
/audit/gbp/<slug> Google Business Profile audit audit_gbp.html
/audit/it/<slug> IT infrastructure audit audit_it.html

Key Features:

  • Public access (no login required)
  • Read-only reports
  • PDF export capability (planned)
  • Share links for business owners
  • Recommendations and action items
  • Historical audit comparisons

3. Service Layer (7 modules)

🔍 SearchService (search_service.py - ~400 lines)

Purpose: Unified company search across multiple strategies Primary Function: search_companies(db, query, limit=10)

Search Strategies:

  1. NIP/REGON Direct Lookup - Exact match on identifiers
  2. Synonym Expansion - Expand keywords (e.g., "strony" → www, web, portal)
  3. PostgreSQL FTS - Full-text search with tsvector (production)
  4. Fuzzy Matching - pg_trgm for typo tolerance
  5. SQLite Fallback - Keyword scoring (development only)

Scoring System:

  • Name match: +10 points
  • Services match: +8 points
  • Competencies match: +7 points
  • Description match: +5 points
  • City match: +3 points

Configuration:

  • Max Results: 10 (configurable)
  • Min Score: 3 (filter low-quality matches)
  • Synonyms: Defined in SEARCH_SYNONYMS dict

Error Handling:

  • PostgreSQL FTS failure → rollback + fallback to SQLite
  • Empty queries → return empty list
  • Invalid parameters → raise ValueError

Usage Example:

from search_service import search_companies

results = search_companies(db, "strony www", limit=10)
# Returns: List[SearchResult(company, score, match_type)]

💬 ChatService (nordabiz_chat.py - ~800 lines)

Purpose: AI chat assistant with company context Primary Function: process_chat_message(session_id, user_message)

Key Responsibilities:

  1. Session Management - Create, load, and manage chat sessions
  2. Context Building - Find relevant companies (max 8)
  3. History Management - Last 10 messages per session
  4. AI Integration - Call Gemini API with streaming
  5. Token Tracking - Monitor usage and costs

Context Limits:

  • Max Companies: 8 (prevents token overflow)
  • Max Messages: 10 (sliding window)
  • Max Tokens: ~30,000 input tokens
  • Streaming: Real-time response chunks

Database Tables:

  • chat_sessions - Session metadata
  • chat_messages - Message history
  • gemini_usage - Token usage tracking

Cost Tracking:

  • Input tokens × $0.075 per 1M
  • Output tokens × $0.30 per 1M
  • Stored in gemini_usage table

Example Flow:

# 1. User sends message
user_msg = "Kto robi strony www?"

# 2. Search for relevant companies
companies = search_companies(db, user_msg, limit=8)

# 3. Build context with last 10 messages
context = build_context(session, companies, history)

# 4. Call Gemini API
response = gemini_service.generate_streaming(context)

# 5. Save message and track tokens
save_message(session, user_msg, response)
track_usage(session, input_tokens, output_tokens)

🤖 GeminiService (gemini_service.py - ~500 lines)

Purpose: Google Gemini AI API integration Primary Functions:

  • generate_text(prompt, model="gemini-3-flash-preview")
  • generate_streaming(prompt, model="gemini-3-flash-preview")
  • analyze_image(image_path, prompt)
  • moderate_content(text)

Supported Models:

  • gemini-3-flash-preview - Default, 7x better reasoning (free tier)
  • gemini-3-pro-preview - Advanced reasoning, 2M context ($2.00/1M tokens)

Key Features:

  1. Text Generation - Chat, content creation, analysis
  2. Image Analysis - Logo recognition, screenshot analysis
  3. Streaming Responses - Real-time output for chat
  4. Content Moderation - Safety filters (harassment, hate, violence)
  5. Cost Tracking - Token usage monitoring

Configuration:

  • API Key: GEMINI_API_KEY (from .env)
  • Rate Limit: 200 requests/day (free tier)
  • Max Tokens: 1M input, 8K output (flash model)
  • Temperature: 0.7 (default for chat)

Safety Settings:

safety_settings = {
    "HARM_CATEGORY_HARASSMENT": "BLOCK_MEDIUM_AND_ABOVE",
    "HARM_CATEGORY_HATE_SPEECH": "BLOCK_MEDIUM_AND_ABOVE",
    "HARM_CATEGORY_SEXUALLY_EXPLICIT": "BLOCK_MEDIUM_AND_ABOVE",
    "HARM_CATEGORY_DANGEROUS_CONTENT": "BLOCK_MEDIUM_AND_ABOVE",
}

Error Handling:

  • API errors → retry with exponential backoff
  • Rate limit exceeded → graceful degradation
  • Safety block → return user-friendly error message

📧 EmailService (email_service.py - ~200 lines)

Purpose: Email notifications via Microsoft Graph API Primary Function: send_email(to, subject, body_html)

Authentication: OAuth 2.0 (MSAL) Configuration:

  • Client ID: MS_GRAPH_CLIENT_ID
  • Client Secret: MS_GRAPH_CLIENT_SECRET
  • Tenant ID: MS_GRAPH_TENANT_ID
  • Sender: noreply@nordabiznes.pl

Email Types:

  1. Email Verification - Registration confirmation
  2. Password Reset - Password recovery
  3. Payment Reminders - Membership fees
  4. Event Notifications - Calendar invites
  5. Forum Notifications - New replies
  6. Admin Alerts - System notifications

Template Rendering:

  • Jinja2 HTML templates in templates/emails/
  • Plain text fallback for compatibility
  • Inline CSS for email client support

Error Handling:

  • OAuth token refresh on 401
  • Retry on transient failures (5xx)
  • Fallback to local logging on total failure

🏛️ KRSService (krs_api_service.py - ~300 lines)

Purpose: Polish company registry (KRS) verification Primary Function: fetch_company_data(krs_number)

API: KRS Open API (Ministry of Justice) Endpoint: https://api-krs.ms.gov.pl/api/krs/OdpisAktualny/{krs} Authentication: Public API (no key required)

Data Retrieved:

  • Company Name - Legal name
  • NIP - Tax identification number
  • REGON - Statistical number
  • Address - Registered office
  • Legal Form - Sp. z o.o., S.A., etc.
  • Share Capital - Initial capital
  • Board Members - Management names
  • Shareholders - Ownership structure

Caching:

  • Database table: company_krs_data
  • TTL: 30 days (data rarely changes)
  • Refresh on demand via admin panel

Error Handling:

  • KRS not found → return None
  • API timeout → retry 3 times
  • Invalid KRS format → validation error

📊 GBPService (gbp_audit_service.py - ~600 lines)

Purpose: Google Business Profile auditing Primary Functions:

  • search_place(company_name, address)
  • get_place_details(place_id)
  • generate_recommendations(audit_data)

APIs Used:

  1. Google Places API - Place search, details, reviews
  2. Gemini AI - Generate improvement recommendations

Audit Metrics:

  • Profile Completeness - % of filled fields
  • Review Count - Number of Google reviews
  • Average Rating - Star rating (1-5)
  • Response Rate - % of reviews replied to
  • Photo Count - Number of uploaded photos
  • Verification Status - Verified vs unverified

Recommendations Generated by AI:

  • Complete missing profile fields
  • Respond to unanswered reviews
  • Upload more photos (categories: exterior, interior, products, team)
  • Improve category selection
  • Add special hours (holidays, events)
  • Enable messaging

Database Storage:

  • gbp_audits - Audit results
  • gbp_recommendations - AI-generated recommendations

Cost:

  • Places API: $0.017 per search, $0.017 per details call
  • Gemini AI: ~$0.02 per recommendation generation

🖥️ ITService (it_audit_service.py - ~500 lines)

Purpose: IT infrastructure maturity assessment Primary Function: calculate_maturity_score(responses)

Assessment Areas (7 domains):

  1. Website & Online Presence - Website quality, SEO, analytics
  2. Email & Communication - Professional email, collaboration tools
  3. Data Security - Backups, encryption, access control
  4. Cloud Services - Cloud adoption, SaaS usage
  5. Business Software - ERP, CRM, accounting tools
  6. IT Support - Support availability, SLA
  7. Digital Skills - Team training, digital literacy

Scoring:

  • Level 0: No implementation (0 points)
  • Level 1: Basic implementation (25 points)
  • Level 2: Intermediate (50 points)
  • Level 3: Advanced (75 points)
  • Level 4: Excellent (100 points)

Maturity Levels:

  • 0-25%: Basic - Minimal digital presence
  • 26-50%: Developing - Some digital tools
  • 51-75%: Advanced - Good digital infrastructure
  • 76-100%: Excellent - Mature digital organization

Report Includes:

  • Overall maturity score
  • Domain-specific scores
  • Recommendations for improvement
  • Comparison to industry average
  • Action plan with priorities

Database Storage:

  • it_infrastructure_audits - Audit results
  • digital_maturity_scores - Historical scores

4. Database Layer (36 SQLAlchemy Models)

🗄️ SQLAlchemy ORM

Location: database.py (~1,500 lines) Purpose: Object-Relational Mapping and database abstraction

Key Features:

  • Database Agnostic: PostgreSQL (production), SQLite (development)
  • Connection Pooling: SQLAlchemy pool management
  • Session Management: Scoped sessions per request
  • Query Builder: Pythonic query construction
  • Relationship Mapping: One-to-many, many-to-many, one-to-one
  • Lazy Loading: Relationships loaded on demand
  • Cascade Behaviors: Delete cascade, update cascade

Session Management:

# Request-scoped session (Flask integration)
@app.before_request
def create_session():
    db.session = db.Session()

@app.teardown_request
def close_session(exception=None):
    db.session.close()

Connection String:

# Production
DATABASE_URL = "postgresql://nordabiz_app:password@127.0.0.1:5432/nordabiz"

# Development
DATABASE_URL = "postgresql://postgres:postgres@localhost:5433/nordabiz"

📂 Domain Models (36 total)

Core Domain (5 models)

Purpose: Fundamental business entities

1. Company

  • Fields: name, slug, nip, regon, krs, category, description, website, email, phone, city, address, logo_url, verified_at, data_quality_level, created_at, updated_at
  • Relationships: social_media (1:N), news (1:N), photos (1:N), audits (1:N), recommendations (1:N), fees (1:N)
  • Indexes: slug (unique), nip (unique), regon (unique), krs (unique), category, city
  • Full-Text Search: tsvector on name, description, services, competencies

2. User

  • Fields: email, password_hash, company_id, is_admin, is_active, email_verified_at, created_at, last_login_at
  • Relationships: company (N:1), chat_sessions (1:N), messages_sent (1:N), messages_received (1:N), forum_topics (1:N), forum_replies (1:N)
  • Indexes: email (unique), company_id, is_admin
  • Authentication: bcrypt password hashing, Flask-Login integration

3. Category

  • Fields: name, slug, icon, description, company_count
  • Relationships: companies (1:N)
  • Values: IT, Construction, Services, Production, Trade, Other

4. CompanyOwner

  • Fields: company_id, name, role, shares_percent, person_url, source
  • Relationships: company (N:1)
  • Purpose: Track board members and shareholders (from rejestr.io)

5. SearchHistory

  • Fields: user_id, query, results_count, clicked_company_id, created_at
  • Relationships: user (N:1), clicked_company (N:1)
  • Purpose: Search analytics and personalization
Content Domain (6 models)

Purpose: User-generated and external content

6. CompanyNews

  • Fields: company_id, title, description, url, source, published_at, news_type, relevance_score, status, moderated_by, moderated_at, rejection_reason
  • Relationships: company (N:1), moderator (N:1), verification (1:1)
  • Status: pending, approved, rejected
  • Types: news_mention, press_release, award

7. NewsVerification

  • Fields: news_id, verified_by, verified_at, verification_notes, ai_confidence_score
  • Relationships: news (1:1), verifier (N:1)
  • Purpose: Track AI and manual verification of news

8. ForumTopic

  • Fields: author_id, title, content, category, is_pinned, is_locked, view_count, reply_count, created_at, updated_at
  • Relationships: author (N:1), replies (1:N)
  • Categories: general, announcements, networking, help, offers

9. ForumReply

  • Fields: topic_id, author_id, content, created_at, updated_at
  • Relationships: topic (N:1), author (N:1)

10. ClassifiedAd

  • Fields: company_id, title, description, category, price, image_url, expires_at, is_active, created_at
  • Relationships: company (N:1)
  • Categories: offers, requests, announcements

11. CompanyPhoto

  • Fields: company_id, url, caption, category, uploaded_by, created_at
  • Relationships: company (N:1), uploader (N:1)
  • Categories: exterior, interior, team, products, events
Social Domain (5 models)

Purpose: Social media and community features

12. CompanySocialMedia

  • Fields: company_id, platform, url, verified_at, source, is_valid, last_checked_at, check_status, page_name, followers_count
  • Relationships: company (N:1), audits (1:N)
  • Platforms: facebook, instagram, linkedin, youtube, tiktok, twitter

13. SocialMediaAudit

  • Fields: company_id, audit_data, audit_type, audited_at
  • Relationships: company (N:1)
  • Types: profile_discovery, activity_check, engagement_analysis

14. SocialMediaProfile

  • Fields: social_media_id, profile_data, last_fetched_at, fetch_status
  • Relationships: social_media (1:1)
  • Purpose: Cache profile data from APIs

15. Recommendation

  • Fields: recommender_company_id, recommended_company_id, comment, rating, status, created_at, moderated_at
  • Relationships: recommender (N:1), recommended (N:1)
  • Status: pending, approved, rejected

16. Like

  • Fields: user_id, target_type, target_id, created_at
  • Relationships: user (N:1)
  • Target Types: forum_topic, forum_reply, company_news, company
Audit Domain (4 models)

Purpose: SEO, GBP, and IT auditing

17. SEOMetrics

  • Fields: company_id, url, seo_score, performance_score, accessibility_score, best_practices_score, pwa_score, audit_data, audited_at
  • Relationships: company (N:1)
  • Source: Google PageSpeed Insights API

18. GBPAudit

  • Fields: company_id, place_id, audit_data, profile_completeness, review_count, average_rating, photo_count, verified_status, audited_at
  • Relationships: company (N:1), recommendations (1:N)
  • Source: Google Places API + Gemini AI

19. ITInfrastructureAudit

  • Fields: company_id, responses, overall_score, domain_scores, recommendations, audited_at
  • Relationships: company (N:1)
  • Purpose: IT maturity self-assessment

20. DigitalMaturityScore

  • Fields: company_id, score, level, breakdown, calculated_at
  • Relationships: company (N:1)
  • Levels: basic, developing, advanced, excellent
Chat Domain (3 models)

Purpose: AI chat assistant

21. ChatSession

  • Fields: user_id, company_context, message_count, total_tokens, total_cost, started_at, last_message_at
  • Relationships: user (N:1), messages (1:N), usage (1:N)

22. ChatMessage

  • Fields: session_id, role, content, created_at
  • Relationships: session (N:1)
  • Roles: user, assistant, system

23. GeminiUsage

  • Fields: session_id, model, input_tokens, output_tokens, total_tokens, cost, created_at
  • Relationships: session (N:1)
  • Purpose: Track AI usage and costs
Community Domain (5 models)

Purpose: Events, fees, messaging, notifications

24. Event

  • Fields: title, description, location, start_time, end_time, organizer_id, max_attendees, rsvp_deadline, created_at
  • Relationships: organizer (N:1), attendees (1:N)

25. EventAttendee

  • Fields: event_id, user_id, status, rsvp_at
  • Relationships: event (N:1), user (N:1)
  • Status: pending, attending, declined

26. MembershipFee

  • Fields: company_id, period_start, period_end, amount, status, paid_at, payment_method, notes
  • Relationships: company (N:1)
  • Status: pending, paid, overdue

27. Message

  • Fields: sender_id, recipient_id, subject, body, is_read, read_at, created_at
  • Relationships: sender (N:1), recipient (N:1)

28. Notification

  • Fields: user_id, type, message, url, is_read, read_at, created_at
  • Relationships: user (N:1)
  • Types: new_news, news_approved, forum_reply, message_received, event_invite
System Domain (8 models)

Purpose: System management and logging

29. EmailVerification

  • Fields: user_id, token, expires_at, verified_at, created_at
  • Relationships: user (N:1)

30. PasswordReset

  • Fields: user_id, token, expires_at, used_at, created_at
  • Relationships: user (N:1)

31. APIQuota

  • Fields: api_name, quota_limit, quota_used, period_start, period_end
  • Purpose: Track API usage against quotas
  • APIs: gemini, brave, pagespeed, places

32. APILog

  • Fields: api_name, endpoint, request_data, response_status, response_time, created_at
  • Purpose: API call logging and debugging

33. DataQualityCheck

  • Fields: company_id, check_type, passed, issues, checked_at
  • Relationships: company (N:1)
  • Check Types: nip_verification, krs_verification, website_check, social_media_check

34. ActivityLog

  • Fields: user_id, action, target_type, target_id, ip_address, user_agent, created_at
  • Relationships: user (N:1)
  • Purpose: User activity tracking

35. AuditLog

  • Fields: user_id, action, target_type, target_id, changes, ip_address, created_at
  • Relationships: user (N:1)
  • Purpose: Admin action auditing

36. SystemSetting

  • Fields: key, value, description, updated_at
  • Purpose: Application configuration
  • Examples: maintenance_mode, registration_enabled, chat_enabled

5. Template Rendering

📄 Jinja2 Template Engine

Location: templates/ directory Purpose: Server-side HTML rendering

Template Structure:

templates/
├── base.html                  # Base template (layout)
├── components/                # Reusable components
│   ├── navbar.html
│   ├── footer.html
│   ├── company_card.html
│   └── pagination.html
├── index.html                 # Homepage
├── company_detail.html        # Company profile
├── search_results.html        # Search page
├── auth/                      # Authentication pages
│   ├── login.html
│   ├── register.html
│   └── reset_password.html
├── dashboard/                 # User dashboard
│   ├── dashboard.html
│   ├── chat.html
│   └── profile.html
├── admin/                     # Admin pages
│   ├── seo_dashboard.html
│   ├── forum_moderation.html
│   └── users.html
├── forum/                     # Forum pages
├── audit/                     # Audit report pages
└── emails/                    # Email templates

Template Inheritance:

{# base.html #}
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Norda Biznes{% endblock %}</title>
    {% block extra_css %}{% endblock %}
</head>
<body>
    {% include 'components/navbar.html' %}

    {% block content %}{% endblock %}

    {% include 'components/footer.html' %}

    <script>{% block extra_js %}{% endblock %}</script>
</body>
</html>

{# company_detail.html #}
{% extends 'base.html' %}

{% block title %}{{ company.name }} - Norda Biznes{% endblock %}

{% block content %}
    <h1>{{ company.name }}</h1>
    <p>{{ company.description }}</p>
{% endblock %}

Common Template Variables:

  • current_user - Logged-in user (Flask-Login)
  • request - Flask request object
  • config - App configuration
  • url_for() - URL generation function
  • get_flashed_messages() - Flash messages

Template Filters:

{{ company.created_at|datetimeformat }}     # Format datetime
{{ company.description|truncate(200) }}     # Truncate text
{{ company.name|title }}                    # Title case
{{ price|currency }}                        # Format currency
{{ url|urlize }}                            # Convert URLs to links

Security:

  • Auto-escaping: HTML is escaped by default
  • CSRF Tokens: Included in all forms via {{ csrf_token() }}
  • XSS Prevention: Jinja2 auto-escapes all variables

6. Static Assets

🎨 Static File Structure

Location: static/ directory

static/
├── css/
│   ├── main.css              # Main stylesheet
│   ├── admin.css             # Admin panel styles
│   └── components.css        # Component styles
├── js/
│   ├── main.js               # Global JavaScript
│   ├── chat.js               # AI chat functionality
│   ├── search.js             # Search autocomplete
│   └── admin.js              # Admin panel JS
├── images/
│   ├── logo.png              # Site logo
│   ├── companies/            # Company logos
│   └── icons/                # UI icons
└── uploads/                  # User uploads (not in Git)
    ├── logos/
    └── photos/

CSS Framework: Custom CSS (no Bootstrap/Tailwind) JavaScript: Vanilla JS (minimal dependencies) Icons: Font Awesome or SVG icons

Key JavaScript Modules:

  • chat.js - WebSocket-like streaming for AI chat
  • search.js - Autocomplete and instant search
  • admin.js - Admin dashboard interactions
  • forum.js - Forum post editing and moderation

Component Interaction Patterns

Flow:

User → /search?q=strony www
  ↓
Router → PublicRoutes.search()
  ↓
SearchService.search_companies(db, "strony www")
  ↓ (synonym expansion)
SearchService → PostgreSQL FTS (tsvector search)
  ↓
ORM → Company model + related data
  ↓
PublicRoutes → Templates (search_results.html)
  ↓
Jinja2 → HTML response
  ↓
User Browser

Key Components:

  • Router - /search route handler
  • SearchService - Query processing and scoring
  • Database - PostgreSQL FTS query
  • Templates - Jinja2 rendering
  • Static - CSS for search results

Pattern 2: AI Chat Request

Flow:

User → /api/chat/<id>/message (POST JSON)
  ↓
Router → APIRoutes.chat_message()
  ↓
Auth → Check @login_required
  ↓
RateLimit → Check API quota (100/day)
  ↓
CSRF → Validate token
  ↓
ChatService.process_message(session_id, message)
  ↓
SearchService.search_companies(db, message, limit=8)
  ↓
ChatService → Build context (companies + history)
  ↓
GeminiService.generate_streaming(prompt)
  ↓
Gemini API → Streaming response
  ↓
ChatService → Save message to DB
  ↓
ChatService → Track token usage
  ↓
JSON response → User (streaming chunks)

Key Components:

  • Router - /api/chat/<id>/message handler
  • Auth - Flask-Login authentication
  • RateLimit - API quota enforcement
  • ChatService - Session and context management
  • SearchService - Company discovery
  • GeminiService - AI integration
  • Database - Message and usage storage

Pattern 3: Admin SEO Audit

Flow:

Admin → /admin/seo (GET)
  ↓
Router → AdminRoutes.seo_dashboard()
  ↓
Auth → Check current_user.is_admin
  ↓
ORM → Load SEOMetrics + Company data
  ↓
Templates → Render admin_seo_dashboard.html
  ↓
User clicks "Audit Company X"
  ↓
JavaScript → POST /api/seo/audit (AJAX)
  ↓
Router → APIRoutes.trigger_seo_audit()
  ↓
Background Script → scripts/seo_audit.py
  ↓
PageSpeed API → Audit URL
  ↓
Background Script → Parse results
  ↓
ORM → Insert/update SEOMetrics
  ↓
JSON response → Update UI

Key Components:

  • Router - /admin/seo and /api/seo/audit handlers
  • Auth - Admin-only access control
  • Templates - Admin dashboard with AJAX
  • Static - JavaScript for audit triggering
  • Background Scripts - SEO audit execution
  • External API - Google PageSpeed Insights
  • Database - SEOMetrics storage

Pattern 4: User Registration

Flow:

User → /register (GET)
  ↓
Router → AuthRoutes.register()
  ↓
Templates → Render register.html (with CSRF token)
  ↓
User submits form
  ↓
POST /register
  ↓
Router → AuthRoutes.register()
  ↓
CSRF → Validate token
  ↓
RateLimit → Check registration quota (5/hour)
  ↓
Validation → Email, password strength, company_id
  ↓
ORM → Create User (bcrypt password hash)
  ↓
EmailVerification → Create token
  ↓
EmailService.send_email(verification email)
  ↓
MSGraph API → Send email
  ↓
Redirect → /login (with flash message)

Key Components:

  • Router - /register GET and POST handlers
  • CSRF - Form protection
  • RateLimit - Registration throttling
  • ORM - User creation
  • EmailService - Verification email
  • External API - Microsoft Graph for email
  • Templates - Registration form

Data Flow Patterns

Database Query Patterns

1. Simple Query (ORM):

# Get company by slug
company = db.session.query(Company).filter_by(slug='pixlab-sp-z-o-o').first()

2. Join Query (Relationships):

# Get company with social media
company = db.session.query(Company)\
    .options(joinedload(Company.social_media))\
    .filter_by(slug='pixlab-sp-z-o-o')\
    .first()

3. Full-Text Search (PostgreSQL):

# Search companies by keyword
results = db.session.query(Company)\
    .filter(Company.search_vector.match('strony www'))\
    .order_by(desc(func.ts_rank(Company.search_vector, func.to_tsquery('strony & www'))))\
    .limit(10)\
    .all()

4. Aggregation Query:

# Count companies by category
category_counts = db.session.query(
    Category.name,
    func.count(Company.id)
).join(Company).group_by(Category.name).all()

Error Handling Patterns

1. Service Layer Error Handling:

def search_companies(db, query, limit=10):
    try:
        # Try PostgreSQL FTS
        results = _search_fts(db, query, limit)
        return results
    except Exception as e:
        logger.error(f"FTS search failed: {e}")
        db.rollback()  # CRITICAL: Rollback failed transaction

        # Fallback to SQLite-style search
        return _search_fallback(db, query, limit)

2. API Route Error Handling:

@app.route('/api/chat/<int:session_id>/message', methods=['POST'])
@login_required
@limiter.limit("100/day")
def chat_message(session_id):
    try:
        data = request.get_json()

        if not data or 'message' not in data:
            return jsonify({"error": "Message required"}), 400

        response = chat_service.process_message(session_id, data['message'])
        return jsonify({"success": True, "response": response}), 200

    except ValueError as e:
        return jsonify({"error": str(e)}), 400
    except Exception as e:
        logger.exception("Chat error")
        return jsonify({"error": "Internal server error"}), 500

3. External API Error Handling:

def call_gemini_api(prompt):
    max_retries = 3
    retry_delay = 1  # seconds

    for attempt in range(max_retries):
        try:
            response = genai.generate_text(prompt)
            return response
        except genai.RateLimitError:
            logger.warning("Gemini rate limit exceeded")
            return {"error": "AI service temporarily unavailable"}
        except genai.APIError as e:
            if attempt < max_retries - 1:
                time.sleep(retry_delay * (2 ** attempt))  # Exponential backoff
                continue
            else:
                logger.error(f"Gemini API failed: {e}")
                raise

Authentication Flow

Login Flow:

1. User submits credentials → POST /login
2. Validate CSRF token
3. Query User by email
4. Verify password (bcrypt.check_password_hash)
5. Check email_verified_at (must not be null)
6. Check is_active flag
7. Flask-Login: login_user(user, remember=True)
8. Update last_login_at timestamp
9. Set session cookie (httponly, secure, samesite)
10. Redirect to /dashboard

Authorization Checks:

# Public route (no auth)
@app.route('/')
def index():
    # Anyone can access
    pass

# User route (requires login)
@app.route('/dashboard')
@login_required
def dashboard():
    # Must be authenticated
    pass

# Admin route (requires admin flag)
@app.route('/admin/users')
@login_required
def admin_users():
    if not current_user.is_admin:
        abort(403)  # Forbidden
    # Admin-only logic
    pass

Configuration and Environment

Environment Variables (.env)

Required Variables:

# Flask
SECRET_KEY=<random-secret-key>
FLASK_ENV=production  # or development

# Database
DATABASE_URL=postgresql://nordabiz_app:password@127.0.0.1:5432/nordabiz

# Google Gemini AI
GEMINI_API_KEY=<api-key>

# Brave Search API
BRAVE_SEARCH_API_KEY=<api-key>

# Google PageSpeed Insights
GOOGLE_PAGESPEED_API_KEY=<api-key>

# Google Places API
GOOGLE_PLACES_API_KEY=<api-key>

# Microsoft Graph API (Email)
MS_GRAPH_CLIENT_ID=<client-id>
MS_GRAPH_CLIENT_SECRET=<client-secret>
MS_GRAPH_TENANT_ID=<tenant-id>

# Rate Limiting
REDIS_URL=redis://localhost:6379/0  # Production only

# Session
SESSION_TYPE=filesystem  # or redis

⚠️ SECURITY WARNING:

  • NEVER commit .env file to Git
  • Use .env.example as template (without actual secrets)
  • Production secrets stored on server only

Application Configuration (app.py)

# Flask configuration
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_POOL_SIZE'] = 10
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 20

# Session configuration
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_PERMANENT'] = True
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)

# Security
app.config['WTF_CSRF_ENABLED'] = True
app.config['WTF_CSRF_TIME_LIMIT'] = None

# Rate limiting
app.config['RATELIMIT_STORAGE_URL'] = os.getenv('REDIS_URL', 'memory://')
app.config['RATELIMIT_HEADERS_ENABLED'] = True

Deployment Configuration

Gunicorn WSGI Server

systemd Service: /etc/systemd/system/nordabiznes.service

[Unit]
Description=Norda Biznes Partner
After=network.target postgresql.service

[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/var/www/nordabiznes
Environment="PATH=/var/www/nordabiznes/venv/bin"
ExecStart=/var/www/nordabiznes/venv/bin/gunicorn \
    --workers 4 \
    --bind 127.0.0.1:5000 \
    --timeout 120 \
    --access-logfile /var/log/nordabiznes/access.log \
    --error-logfile /var/log/nordabiznes/error.log \
    app:app

Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Key Settings:

  • Workers: 4 (2 × CPU cores + 1)
  • Bind: 127.0.0.1:5000 (localhost only, NPM proxies from external)
  • Timeout: 120 seconds (for long AI requests)
  • User: www-data (non-root for security)

Service Management:

# Start service
sudo systemctl start nordabiznes

# Stop service
sudo systemctl stop nordabiznes

# Restart service
sudo systemctl restart nordabiznes

# Check status
sudo systemctl status nordabiznes

# View logs
sudo journalctl -u nordabiznes -f

Logging and Monitoring

Application Logging

Configuration:

import logging

# Production logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/var/log/nordabiznes/app.log'),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger(__name__)

Log Locations:

  • Application: /var/log/nordabiznes/app.log
  • Gunicorn Access: /var/log/nordabiznes/access.log
  • Gunicorn Error: /var/log/nordabiznes/error.log
  • systemd: journalctl -u nordabiznes

Log Levels:

  • DEBUG: Development only, verbose output
  • INFO: General information (startup, shutdown, API calls)
  • WARNING: Degraded performance, fallback scenarios
  • ERROR: Errors that don't crash the app
  • CRITICAL: Errors that crash the app

Health Check Endpoint

Route: /health Method: GET Authentication: None (public)

Response:

{
  "status": "healthy",
  "database": "connected",
  "timestamp": "2026-01-10T12:00:00Z",
  "version": "1.0.0"
}

Usage:

  • NPM health checks
  • Monitoring systems (Zabbix, Prometheus)
  • Uptime monitoring (UptimeRobot)
  • Load balancer health checks

Security Features

1. Authentication Security

  • Password Hashing: bcrypt (cost factor 12)
  • Session Security: httponly, secure, samesite cookies
  • Email Verification: Required before login
  • Password Reset: Time-limited tokens (1 hour expiry)
  • Account Lockout: (Planned) After 5 failed attempts

2. Authorization

  • Three Levels: Public, User, Admin
  • Decorator Pattern: @login_required, @admin_required
  • Object-Level: Company owners can edit their profiles

3. Input Validation

  • CSRF Protection: All POST/PUT/DELETE requests
  • XSS Prevention: Jinja2 auto-escaping
  • SQL Injection: SQLAlchemy parameterized queries
  • File Upload: Whitelist extensions, size limits

4. API Security

  • Rate Limiting: 200/day global, 100/day chat
  • API Keys: Environment variables only
  • CORS: Disabled by default
  • HTTPS Only: All API calls to external services

5. Database Security

  • Localhost Only: PostgreSQL accepts only 127.0.0.1 connections
  • Password Auth: Strong passwords for DB users
  • Least Privilege: Application user has limited permissions
  • No Root Access: Application runs as www-data user

Higher-Level Diagrams

Same-Level Diagrams

Lower-Level Documentation

Infrastructure Documentation

Analysis Documents (Phase 1)


Maintenance Notes

When to Update This Diagram

Update this document when:

  • New routes are added to app.py
  • New service modules are created
  • Database models are added or significantly changed
  • Major refactoring of component structure
  • New external API integrations
  • Authentication/authorization logic changes

What NOT to Update Here

Don't update for:

  • Bug fixes that don't change architecture
  • Template content changes
  • CSS/JS styling updates
  • Minor field additions to existing models
  • Configuration value changes

Review Frequency

  • Quarterly review during architecture meetings
  • After major releases (version bumps)
  • Before onboarding new developers

Glossary

C4 Model

  • Software architecture diagramming approach with 4 levels: Context, Container, Component, Code

Flask

  • Python web framework for building web applications

SQLAlchemy

  • Object-Relational Mapping (ORM) library for Python

Gunicorn

  • WSGI HTTP server for Python applications

WSGI

  • Web Server Gateway Interface, Python web application standard

ORM

  • Object-Relational Mapping, database abstraction layer

FTS

  • Full-Text Search, PostgreSQL text search feature

pg_trgm

  • PostgreSQL extension for fuzzy text matching using trigrams

Jinja2

  • Template engine for Python (used by Flask)

bcrypt

  • Password hashing algorithm

CSRF

  • Cross-Site Request Forgery, web security vulnerability

XSS

  • Cross-Site Scripting, web security vulnerability

Rate Limiting

  • Controlling request frequency to prevent abuse

Streaming Response

  • Sending response data in chunks (used for AI chat)

Document Status: Complete Last Reviewed: 2026-01-10 Next Review: 2026-04-10 (Quarterly)