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

1712 lines
54 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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-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:**
```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)