- Zmiana nazwy: "Norda Biznes Hub" → "Norda Biznes Partner" - Aktualizacja modelu AI: Gemini 2.0 Flash → Gemini 3 Flash - Zachowano historyczne odniesienia w timeline i dokumentacji Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1713 lines
54 KiB
Markdown
1713 lines
54 KiB
Markdown
# 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
|
||
|
||
```mermaid
|
||
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:**
|
||
```python
|
||
@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:**
|
||
```python
|
||
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:**
|
||
```python
|
||
# 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-2.5-flash")`
|
||
- `generate_streaming(prompt, model="gemini-2.5-flash")`
|
||
- `analyze_image(image_path, prompt)`
|
||
- `moderate_content(text)`
|
||
|
||
**Supported Models:**
|
||
- **gemini-2.5-flash** - Fast, cheap ($0.075/1M tokens)
|
||
- **gemini-2.5-pro** - High quality ($1.25/1M tokens)
|
||
- **gemini-3-flash-preview** - Experimental (free)
|
||
|
||
**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:**
|
||
```python
|
||
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:**
|
||
```python
|
||
# 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:**
|
||
```python
|
||
# 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:**
|
||
```jinja2
|
||
{# 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:**
|
||
```jinja2
|
||
{{ 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
|
||
|
||
### Pattern 1: Public Company Search
|
||
|
||
**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):**
|
||
```python
|
||
# Get company by slug
|
||
company = db.session.query(Company).filter_by(slug='pixlab-sp-z-o-o').first()
|
||
```
|
||
|
||
**2. Join Query (Relationships):**
|
||
```python
|
||
# 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):**
|
||
```python
|
||
# 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:**
|
||
```python
|
||
# 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:**
|
||
```python
|
||
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:**
|
||
```python
|
||
@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:**
|
||
```python
|
||
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:**
|
||
```python
|
||
# 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:**
|
||
```bash
|
||
# 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)
|
||
|
||
```python
|
||
# 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`
|
||
|
||
```ini
|
||
[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:**
|
||
```bash
|
||
# 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:**
|
||
```python
|
||
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:**
|
||
```json
|
||
{
|
||
"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
|
||
|
||
---
|
||
|
||
## Related Documentation
|
||
|
||
### Higher-Level Diagrams
|
||
- [System Context Diagram (C4 Level 1)](./01-system-context.md) - External actors and systems
|
||
- [Container Diagram (C4 Level 2)](./02-container-diagram.md) - Major containers and technology stack
|
||
|
||
### Same-Level Diagrams
|
||
- [Database Schema Diagram](./05-database-schema.md) - (Planned) Detailed ER diagram
|
||
- [External Integrations Diagram](./06-external-integrations.md) - (Planned) API integration details
|
||
|
||
### Lower-Level Documentation
|
||
- [Data Flow Diagrams](./flows/) - (Planned) Sequence diagrams for key flows
|
||
- [API Endpoints Reference](./10-api-endpoints.md) - (Planned) Complete API documentation
|
||
|
||
### Infrastructure Documentation
|
||
- [Deployment Architecture](./03-deployment-architecture.md) - Servers, network, ports
|
||
- [Network Topology](./07-network-topology.md) - (Planned) Network diagram
|
||
- [Critical Configurations](./08-critical-configurations.md) - (Planned) NPM, SSL, etc.
|
||
|
||
### Analysis Documents (Phase 1)
|
||
- [Flask Application Structure Analysis](../.auto-claude/specs/003-.../analysis/flask-application-structure.md) - Detailed code analysis
|
||
- [Database Schema Analysis](../.auto-claude/specs/003-.../analysis/database-schema.md) - Database deep dive
|
||
- [External API Integrations Analysis](../.auto-claude/specs/003-.../analysis/external-api-integrations.md) - API details
|
||
- [Data Flows Analysis](../.auto-claude/specs/003-.../analysis/data-flows.md) - Flow documentation
|
||
|
||
---
|
||
|
||
## 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)
|