- Document Auto Claude state files that should never be committed - Add pre-commit hook that automatically unstages Auto Claude files - Include troubleshooting steps for merge conflicts - Document worktree management commands This prevents future merge conflicts caused by .auto-claude-* files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
964 lines
33 KiB
Markdown
964 lines
33 KiB
Markdown
# Norda Biznes Hub - Instrukcje dla Claude
|
|
|
|
## Opis projektu
|
|
|
|
Platforma katalogowa i networkingowa dla członków stowarzyszenia Norda Biznes z Wejherowa.
|
|
- **Produkcja:** https://nordabiznes.pl
|
|
- **Status:** LIVE (od 2025-11-23)
|
|
- **Firmy:** 80 członków Norda Biznes (100% pokrycia)
|
|
|
|
## Struktura projektu
|
|
|
|
```
|
|
nordabiz/
|
|
├── app.py # Główna aplikacja Flask (routes, auth, API)
|
|
├── database.py # Modele SQLAlchemy (Company, User, Chat)
|
|
├── gemini_service.py # Integracja Google Gemini AI
|
|
├── nordabiz_chat.py # Silnik chatu AI z kontekstem firm
|
|
├── search_service.py # Unified SearchService (synonimy, FTS, fuzzy)
|
|
├── templates/ # Szablony Jinja2
|
|
├── static/ # CSS, JS, obrazy
|
|
├── database/ # Schematy SQL, migracje
|
|
├── data/ # Dane źródłowe JSON
|
|
├── tests/ # Testy jakości AI
|
|
│ ├── ai_quality_evaluator.py
|
|
│ ├── ai_quality_test_cases.json
|
|
│ └── results/ # Wyniki testów (JSON)
|
|
├── scripts/ # Narzędzia Node.js
|
|
└── docs/ # Dokumentacja
|
|
├── architecture/ # Architektura systemu (diagramy, przepływy)
|
|
└── INCIDENT_REPORT_20260102.md
|
|
```
|
|
|
|
## Dokumentacja architektury
|
|
|
|
Kompletna dokumentacja architektury systemu dostępna w katalogu `docs/architecture/`.
|
|
|
|
### 📚 Dokumenty główne
|
|
|
|
| Dokument | Opis |
|
|
|----------|------|
|
|
| [**README.md**](docs/architecture/README.md) | Przegląd całej dokumentacji architektury (start tutaj!) |
|
|
| [01-system-context.md](docs/architecture/01-system-context.md) | Kontekst systemu (C4 Level 1) - aktorzy i systemy zewnętrzne |
|
|
| [02-container-diagram.md](docs/architecture/02-container-diagram.md) | Diagram kontenerów (C4 Level 2) - Flask, PostgreSQL, NPM, API |
|
|
| [03-deployment-architecture.md](docs/architecture/03-deployment-architecture.md) | Architektura wdrożenia - serwery, porty, infrastruktura |
|
|
| [04-flask-components.md](docs/architecture/04-flask-components.md) | Komponenty Flask - routes, services, models |
|
|
| [05-database-schema.md](docs/architecture/05-database-schema.md) | Schemat bazy danych - 36 tabel, relacje, indeksy |
|
|
| [06-external-integrations.md](docs/architecture/06-external-integrations.md) | Integracje API - Gemini, Brave, PageSpeed, Places, KRS, MS Graph |
|
|
| [07-network-topology.md](docs/architecture/07-network-topology.md) | Topologia sieci - Fortigate, NPM, routing, DNS |
|
|
| [08-critical-configurations.md](docs/architecture/08-critical-configurations.md) | Konfiguracje krytyczne - NPM proxy, SSL, PostgreSQL, systemd |
|
|
| [09-security-architecture.md](docs/architecture/09-security-architecture.md) | Architektura bezpieczeństwa - RBAC, CSRF, strefy zaufania |
|
|
| [10-api-endpoints.md](docs/architecture/10-api-endpoints.md) | Referencja API - 90+ endpointów, auth, rate limiting |
|
|
|
|
### 🔄 Przepływy danych (Data Flows)
|
|
|
|
| Przepływ | Opis |
|
|
|----------|------|
|
|
| [01-authentication-flow.md](docs/architecture/flows/01-authentication-flow.md) | Rejestracja, login, reset hasła, sesje |
|
|
| [02-search-flow.md](docs/architecture/flows/02-search-flow.md) | Wyszukiwanie firm - synonimy, FTS, fuzzy matching |
|
|
| [03-ai-chat-flow.md](docs/architecture/flows/03-ai-chat-flow.md) | Chat AI - kontekst, Gemini API, tracking kosztów |
|
|
| [04-seo-audit-flow.md](docs/architecture/flows/04-seo-audit-flow.md) | Audyt SEO - PageSpeed API, analiza on-page/technical |
|
|
| [05-news-monitoring-flow.md](docs/architecture/flows/05-news-monitoring-flow.md) | Monitoring newsów - Brave API, filtrowanie AI, moderacja |
|
|
| [06-http-request-flow.md](docs/architecture/flows/06-http-request-flow.md) | Przepływ HTTP - user → NPM → Flask → PostgreSQL |
|
|
|
|
### ⚡ Szybki start
|
|
|
|
**Dla deweloperów:**
|
|
- Zacznij od [architecture/README.md](docs/architecture/README.md)
|
|
- Przejrzyj [04-flask-components.md](docs/architecture/04-flask-components.md) i [05-database-schema.md](docs/architecture/05-database-schema.md)
|
|
- Sprawdź przepływy w [flows/](docs/architecture/flows/) dla zrozumienia logiki biznesowej
|
|
|
|
**Dla DevOps:**
|
|
- [03-deployment-architecture.md](docs/architecture/03-deployment-architecture.md) - infrastruktura
|
|
- [07-network-topology.md](docs/architecture/07-network-topology.md) - sieć i routing
|
|
- [08-critical-configurations.md](docs/architecture/08-critical-configurations.md) - **KRYTYCZNE!** NPM port 5000
|
|
|
|
**Dla architektów:**
|
|
- [01-system-context.md](docs/architecture/01-system-context.md) - widok wysokopoziomowy
|
|
- [02-container-diagram.md](docs/architecture/02-container-diagram.md) - komponenty główne
|
|
- [06-external-integrations.md](docs/architecture/06-external-integrations.md) - zależności zewnętrzne
|
|
|
|
### 🛡️ Kluczowe ostrzeżenia z dokumentacji
|
|
|
|
**NPM Proxy (KRYTYCZNE!):**
|
|
- Port forward **MUSI być 5000**, NIE 80!
|
|
- Szczegóły: [08-critical-configurations.md](docs/architecture/08-critical-configurations.md#npm-reverse-proxy)
|
|
- Incydent: [INCIDENT_REPORT_20260102.md](docs/INCIDENT_REPORT_20260102.md)
|
|
|
|
**PostgreSQL:**
|
|
- Skrypty używają `localhost (127.0.0.1)`, NIE `10.22.68.249`
|
|
- Szczegóły: [08-critical-configurations.md](docs/architecture/08-critical-configurations.md#database-configuration)
|
|
|
|
**API Limity:**
|
|
- Gemini: 1,500 req/dzień (free tier)
|
|
- PageSpeed: 25,000 req/dzień
|
|
- Brave Search: 2,000 req/miesiąc
|
|
- Szczegóły: [06-external-integrations.md](docs/architecture/06-external-integrations.md)
|
|
|
|
## Technologie
|
|
|
|
| Warstwa | Technologia |
|
|
|---------|-------------|
|
|
| Backend | Flask 3.0, SQLAlchemy 2.0, Python 3.9+ |
|
|
| Frontend | HTML5, CSS3, Vanilla JS, Jinja2 |
|
|
| Baza danych | PostgreSQL (prod i dev via Docker) |
|
|
| AI | Google Gemini 2.0 Flash (free tier, 200 req/dzień) |
|
|
| Security | Flask-Login, Flask-WTF (CSRF), Flask-Limiter |
|
|
|
|
## Środowiska
|
|
|
|
### Development (lokalne)
|
|
- **Baza:** PostgreSQL via Docker (`localhost:5433/nordabiz`)
|
|
- **Port:** 5000 lub 5001
|
|
- **Uruchomienie:** `python3 app.py`
|
|
- **Docker DB:** `docker compose up -d` (jeśli nie działa)
|
|
|
|
### Production
|
|
- **Serwer:** NORDABIZ-01 (VM 249, IP 10.22.68.249)
|
|
- **Baza:** PostgreSQL na 10.22.68.249:5432
|
|
- **Reverse Proxy:** NPM na R11-REVPROXY-01 (VM 119, IP 10.22.68.250)
|
|
- **Domena:** nordabiznes.pl (DNS w OVH)
|
|
- **SSL:** Let's Encrypt (auto-renewal)
|
|
|
|
### NPM Proxy Configuration (KRYTYCZNE!)
|
|
|
|
**Proxy Host ID:** 27
|
|
**Forward Port:** 5000 (NIE 80!)
|
|
|
|
```
|
|
PRAWIDŁOWA KONFIGURACJA:
|
|
NPM (10.22.68.250) → Backend (10.22.68.249:5000) ✓
|
|
|
|
BŁĘDNA KONFIGURACJA (powoduje pętlę przekierowań):
|
|
NPM (10.22.68.250) → Backend (10.22.68.249:80) ✗
|
|
```
|
|
|
|
**UWAGA:** Na serwerze 10.22.68.249 działa nginx na porcie 80 który przekierowuje na HTTPS.
|
|
Flask/Gunicorn działa na porcie 5000. Przy edycji proxy hosta ZAWSZE sprawdź czy port = 5000!
|
|
|
|
**Weryfikacja po zmianach NPM:**
|
|
```bash
|
|
curl -I https://nordabiznes.pl/health
|
|
# Oczekiwany: HTTP 200
|
|
```
|
|
|
|
**Raport incydentu:** `docs/INCIDENT_REPORT_20260102.md`
|
|
|
|
## Git & Deployment
|
|
|
|
### Repozytoria Git
|
|
|
|
| Remote | URL | Cel |
|
|
|--------|-----|-----|
|
|
| **origin** (GitHub) | `git@github.com:pienczyn/nordabiz.git` | Cloud backup, CI/CD ready |
|
|
| **inpi** (Gitea) | `git@10.22.68.180:maciejpi/nordabiz.git` | Wewnętrzny backup, deploy source |
|
|
|
|
**Konta:**
|
|
- GitHub: `pienczyn`
|
|
- Gitea (r11-git-inpi): `maciejpi` (osobiste), `gitadmin` (admin Gitea)
|
|
|
|
### Workflow Deployment
|
|
|
|
```
|
|
┌─────────┐ git push ┌─────────┐ git pull ┌─────────┐
|
|
│ DEV │ ────────────► │ Gitea │ ◄──────────── │ PROD │
|
|
│ (Mac) │ │ (INPI) │ │ │
|
|
└─────────┘ └─────────┘ └─────────┘
|
|
│
|
|
└──── git push ────► GitHub (backup)
|
|
```
|
|
|
|
**Komendy deployment:**
|
|
```bash
|
|
# 1. DEV: Push do obu repozytoriów
|
|
git push origin master && git push inpi master
|
|
|
|
# 2. PROD: Pull i restart
|
|
ssh maciejpi@10.22.68.249 "cd /var/www/nordabiznes && sudo -u www-data git pull && sudo systemctl restart nordabiznes"
|
|
```
|
|
|
|
### Serwery Git
|
|
|
|
| Serwer | IP | Port | Usługa |
|
|
|--------|-----|------|--------|
|
|
| r11-git-inpi | 10.22.68.180 | 3000 (HTTPS) | Gitea |
|
|
| GitHub | github.com | 22/443 | GitHub |
|
|
|
|
**Gitea wymaga HTTPS** (nie HTTP) - URL: `https://10.22.68.180:3000/`
|
|
|
|
### PROD Git Config
|
|
|
|
- **Remote:** `https://10.22.68.180:3000/maciejpi/nordabiz.git`
|
|
- **User:** www-data
|
|
- **SSL verify:** disabled (`git -c http.sslVerify=false`)
|
|
|
|
## Auto Claude - Konfiguracja i rozwiązywanie problemów
|
|
|
|
### Pliki stanu Auto Claude (WAŻNE!)
|
|
|
|
Auto Claude tworzy lokalne pliki stanu które **NIE POWINNY** być commitowane:
|
|
- `.auto-claude-security.json` - stan bezpieczeństwa projektu
|
|
- `.auto-claude-status` - status bieżącego zadania
|
|
- `.auto-claude/` - katalog roboczy Auto Claude
|
|
|
|
**Problem:** Auto Claude czasami dodaje te pliki do staging area w worktree branches, co powoduje konflikty merge gdy branch jest mergowany do master.
|
|
|
|
**Rozwiązanie (wdrożone 2026-01-10):**
|
|
|
|
1. **`.gitignore`** - pliki są ignorowane:
|
|
```
|
|
.auto-claude/
|
|
.auto-claude-security.json
|
|
.auto-claude-status
|
|
```
|
|
|
|
2. **Pre-commit hook** - automatycznie usuwa te pliki ze staging area:
|
|
```
|
|
.git/hooks/pre-commit
|
|
```
|
|
Hook sprawdza przed każdym commitem czy pliki Auto Claude są staged i automatycznie je usuwa.
|
|
|
|
3. **Pliki usunięte z śledzenia** - wykonano `git rm --cached` na master
|
|
|
|
### Rozwiązywanie konfliktów merge z Auto Claude
|
|
|
|
Jeśli pojawi się konflikt merge z plikami `.auto-claude-*`:
|
|
|
|
```bash
|
|
# 1. Sprawdź czy to konflikt zmiana/usunięcie
|
|
git status
|
|
|
|
# 2. Usuń pliki Auto Claude z merge (akceptuj usunięcie z master)
|
|
git rm .auto-claude-security.json .auto-claude-status
|
|
|
|
# 3. Dokończ merge
|
|
git commit -m "Merge branch 'feature' - resolve Auto Claude file conflicts"
|
|
```
|
|
|
|
### Worktrees Auto Claude
|
|
|
|
Auto Claude tworzy worktrees dla każdego zadania w:
|
|
```
|
|
.auto-claude/worktrees/tasks/<task-id>/
|
|
```
|
|
|
|
Każdy worktree ma własny branch i własne pliki stanu. Po zamergowaniu zadania worktree może być usunięty.
|
|
|
|
**Sprawdzenie aktywnych worktrees:**
|
|
```bash
|
|
git worktree list
|
|
```
|
|
|
|
**Usunięcie nieaktualnego worktree:**
|
|
```bash
|
|
git worktree remove .auto-claude/worktrees/tasks/<task-id>
|
|
git branch -d auto-claude/<task-id>
|
|
```
|
|
|
|
## Konwencje danych
|
|
|
|
### Identyfikatory firm
|
|
- **Slug:** kebab-case z nazwy, np. `pixlab-sp-z-o-o`
|
|
- **NIP:** 10 cyfr bez myślników, np. `5882436505`
|
|
- **REGON:** 9 lub 14 cyfr
|
|
- **KRS:** 10 cyfr (tylko spółki)
|
|
|
|
### Kategorie firm
|
|
- `IT` - IT i Technologie
|
|
- `Construction` - Budownictwo
|
|
- `Services` - Usługi (prawne, księgowe, doradcze)
|
|
- `Production` - Produkcja
|
|
- `Trade` - Handel
|
|
- `Other` - Pozostałe
|
|
|
|
### Poziomy jakości danych
|
|
- `basic` - Nazwa, NIP, kontakt
|
|
- `enhanced` - Pełne dane, zweryfikowane
|
|
- `complete` - Wzbogacone o usługi, kompetencje, certyfikaty
|
|
|
|
## Ważne zasady
|
|
|
|
### Bezpieczeństwo
|
|
- NIE edytuj bezpośrednio bazy produkcyjnej PostgreSQL
|
|
- Zawsze testuj zmiany na DEV PostgreSQL (Docker: localhost:5433) przed wdrożeniem
|
|
- Klucze API i hasła tylko w `.env` (nigdy w kodzie)
|
|
- Rate limiting: 200 req/dzień, 50 req/godzinę
|
|
|
|
#### Zarządzanie danymi uwierzytelniającymi (KRYTYCZNE!)
|
|
|
|
**NIGDY nie umieszczaj haseł i kluczy API bezpośrednio w kodzie źródłowym!**
|
|
|
|
Jest to krytyczna podatność bezpieczeństwa (CWE-798: Use of Hard-coded Credentials). Narusza standardy bezpieczeństwa i może prowadzić do kompromitacji systemu jeśli repozytorium zostanie ujawnione.
|
|
|
|
**Zasady obowiązkowe:**
|
|
|
|
1. **Używaj zmiennych środowiskowych dla wszystkich wrażliwych danych:**
|
|
```python
|
|
# PRAWIDŁOWO:
|
|
DATABASE_URL = os.getenv('DATABASE_URL')
|
|
API_KEY = os.getenv('GOOGLE_PAGESPEED_API_KEY')
|
|
|
|
# BŁĘDNIE - NIGDY TAK NIE RÓB:
|
|
DATABASE_URL = 'postgresql://user:password123@localhost/db'
|
|
API_KEY = 'AIzaSyAbc123...'
|
|
```
|
|
|
|
2. **Konfiguruj wartości domyślne jako bezpieczne placeholdery:**
|
|
```python
|
|
# PRAWIDŁOWO - wartość domyślna która wymusi konfigurację .env:
|
|
DATABASE_URL = os.getenv('DATABASE_URL', 'postgresql://user:CHANGE_ME@localhost/nordabiz')
|
|
|
|
# BŁĘDNIE - wartość produkcyjna jako fallback:
|
|
DATABASE_URL = os.getenv('DATABASE_URL', 'postgresql://user:RealPassword@10.22.68.249/nordabiz')
|
|
```
|
|
|
|
3. **Przechowuj dane uwierzytelniające w plikach .env:**
|
|
- Produkcja: `/var/www/nordabiznes/.env`
|
|
- Development: `.env` w katalogu projektu
|
|
- Wzorzec: `.env.example` (bez prawdziwych wartości!)
|
|
|
|
4. **Wymagane zmienne środowiskowe:**
|
|
|
|
| Zmienna | Cel | Przykład |
|
|
|---------|-----|----------|
|
|
| `DATABASE_URL` | Połączenie PostgreSQL dla skryptów Python | `postgresql://user:pass@127.0.0.1:5432/nordabiz` |
|
|
| `PGPASSWORD` | Hasło PostgreSQL dla skryptów shell | `export PGPASSWORD='your_password'` |
|
|
| `GOOGLE_PAGESPEED_API_KEY` | API Key Google PageSpeed | `AIzaSy...` |
|
|
| `BRAVE_SEARCH_API_KEY` | API Key Brave Search | `BSA...` |
|
|
| `GEMINI_API_KEY` | API Key Google Gemini AI | `AIzaSy...` |
|
|
|
|
5. **Skrypty shell - zawsze sprawdzaj czy zmienne są ustawione:**
|
|
```bash
|
|
# PRAWIDŁOWO:
|
|
if [ -z "$PGPASSWORD" ]; then
|
|
echo "ERROR: PGPASSWORD not set"
|
|
exit 1
|
|
fi
|
|
psql -h localhost -U nordabiz_app -d nordabiz
|
|
|
|
# BŁĘDNIE:
|
|
PGPASSWORD='hardcoded_password' psql -h localhost -U nordabiz_app -d nordabiz
|
|
```
|
|
|
|
6. **NIGDY nie commituj plików z credentials:**
|
|
- `.env` jest w `.gitignore`
|
|
- Sprawdzaj przed commitem: `git diff` i `git status`
|
|
- W razie wątpliwości: `git log -p | grep -i password`
|
|
|
|
7. **Co zrobić jeśli przypadkowo scommitujesz hasło:**
|
|
- ⚠️ **NATYCHMIAST zmień hasło w bazie/API**
|
|
- Nie wystarczy usunąć z najnowszego commita - hasło pozostaje w historii Git
|
|
- Rozważ użycie `git filter-branch` lub `BFG Repo-Cleaner` (skomplikowane)
|
|
- Najlepiej: zmień hasło i traktuj stare jako skompromitowane
|
|
|
|
8. **Wyjątki (kiedy dozwolone jest hasło w kodzie):**
|
|
- ✅ Pliki dokumentacji (np. przykłady w CLAUDE.md, README)
|
|
- ✅ `.env.example` jako szablon (z placeholderami)
|
|
- ⛔ NIGDY w plikach wykonywalnych (.py, .sh, .js)
|
|
|
|
**Weryfikacja przed wdrożeniem:**
|
|
```bash
|
|
# Sprawdź czy nie ma hardcoded credentials w kodzie:
|
|
grep -r "NordaBiz2025Secure" --include="*.py" --include="*.sh" .
|
|
grep -r "PGPASSWORD=" --include="*.sh" .
|
|
grep -r "postgresql://.*:.*@" --include="*.py" . | grep -v "CHANGE_ME" | grep -v ".example"
|
|
|
|
# Oczekiwany wynik: brak znalezisk (lub tylko w dokumentacji)
|
|
```
|
|
|
|
### Import danych
|
|
- Używaj skryptów `import_*.py` do dodawania firm
|
|
- Weryfikuj NIP przez API przed importem
|
|
- Zachowaj spójność slugów (unikalne, lowercase)
|
|
|
|
### Deployment
|
|
- Przed wdrożeniem: `python -m py_compile app.py`
|
|
- SSH do NORDABIZ-01: `ssh maciejpi@10.22.68.249` (ZAWSZE jako maciejpi, NIE root!)
|
|
- Ścieżka aplikacji: `/var/www/nordabiznes`
|
|
- Restart: `sudo systemctl restart nordabiznes`
|
|
- **ZAWSZE** aktualizuj historię zmian (`release_notes` w app.py) po wdrożeniu
|
|
- Historia zmian: efekt końcowy, bez powtórzeń, prostym językiem
|
|
|
|
### Szablony Jinja2 - WAŻNE!
|
|
- Blok `{% block extra_js %}` w `base.html` jest już wewnątrz tagu `<script>`
|
|
- **NIE DODAWAJ** własnych tagów `<script>` w `extra_js` - spowoduje zagnieżdżenie i błąd JS
|
|
- Prawidłowo: `{% block extra_js %}function foo() {...}{% endblock %}`
|
|
- Błędnie: `{% block extra_js %}<script>function foo() {...}</script>{% endblock %}`
|
|
|
|
### Uprawnienia PostgreSQL
|
|
- Po utworzeniu nowych tabel: `GRANT ALL ON TABLE ... TO nordabiz_app`
|
|
- Po utworzeniu sekwencji: `GRANT USAGE, SELECT ON SEQUENCE ... TO nordabiz_app`
|
|
- Baza: `nordabiz`, użytkownik aplikacji: `nordabiz_app`
|
|
|
|
### Testowanie na produkcji
|
|
- **ZAWSZE używaj kont testowych** do weryfikacji funkcjonalności
|
|
- Używaj przeglądarki (browser automation) do testów wymagających logowania
|
|
|
|
**Konta testowe (PROD):**
|
|
|
|
| Konto | Email | Hasło | Rola |
|
|
|-------|-------|-------|------|
|
|
| Test User | `test@nordabiznes.pl` | `&Rc2LdbSw&jiGR0ek@Bz` | Zwykły użytkownik |
|
|
| Test Admin | `testadmin@nordabiznes.pl` | `cSfQbbwegwv1v3Q2Dm0Q` | Administrator |
|
|
|
|
**Użycie:**
|
|
- **Test User** - do testowania funkcji dostępnych dla zwykłych użytkowników
|
|
- **Test Admin** - do testowania panelu admina (rekomendacje, składki, kalendarz, forum, news)
|
|
|
|
## Skrypty danych
|
|
|
|
### Import (wykonywać kolejno)
|
|
```bash
|
|
python import_norda_companies.py # Batch 1 (56 firm)
|
|
python import_norda_batch2.py # Batch 2
|
|
python import_norda_batch3.py # Batch 3
|
|
python import_norda_batch4.py # Batch 4 (9 firm)
|
|
python import_norda_batch5.py # Batch 5 (8 firm)
|
|
```
|
|
|
|
### Weryfikacja
|
|
```bash
|
|
python verify_all_companies_data.py # Raport jakości danych
|
|
python fix_krs_verification.py # Weryfikacja KRS
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
| Endpoint | Metoda | Opis |
|
|
|----------|--------|------|
|
|
| `/` | GET | Katalog firm |
|
|
| `/company/<slug>` | GET | Profil firmy |
|
|
| `/search` | GET | Wyszukiwanie |
|
|
| `/api/companies` | GET | Lista firm (JSON) |
|
|
| `/api/verify-nip` | GET | Weryfikacja NIP |
|
|
| `/health` | GET | Health check |
|
|
| `/chat` | GET | Interfejs chatu AI |
|
|
| `/admin/news` | GET/POST | Panel moderacji newsów (wymaga admin) |
|
|
| `/api/notifications` | GET | Powiadomienia użytkownika (JSON) |
|
|
|
|
## SearchService (search_service.py)
|
|
|
|
Unified search dla chatbota AI i wyszukiwarki `/search`.
|
|
|
|
### Funkcje:
|
|
- **NIP/REGON lookup** - bezpośrednie wyszukiwanie po identyfikatorach
|
|
- **Synonym expansion** - rozszerzenie słów kluczowych (np. "strony" → www, web, portal)
|
|
- **PostgreSQL FTS** - full-text search z tsvector (DEV i PROD)
|
|
- **SQLite fallback** - keyword scoring (tylko jako fallback, nieużywane)
|
|
- **Fuzzy matching** - pg_trgm dla literówek (gdy dostępne)
|
|
|
|
### Scoring:
|
|
- Nazwa firmy: +10 punktów
|
|
- Opis: +5 punktów
|
|
- Usługi: +8 punktów
|
|
- Kompetencje: +7 punktów
|
|
- Miasto: +3 punktów
|
|
|
|
### Użycie:
|
|
```python
|
|
from search_service import search_companies
|
|
results = search_companies(db, "strony www", limit=10)
|
|
# Zwraca List[SearchResult] z company, score, match_type
|
|
```
|
|
|
|
### UWAGA (PostgreSQL):
|
|
- Gdy FTS się nie powiedzie, wykonywany jest `db.rollback()` przed fallbackiem
|
|
- Bez tego następuje błąd `InFailedSqlTransaction`
|
|
|
|
## Chatbot AI (nordabiz_chat.py)
|
|
|
|
### Konfiguracja:
|
|
- **Limit firm do AI:** 8 (zmienne w `_build_conversation_context`, linia ~312)
|
|
- **Historia wiadomości:** 10 ostatnich
|
|
- **Search:** używa `search_companies()` z SearchService
|
|
|
|
## Testy jakości AI
|
|
|
|
### Uruchomienie:
|
|
```bash
|
|
python run_ai_quality_tests.py -v # Verbose output
|
|
python run_ai_quality_tests.py -v -s # Verbose + save report
|
|
python run_ai_quality_tests.py -q # Quick (tylko high-priority)
|
|
```
|
|
|
|
### Przypadki testowe (`tests/ai_quality_test_cases.json`):
|
|
- 15 przypadków w 8 kategoriach
|
|
- Próg zaliczenia: 70%
|
|
- Kategorie: IT/Web, Services/Legal, Services/Accounting, Production/Metal, Construction, HVAC, Energy/Renewable, IT/Security
|
|
|
|
## Powiązane zasoby
|
|
|
|
- **Źródło danych:** https://norda-biznes.info/czlonkowie
|
|
- **Monitoring:** Zabbix (do konfiguracji)
|
|
- **Backup:** Proxmox Backup Server (VM snapshots)
|
|
- **DNS wewnętrzny:** nordabiznes.inpi.local
|
|
|
|
## Kontakty
|
|
|
|
- **Projekt:** Norda Biznes Hub
|
|
- **Infrastruktura:** INPI (skills: proxmox-manager, dns-manager, npm-manager)
|
|
|
|
## Szablon profilu firmy (company profile)
|
|
|
|
### Zatwierdzone zmiany do wdrożenia
|
|
|
|
Sekcje do **połączenia** (redukcja duplikatów):
|
|
1. **"O firmie" + "Profil działalności"** → jedna sekcja "O firmie"
|
|
2. **"Oferta i usługi" + "Słowa kluczowe"** → jedna sekcja "Usługi i kompetencje"
|
|
3. **"Wyróżniki" + "Wartości firmy"** → jedna sekcja "Wyróżniki"
|
|
4. **Blok "Jakość Danych"** → usunąć (badge przy nazwie wystarczy)
|
|
|
|
### Sekcje które MUSZĄ pozostać
|
|
|
|
- **Social Media (6 kafelków)** - pokazywać WSZYSTKIE platformy, także te bez profilu ("Brak profilu") - ważne by widzieć czego brakuje
|
|
- **Dane kontaktowe (sekcja z kartami)** - to docelowe miejsce na WSZYSTKIE dane kontaktowe firmy (adres, telefony, emaile, godziny otwarcia, itp.)
|
|
|
|
### Docelowa struktura profilu (po optymalizacji)
|
|
|
|
```
|
|
1. Header (nazwa, kategoria, badge weryfikacji, krótki opis)
|
|
2. Pasek kontaktowy (www, email, telefon, lokalizacja) - szybki dostęp
|
|
3. O firmie (połączone opisy)
|
|
4. Usługi i kompetencje (połączone tagi)
|
|
5. Wyróżniki (połączone z wartościami)
|
|
6. Dane kontaktowe (pełne karty - główne miejsce na kontakt)
|
|
7. Informacje prawne i biznesowe (NIP, REGON, KRS, rok założenia)
|
|
8. Social Media (wszystkie 6 platform - widoczne braki)
|
|
9. Strona WWW (analiza techniczna) - zawsze na końcu
|
|
```
|
|
|
|
### Szablon: templates/company_detail.html
|
|
|
|
Plik do modyfikacji przy implementacji zmian.
|
|
|
|
## Plan rozwoju - Aktualności
|
|
|
|
### Social Media Audit (WDROŻONE)
|
|
**Status:** Wdrożone (2026-01-09)
|
|
**Panel:** `/admin/social-media`
|
|
**Funkcje:**
|
|
- Audyt profili Social Media firm (Facebook, Instagram, LinkedIn, YouTube, TikTok, Twitter)
|
|
- Weryfikacja aktywności profili (last_checked_at, followers_count)
|
|
- Raportowanie brakujących profili
|
|
|
|
### Priorytet 1: Social Media Integration (Posts/Events)
|
|
**Status:** Planowane
|
|
**Cel:** Pobieranie postów i wydarzeń z Social Media firm
|
|
|
|
**Źródła danych:**
|
|
- Facebook Pages firm członkowskich (posty, wydarzenia)
|
|
- LinkedIn Company Pages
|
|
- Google My Business (recenzje, posty)
|
|
|
|
**Wymagania techniczne:**
|
|
- Facebook Graph API (wymaga App Review dla pages_read_engagement)
|
|
- LinkedIn Marketing API (wymaga partnera lub OAuth)
|
|
- Google Business Profile API
|
|
|
|
**Typy zdarzeń do importu:**
|
|
- `social_post` - posty z social media
|
|
- `social_event` - wydarzenia z Facebooka
|
|
- `review` - nowe recenzje Google
|
|
|
|
### Priorytet 2: News Monitoring (Google/Brave API)
|
|
**Status:** Wdrożone (2025-12-29)
|
|
**Źródła danych:**
|
|
- Wzmianki o firmach w mediach lokalnych/branżowych
|
|
- Artykuły prasowe
|
|
- Komunikaty branżowe
|
|
|
|
**Wymagania techniczne:**
|
|
- Brave Search API (bezpłatny tier) LUB
|
|
- Google Custom Search API ($5/1000 queries)
|
|
- Cykliczne wyszukiwanie nazw firm
|
|
|
|
**Typy zdarzeń do importu:**
|
|
- `news_mention` - wzmianka w mediach
|
|
- `press_release` - komunikat prasowy
|
|
- `award` - nagroda/wyróżnienie
|
|
|
|
### Priorytet 3: Zarząd i Wspólnicy (rejestr.io)
|
|
**Status:** Planowane
|
|
**Cel:** Wyświetlanie osób powiązanych z firmą bezpośrednio na stronie profilu
|
|
|
|
**Dane do pobrania z rejestr.io:**
|
|
- Zarząd (Prezes, Wiceprezes, Członkowie Zarządu)
|
|
- Prokurenci
|
|
- Wspólnicy z % udziałów
|
|
- Beneficjenci rzeczywiści
|
|
- Linki do profili osób (powiązania z innymi firmami)
|
|
|
|
**Wymagania techniczne:**
|
|
- Tabela `company_people` (company_id, name, role, shares_percent, person_url)
|
|
- Scraper Playwright (już mamy bazę w `analyze_connections.py`)
|
|
- Sekcja w `company_detail.html` po "Informacje prawne i biznesowe"
|
|
|
|
**Przykład wyświetlania:**
|
|
```
|
|
👥 ZARZĄD I WSPÓLNICY
|
|
┌─────────────────────────────────────────┐
|
|
│ 👔 Jan Kowalski - Prezes Zarządu │
|
|
│ 👔 Anna Nowak - Członek Zarządu │
|
|
│ 💼 Firma XYZ Sp. z o.o. - 60% udziałów │
|
|
│ 💼 Jan Kowalski - 40% udziałów │
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
**Korzyści:**
|
|
- Widoczne powiązania między firmami Norda Biznes
|
|
- Ułatwiony networking (kto zna kogo)
|
|
- Transparentność struktury właścicielskiej
|
|
|
|
### Notatki implementacyjne
|
|
- Scraper powinien deduplikować wydarzenia (hash tytułu + daty)
|
|
- Moderacja: nowe wydarzenia jako "pending" do zatwierdzenia przez admina
|
|
- Rate limiting: max 100 requestów/dzień do zewnętrznych API
|
|
|
|
## News Monitoring
|
|
|
|
### Opis funkcjonalności
|
|
|
|
System automatycznego monitoringu wzmianek o firmach Norda Biznes w mediach lokalnych i branżowych.
|
|
|
|
### Tabela w bazie danych
|
|
|
|
```sql
|
|
company_news (
|
|
id SERIAL PRIMARY KEY,
|
|
company_id INTEGER REFERENCES companies(id),
|
|
title VARCHAR(500) NOT NULL,
|
|
description TEXT,
|
|
url VARCHAR(1000) NOT NULL,
|
|
source VARCHAR(200), -- nazwa portalu/medium
|
|
published_at TIMESTAMP,
|
|
news_type VARCHAR(50), -- news_mention, press_release, award
|
|
relevance_score FLOAT, -- 0.0-1.0 (AI scoring)
|
|
status VARCHAR(20) DEFAULT 'pending', -- pending, approved, rejected
|
|
moderated_by INTEGER, -- user_id admina
|
|
moderated_at TIMESTAMP,
|
|
rejection_reason TEXT,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW(),
|
|
UNIQUE(company_id, url)
|
|
)
|
|
```
|
|
|
|
**Statusy newsów:**
|
|
- `pending` - oczekuje na moderację
|
|
- `approved` - zatwierdzony, widoczny na profilu firmy
|
|
- `rejected` - odrzucony (spam, nieistotny, duplikat)
|
|
|
|
### Brave Search API Integration
|
|
|
|
**Konfiguracja:**
|
|
- API Key w `.env`: `BRAVE_SEARCH_API_KEY`
|
|
- Endpoint: `https://api.search.brave.com/res/v1/news/search`
|
|
- Limit: 2000 req/miesiąc (free tier)
|
|
|
|
**Parametry wyszukiwania:**
|
|
```python
|
|
params = {
|
|
"q": f'"{company_name}" OR "{nip}"',
|
|
"count": 10,
|
|
"freshness": "pw", # past week
|
|
"country": "pl",
|
|
"search_lang": "pl"
|
|
}
|
|
```
|
|
|
|
**Skrypt pobierania:** (do implementacji)
|
|
```bash
|
|
# TODO: Skrypt fetch_company_news.py wymaga implementacji
|
|
# cd /var/www/nordabiznes
|
|
# sudo -u www-data /var/www/nordabiznes/venv/bin/python3 scripts/fetch_company_news.py
|
|
```
|
|
|
|
### AI Filtering (Gemini)
|
|
|
|
Filtracja wyników przez Google Gemini:
|
|
- Ocena relevance_score (0.0-1.0)
|
|
- Kategoryzacja news_type
|
|
- Wykrywanie duplikatów/spamu
|
|
- Automatyczne odrzucanie wyników < 0.3 relevance
|
|
|
|
**Prompt systemu:**
|
|
```
|
|
Oceń czy artykuł dotyczy działalności firmy {company_name}.
|
|
Zwróć JSON: {"relevance": 0.0-1.0, "type": "news_mention|press_release|award", "reason": "..."}
|
|
```
|
|
|
|
### Panel admina /admin/news
|
|
|
|
**URL:** `/admin/news`
|
|
**Wymaga:** Zalogowany użytkownik z `is_admin=True`
|
|
|
|
**Funkcje:**
|
|
- Lista newsów pending do moderacji
|
|
- Filtrowanie po firmie, statusie, dacie
|
|
- Zatwierdzanie/odrzucanie z powodem
|
|
- Podgląd oryginalnego artykułu
|
|
- Bulk actions (zatwierdź wszystkie z relevance > 0.8)
|
|
|
|
### Sekcja Aktualności na profilu firmy
|
|
|
|
**Lokalizacja:** `templates/company_detail.html`
|
|
**Warunek:** Tylko newsy ze statusem `approved`
|
|
**Sortowanie:** Po `published_at` DESC
|
|
**Limit:** 5 ostatnich newsów
|
|
|
|
**Struktura wyświetlania:**
|
|
```
|
|
AKTUALNOŚCI
|
|
├── [data] Tytuł artykułu (źródło)
|
|
│ Krótki opis...
|
|
│ [Czytaj więcej →]
|
|
└── [data] Kolejny artykuł...
|
|
```
|
|
|
|
### System powiadomień
|
|
|
|
**Endpoint:** `/api/notifications`
|
|
**Zwraca:** JSON z listą powiadomień użytkownika
|
|
|
|
**Typy powiadomień:**
|
|
- `new_news` - nowy news o obserwowanej firmie (dla zalogowanych)
|
|
- `news_approved` - news firmy użytkownika został zatwierdzony
|
|
- `news_rejected` - news firmy użytkownika został odrzucony
|
|
|
|
**Struktura odpowiedzi:**
|
|
```json
|
|
{
|
|
"notifications": [
|
|
{
|
|
"id": 1,
|
|
"type": "new_news",
|
|
"message": "Nowa wzmianka o PIXLAB",
|
|
"url": "/company/pixlab-sp-z-o-o#news",
|
|
"created_at": "2025-12-29T10:30:00",
|
|
"read": false
|
|
}
|
|
],
|
|
"unread_count": 3
|
|
}
|
|
```
|
|
|
|
### Skrypty i cron (do implementacji)
|
|
|
|
```bash
|
|
# TODO: Skrypty do pobierania newsów wymagają implementacji
|
|
# Planowane komendy:
|
|
# python scripts/fetch_company_news.py --all
|
|
# python scripts/fetch_company_news.py --company pixlab-sp-z-o-o
|
|
|
|
# Cron job (do skonfigurowania po implementacji)
|
|
# 0 */6 * * * cd /var/www/nordabiznes && /var/www/nordabiznes/venv/bin/python3 scripts/fetch_company_news.py --all >> /var/log/nordabiznes/news_fetch.log 2>&1
|
|
```
|
|
|
|
## Social Media - Stan aktualny
|
|
|
|
### Statystyki (2025-12-29)
|
|
|
|
| Platforma | Liczba firm | Pokrycie |
|
|
|-----------|-------------|----------|
|
|
| Facebook | 39 | 49% |
|
|
| Instagram | 26 | 33% |
|
|
| LinkedIn | 22 | 28% |
|
|
| YouTube | 17 | 21% |
|
|
| Twitter/X | 7 | 9% |
|
|
| TikTok | 4 | 5% |
|
|
|
|
**Łącznie:** 115 profili dla 53 firm (66% pokrycia)
|
|
**Firmy bez Social Media:** 27
|
|
|
|
### Tabela w bazie danych
|
|
|
|
```sql
|
|
company_social_media (
|
|
id, company_id, platform, url,
|
|
verified_at, source, is_valid,
|
|
last_checked_at, check_status,
|
|
page_name, followers_count,
|
|
created_at, updated_at
|
|
)
|
|
```
|
|
|
|
**Platformy:** facebook, instagram, youtube, linkedin, tiktok, twitter
|
|
|
|
### Skrypty aktualizacji
|
|
|
|
```bash
|
|
# Aktualizacja Social Media z pliku JSON
|
|
cd /var/www/nordabiznes
|
|
sudo -u www-data /var/www/nordabiznes/venv/bin/python3 update_social_media.py --dry-run # Test
|
|
sudo -u www-data /var/www/nordabiznes/venv/bin/python3 update_social_media.py # Produkcja
|
|
```
|
|
|
|
**Pliki:**
|
|
- `social_media_found.json` - wyniki wyszukiwania (źródło danych)
|
|
- `update_social_media.py` - skrypt aktualizujący bazę
|
|
|
|
### Firmy z najlepszym pokryciem Social Media
|
|
|
|
1. **PORTA KMI** - Facebook, Instagram, YouTube, LinkedIn (4 platformy, 124K FB fans)
|
|
2. **Rumia Invest Park** - Facebook, Instagram, YouTube, LinkedIn, Twitter (5 platform)
|
|
3. **GRAAL** - Facebook, Instagram, YouTube, LinkedIn (4 platformy)
|
|
4. **Chopin Telewizja Kablowa** - Facebook, Instagram, YouTube, Twitter (4 platformy)
|
|
5. **Hotel SPA Wieniawa** - Facebook, Instagram, YouTube, TikTok (4 platformy)
|
|
|
|
### Firmy bez Social Media (do uzupełnienia)
|
|
|
|
SIM Rumia, Rubinsolar, KORNIX, KBMS, Semerling Security, ARD Invest, AMA,
|
|
Jubiler Agat, P&P, Progress Optima, Ampery, Bibrokers, CoolAir, Joker,
|
|
KAMMET, Alumech, Litwic&Litwic, Orlex MG, Pro-Invest, Round Two, SCROL,
|
|
ALMARES, Pucka Gospodarka Komunalna, Hebel Masiak, Lenap Hale, MKonsult, Portal
|
|
|
|
## Audyt SEO (Panel /admin/seo)
|
|
|
|
### Opis funkcjonalności
|
|
|
|
System audytu SEO stron internetowych firm członkowskich Norda Biznes.
|
|
Wykorzystuje Google PageSpeed Insights API do analizy wydajności i jakości stron.
|
|
|
|
**URL panelu:** `/admin/seo`
|
|
**Wymaga:** Zalogowany użytkownik z `is_admin=True`
|
|
|
|
### Konfiguracja API
|
|
|
|
**Google PageSpeed Insights API:**
|
|
- API Key w `.env`: `GOOGLE_PAGESPEED_API_KEY`
|
|
- Projekt Google Cloud: NORDABIZNES (`gen-lang-client-0540794446`)
|
|
- Limit: 25,000 zapytań/dzień (free tier)
|
|
- Endpoint: `https://www.googleapis.com/pagespeedonline/v5/runPagespeed`
|
|
|
|
**Klucz API:**
|
|
- **Nazwa w Google Cloud:** `Page SPEED SEO Audit v2`
|
|
- **Wartość:** Przechowywany w `.env` (GOOGLE_PAGESPEED_API_KEY)
|
|
- **UWAGA:** Nigdy nie commituj kluczy API do repozytorium!
|
|
|
|
### Metryki audytu
|
|
|
|
| Metryka | Źródło | Skala |
|
|
|---------|--------|-------|
|
|
| WYNIK SEO | PageSpeed Insights | 0-100 |
|
|
| PERFORMANCE | PageSpeed Insights | 0-100 |
|
|
| DOSTĘPNOŚĆ | PageSpeed Insights | 0-100 |
|
|
| BEST PRACTICES | PageSpeed Insights | 0-100 |
|
|
|
|
**Interpretacja wyników:**
|
|
- 90-100 (zielony) - Doskonały
|
|
- 50-89 (żółty) - Wymaga poprawy
|
|
- 0-49 (czerwony) - Słaby
|
|
|
|
### Skrypty SEO
|
|
|
|
```bash
|
|
# Audyt pojedynczej firmy
|
|
cd /var/www/nordabiznes/scripts
|
|
python seo_audit.py --company-id 26
|
|
|
|
# Audyt wsadowy (batch)
|
|
python seo_audit.py --batch 1-10
|
|
|
|
# Audyt wszystkich firm
|
|
python seo_audit.py --all
|
|
|
|
# Tryb testowy (bez zapisu)
|
|
python seo_audit.py --company-id 26 --dry-run
|
|
```
|
|
|
|
### WAŻNE - Połączenie z bazą danych
|
|
|
|
Skrypty w `scripts/` muszą używać **localhost (127.0.0.1)** do połączenia z PostgreSQL:
|
|
|
|
```python
|
|
# PRAWIDŁOWO:
|
|
DATABASE_URL = 'postgresql://nordabiz_app:NordaBiz2025Secure@127.0.0.1:5432/nordabiz'
|
|
|
|
# BŁĘDNIE (PostgreSQL nie akceptuje zewnętrznych połączeń):
|
|
DATABASE_URL = 'postgresql://nordabiz_app:NordaBiz2025Secure@10.22.68.249:5432/nordabiz'
|
|
```
|
|
|
|
**Pliki z konfiguracją bazy:**
|
|
- `scripts/seo_audit.py` (linia ~79)
|
|
- `scripts/seo_report_generator.py` (linia ~47)
|
|
- `scripts/social_media_audit.py` (linia ~53)
|
|
|
|
### Tabela w bazie danych
|
|
|
|
```sql
|
|
seo_metrics (
|
|
id SERIAL PRIMARY KEY,
|
|
company_id INTEGER REFERENCES companies(id),
|
|
url VARCHAR(500),
|
|
seo_score INTEGER,
|
|
performance_score INTEGER,
|
|
accessibility_score INTEGER,
|
|
best_practices_score INTEGER,
|
|
pwa_score INTEGER,
|
|
audit_data JSONB, -- pełne dane z PageSpeed
|
|
audited_at TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
)
|
|
```
|
|
|
|
### UI - Stylizowane modale
|
|
|
|
Panel SEO używa niestandardowych modali (zamiast natywnych `confirm()`/`alert()`):
|
|
- Modal potwierdzenia audytu z ikoną ostrzeżenia
|
|
- Modal informacyjny o błędach
|
|
- Animacje CSS (fade in/out)
|
|
|
|
**Lokalizacja kodu:** `templates/admin_seo_dashboard.html`
|
|
|
|
## Planowane funkcjonalności (Backlog)
|
|
|
|
### Priorytet 4: System rekomendacji i zdjęć
|
|
**Status:** Planowane
|
|
**Cel:** Umożliwienie firmom członkowskim wzajemnego polecania się oraz prezentacji zdjęć
|
|
|
|
**Funkcje:**
|
|
- Rekomendacje między firmami (kto poleca kogo)
|
|
- Galeria zdjęć firmy (realizacje, zespół, biuro)
|
|
- Wyświetlanie na profilu firmy
|
|
|
|
### Priorytet 5: Status członkostwa i płatności
|
|
**Status:** Planowane
|
|
**Cel:** Śledzenie statusu członkostwa i składek miesięcznych
|
|
|
|
**Funkcje:**
|
|
- Status członka (aktywny, zawieszony, były członek)
|
|
- Informacja o opłaconych składkach
|
|
- Historia płatności
|
|
- Przypomnienia o zaległościach (dla admina)
|
|
|
|
**Tabela `membership_fees`:**
|
|
```sql
|
|
membership_fees (
|
|
id SERIAL PRIMARY KEY,
|
|
company_id INTEGER REFERENCES companies(id),
|
|
period_start DATE NOT NULL, -- początek okresu (np. 2026-01-01)
|
|
period_end DATE NOT NULL, -- koniec okresu (np. 2026-01-31)
|
|
amount DECIMAL(10,2) NOT NULL, -- kwota składki
|
|
status VARCHAR(20) DEFAULT 'pending', -- pending, paid, overdue
|
|
paid_at TIMESTAMP,
|
|
payment_method VARCHAR(50), -- przelew, gotówka
|
|
notes TEXT,
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
)
|
|
```
|
|
|
|
## Forma prawna Norda Biznes
|
|
|
|
### Stan obecny
|
|
- **Forma:** OPP (Organizacja Pożytku Publicznego)
|
|
- **Typ:** Stowarzyszenie non-profit
|
|
|
|
### Planowana transformacja
|
|
- **Docelowa forma:** Działalność gospodarcza (przy Izbie)
|
|
- **Cel:** Możliwość pozyskiwania dofinansowań (granty, projekty UE)
|
|
- **Korzyści:**
|
|
- Dostęp do funduszy na rozwój platformy
|
|
- Możliwość świadczenia płatnych usług
|
|
- Elastyczność finansowa
|