Przejdź do treści

🏗️ Przegląd Architektury

Ten dokument opisuje ogólną architekturę systemu Panel Księgowy.


🎯 Architektura wysokiego poziomu

Panel Księgowy to multi-tenant SaaS platform zbudowana na Django 5.2, która umożliwia biurom rachunkowym zarządzanie klientami, fakturami, zadaniami i innymi aspektami działalności.

Kluczowe cechy

  • Multi-tenancy - Każdy zespół (Team) ma izolowaną bazę danych logicznie
  • Team-based URLs - Wszystkie URL-e są w kontekście zespołu
  • Function-based views - Preferowane nad class-based views
  • HTMX + Alpine.js - Nowoczesny frontend bez SPA
  • PostgreSQL - Baza danych główna
  • Redis - Cache i message broker
  • Celery - Asynchroniczne zadania

🏗️ Warstwy architektury

1. Frontend Layer

Technologie: - HTMX - Interakcje z backendem (AJAX bez JavaScript) - Alpine.js - Interakcje po stronie klienta - Tailwind CSS 4 - Framework CSS - DaisyUI - Komponenty UI - Vite - Build system

Charakterystyka: - Progressive Enhancement - Działa bez JavaScript, lepiej z nim - Server-side rendering - Django templates - No SPA - Tradycyjne request/response z HTMX enhancements

2. Application Layer

Technologie: - Django 5.2 - Framework backendowy - Python 3.12 - Język programowania - Django ORM - Warstwa dostępu do danych - Celery - Asynchroniczne zadania - Django REST Framework - API (gdy potrzebne)

Charakterystyka: - Function-based views - Preferowane - Team isolation - Wszystkie zapytania filtrowane po team - BaseTeamModel - Wszystkie modele biznesowe dziedziczą po BaseTeamModel

3. Data Layer

Technologie: - PostgreSQL - Baza danych główna - Redis - Cache i message broker dla Celery - File Storage - Przechowywanie plików (local/S3)

Charakterystyka: - Multi-tenant - Fizycznie jedna baza, logicznie izolowana - Team filtering - Wszystkie zapytania filtrowane po team_id - Indexes - Zoptymalizowane indeksy na team_id


🔐 Multi-tenancy

Virtual Tenant Isolation

System używa virtual tenant isolation - wszystkie dane są w jednej bazie PostgreSQL, ale logicznie izolowane przez filtrowanie po team_id.

Zalety: - ✅ Prostsze zarządzanie (jedna baza) - ✅ Łatwiejsze backup i restore - ✅ Lepsze wykorzystanie zasobów - ✅ Prostsze skalowanie

Bezpieczeństwo: - ✅ Wszystkie zapytania filtrowane po team_id - ✅ BaseTeamModel wymusza team field - ✅ Decorators sprawdzają dostęp do team - ✅ Brak możliwości cross-team access

Team Model

class Team(SubscriptionModelBase, BaseModel):
    """Team (virtual tenant) model."""

    name = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    nip = models.CharField(max_length=10)
    # ... inne pola

BaseTeamModel

class BaseTeamModel(BaseModel):
    """Abstract model for objects that are part of a team."""

    team = models.ForeignKey("teams.Team", on_delete=models.CASCADE)

    class Meta:
        abstract = True

Użycie:

class Client(BaseTeamModel):
    name = models.CharField(max_length=200)
    nip = models.CharField(max_length=10)
    # team field jest automatycznie dodany


🌐 URL Structure

Team-based URLs

Wszystkie URL-e biznesowe są w kontekście zespołu:

/a/<team_slug>/<module>/<action>/

Przykłady: - /a/my-team/clients/ - Lista klientów - /a/my-team/clients/123/ - Szczegóły klienta - /a/my-team/invoicing/ - Faktury - /a/my-team/tasks/ - Zadania

Decorators

@login_and_team_required
def client_list(request, team_slug):
    """Lista klientów - wymaga logowania i członkostwa w team."""
    team = request.team  # Automatycznie dodane przez decorator
    clients = Client.objects.filter(team=team)
    # ...

📦 Struktura modułów

Każdy moduł ma standardową strukturę:

apps/module_name/
├── __init__.py
├── models/
│   ├── __init__.py
│   └── main.py          # BaseTeamModel models
├── views/
│   ├── __init__.py
│   ├── dashboard.py     # Dashboard view
│   ├── settings.py      # Settings view
│   └── crud.py          # CRUD views
├── templates/module_name/
│   ├── dashboard.html
│   └── settings.html
├── urls.py              # team_urlpatterns
├── admin.py
├── forms.py
├── services.py          # Business logic
├── tasks.py             # Celery tasks
└── README.md

🔄 Request Flow

Standardowy request

  1. User → Kliknięcie linku/przycisku
  2. HTMX → AJAX request do Django
  3. Django → Decorator sprawdza dostęp do team
  4. View → Pobiera dane (filtrowane po team)
  5. Template → Renderuje HTML
  6. HTMX → Wstawia HTML do DOM

Przykład

# views.py
@login_and_team_required
def client_list(request, team_slug):
    clients = Client.objects.filter(team=request.team)
    return render(request, 'crm/client_list.html', {
        'clients': clients
    })
<!-- client_list.html -->
{% for client in clients %}
  <div hx-get="/a/{{ team.slug }}/clients/{{ client.id }}/"
       hx-target="#client-detail">
    {{ client.name }}
  </div>
{% endfor %}

🗄️ Database Schema

Kluczowe tabele

  • teams_team - Zespoły (virtual tenants)
  • teams_membership - Członkostwo użytkowników w zespołach
  • crm_client - Klienci (z team_id)
  • invoicing_invoice - Faktury (z team_id)
  • tasks_task - Zadania (z team_id)

Relacje

Team (1) ──< (N) Membership
Team (1) ──< (N) Client
Team (1) ──< (N) Invoice
Team (1) ──< (N) Task

🔧 Services Layer

Business Logic

Business logic jest w services.py:

# services.py
class ClientService:
    @staticmethod
    def create_client(team, data):
        """Tworzy klienta z walidacją."""
        # Walidacja
        # Tworzenie
        # Integracje
        return client

📚 Więcej informacji


Ostatnia aktualizacja: 2025-11-29
Wersja dokumentacji: 1.0