3782 lines
152 KiB
Python
3782 lines
152 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Generator documente livrabile PNRR - Platforma DiDi
|
|
TOP CLOSSERS SRL | CUI: 36193026
|
|
Proiect: PNRR Contract 11.1.i3.c9/10.05.2024
|
|
|
|
Genereaza 4 documente DOCX profesionale:
|
|
1. Manual_Utilizare_Website.docx
|
|
2. Ghid_Administrare_ERPNext.docx
|
|
3. Documentatie_API.docx
|
|
4. Arhitectura_Detaliata.docx
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
|
|
# Force UTF-8 output
|
|
if sys.stdout.encoding != "utf-8":
|
|
sys.stdout.reconfigure(encoding="utf-8")
|
|
|
|
from docx import Document
|
|
from docx.shared import Inches, Pt, Cm, RGBColor, Emu
|
|
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
|
from docx.enum.table import WD_TABLE_ALIGNMENT
|
|
from docx.enum.section import WD_ORIENT
|
|
from docx.oxml.ns import qn, nsdecls
|
|
from docx.oxml import parse_xml
|
|
import datetime
|
|
|
|
# ==============================================================================
|
|
# CONFIGURATION
|
|
# ==============================================================================
|
|
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
SCREENSHOTS_DIR = os.path.join(BASE_DIR, "screenshots")
|
|
OUTPUT_DIR = BASE_DIR
|
|
|
|
COMPANY = {
|
|
"name": "TOP CLOSSERS SRL",
|
|
"cui": "36193026",
|
|
"address": "Str. Targovistei 15, Ploiesti, 100299, Prahova",
|
|
"representative": "Alexe Vasile-Emilian",
|
|
"project_ref": "PNRR Contract 11.1.i3.c9/10.05.2024",
|
|
"platform": "DiDi - Platforma Digitala Inteligenta pentru Prevenirea si Combaterea Dezinformarii",
|
|
"date": "Aprilie 2026",
|
|
}
|
|
|
|
HEADER_TEXT = "DiDi - Platforma Digitala Inteligenta"
|
|
FOOTER_TEXT = "TOP CLOSSERS SRL | CUI: 36193026 | Confidential"
|
|
|
|
|
|
# ==============================================================================
|
|
# HELPER FUNCTIONS
|
|
# ==============================================================================
|
|
|
|
|
|
def create_document():
|
|
"""Create a new document with base styles configured."""
|
|
doc = Document()
|
|
|
|
# Configure default font
|
|
style = doc.styles["Normal"]
|
|
font = style.font
|
|
font.name = "Calibri"
|
|
font.size = Pt(11)
|
|
font.color.rgb = RGBColor(0x33, 0x33, 0x33)
|
|
style.paragraph_format.space_after = Pt(6)
|
|
style.paragraph_format.line_spacing = 1.15
|
|
|
|
# Configure heading styles
|
|
for level, (size, color, bold) in {
|
|
"Heading 1": (Pt(20), RGBColor(0x1A, 0x3C, 0x6E), True),
|
|
"Heading 2": (Pt(16), RGBColor(0x2B, 0x57, 0x9A), True),
|
|
"Heading 3": (Pt(13), RGBColor(0x3A, 0x6E, 0xAF), True),
|
|
}.items():
|
|
h_style = doc.styles[level]
|
|
h_style.font.name = "Calibri"
|
|
h_style.font.size = size
|
|
h_style.font.color.rgb = color
|
|
h_style.font.bold = bold
|
|
h_style.paragraph_format.space_before = Pt(18 if level == "Heading 1" else 12)
|
|
h_style.paragraph_format.space_after = Pt(8)
|
|
|
|
# Set margins
|
|
for section in doc.sections:
|
|
section.top_margin = Cm(2.5)
|
|
section.bottom_margin = Cm(2.5)
|
|
section.left_margin = Cm(2.5)
|
|
section.right_margin = Cm(2.5)
|
|
|
|
return doc
|
|
|
|
|
|
def add_header_footer(doc):
|
|
"""Add header and footer to all sections."""
|
|
for section in doc.sections:
|
|
# Header
|
|
header = section.header
|
|
header.is_linked_to_previous = False
|
|
hp = header.paragraphs[0] if header.paragraphs else header.add_paragraph()
|
|
hp.text = HEADER_TEXT
|
|
hp.alignment = WD_ALIGN_PARAGRAPH.RIGHT
|
|
run = hp.runs[0] if hp.runs else hp.add_run()
|
|
run.font.size = Pt(9)
|
|
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
|
run.font.italic = True
|
|
|
|
# Footer
|
|
footer = section.footer
|
|
footer.is_linked_to_previous = False
|
|
fp = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph()
|
|
fp.text = FOOTER_TEXT
|
|
fp.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
run = fp.runs[0] if fp.runs else fp.add_run()
|
|
run.font.size = Pt(8)
|
|
run.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
|
|
|
|
|
|
def add_cover_page(doc, title, subtitle=None):
|
|
"""Add a professional cover page."""
|
|
# Add empty paragraphs for spacing
|
|
for _ in range(4):
|
|
p = doc.add_paragraph()
|
|
p.paragraph_format.space_after = Pt(0)
|
|
|
|
# Main title
|
|
p = doc.add_paragraph()
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
run = p.add_run(title)
|
|
run.bold = True
|
|
run.font.size = Pt(28)
|
|
run.font.color.rgb = RGBColor(0x1A, 0x3C, 0x6E)
|
|
run.font.name = "Calibri"
|
|
|
|
if subtitle:
|
|
p = doc.add_paragraph()
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
run = p.add_run(subtitle)
|
|
run.font.size = Pt(16)
|
|
run.font.color.rgb = RGBColor(0x2B, 0x57, 0x9A)
|
|
run.font.name = "Calibri"
|
|
|
|
# Separator line
|
|
doc.add_paragraph()
|
|
p = doc.add_paragraph()
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
run = p.add_run("_" * 60)
|
|
run.font.color.rgb = RGBColor(0xCC, 0xCC, 0xCC)
|
|
|
|
doc.add_paragraph()
|
|
|
|
# Project info table
|
|
info_data = [
|
|
("Beneficiar", COMPANY["name"]),
|
|
("CUI", COMPANY["cui"]),
|
|
("Adresa", COMPANY["address"]),
|
|
("Reprezentant Legal", COMPANY["representative"]),
|
|
("Referinta Proiect", COMPANY["project_ref"]),
|
|
("Platforma", COMPANY["platform"]),
|
|
("Data", COMPANY["date"]),
|
|
]
|
|
|
|
table = doc.add_table(rows=len(info_data), cols=2)
|
|
table.alignment = WD_TABLE_ALIGNMENT.CENTER
|
|
table.style = "Table Grid"
|
|
|
|
for i, (label, value) in enumerate(info_data):
|
|
cell_label = table.rows[i].cells[0]
|
|
cell_value = table.rows[i].cells[1]
|
|
|
|
# Label cell
|
|
p = cell_label.paragraphs[0]
|
|
run = p.add_run(label)
|
|
run.bold = True
|
|
run.font.size = Pt(10)
|
|
run.font.name = "Calibri"
|
|
run.font.color.rgb = RGBColor(0x1A, 0x3C, 0x6E)
|
|
|
|
# Value cell
|
|
p = cell_value.paragraphs[0]
|
|
run = p.add_run(value)
|
|
run.font.size = Pt(10)
|
|
run.font.name = "Calibri"
|
|
|
|
# Style cells
|
|
for cell in [cell_label, cell_value]:
|
|
tc = cell._tc
|
|
tcPr = tc.get_or_add_tcPr()
|
|
shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="F5F7FA" w:val="clear"/>')
|
|
tcPr.append(shading)
|
|
|
|
# Set column widths
|
|
for row in table.rows:
|
|
row.cells[0].width = Inches(2.2)
|
|
row.cells[1].width = Inches(4.0)
|
|
|
|
# Add page break after cover
|
|
doc.add_page_break()
|
|
|
|
|
|
def add_screenshot(doc, subfolder, filename, caption=None, width=Inches(6)):
|
|
"""Add a screenshot image with caption. Skip gracefully if not found."""
|
|
img_path = os.path.join(SCREENSHOTS_DIR, subfolder, filename)
|
|
if not os.path.exists(img_path):
|
|
p = doc.add_paragraph()
|
|
run = p.add_run(f"[Captura de ecran: {filename} - fisier indisponibil]")
|
|
run.italic = True
|
|
run.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
|
|
run.font.size = Pt(9)
|
|
return
|
|
|
|
try:
|
|
doc.add_picture(img_path, width=width)
|
|
# Center the image
|
|
last_paragraph = doc.paragraphs[-1]
|
|
last_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
|
|
if caption:
|
|
p = doc.add_paragraph()
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
run = p.add_run(f"Figura: {caption}")
|
|
run.italic = True
|
|
run.font.size = Pt(9)
|
|
run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
|
|
p.paragraph_format.space_after = Pt(12)
|
|
except Exception as e:
|
|
p = doc.add_paragraph()
|
|
run = p.add_run(f"[Eroare la incarcarea capturii: {filename} - {str(e)}]")
|
|
run.italic = True
|
|
run.font.color.rgb = RGBColor(0xCC, 0x00, 0x00)
|
|
run.font.size = Pt(9)
|
|
|
|
|
|
def add_table_with_header(doc, headers, rows, col_widths=None):
|
|
"""Add a formatted table with header row."""
|
|
table = doc.add_table(rows=1 + len(rows), cols=len(headers))
|
|
table.style = "Table Grid"
|
|
table.alignment = WD_TABLE_ALIGNMENT.CENTER
|
|
|
|
# Header row
|
|
for i, header in enumerate(headers):
|
|
cell = table.rows[0].cells[i]
|
|
p = cell.paragraphs[0]
|
|
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
|
run = p.add_run(header)
|
|
run.bold = True
|
|
run.font.size = Pt(9)
|
|
run.font.name = "Calibri"
|
|
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
|
|
# Dark blue background
|
|
tc = cell._tc
|
|
tcPr = tc.get_or_add_tcPr()
|
|
shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="1A3C6E" w:val="clear"/>')
|
|
tcPr.append(shading)
|
|
|
|
# Data rows
|
|
for row_idx, row_data in enumerate(rows):
|
|
for col_idx, value in enumerate(row_data):
|
|
cell = table.rows[row_idx + 1].cells[col_idx]
|
|
p = cell.paragraphs[0]
|
|
run = p.add_run(str(value))
|
|
run.font.size = Pt(9)
|
|
run.font.name = "Calibri"
|
|
# Alternate row shading
|
|
if row_idx % 2 == 0:
|
|
tc = cell._tc
|
|
tcPr = tc.get_or_add_tcPr()
|
|
shading = parse_xml(
|
|
f'<w:shd {nsdecls("w")} w:fill="F5F7FA" w:val="clear"/>'
|
|
)
|
|
tcPr.append(shading)
|
|
|
|
# Set column widths if specified
|
|
if col_widths:
|
|
for row in table.rows:
|
|
for i, width in enumerate(col_widths):
|
|
if i < len(row.cells):
|
|
row.cells[i].width = width
|
|
|
|
doc.add_paragraph() # Spacing after table
|
|
return table
|
|
|
|
|
|
def add_bullet_list(doc, items, level=0):
|
|
"""Add a bulleted list."""
|
|
for item in items:
|
|
p = doc.add_paragraph(style="List Bullet")
|
|
run = p.add_run(item)
|
|
run.font.size = Pt(10)
|
|
run.font.name = "Calibri"
|
|
if level > 0:
|
|
p.paragraph_format.left_indent = Cm(1.5 * level)
|
|
|
|
|
|
def add_numbered_list(doc, items):
|
|
"""Add a numbered list."""
|
|
for item in items:
|
|
p = doc.add_paragraph(style="List Number")
|
|
run = p.add_run(item)
|
|
run.font.size = Pt(10)
|
|
run.font.name = "Calibri"
|
|
|
|
|
|
def add_note_box(doc, text, note_type="info"):
|
|
"""Add a styled note/info box using a single-cell table."""
|
|
colors = {
|
|
"info": ("E8F0FE", "1A3C6E"),
|
|
"warning": ("FFF3CD", "856404"),
|
|
"tip": ("D4EDDA", "155724"),
|
|
}
|
|
bg_color, text_color = colors.get(note_type, colors["info"])
|
|
|
|
table = doc.add_table(rows=1, cols=1)
|
|
table.style = "Table Grid"
|
|
cell = table.rows[0].cells[0]
|
|
|
|
# Set background
|
|
tc = cell._tc
|
|
tcPr = tc.get_or_add_tcPr()
|
|
shading = parse_xml(
|
|
f'<w:shd {nsdecls("w")} w:fill="{bg_color}" w:val="clear"/>'
|
|
)
|
|
tcPr.append(shading)
|
|
|
|
p = cell.paragraphs[0]
|
|
prefix = {"info": "NOTA: ", "warning": "ATENTIE: ", "tip": "SFAT: "}.get(
|
|
note_type, ""
|
|
)
|
|
run = p.add_run(prefix)
|
|
run.bold = True
|
|
run.font.size = Pt(9)
|
|
run.font.color.rgb = RGBColor(
|
|
int(text_color[0:2], 16), int(text_color[2:4], 16), int(text_color[4:6], 16)
|
|
)
|
|
run = p.add_run(text)
|
|
run.font.size = Pt(9)
|
|
run.font.color.rgb = RGBColor(
|
|
int(text_color[0:2], 16), int(text_color[2:4], 16), int(text_color[4:6], 16)
|
|
)
|
|
|
|
doc.add_paragraph() # Spacing
|
|
|
|
|
|
def add_code_block(doc, code_text):
|
|
"""Add a code block with monospace font and gray background."""
|
|
table = doc.add_table(rows=1, cols=1)
|
|
table.style = "Table Grid"
|
|
cell = table.rows[0].cells[0]
|
|
|
|
tc = cell._tc
|
|
tcPr = tc.get_or_add_tcPr()
|
|
shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="F4F4F4" w:val="clear"/>')
|
|
tcPr.append(shading)
|
|
|
|
p = cell.paragraphs[0]
|
|
for line in code_text.strip().split("\n"):
|
|
run = p.add_run(line + "\n")
|
|
run.font.name = "Consolas"
|
|
run.font.size = Pt(8.5)
|
|
run.font.color.rgb = RGBColor(0x2D, 0x2D, 0x2D)
|
|
|
|
doc.add_paragraph()
|
|
|
|
|
|
def add_toc_placeholder(doc):
|
|
"""Add a Table of Contents placeholder heading."""
|
|
doc.add_heading("Cuprins", level=1)
|
|
p = doc.add_paragraph()
|
|
run = p.add_run(
|
|
"[Cuprinsul se genereaza automat in Microsoft Word: References > Table of Contents > Update Table]"
|
|
)
|
|
run.italic = True
|
|
run.font.size = Pt(10)
|
|
run.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
|
|
|
|
# Insert TOC field
|
|
paragraph = doc.add_paragraph()
|
|
run = paragraph.add_run()
|
|
fldChar = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="begin"/>')
|
|
run._r.append(fldChar)
|
|
run = paragraph.add_run()
|
|
instrText = parse_xml(
|
|
f'<w:instrText {nsdecls("w")} xml:space="preserve"> TOC \\o "1-3" \\h \\z \\u </w:instrText>'
|
|
)
|
|
run._r.append(instrText)
|
|
run = paragraph.add_run()
|
|
fldChar = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="separate"/>')
|
|
run._r.append(fldChar)
|
|
run = paragraph.add_run("Actualizati cuprinsul dupa deschiderea documentului.")
|
|
run.font.color.rgb = RGBColor(0x99, 0x99, 0x99)
|
|
run.font.italic = True
|
|
run = paragraph.add_run()
|
|
fldChar = parse_xml(f'<w:fldChar {nsdecls("w")} w:fldCharType="end"/>')
|
|
run._r.append(fldChar)
|
|
|
|
doc.add_page_break()
|
|
|
|
|
|
# ==============================================================================
|
|
# DOCUMENT 1: Manual Utilizare Website
|
|
# ==============================================================================
|
|
|
|
|
|
def generate_manual_utilizare():
|
|
"""Generate Manual_Utilizare_Website.docx"""
|
|
print("[1/4] Generare Manual_Utilizare_Website.docx ...")
|
|
|
|
doc = create_document()
|
|
|
|
# Cover page
|
|
add_cover_page(
|
|
doc,
|
|
"MANUAL DE UTILIZARE",
|
|
"Website DiDi cu E-commerce",
|
|
)
|
|
|
|
add_header_footer(doc)
|
|
add_toc_placeholder(doc)
|
|
|
|
# =========================================================================
|
|
# CHAPTER 1: Introducere
|
|
# =========================================================================
|
|
doc.add_heading("1. Introducere", level=1)
|
|
|
|
doc.add_heading("1.1 Prezentarea Platformei DiDi", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"DiDi (Platforma Digitala Inteligenta pentru Prevenirea si Combaterea Dezinformarii) "
|
|
"este o solutie web inovatoare dezvoltata in cadrul proiectului PNRR Contract 11.1.i3.c9/10.05.2024 "
|
|
"de catre TOP CLOSSERS SRL. Platforma ofera instrumente avansate bazate pe inteligenta artificiala "
|
|
"pentru detectarea si analiza dezinformarii in continut digital."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma DiDi combina tehnologii de ultima generatie in procesarea limbajului natural (NLP), "
|
|
"detectia deepfake-urilor, verificarea faptelor (fact-checking), evaluarea credibilitatii surselor "
|
|
"si identificarea tehnicilor de manipulare. Aceste capabilitati sunt disponibile prin intermediul "
|
|
"unui website modern, intuitiv si accesibil, integrat cu un sistem de e-commerce care permite "
|
|
"achizitionarea serviciilor de analiza in mod simplu si securizat."
|
|
)
|
|
|
|
doc.add_heading("1.2 Scopul Documentului", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Prezentul manual de utilizare are ca scop principal furnizarea instructiunilor detaliate pentru "
|
|
"utilizarea website-ului DiDi de catre toate categoriile de utilizatori. Documentul acopera:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Navigarea pe paginile publice ale website-ului",
|
|
"Procesul de inregistrare si autentificare",
|
|
"Utilizarea dashboard-ului client pentru achizitionarea si rularea analizelor",
|
|
"Procesul de plata prin Stripe",
|
|
"Vizualizarea facturilor si gestionarea profilului",
|
|
"Functionalitati tehnice suplimentare (responsive design, multilingvism, SEO)",
|
|
])
|
|
|
|
doc.add_heading("1.3 Audienta Tinta", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Acest manual se adreseaza urmatoarelor categorii de utilizatori:")
|
|
add_bullet_list(doc, [
|
|
"Clienti finali - persoane fizice sau juridice care doresc sa utilizeze serviciile de analiza DiDi pentru verificarea continutului digital",
|
|
"Administratori de continut - personal responsabil cu gestionarea informatiilor de pe website",
|
|
"Personal tehnic de suport - echipa care ofera asistenta utilizatorilor platformei",
|
|
"Evaluatori PNRR - persoane implicate in verificarea si evaluarea livrabilelor proiectului",
|
|
])
|
|
|
|
doc.add_heading("1.4 Conventii Utilizate in Document", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run("In cadrul acestui manual se utilizeaza urmatoarele conventii:")
|
|
add_bullet_list(doc, [
|
|
"Textul bold indica elemente de interfata (butoane, meniuri, etichete)",
|
|
"Textul italic indica note importante sau observatii",
|
|
"Capturile de ecran ilustreaza starea reala a interfetei la momentul documentarii",
|
|
"Casetele colorate contin note, avertismente sau sfaturi utile",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 2: Accesare si Navigare
|
|
# =========================================================================
|
|
doc.add_heading("2. Accesare si Navigare", level=1)
|
|
|
|
doc.add_heading("2.1 Accesarea Website-ului", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul DiDi este accesibil prin intermediul unui browser web modern (Google Chrome, Mozilla Firefox, "
|
|
"Microsoft Edge, Safari) la urmatoarea adresa URL:"
|
|
)
|
|
add_code_block(doc, "https://didi365.eu")
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul este optimizat pentru cele mai recente versiuni ale browserelor mentionate si suporta "
|
|
"atat conexiuni desktop cat si dispozitive mobile (tableta, smartphone). Conexiunea este securizata "
|
|
"prin protocol HTTPS cu certificat TLS valid."
|
|
)
|
|
|
|
doc.add_heading("2.2 Structura de Navigare", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Bara de navigare principala (navbar) este afisata in partea superioara a fiecarei pagini si contine "
|
|
"urmatoarele elemente:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Element", "Descriere", "Pozitie"],
|
|
[
|
|
["Logo DiDi", "Logo-ul platformei, click redirectioneaza la homepage", "Stanga"],
|
|
["Servicii", "Link catre pagina de prezentare a serviciilor de analiza", "Centru"],
|
|
["Despre", "Link catre pagina cu informatii despre companie si platforma", "Centru"],
|
|
["Pricing", "Link catre pagina cu preturile serviciilor", "Centru"],
|
|
["Contact", "Link catre formularul de contact", "Centru"],
|
|
["Language Switcher", "Comutator RO/EN pentru schimbarea limbii interfetei", "Dreapta"],
|
|
["Autentificare / Dashboard", "Buton de login sau acces la dashboard (dupa autentificare)", "Dreapta"],
|
|
],
|
|
col_widths=[Inches(1.5), Inches(3.5), Inches(1.0)],
|
|
)
|
|
|
|
doc.add_heading("2.3 Footer", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Footer-ul website-ului contine informatii suplimentare organizate in sectiuni:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Linkuri rapide catre paginile principale (Servicii, Despre, Pricing, Contact)",
|
|
"Linkuri legale: Politica de Confidentialitate, Termeni si Conditii",
|
|
"Informatii de contact: adresa email, telefon",
|
|
"Copyright si informatii companie: TOP CLOSSERS SRL",
|
|
"Referinta proiect PNRR",
|
|
])
|
|
|
|
doc.add_heading("2.4 Selectarea Limbii (Language Switcher)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul DiDi este disponibil in doua limbi: Romana (RO) si Engleza (EN). "
|
|
"Utilizatorul poate comuta intre cele doua limbi folosind selectorul de limba "
|
|
"din coltul din dreapta sus al barei de navigare. Preferinta de limba se salveaza "
|
|
"in localStorage-ul browserului si se pastreaza la vizitele ulterioare."
|
|
)
|
|
|
|
add_screenshot(
|
|
doc, "website", "01-homepage.png", "Pagina principala DiDi - Navigare si structura generala"
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 3: Pagini Publice
|
|
# =========================================================================
|
|
doc.add_heading("3. Pagini Publice", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul DiDi ofera mai multe pagini publice accesibile fara autentificare, "
|
|
"care prezinta informatii despre platforma, serviciile disponibile si modalitatile de contact."
|
|
)
|
|
|
|
# 3.1 Homepage
|
|
doc.add_heading("3.1 Homepage (Pagina Principala)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina principala este punctul de intrare al website-ului si ofera o prezentare "
|
|
"completa a platformei DiDi. Este structurata in mai multe sectiuni verticale, "
|
|
"fiecare proiectata pentru a comunica clar valoarea si capabilitatile platformei."
|
|
)
|
|
|
|
doc.add_heading("Hero Section", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
'Sectiunea principala afiseaza branding-ul "by Clossers / didi" impreuna cu '
|
|
"un mesaj concis despre misiunea platformei de combatere a dezinformarii. "
|
|
"Include un buton CTA (Call-to-Action) care directioneaza utilizatorul catre "
|
|
"sectiunea de servicii sau catre inregistrare."
|
|
)
|
|
|
|
doc.add_heading("Sectiunea Despre Platforma", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Prezinta pe scurt scopul platformei DiDi si contextul in care a fost dezvoltata "
|
|
"(proiect PNRR pentru digitalizarea luptei impotriva dezinformarii). Se evidentiaza "
|
|
"caracterul inovator al solutiei si tehnologiile AI utilizate."
|
|
)
|
|
|
|
doc.add_heading("Sectiunea Capabilitati", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Afiseaza cele 6 module principale de analiza AI disponibile in platforma, fiecare "
|
|
"cu un icon reprezentativ, titlu si descriere scurta. Modulele acoperite sunt: "
|
|
"Analiza Text/NLP, Detectie Deepfake, Fact-Checking, Evaluare Surse, "
|
|
"Detectie Tehnici de Manipulare si Monitorizare in Timp Real."
|
|
)
|
|
|
|
doc.add_heading("Cum Functioneaza - 4 Pasi", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Aceasta sectiune prezinta procesul de utilizare a platformei in 4 pasi simpli:"
|
|
)
|
|
add_numbered_list(doc, [
|
|
"Creaza un cont - Inregistrare rapida prin sistemul de autentificare securizat Keycloak SSO",
|
|
"Achizitioneaza o analiza - Selecteaza tipul de analiza dorit si efectueaza plata prin Stripe",
|
|
"Incarca continutul - Introdu textul, URL-ul sau incarca fisierul media (imagine, audio, video)",
|
|
"Primeste rezultatele - Obtine un raport detaliat cu scorul de risc, incredere si recomandari",
|
|
])
|
|
|
|
doc.add_heading("Cazuri de Utilizare", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Sectiunea prezinta scenarii concrete in care platforma DiDi poate fi utilizata: "
|
|
"verificarea stirilor online, analiza continutului viral pe retele sociale, "
|
|
"detectarea imaginilor sau videoclipurilor manipulate, evaluarea credibilitatii "
|
|
"surselor de informatii si monitorizarea campaniilor de dezinformare."
|
|
)
|
|
|
|
doc.add_heading("Call-to-Action Final", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina se incheie cu o sectiune CTA care invita utilizatorii sa creeze un cont "
|
|
"si sa inceapa sa utilizeze platforma, oferind un buton de inregistrare prominent."
|
|
)
|
|
|
|
add_screenshot(doc, "website", "01-homepage.png", "Homepage - Pagina principala a website-ului DiDi")
|
|
|
|
doc.add_page_break()
|
|
|
|
# 3.2 Servicii
|
|
doc.add_heading("3.2 Servicii", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina de Servicii prezinta in detaliu cele 6 module de analiza AI disponibile "
|
|
"in platforma DiDi. Fiecare modul este descris cu functionalitati specifice, "
|
|
"tipuri de continut suportate si beneficii pentru utilizator."
|
|
)
|
|
|
|
doc.add_heading("Modulele de Analiza AI", level=3)
|
|
|
|
services_data = [
|
|
("Analiza Text / NLP", "Procesare avansata a limbajului natural pentru detectarea elementelor de dezinformare in texte. Identifica manipulari lingvistice, bias-uri si inconsistente factuale."),
|
|
("Detectie Deepfake", "Algoritmi de inteligenta artificiala pentru detectarea continutului media manipulat (imagini, audio, video). Identifica semne de alterare digitala si generare AI."),
|
|
("Fact-Checking", "Verificare automata a afirmatiilor din continut prin comparare cu surse credibile si baze de date verificate. Evalueaza veridicitatea informatiilor."),
|
|
("Evaluare Surse", "Analiza credibilitatii si reputatiei surselor de informatii. Evalueaza domenii web, publicatii si autori pe baza unui scoring multi-criterial."),
|
|
("Detectie Tehnici de Manipulare", "Identificarea tehnicilor specifice de manipulare si propaganda utilizate in continut: apel la emotie, cherry-picking, whataboutism, etc."),
|
|
("Monitorizare in Timp Real", "Monitorizare continua a fluxurilor de informatii pentru identificarea rapida a campaniilor de dezinformare si a trendurilor de manipulare."),
|
|
]
|
|
|
|
for name, desc in services_data:
|
|
doc.add_heading(name, level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(desc)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Fiecare serviciu este disponibil pentru diferite tipuri de media: text, imagine, audio, video "
|
|
"si URL. Preturile variaza in functie de complexitatea analizei si tipul de continut procesat."
|
|
)
|
|
|
|
add_screenshot(doc, "website", "02-services.png", "Pagina Servicii - Modulele de analiza AI DiDi")
|
|
|
|
doc.add_page_break()
|
|
|
|
# 3.3 Despre
|
|
doc.add_heading("3.3 Despre", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Despre ofera informatii detaliate despre compania Clossers si platforma DiDi. "
|
|
"Sectiunea prezinta misiunea companiei, viziunea pe termen lung in domeniul combaterii "
|
|
"dezinformarii si echipa de specialisti implicata in dezvoltarea platformei."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Se evidentiaza contextul dezvoltarii platformei in cadrul programului PNRR, obiectivele "
|
|
"urmarite si impactul asteptat asupra ecosistemului informational din Romania. Pagina include "
|
|
"de asemenea informatii despre metodologia de lucru si tehnologiile utilizate."
|
|
)
|
|
|
|
add_screenshot(doc, "website", "03-about.png", "Pagina Despre - Informatii companie si echipa")
|
|
|
|
# 3.4 Pricing
|
|
doc.add_heading("3.4 Pricing (Preturi)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Pricing afiseaza preturile serviciilor de analiza organizate pe 4 categorii de servicii "
|
|
"si tipuri de media. Preturile sunt exprimate in RON (lei romanesti) si includ TVA."
|
|
)
|
|
|
|
doc.add_heading("Categorii de Servicii si Preturi", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Categorie", "Text", "Imagine", "Audio", "Video", "URL"],
|
|
[
|
|
["Detectie Tehnici Manipulare", "9,99 RON", "14,99 RON", "19,99 RON", "24,99 RON", "9,99 RON"],
|
|
["AI Detection (Deepfake)", "9,99 RON", "14,99 RON", "19,99 RON", "24,99 RON", "9,99 RON"],
|
|
["Fact-Checking", "9,99 RON", "14,99 RON", "19,99 RON", "24,99 RON", "9,99 RON"],
|
|
["Evaluare Surse", "9,99 RON", "14,99 RON", "19,99 RON", "24,99 RON", "9,99 RON"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate serviciile sunt de tip one-time (plata unica per analiza). Fiecare achizitie ofera "
|
|
"dreptul de a efectua o singura analiza pe tipul de continut si categoria selectata. "
|
|
"Serviciile achizitionate nu expira si pot fi utilizate oricand."
|
|
)
|
|
|
|
add_screenshot(doc, "website", "04-pricing.png", "Pagina Pricing - Preturi servicii analiza")
|
|
|
|
doc.add_page_break()
|
|
|
|
# 3.5 Contact
|
|
doc.add_heading("3.5 Contact", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina de Contact pune la dispozitia vizitatorilor un formular simplu si intuitiv "
|
|
"pentru transmiterea mesajelor catre echipa DiDi. Formularul contine urmatoarele campuri:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Tip", "Obligatoriu", "Descriere"],
|
|
[
|
|
["Nume", "Text", "Da", "Numele complet al persoanei de contact"],
|
|
["Email", "Email", "Da", "Adresa de email pentru raspuns"],
|
|
["Mesaj", "Textarea", "Da", "Continutul mesajului (intrebare, solicitare, feedback)"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"La trimiterea formularului, datele sunt procesate automat si se creaza un Lead in sistemul "
|
|
"CRM ERPNext. Acest mecanism asigura ca fiecare solicitare este inregistrata si urmarita "
|
|
"de echipa de vanzari sau suport. Formularul suporta si parametri UTM pentru tracking-ul "
|
|
"sursei vizitatorului (sursa, mediu, campanie)."
|
|
)
|
|
|
|
add_note_box(
|
|
doc,
|
|
"Toate datele transmise prin formularul de contact sunt prelucrate in conformitate "
|
|
"cu Regulamentul General privind Protectia Datelor (GDPR). Consultati Politica de "
|
|
"Confidentialitate pentru detalii complete.",
|
|
"info",
|
|
)
|
|
|
|
add_screenshot(doc, "website", "05-contact.png", "Pagina Contact - Formularul de contact")
|
|
|
|
# 3.6 Confidentialitate
|
|
doc.add_heading("3.6 Politica de Confidentialitate", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina de Politica de Confidentialitate contine documentul complet privind protectia "
|
|
"datelor cu caracter personal, in conformitate cu Regulamentul (UE) 2016/679 (GDPR). "
|
|
"Documentul acopera urmatoarele aspecte principale:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Identitatea si datele de contact ale operatorului de date (TOP CLOSSERS SRL)",
|
|
"Categoriile de date cu caracter personal colectate",
|
|
"Scopurile si temeiurile juridice ale prelucrarii datelor",
|
|
"Durata de pastrare a datelor personale",
|
|
"Drepturile persoanelor vizate (acces, rectificare, stergere, portabilitate, opozitie)",
|
|
"Informatii privind utilizarea cookie-urilor si tehnologiilor de urmarire",
|
|
"Masurile de securitate implementate pentru protectia datelor",
|
|
"Procedura de depunere a plangerilor la Autoritatea Nationala de Supraveghere (ANSPDCP)",
|
|
])
|
|
|
|
add_screenshot(doc, "website", "06-privacy.png", "Pagina Politica de Confidentialitate")
|
|
|
|
doc.add_page_break()
|
|
|
|
# 3.7 Termeni si Conditii
|
|
doc.add_heading("3.7 Termeni si Conditii", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Termeni si Conditii contine acordul legal complet care guverneaza utilizarea "
|
|
"platformei DiDi. Documentul stabileste drepturile si obligatiile utilizatorilor, "
|
|
"precum si ale operatorului platformei. Principalele capitole includ:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Definitii si terminologie utilizata in cadrul acordului",
|
|
"Conditii de utilizare a platformei si serviciilor",
|
|
"Procesul de inregistrare si obligatiile utilizatorului privind securitatea contului",
|
|
"Descrierea serviciilor oferite si limitarile acestora",
|
|
"Politica de preturi, plati si rambursari",
|
|
"Proprietatea intelectuala si drepturile de autor",
|
|
"Limitarea raspunderii operatorului platformei",
|
|
"Procedura de rezolvare a disputelor",
|
|
"Legislatia aplicabila si jurisdictia competenta",
|
|
])
|
|
|
|
add_screenshot(doc, "website", "07-terms.png", "Pagina Termeni si Conditii")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 4: Autentificare
|
|
# =========================================================================
|
|
doc.add_heading("4. Autentificare si Gestionarea Contului", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma DiDi utilizeaza sistemul de autentificare Keycloak SSO (Single Sign-On) "
|
|
"pentru gestionarea securizata a conturilor utilizatorilor. Acest sistem ofera un nivel "
|
|
"ridicat de securitate si o experienta consistenta de autentificare."
|
|
)
|
|
|
|
doc.add_heading("4.1 Crearea Contului (Inregistrare)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pentru a utiliza serviciile platite ale platformei DiDi, utilizatorul trebuie sa isi "
|
|
"creeze un cont. Procesul de inregistrare se desfasoara in urmatorii pasi:"
|
|
)
|
|
|
|
add_numbered_list(doc, [
|
|
'Accesati website-ul DiDi si apasati butonul "Autentificare" sau "Inregistrare" din bara de navigare',
|
|
"Veti fi redirectionat automat catre pagina de autentificare Keycloak SSO (didi365.eu/didi-auth)",
|
|
'Apasati linkul "Inregistrare" de sub formularul de login',
|
|
"Completati formularul de inregistrare cu urmatoarele informatii: prenume, nume, adresa de email, parola (minim 8 caractere)",
|
|
"Confirmati adresa de email prin accesarea linkului primit in casuta de email",
|
|
"Dupa confirmare, contul este activ si puteti accesa dashboard-ul client",
|
|
])
|
|
|
|
add_note_box(
|
|
doc,
|
|
"La prima autentificare, sistemul creeaza automat un profil de client in ERPNext "
|
|
"asociat cu ID-ul unic Keycloak (UUID). Acest profil va fi utilizat pentru facturare, "
|
|
"istoricul achizitiilor si gestionarea serviciilor.",
|
|
"info",
|
|
)
|
|
|
|
doc.add_heading("4.2 Autentificare (Login)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Procesul de autentificare se desfasoara astfel:")
|
|
|
|
add_numbered_list(doc, [
|
|
'Apasati butonul "Autentificare" din bara de navigare a website-ului',
|
|
"Sunteti redirectionat catre pagina de login Keycloak SSO",
|
|
"Introduceti adresa de email si parola contului dvs.",
|
|
'Apasati butonul "Conectare"',
|
|
"Dupa autentificarea reusita, sunteti redirectionat inapoi pe website cu o sesiune activa",
|
|
"In bara de navigare va aparea optiunea de acces la Dashboard in locul butonului de login",
|
|
])
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Sesiunea de autentificare este gestionata prin JWT (JSON Web Token) cu durata limitata. "
|
|
"Sesiunea se reinnoieste automat prin mecanismul de refresh token, asigurand o experienta "
|
|
"fluida fara deconectari frecvente."
|
|
)
|
|
|
|
doc.add_heading("4.3 Deconectare (Logout)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
'Pentru a va deconecta din platforma, apasati butonul "Deconectare" disponibil in '
|
|
"bara de navigare sau in meniul de profil din dashboard. La deconectare:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Sesiunea locala este invalidata",
|
|
"Token-ul JWT este revocat",
|
|
"Sunteti redirectionat catre pagina principala a website-ului",
|
|
"Pentru a accesa din nou dashboard-ul, va trebui sa va autentificati din nou",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 5: Dashboard Client
|
|
# =========================================================================
|
|
doc.add_heading("5. Dashboard Client", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Dashboard-ul client este zona privata a platformei, accesibila doar utilizatorilor autentificati. "
|
|
"Ofera acces la toate functionalitatile de achizitionare, rulare analize, vizualizare rezultate "
|
|
"si gestionare a contului."
|
|
)
|
|
|
|
# 5.1 Overview
|
|
doc.add_heading("5.1 Overview (Pagina Principala Dashboard)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Overview este prima pagina afisata dupa autentificare si ofera o vedere de ansamblu "
|
|
"asupra contului si activitatii utilizatorului. Elementele principale includ:"
|
|
)
|
|
|
|
doc.add_heading("Salut Personalizat", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"In partea superioara se afiseaza un mesaj de bun venit personalizat cu numele utilizatorului "
|
|
'autentificat (exemplu: "Buna ziua, Vasile!").'
|
|
)
|
|
|
|
doc.add_heading("Carduri Statistici", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Dashboard-ul afiseaza carduri informative cu urmatoarele statistici:")
|
|
add_bullet_list(doc, [
|
|
"Achizitii totale - numarul total de servicii de analiza achizitionate",
|
|
"Disponibile - numarul de analize achizitionate dar inca neutilizate",
|
|
"Rezumat - prezentare generala a activitatii contului",
|
|
])
|
|
|
|
doc.add_heading("Ultimele Facturi", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"In sectiunea inferioara se afiseaza o lista cu ultimele facturi emise, permitand "
|
|
"vizualizarea rapida a tranzactiilor recente."
|
|
)
|
|
|
|
add_screenshot(doc, "dashboard", "01-overview.png", "Dashboard - Pagina Overview cu statistici si rezumat")
|
|
|
|
doc.add_page_break()
|
|
|
|
# 5.2 Achizitioneaza Analiza
|
|
doc.add_heading("5.2 Achizitioneaza Analiza", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Achizitioneaza Analiza permite utilizatorilor sa cumpere servicii de analiza AI. "
|
|
"Serviciile sunt organizate pe 4 categorii principale, fiecare disponibila pentru "
|
|
"diferite tipuri de media."
|
|
)
|
|
|
|
doc.add_heading("Categorii de Servicii Disponibile", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Categorie", "Cod Intern", "Descriere"],
|
|
[
|
|
["Detectie Tehnici Manipulare", "DIDI-TECHNIQUES-*", "Identificarea tehnicilor de propaganda si manipulare in continut"],
|
|
["AI Detection (Deepfake)", "DIDI-AI_DETECTION-*", "Detectarea continutului generat sau modificat de AI"],
|
|
["Fact-Checking", "DIDI-CLAIMS-*", "Verificarea automata a afirmatiilor si informatiilor"],
|
|
["Evaluare Surse", "DIDI-SOURCE-*", "Analiza credibilitatii domeniilor si surselor de informatii"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Tipuri de Media Acceptate", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Tip Media", "Format", "Descriere"],
|
|
[
|
|
["Text", "Text liber", "Continut text introdus direct in platforma"],
|
|
["Imagine", "PNG, JPG, WEBP", "Fisiere imagine incarcate de utilizator"],
|
|
["Audio", "MP3, WAV, OGG", "Fisiere audio incarcate de utilizator"],
|
|
["Video", "MP4, MOV, AVI", "Fisiere video incarcate de utilizator"],
|
|
["URL", "Link web", "Adresa URL a continutului de analizat"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Procesul de Achizitie", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Pentru a achizitiona o analiza, urmati pasii:")
|
|
add_numbered_list(doc, [
|
|
"Navigati la sectiunea 'Achizitioneaza Analiza' din meniul lateral al dashboard-ului",
|
|
"Selectati categoria de analiza dorita (Detectie Tehnici, AI Detection, Fact-Checking, Evaluare Surse)",
|
|
"Selectati tipul de media (Text, Imagine, Audio, Video, URL)",
|
|
"Verificati pretul afisat pentru combinatia selectata",
|
|
'Apasati butonul "Cumpara" pentru a initia procesul de plata',
|
|
"Veti fi redirectionat catre pagina de plata Stripe (detalii in Capitolul 6)",
|
|
])
|
|
|
|
add_screenshot(doc, "dashboard", "03-achizitioneaza.png", "Dashboard - Pagina de achizitie servicii analiza")
|
|
|
|
doc.add_page_break()
|
|
|
|
# 5.3 Analize
|
|
doc.add_heading("5.3 Analize (Lista Analize)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Analize afiseaza toate analizele asociate contului utilizatorului, organizate "
|
|
"in doua categorii:"
|
|
)
|
|
|
|
doc.add_heading("Analize Disponibile (Neconsumate)", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Analizele achizitionate dar inca neutilizate sunt afisate ca disponibile. Pentru fiecare "
|
|
"analiza disponibila se afiseaza:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Tipul analizei (categorie + tip media)",
|
|
"Data achizitiei",
|
|
"Numarul facturii asociate",
|
|
'Buton "Ruleaza Analiza" pentru a incepe procesul de analiza',
|
|
])
|
|
|
|
doc.add_heading("Rapoarte Salvate", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Analizele deja efectuate sunt afisate ca rapoarte salvate. Pentru fiecare raport "
|
|
"se afiseaza:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Titlul raportului si categoria analizei",
|
|
"Data efectuarii analizei",
|
|
"Scorul de risc si nivelul de incredere",
|
|
'Buton "Descarca PDF" pentru generarea si descarcarea raportului complet',
|
|
])
|
|
|
|
add_screenshot(doc, "dashboard", "02-analize.png", "Dashboard - Lista analize disponibile si rapoarte salvate")
|
|
|
|
# 5.4 Rulare Analiza
|
|
doc.add_heading("5.4 Rularea unei Analize", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Procesul de rulare a unei analize este nucleul functionalitatii platformei DiDi. "
|
|
"Dupa achizitionarea unui serviciu de analiza, utilizatorul poate rula analiza "
|
|
"pe continutul dorit."
|
|
)
|
|
|
|
doc.add_heading("Pasii pentru Rularea unei Analize", level=3)
|
|
add_numbered_list(doc, [
|
|
"Din pagina Analize, selectati o analiza disponibila (neConsumata) si apasati 'Ruleaza Analiza'",
|
|
"Se deschide interfata de introducere a continutului, adaptata tipului de media al analizei",
|
|
"Pentru analize de tip Text: introduceti textul de analizat in campul dedicat",
|
|
"Pentru analize de tip URL: introduceti adresa web a continutului de analizat",
|
|
"Pentru analize de tip Imagine/Audio/Video: incarcati fisierul media folosind butonul de upload",
|
|
'Apasati butonul "Porneste analiza" pentru a initia procesarea',
|
|
"Platforma afiseaza un indicator de progres in timp ce analiza este procesata",
|
|
"Dupa finalizare, rezultatele sunt afisate direct in interfata",
|
|
])
|
|
|
|
doc.add_heading("Structura Rezultatelor", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Rezultatele unei analize includ urmatoarele informatii:")
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Element", "Descriere"],
|
|
[
|
|
["Scor de Risc", "Valoare numerica (0-100%) care indica nivelul de risc de dezinformare detectat"],
|
|
["Nivel de Incredere", "Gradul de incredere al algoritmului in rezultatul furnizat"],
|
|
["Categorie de Risc", "Clasificare: Scazut / Mediu / Ridicat / Critic"],
|
|
["Tehnici Detectate", "Lista tehnicilor de manipulare identificate (pentru categoria Detectie Tehnici)"],
|
|
["Verdict", "Concluzia generala a analizei in format text descriptiv"],
|
|
["Afirmatii Verificate", "Lista afirmatiilor verificate si statusul lor (pentru Fact-Checking)"],
|
|
["Scor AI Tampered", "Probabilitatea ca media sa fie generata/modificata de AI (pentru AI Detection)"],
|
|
["Evaluare Domeniu", "Scorul de credibilitate al domeniului analizat (pentru Evaluare Surse)"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Procesare Sincrona vs. Asincrona", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"In functie de tipul de continut, analiza poate fi procesata sincron sau asincron:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Sincron (rezultat imediat): analize de tip Text, URL si Imagine - rezultatele sunt returnate in cateva secunde",
|
|
"Asincron (cu polling): analize de tip Audio si Video - procesarea poate dura mai mult, iar platforma verifica periodic statusul analizei (polling) si afiseaza rezultatele cand acestea sunt disponibile",
|
|
])
|
|
|
|
doc.add_heading("Rezultate pentru Diferite Tipuri de Media", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Mai jos sunt prezentate exemple de rezultate pentru fiecare tip de media analizat:"
|
|
)
|
|
|
|
add_screenshot(doc, "dashboard", "08-rezultat-text.png", "Rezultat analiza text - Scor de risc si tehnici detectate")
|
|
add_screenshot(doc, "dashboard", "09-rezultat-imagine.png", "Rezultat analiza imagine - Detectie AI/manipulare")
|
|
add_screenshot(doc, "dashboard", "10-rezultat-audio.png", "Rezultat analiza audio - Evaluare continut audio")
|
|
add_screenshot(doc, "dashboard", "11-rezultat-video.png", "Rezultat analiza video - Detectie deepfake")
|
|
|
|
doc.add_heading("Descarcare Raport PDF", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Dupa finalizarea analizei, utilizatorul poate descarca un raport complet in format PDF "
|
|
"care contine toate informatiile analizei, inclusiv detalii tehnice, grafice si recomandari. "
|
|
'Raportul se genereaza prin apasarea butonului "Descarca PDF" disponibil in pagina de rezultate.'
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# 5.5 Facturi
|
|
doc.add_heading("5.5 Facturi", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Facturi ofera acces la toate facturile emise pentru achizitiile efectuate. "
|
|
"Facturile sunt generate automat in sistemul ERPNext la finalizarea fiecarei plati."
|
|
)
|
|
|
|
doc.add_heading("Informatii Afisate", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Pentru fiecare factura se afiseaza urmatoarele informatii:")
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Descriere"],
|
|
[
|
|
["Numar Factura", "Identificator unic in formatul DIDI-INV-YYYY-##### (exemplu: DIDI-INV-2026-00001)"],
|
|
["Data Emitere", "Data la care factura a fost emisa"],
|
|
["Suma", "Valoarea totala a facturii (inclusiv TVA 19%)"],
|
|
["Status", "Starea facturii: Platita, Anulata"],
|
|
["Actiuni", "Buton pentru descarcarea facturii in format PDF"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Facturile pot fi filtrate si sortate dupa data sau status. Fiecare factura poate fi "
|
|
"descarcata in format PDF cu branding DiDi, incluzand toate detaliile legale necesare "
|
|
"(date companie, CUI, numar de inregistrare, adresa)."
|
|
)
|
|
|
|
add_screenshot(doc, "dashboard", "04-facturi.png", "Dashboard - Lista facturi cu status si actiuni")
|
|
|
|
# 5.6 Profil
|
|
doc.add_heading("5.6 Profil Utilizator", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina Profil permite utilizatorului sa vizualizeze si sa editeze informatiile "
|
|
"asociate contului sau. Informatiile disponibile includ:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Datele personale: nume, prenume, adresa de email (sincronizate din Keycloak)",
|
|
"Date companie: numele companiei, CUI (pentru facturare persoane juridice)",
|
|
"Planul activ: tipul de abonament curent (Free Tier, Paid Tier, Enterprise Tier)",
|
|
"Optiuni GDPR: gestionarea consimtamintelor pentru prelucrarea datelor personale",
|
|
"Posibilitatea de a solicita exportul sau stergerea datelor personale",
|
|
])
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Modificarile la datele de companie si CUI se sincronizeaza automat cu fisa clientului "
|
|
"din ERPNext, asigurand consistenta datelor de facturare."
|
|
)
|
|
|
|
add_screenshot(doc, "dashboard", "05-profil.png", "Dashboard - Pagina de profil utilizator")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 6: Plata cu Stripe
|
|
# =========================================================================
|
|
doc.add_heading("6. Plata cu Stripe", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma DiDi utilizeaza serviciul de plati online Stripe pentru procesarea securizata "
|
|
"a tranzactiilor. Stripe este un procesator de plati certificat PCI DSS Level 1, "
|
|
"garantand cel mai inalt nivel de securitate pentru datele cardului."
|
|
)
|
|
|
|
doc.add_heading("6.1 Fluxul de Plata", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Procesul de plata se desfasoara in urmatorii pasi:"
|
|
)
|
|
|
|
add_numbered_list(doc, [
|
|
"Selectie serviciu: din pagina Achizitioneaza Analiza, selectati serviciul dorit si apasati 'Cumpara'",
|
|
"Creare sesiune Stripe: website-ul creeaza automat o sesiune de checkout Stripe pe server (API route /api/checkout)",
|
|
"Redirect la Stripe: sunteti redirectionat catre pagina securizata Stripe Checkout",
|
|
"Completare date card: introduceti numarul cardului, data expirare, CVV si numele titularului",
|
|
"Procesare plata: Stripe proceseaza plata si valideaza tranzactia",
|
|
"Redirect success: dupa plata reusita, sunteti redirectionat inapoi pe website la pagina de confirmare",
|
|
"Confirmare: se afiseaza referinta platii si numarul facturii generate automat in ERPNext",
|
|
])
|
|
|
|
doc.add_heading("6.2 Procesare Automata (Webhook Fulfillment)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"La confirmarea platii, Stripe trimite automat o notificare (webhook) catre platforma DiDi. "
|
|
"Aceasta notificare declanseaza urmatorul proces automat:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Verificarea si validarea platii prin semnatura webhook-ului Stripe",
|
|
"Crearea sau identificarea clientului in ERPNext (pe baza ID-ului Keycloak)",
|
|
"Generarea automata a facturii (Sales Invoice) cu seria DIDI-INV-YYYY-#####",
|
|
"Inregistrarea automata a platii (Payment Entry) in contabilitatea ERPNext",
|
|
"Crearea acordului de servicii (Service Agreement) care activeaza analiza achizitionata",
|
|
"Actualizarea planului clientului daca este cazul",
|
|
"Inregistrarea tranzactiei in jurnalul de plati (Payment Log) pentru audit",
|
|
"Trimiterea automata a facturii prin email catre client",
|
|
])
|
|
|
|
doc.add_heading("6.3 Carduri Acceptate", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Stripe accepta urmatoarele metode de plata: Visa, Mastercard, American Express, "
|
|
"Discover si alte carduri bancare internationale. De asemenea, sunt suportate "
|
|
"portofelele digitale Apple Pay si Google Pay (in functie de browser si dispozitiv)."
|
|
)
|
|
|
|
add_note_box(
|
|
doc,
|
|
"Datele cardului dvs. sunt procesate exclusiv de Stripe si nu sunt niciodata "
|
|
"stocate pe serverele platformei DiDi. Platforma nu are acces la numarul "
|
|
"complet al cardului sau la codul CVV.",
|
|
"info",
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 7: Design Responsive
|
|
# =========================================================================
|
|
doc.add_heading("7. Design Responsive", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul DiDi este dezvoltat cu un design responsive care se adapteaza automat "
|
|
"la dimensiunea ecranului dispozitivului utilizat. Interfata a fost optimizata "
|
|
"pentru trei categorii principale de dispozitive:"
|
|
)
|
|
|
|
doc.add_heading("7.1 Desktop (> 1024px)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pe ecranele de desktop, website-ul afiseaza continutul la latimea completa, "
|
|
"cu bara de navigare orizontala vizibila permanent, layout pe coloane multiple "
|
|
"si imagini la rezolutie completa. Aceasta este experienta optima recomanda."
|
|
)
|
|
|
|
doc.add_heading("7.2 Tableta (768px - 1024px)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pe tablete, layout-ul se reorganizeaza pentru a se adapta la ecranul mai mic. "
|
|
"Coloanele se reduc, iar unele elemente se stivuiesc vertical. Bara de navigare "
|
|
"poate trece in modul hamburger menu."
|
|
)
|
|
|
|
add_screenshot(doc, "website", "09-homepage-tablet.png", "Website - Vizualizare pe tableta")
|
|
|
|
doc.add_heading("7.3 Mobil (< 768px)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pe dispozitive mobile, interfata se optimizeaza complet: navbar-ul devine un "
|
|
"meniu hamburger, continutul se afiseaza pe o singura coloana, butoanele si "
|
|
"elementele interactive sunt dimensionate pentru interactiunea tactila, iar "
|
|
"textul se redimensioneaza pentru lizibilitate optima."
|
|
)
|
|
|
|
add_screenshot(doc, "website", "08-homepage-mobile.png", "Website - Vizualizare pe mobil (smartphone)")
|
|
add_screenshot(doc, "dashboard", "06-overview-mobile.png", "Dashboard - Vizualizare pe mobil")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 8: Functionalitati Suplimentare
|
|
# =========================================================================
|
|
doc.add_heading("8. Functionalitati Suplimentare", level=1)
|
|
|
|
doc.add_heading("8.1 Cookie Consent (Consimtamant Cookie-uri)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"La prima vizita pe website, utilizatorului i se prezinta un banner de consimtamant "
|
|
"pentru cookie-uri, in conformitate cu legislatia europeana. Utilizatorul poate "
|
|
"gestiona urmatoarele categorii de cookie-uri:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Categorie", "Obligatoriu", "Descriere"],
|
|
[
|
|
["Necesare", "Da", "Cookie-uri esentiale pentru functionarea website-ului (sesiune, securitate)"],
|
|
["Functionale", "Nu", "Cookie-uri care imbunatatesc experienta (preferinte limba, tema)"],
|
|
["Analitice", "Nu", "Cookie-uri pentru colectarea datelor de utilizare si performanta"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Cookie-urile necesare nu pot fi dezactivate deoarece sunt esentiale pentru "
|
|
"functionarea corecta a website-ului. Cookie-urile functionale si analitice "
|
|
"pot fi activate sau dezactivate individual de catre utilizator."
|
|
)
|
|
|
|
doc.add_heading("8.2 Internationalizare (i18n) - RO/EN", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul suporta doua limbi: Romana (RO) si Engleza (EN). Continutul tuturor "
|
|
"paginilor publice este disponibil in ambele limbi, inclusiv: texte interfata, "
|
|
"etichete butoane, mesaje de eroare si notificari, continut pagini (gestionat "
|
|
"prin CMS ERPNext). Preferinta de limba se salveaza in browserul utilizatorului "
|
|
"(localStorage) si este pastrata la vizitele ulterioare."
|
|
)
|
|
|
|
doc.add_heading("8.3 Sitemap.xml si SEO", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul genereaza automat un fisier sitemap.xml care contine toate paginile "
|
|
"publice ale website-ului. Acest fisier este utilizat de motoarele de cautare "
|
|
"(Google, Bing) pentru indexarea corecta a continutului."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Optimizarile SEO implementate includ:")
|
|
add_bullet_list(doc, [
|
|
"Metadata (title, description) unice pentru fiecare pagina",
|
|
"Tag-uri Open Graph pentru partajarea pe retele sociale",
|
|
"Structura semantica HTML5 corecta (headings, sections, articles)",
|
|
"Fisier robots.txt configurat corect",
|
|
"URL-uri curate si descriptive",
|
|
"Performanta optimizata (Lighthouse SEO score: 100/100)",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 9: Depanare si Contact
|
|
# =========================================================================
|
|
doc.add_heading("9. Depanare si Contact Suport", level=1)
|
|
|
|
doc.add_heading("9.1 Probleme Frecvente", level=2)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Problema", "Cauza Posibila", "Solutie"],
|
|
[
|
|
["Nu pot accesa website-ul", "Conexiune internet instabila sau URL incorect", "Verificati conexiunea si accesati https://didi365.eu"],
|
|
["Nu ma pot autentifica", "Credentiale incorecte sau cont neconfirmat", "Verificati email-ul de confirmare sau resetati parola"],
|
|
["Plata a esuat", "Card expirat, fonduri insuficiente sau eroare Stripe", "Verificati datele cardului sau incercati alt card"],
|
|
["Analiza nu porneste", "Nu exista analize disponibile (neachizitionate)", "Achizitionati o analiza noua din pagina dedicata"],
|
|
["Rezultatele intarzie", "Analiza asincrona (audio/video) in procesare", "Asteptati finalizarea - platforma verifica automat statusul"],
|
|
["Nu pot descarca factura", "Eroare temporara de conectare la ERPNext", "Reincarcati pagina sau incercati mai tarziu"],
|
|
["Website-ul se afiseaza incorect", "Browser vechi sau cache corupt", "Actualizati browserul si stergeti cache-ul"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("9.2 Contact Suport Tehnic", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pentru asistenta suplimentara sau probleme nerezolvate, puteti contacta "
|
|
"echipa de suport prin urmatoarele canale:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Canal", "Detalii"],
|
|
[
|
|
["Email", "office@clossers.com"],
|
|
["Formular Contact", "Accesibil pe pagina Contact a website-ului"],
|
|
["Program Suport", "Luni - Vineri, 09:00 - 18:00"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Cand contactati echipa de suport, va rugam sa includeti urmatoarele informatii "
|
|
"pentru a facilita rezolvarea rapida a problemei:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Adresa de email asociata contului DiDi",
|
|
"Descrierea detaliata a problemei intampinate",
|
|
"Pasii parcursi inainte de aparitia problemei",
|
|
"Capturi de ecran relevante (daca este posibil)",
|
|
"Browserul si versiunea utilizata",
|
|
"Dispozitivul folosit (desktop, tableta, mobil)",
|
|
])
|
|
|
|
# Save document
|
|
output_path = os.path.join(OUTPUT_DIR, "Manual_Utilizare_Website.docx")
|
|
doc.save(output_path)
|
|
print(f" -> Salvat: {output_path}")
|
|
return output_path
|
|
|
|
|
|
# ==============================================================================
|
|
# DOCUMENT 2: Ghid Administrare ERPNext
|
|
# ==============================================================================
|
|
|
|
|
|
def generate_ghid_erpnext():
|
|
"""Generate Ghid_Administrare_ERPNext.docx"""
|
|
print("[2/4] Generare Ghid_Administrare_ERPNext.docx ...")
|
|
|
|
doc = create_document()
|
|
|
|
add_cover_page(
|
|
doc,
|
|
"GHID DE ADMINISTRARE",
|
|
"ERPNext ERP & CRM",
|
|
)
|
|
|
|
add_header_footer(doc)
|
|
add_toc_placeholder(doc)
|
|
|
|
# =========================================================================
|
|
# CHAPTER 1: Introducere
|
|
# =========================================================================
|
|
doc.add_heading("1. Introducere", level=1)
|
|
|
|
doc.add_heading("1.1 Scopul Documentului", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Acest ghid de administrare ofera instructiuni detaliate pentru utilizarea si "
|
|
"gestionarea sistemului ERPNext ERP & CRM integrat in platforma DiDi. Documentul "
|
|
"se adreseaza administratorilor de sistem si personalului responsabil cu operatiunile "
|
|
"de back-office ale platformei."
|
|
)
|
|
|
|
doc.add_heading("1.2 Despre ERPNext", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"ERPNext este o solutie open-source de tip Enterprise Resource Planning (ERP) si "
|
|
"Customer Relationship Management (CRM), dezvoltata pe framework-ul Frappe. "
|
|
"Platforma DiDi utilizeaza ERPNext versiunea 15, configurata si personalizata "
|
|
"pentru nevoile specifice ale proiectului."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("ERPNext ofera urmatoarele module integrate utilizate in cadrul platformei DiDi:")
|
|
add_bullet_list(doc, [
|
|
"Facturare (Sales Invoice) - generarea si gestionarea facturilor fiscale",
|
|
"CRM (Lead Management) - gestionarea lead-urilor si pipeline-ului de vanzari",
|
|
"Gestiune Clienti (Customer) - evidenta clientilor cu date personalizate",
|
|
"Plati (Payment Entry, Payment Log) - inregistrarea si urmarirea platilor",
|
|
"Rapoarte Analiza (Analysis Report) - stocarea rezultatelor analizelor AI",
|
|
"Servicii (Item, Service Agreement) - catalogul de servicii si acordurile active",
|
|
"CMS (Website Content) - gestionarea continutului website-ului bilingv",
|
|
"Notificari Email - comunicare automata cu clientii",
|
|
"Contabilitate - plan de conturi Romania cu TVA 19%",
|
|
])
|
|
|
|
doc.add_heading("1.3 Deployment Docker", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"ERPNext este rulat intr-un mediu containerizat Docker, asigurand izolarea "
|
|
"serviciilor, reproducibilitate si usurinta in administrare. Stiva de containere "
|
|
"include: ERPNext web, MariaDB (baza de date), Redis Cache, Redis Queue, "
|
|
"3 workeri pentru procesare asincrona si un scheduler pentru taskuri planificate."
|
|
)
|
|
|
|
doc.add_heading("1.4 URL de Acces", level=2)
|
|
add_code_block(doc, "http://localhost:8080")
|
|
|
|
add_note_box(
|
|
doc,
|
|
"Accesul la interfata de administrare ERPNext este disponibil exclusiv din "
|
|
"reteaua interna sau prin tunel securizat. Nu expuneti portul 8080 direct "
|
|
"pe internet fara masuri de securitate suplimentare (firewall, VPN).",
|
|
"warning",
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 2: Acces si Autentificare
|
|
# =========================================================================
|
|
doc.add_heading("2. Acces si Autentificare", level=1)
|
|
|
|
doc.add_heading("2.1 Autentificare Administrator", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pentru a accesa interfata de administrare ERPNext, navigati la adresa de acces "
|
|
"si utilizati credentialele de administrator:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Valoare"],
|
|
[
|
|
["URL", "http://localhost:8080"],
|
|
["Utilizator", "Administrator"],
|
|
["Parola", "admin (de schimbat la prima utilizare)"],
|
|
],
|
|
)
|
|
|
|
add_note_box(
|
|
doc,
|
|
"La prima accesare, este obligatorie schimbarea parolei implicite 'admin' "
|
|
"cu o parola complexa (minim 12 caractere, litere mari si mici, cifre, "
|
|
"caractere speciale).",
|
|
"warning",
|
|
)
|
|
|
|
doc.add_heading("2.2 Interfata in Limba Romana", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"ERPNext a fost configurat cu limba romana ca limba principala a interfetei. "
|
|
"Toate meniurile, etichetele si mesajele de sistem sunt afisate in limba romana. "
|
|
"Limba poate fi modificata din setarile profilului utilizatorului daca este necesar."
|
|
)
|
|
|
|
doc.add_heading("2.3 Navigarea in Interfata", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Interfata ERPNext este organizata pe baza de Workspace-uri (spatii de lucru). "
|
|
"Fiecare workspace grupeaza functionalitatile relevante pentru un domeniu specific. "
|
|
"Navigarea se face prin:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Sidebar (bara laterala stanga) - acces rapid la workspace-uri si module",
|
|
"Awesome Bar (bara de cautare) - cautare rapida documente, rapoarte, pagini (Ctrl+K)",
|
|
"Breadcrumbs - navigare ierarhica in structura de documente",
|
|
"Shortcuts (scurtaturi) - acces rapid la documentele frecvent utilizate",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 3: Workspace DiDi Platform
|
|
# =========================================================================
|
|
doc.add_heading("3. Workspace DiDi Platform", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Workspace-ul DiDi Platform este spatiul de lucru personalizat care centralizeaza "
|
|
"toate functionalitatile specifice platformei DiDi. Acesta ofera scurtaturi rapide "
|
|
"catre cele mai utilizate documente si rapoarte."
|
|
)
|
|
|
|
doc.add_heading("3.1 Scurtaturi Disponibile", level=2)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Scurtatura", "DocType / Modul", "Descriere"],
|
|
[
|
|
["Facturi", "Sales Invoice", "Lista si gestionarea facturilor emise"],
|
|
["Clienti", "Customer", "Evidenta clientilor platformei"],
|
|
["CRM", "Lead", "Gestionarea lead-urilor si pipeline vanzari"],
|
|
["Servicii", "Item", "Catalogul de servicii DiDi"],
|
|
["Plati", "Payment Log", "Jurnalul de plati Stripe"],
|
|
["Contabilitate", "Account", "Plan de conturi si rapoarte financiare"],
|
|
["Website CMS", "Website Content", "Gestionarea continutului website-ului"],
|
|
["Rapoarte Analiza", "Analysis Report", "Rezultatele analizelor AI efectuate"],
|
|
["Acorduri Servicii", "Service Agreement", "Acorduri active de prestare servicii"],
|
|
["Incasari", "Payment Entry", "Inregistrari plati in contabilitate"],
|
|
["Notificari", "Notification", "Configurare notificari email automate"],
|
|
],
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "01-workspace.png", "Workspace DiDi Platform - Panou central de administrare")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 4: Gestiune Facturi
|
|
# =========================================================================
|
|
doc.add_heading("4. Gestiune Facturi (Facturare)", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Modulul de facturare gestioneaza toate facturile emise prin platforma DiDi. "
|
|
"Facturile sunt generate automat la finalizarea platilor prin Stripe si "
|
|
"urmeaza seria de numerotare DIDI-INV-YYYY-#####."
|
|
)
|
|
|
|
doc.add_heading("4.1 Lista Facturi", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Lista facturilor afiseaza toate facturile emise in sistem. Interfata permite:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Filtrare dupa status (Platita, Anulata, Ciorna), client, data, suma",
|
|
"Sortare dupa orice coloana (numar, data, client, suma, status)",
|
|
"Cautare rapida dupa numarul facturii sau numele clientului",
|
|
"Export lista in format CSV sau Excel",
|
|
"Creare manuala de facturi noi (pentru cazuri speciale)",
|
|
])
|
|
|
|
doc.add_heading("Statusuri Factura", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Status", "Cod Culoare", "Descriere"],
|
|
[
|
|
["Ciorna (Draft)", "Gri", "Factura creata dar nevalidata - poate fi editata"],
|
|
["Trimisa (Submitted)", "Albastru", "Factura validata si trimisa clientului"],
|
|
["Platita (Paid)", "Verde", "Factura a fost achitata integral"],
|
|
["Anulata (Cancelled)", "Rosu", "Factura a fost anulata (storno)"],
|
|
],
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "02-facturi.png", "Lista facturi - Vizualizare si filtrare")
|
|
|
|
doc.add_heading("4.2 Detaliu Factura", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina de detaliu a unei facturi contine toate informatiile asociate tranzactiei:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Date client: nume, adresa, CUI (pentru persoane juridice)",
|
|
"Articole facturate: serviciul DiDi achizitionat, cantitate, pret unitar",
|
|
"TVA 19%: calculat automat conform legislatiei fiscale romanesti",
|
|
"Totaluri: subtotal, TVA, total de plata",
|
|
"Referinte: numar factura, seria, data emitere, data scadenta",
|
|
"Camp custom 'Analiza Consumata': indica daca analiza asociata a fost utilizata",
|
|
"Camp custom 'Session ID': identificatorul sesiunii de analiza AI (daca a fost rulata)",
|
|
"Istoric: timeline cu toate actiunile efectuate asupra facturii",
|
|
])
|
|
|
|
add_screenshot(doc, "erpnext", "03-factura-detaliu.png", "Detaliu factura - Informatii complete despre tranzactie")
|
|
|
|
doc.add_heading("4.3 Print Format DiDi Invoice", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Facturile DiDi utilizeaza un format de tiparire (Print Format) personalizat "
|
|
"care include branding-ul platformei si toate informatiile legale obligatorii:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Logo si branding DiDi / TOP CLOSSERS SRL",
|
|
"Date complete emitent: nume companie, CUI, numar registru comert, adresa, cont bancar",
|
|
"Date complete beneficiar: nume, CUI (daca exista), adresa",
|
|
"Tabel articole cu descriere detaliata, cantitate, pret unitar, valoare",
|
|
"Totaluri: subtotal, TVA 19%, total de plata",
|
|
"Seria si numarul facturii, data emitere",
|
|
"Mentiuni legale obligatorii conform legislatiei fiscale romanesti",
|
|
])
|
|
|
|
add_screenshot(doc, "erpnext", "13-print-format-factura.png", "Print Format - Factura PDF cu branding DiDi")
|
|
|
|
doc.add_heading("4.4 Serie Facturi", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate facturile emise in platforma DiDi utilizeaza seria de numerotare "
|
|
"DIDI-INV-YYYY-##### unde YYYY este anul curent si ##### este numarul "
|
|
"secvential (cu 5 cifre, completat cu zero-uri). Exemplu: DIDI-INV-2026-00042."
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 5: Gestiune Clienti
|
|
# =========================================================================
|
|
doc.add_heading("5. Gestiune Clienti", level=1)
|
|
|
|
doc.add_heading("5.1 Fisa Client", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Fiecare client al platformei DiDi are o fisa detaliata in ERPNext care contine "
|
|
"atat informatiile standard ale unui client ERPNext cat si campuri personalizate "
|
|
"specifice platformei."
|
|
)
|
|
|
|
doc.add_heading("Campuri Standard", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Descriere"],
|
|
[
|
|
["Customer Name", "Numele complet al clientului"],
|
|
["Customer Type", "Tip client: Individual sau Company"],
|
|
["Customer Group", "Grupul de clienti (ex: Individual, Corporate)"],
|
|
["Territory", "Teritoriul geografic (ex: Romania)"],
|
|
["Email", "Adresa de email principala"],
|
|
["Mobile No", "Numar de telefon mobil"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("5.2 Campuri Personalizate (Custom Fields)", level=2)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Fieldname", "Tip", "Descriere"],
|
|
[
|
|
["ID Utilizator DiDi", "didi_user_id", "Data", "UUID Keycloak - legatura unica cu contul de autentificare"],
|
|
["Rol IAM", "iam_role", "Select", "Rol acces: free_tier / paid_tier / enterprise_tier"],
|
|
["Plan Activ", "active_plan", "Data", "Planul de abonament activ al clientului"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Campul didi_user_id este esential pentru integrarea cu sistemul de autentificare "
|
|
"Keycloak. Acest camp stocheaza UUID-ul unic al utilizatorului din Keycloak si este "
|
|
"folosit de website pentru a identifica clientul ERPNext asociat sesiunii autentificate."
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "04-client.png", "Fisa client - Campuri standard si personalizate")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 6: CRM - Gestiune Lead-uri
|
|
# =========================================================================
|
|
doc.add_heading("6. CRM - Gestiune Lead-uri", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Modulul CRM din ERPNext gestioneaza pipeline-ul de vanzari al platformei DiDi, "
|
|
"de la captarea lead-urilor pana la conversia acestora in clienti activi."
|
|
)
|
|
|
|
doc.add_heading("6.1 Pipeline Vanzari", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Lead-urile parcurg urmatorul pipeline de vanzari in cadrul platformei DiDi:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Etapa", "Status", "Descriere", "Actiune Urmatoare"],
|
|
[
|
|
["1. Lead", "Open", "Lead nou capturat prin formular contact sau pagina pricing", "Calificare"],
|
|
["2. Calificat", "Replied", "Lead calificat de echipa de vanzari", "Programare demo"],
|
|
["3. Demo", "Opportunity", "Demo programat sau efectuat cu potentialul client", "Conversie"],
|
|
["4. Client", "Converted", "Lead convertit in client activ cu cont pe platforma", "Finalizat"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("6.2 Surse Lead-uri (Lead Sources)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma DiDi capteaza lead-uri din urmatoarele surse, fiecare configurata "
|
|
"in ERPNext pentru tracking precis:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Sursa", "Descriere", "Mecanism Captura"],
|
|
[
|
|
["Website Contact Form", "Formularul de contact de pe pagina Contact", "API POST /api/leads automat"],
|
|
["Pricing Page", "Vizitatori care interactioneaza cu pagina de preturi", "Tracking UTM + formular"],
|
|
["Demo Request", "Solicitari directe de demonstratie a platformei", "Email sau formular dedicat"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("6.3 UTM Tracking", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate lead-urile captate prin website includ parametri UTM pentru identificarea "
|
|
"sursei de trafic. Parametrii UTM stocati in fisa lead-ului sunt:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"UTM Source - sursa traficului (ex: google, facebook, newsletter)",
|
|
"UTM Medium - mediul de marketing (ex: cpc, organic, email, social)",
|
|
"UTM Campaign - campania specifica (ex: launch_2026, pnrr_awareness)",
|
|
])
|
|
|
|
add_screenshot(doc, "erpnext", "05-leaduri-crm.png", "CRM - Lista lead-uri si pipeline vanzari")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 7: Plati si Incasari
|
|
# =========================================================================
|
|
doc.add_heading("7. Plati si Incasari", level=1)
|
|
|
|
doc.add_heading("7.1 Payment Log (Jurnal Plati)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Payment Log este un DocType custom dezvoltat special pentru platforma DiDi, care "
|
|
"inregistreaza un audit trail complet al tuturor tranzactiilor Stripe. Fiecare "
|
|
"intrare in jurnal contine:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Descriere"],
|
|
[
|
|
["Customer", "Referinta catre clientul ERPNext asociat platii"],
|
|
["Event Type", "Tipul evenimentului Stripe (ex: checkout.session.completed)"],
|
|
["Status", "Statusul tranzactiei (Success, Failed, Pending)"],
|
|
["Amount", "Suma platita (in RON)"],
|
|
["Stripe Payment ID", "Identificatorul unic al platii in Stripe (pi_xxx)"],
|
|
["Stripe Session ID", "Identificatorul sesiunii de checkout Stripe (cs_xxx)"],
|
|
["Invoice Reference", "Referinta catre factura ERPNext generata"],
|
|
["Timestamp", "Data si ora exacta a tranzactiei"],
|
|
["Raw Webhook Data", "Datele brute primite de la Stripe (JSON) pentru audit complet"],
|
|
],
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "06-payment-logs.png", "Payment Log - Jurnalul de plati Stripe")
|
|
|
|
doc.add_heading("7.2 Payment Entry (Incasari)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Payment Entry este documentul standard ERPNext pentru inregistrarea incasarilor "
|
|
"in contabilitate. Fiecare plata Stripe reusita genereaza automat un Payment Entry "
|
|
"care reconciliaza factura emisa cu suma incasata."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Informatii stocate in Payment Entry:")
|
|
add_bullet_list(doc, [
|
|
"Tipul platii: Receive (incasare)",
|
|
"Modul de plata: Stripe (plata online)",
|
|
"Cont incasari: contul bancar configurat pentru Stripe",
|
|
"Referinta: legatura cu factura (Sales Invoice) corespunzatoare",
|
|
"Suma: valoarea incasata in RON",
|
|
"Data platii: data la care a fost procesata plata de Stripe",
|
|
])
|
|
|
|
add_screenshot(doc, "erpnext", "11-plati-incasari.png", "Payment Entry - Incasari inregistrate automat")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 8: Rapoarte Analiza
|
|
# =========================================================================
|
|
doc.add_heading("8. Rapoarte Analiza", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Analysis Report este un DocType custom care stocheaza rezultatele complete ale "
|
|
"analizelor AI efectuate prin platforma DiDi."
|
|
)
|
|
|
|
doc.add_heading("8.1 Lista Rapoarte", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run("Fiecare raport de analiza contine urmatoarele informatii:")
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Descriere"],
|
|
[
|
|
["Titlu", "Titlul descriptiv al raportului de analiza"],
|
|
["Client", "Referinta catre clientul care a solicitat analiza"],
|
|
["Factura", "Referinta catre factura asociata achizitiei"],
|
|
["Status", "Statusul raportului (Finalizat, In Procesare, Eroare)"],
|
|
["Session ID", "Identificatorul sesiunii de analiza din DiDi API"],
|
|
["Tip Analiza", "Categoria analizei (Tehnici, AI Detection, Claims, Source)"],
|
|
["Tip Media", "Tipul de continut analizat (Text, Imagine, Audio, Video, URL)"],
|
|
["Data Creare", "Data si ora la care a fost generat raportul"],
|
|
],
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "07-rapoarte-analiza.png", "Lista rapoarte analiza - Vizualizare si filtrare")
|
|
|
|
doc.add_heading("8.2 Detaliu Raport", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pagina de detaliu a unui raport de analiza contine informatiile complete "
|
|
"ale rezultatului, inclusiv:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Result JSON - rezultatul complet al analizei in format JSON structurat, incluzand: scor de risc, nivel de incredere, categorie de risc, tehnici detectate, verdict, afirmatii verificate",
|
|
"PDF Atasat - raportul generat in format PDF care poate fi descarcat sau trimis clientului",
|
|
"Metadate - informatii despre procesarea analizei: durata, timestamp-uri, versiunea API",
|
|
"Legatura cu factura si acordul de servicii asociat",
|
|
])
|
|
|
|
add_screenshot(doc, "erpnext", "14-raport-analiza-detaliu.png", "Detaliu raport analiza - Rezultat JSON si PDF")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 9: Servicii si Produse
|
|
# =========================================================================
|
|
doc.add_heading("9. Servicii si Produse", level=1)
|
|
|
|
doc.add_heading("9.1 Items DiDi (Catalogul de Servicii)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Catalogul de servicii DiDi contine 17 articole (Items) care corespund tuturor "
|
|
"combinatiilor de categorii de analiza si tipuri de media disponibile. "
|
|
"Fiecare articol are un cod unic, un pret stabilit si este asociat cu un "
|
|
"price ID Stripe pentru procesarea platilor."
|
|
)
|
|
|
|
doc.add_heading("Lista Completa Servicii", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Cod Articol", "Categorie", "Tip Media", "Pret (RON)"],
|
|
[
|
|
["DIDI-TECHNIQUES-TEXT", "Detectie Tehnici", "Text", "9,99"],
|
|
["DIDI-TECHNIQUES-IMAGE", "Detectie Tehnici", "Imagine", "14,99"],
|
|
["DIDI-TECHNIQUES-AUDIO", "Detectie Tehnici", "Audio", "19,99"],
|
|
["DIDI-TECHNIQUES-VIDEO", "Detectie Tehnici", "Video", "24,99"],
|
|
["DIDI-AI_DETECTION-TEXT", "AI Detection", "Text", "9,99"],
|
|
["DIDI-AI_DETECTION-IMAGE", "AI Detection", "Imagine", "14,99"],
|
|
["DIDI-AI_DETECTION-AUDIO", "AI Detection", "Audio", "19,99"],
|
|
["DIDI-AI_DETECTION-VIDEO", "AI Detection", "Video", "24,99"],
|
|
["DIDI-CLAIMS-TEXT", "Fact-Checking", "Text", "9,99"],
|
|
["DIDI-CLAIMS-IMAGE", "Fact-Checking", "Imagine", "14,99"],
|
|
["DIDI-CLAIMS-AUDIO", "Fact-Checking", "Audio", "19,99"],
|
|
["DIDI-CLAIMS-VIDEO", "Fact-Checking", "Video", "24,99"],
|
|
["DIDI-SOURCE-TEXT", "Evaluare Surse", "Text", "9,99"],
|
|
["DIDI-SOURCE-IMAGE", "Evaluare Surse", "Imagine", "14,99"],
|
|
["DIDI-SOURCE-AUDIO", "Evaluare Surse", "Audio", "19,99"],
|
|
["DIDI-SOURCE-VIDEO", "Evaluare Surse", "Video", "24,99"],
|
|
["DIDI-SOURCE-URL", "Evaluare Surse", "URL", "9,99"],
|
|
],
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "08-servicii-didi.png", "Lista servicii DiDi - Catalogul complet de articole")
|
|
|
|
doc.add_heading("9.2 Acorduri Servicii (Service Agreement)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Service Agreement este un DocType custom care inregistreaza dreptul clientului "
|
|
"de a utiliza un serviciu de analiza achizitionat. Fiecare acord contine:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Referinta client - clientul beneficiar al acordului",
|
|
"Serviciu - articolul DiDi achizitionat (ex: DIDI-TECHNIQUES-TEXT)",
|
|
"Factura de origine - factura care a generat acordul",
|
|
"Status - Activ (neutilizat) / Consumat (analiza efectuata) / Expirat",
|
|
"Data creare - momentul activarii acordului (la confirmarea platii)",
|
|
"Data expirare - data limita de utilizare (daca aplicabil)",
|
|
])
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Cand un client ruleaza o analiza, acordul de servicii corespunzator este marcat "
|
|
"automat ca 'Consumat', iar factura asociata primeste referinta la sesiunea de "
|
|
"analiza (analysis_session_id) si flagul analysis_consumed."
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "09-acorduri-servicii.png", "Acorduri servicii - Evidenta drepturilor de utilizare")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 10: CMS - Continut Website
|
|
# =========================================================================
|
|
doc.add_heading("10. CMS - Continut Website", level=1)
|
|
|
|
doc.add_heading("10.1 Website Content", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website Content este un DocType custom care permite gestionarea continutului "
|
|
"paginilor website-ului DiDi direct din interfata de administrare ERPNext. "
|
|
"Acest mecanism CMS elimina necesitatea modificarii codului sursa pentru "
|
|
"actualizarea continutului."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Paginile gestionate prin CMS:")
|
|
add_table_with_header(
|
|
doc,
|
|
["Pagina", "Slug", "Descriere"],
|
|
[
|
|
["Homepage", "homepage", "Continutul paginii principale (hero, features, how it works)"],
|
|
["Servicii", "services", "Descrierile detaliate ale celor 6 module de analiza"],
|
|
["Despre", "about", "Informatii despre companie, echipa si viziune"],
|
|
["Pricing", "pricing", "Descrieri categorii si mesaje comerciale"],
|
|
["Contact", "contact", "Informatii de contact si text introductiv formular"],
|
|
["Privacy", "privacy", "Politica de confidentialitate GDPR completa"],
|
|
["Terms", "terms", "Termenii si conditiile de utilizare complete"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Continut Bilingv (RO/EN)", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Fiecare intrare Website Content contine campuri separate pentru limba romana "
|
|
"si limba engleza. Atunci cand website-ul solicita continutul unei pagini, "
|
|
"API-ul ERPNext returneaza textul in limba solicitata de utilizator. "
|
|
"Modificarile de continut se fac direct din ERPNext fara deployment nou."
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "10-cms-content.png", "CMS Website Content - Gestionare continut bilingv")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 11: Notificari Email
|
|
# =========================================================================
|
|
doc.add_heading("11. Notificari Email", level=1)
|
|
|
|
doc.add_heading("11.1 Email-uri Automate Configurate", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma DiDi are configurate urmatoarele notificari email automate care "
|
|
"se trimit in mod automat la producerea evenimentelor asociate:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Notificare", "Eveniment Declansator", "Destinatar", "Continut"],
|
|
[
|
|
["Factura Emisa", "Creare Sales Invoice (Submit)", "Client (email)", "Factura in format PDF atasata, detalii tranzactie"],
|
|
["Plata Confirmata", "Payment Entry creat cu succes", "Client (email)", "Confirmare plata, referinta tranzactie, acces serviciu"],
|
|
["Expirare Abonament", "Service Agreement aproape de expirare", "Client (email)", "Avertisment expirare, link reinnoire"],
|
|
],
|
|
)
|
|
|
|
add_screenshot(doc, "erpnext", "12-notificari-email.png", "Configurare notificari email automate")
|
|
|
|
doc.add_heading("11.2 Email Account - DiDi Outgoing", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Trimiterea email-urilor se face prin contul de email configurat cu SendGrid SMTP. "
|
|
"Configurarea include:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Provider", "SendGrid"],
|
|
["Protocol", "SMTP (TLS)"],
|
|
["Server", "smtp.sendgrid.net"],
|
|
["Port", "587"],
|
|
["Autentificare", "API Key SendGrid"],
|
|
["Email Expeditor", "noreply@didi365.eu"],
|
|
["Nume Expeditor", "DiDi Platform"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 12: Contabilitate
|
|
# =========================================================================
|
|
doc.add_heading("12. Contabilitate", level=1)
|
|
|
|
doc.add_heading("12.1 Plan de Conturi Romania", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"ERPNext a fost configurat cu planul de conturi conform reglementarilor contabile "
|
|
"din Romania. Principalele conturi utilizate in operatiunile platformei DiDi includ:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Cont", "Tip", "Descriere"],
|
|
[
|
|
["Venituri din Servicii", "Venit", "Venituri din prestarea serviciilor de analiza DiDi"],
|
|
["TVA Colectat", "Pasiv", "TVA 19% colectat la facturarea serviciilor"],
|
|
["Cont Stripe", "Activ (Banca)", "Incasari din platile Stripe"],
|
|
["Cheltuieli Hosting", "Cheltuiala", "Costuri server Hetzner"],
|
|
["Cheltuieli Software", "Cheltuiala", "Licente si abonamente software"],
|
|
["Cheltuieli Marketing", "Cheltuiala", "Costuri campanii marketing"],
|
|
["Comisioane Stripe", "Cheltuiala", "Comisioanele procesatorului de plati Stripe"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("12.2 TVA 19%", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate facturile emise prin platforma DiDi includ TVA 19% conform legislatiei "
|
|
"fiscale romanesti. TVA-ul este calculat automat de ERPNext pe baza template-ului "
|
|
"de taxe configurat. Preturile afisate pe website includ TVA."
|
|
)
|
|
|
|
doc.add_heading("12.3 Furnizori", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"In contabilitatea ERPNext sunt configurati urmatorii furnizori principali "
|
|
"ai platformei:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Furnizor", "Serviciu", "Tip Cheltuiala"],
|
|
[
|
|
["Hetzner Online GmbH", "Hosting servere (VPS, Cloud)", "Cheltuieli Hosting"],
|
|
["Stripe, Inc.", "Procesare plati online", "Comisioane Stripe"],
|
|
["SendGrid (Twilio)", "Serviciu email transactional SMTP", "Cheltuieli Software"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 13: Docker si Mentenanta
|
|
# =========================================================================
|
|
doc.add_heading("13. Docker si Mentenanta", level=1)
|
|
|
|
doc.add_heading("13.1 Pornirea Serviciilor", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"ERPNext ruleaza intr-un mediu Docker Compose. Pentru pornirea intregului "
|
|
"stack de servicii se utilizeaza comanda:"
|
|
)
|
|
add_code_block(doc, "docker compose up -d")
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Pentru oprirea serviciilor:")
|
|
add_code_block(doc, "docker compose down")
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Pentru vizualizarea log-urilor:")
|
|
add_code_block(doc, "docker compose logs -f erpnext")
|
|
|
|
doc.add_heading("13.2 Containere", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Stack-ul Docker Compose include urmatoarele containere:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Container", "Serviciu", "Port", "Descriere"],
|
|
[
|
|
["erpnext", "ERPNext Web", "8080", "Interfata web si API ERPNext"],
|
|
["mariadb", "MariaDB", "3306", "Baza de date relationala"],
|
|
["redis-cache", "Redis Cache", "6379", "Cache pentru sesiuni si date frecvente"],
|
|
["redis-queue", "Redis Queue", "6380", "Coada de mesaje pentru joburi asincrone"],
|
|
["worker-default", "Worker Default", "-", "Procesare joburi standard"],
|
|
["worker-short", "Worker Short", "-", "Procesare joburi rapide"],
|
|
["worker-long", "Worker Long", "-", "Procesare joburi de durata lunga"],
|
|
["scheduler", "Scheduler", "-", "Planificator taskuri recurente (cron-like)"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("13.3 Backup si Restaurare", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Datele ERPNext sunt persistate in volume Docker, asigurand pastrarea informatiilor "
|
|
"intre repornirile containerelor. Pentru backup se recomanda:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Backup automat zilnic al bazei de date MariaDB folosind cron job-ul integrat in scheduler",
|
|
"Export periodic al fisierelor uploadate (volume Docker)",
|
|
"Stocare backup-uri pe un server extern sau serviciu cloud (offsite backup)",
|
|
"Testarea periodica a procesului de restaurare din backup",
|
|
])
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Comanda pentru backup manual:")
|
|
add_code_block(doc, "docker compose exec erpnext bench --site frontend backup --with-files")
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 14: Securitate
|
|
# =========================================================================
|
|
doc.add_heading("14. Securitate", level=1)
|
|
|
|
doc.add_heading("14.1 API User (Utilizator pentru Integrari)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Comunicarea intre website-ul Next.js si ERPNext se realizeaza printr-un "
|
|
"utilizator API dedicat, configurat cu permisiuni minimale (principiul "
|
|
"least privilege):"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Utilizator", "website_api@didi.localhost"],
|
|
["Tip", "API User (System User fara Desk Access)"],
|
|
["Rol", "Website Integration"],
|
|
["Autentificare", "API Key + API Secret (token-based)"],
|
|
["Desk Access", "Dezactivat (fara acces la interfata web ERPNext)"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("14.2 Rol Website Integration", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Rolul Website Integration a fost creat special pentru utilizatorul API si ofera "
|
|
"acces limitat doar la operatiunile necesare integrarii:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"Customer - citire si creare (pentru inregistrarea clientilor noi)",
|
|
"Sales Invoice - citire si creare (pentru generarea facturilor)",
|
|
"Payment Entry - citire si creare (pentru inregistrarea platilor)",
|
|
"Service Agreement - citire, creare si modificare (pentru gestionarea drepturilor)",
|
|
"Payment Log - citire si creare (pentru audit trail plati)",
|
|
"Analysis Report - citire, creare si modificare (pentru rapoarte analiza)",
|
|
"Website Content - doar citire (pentru afisarea continutului pe website)",
|
|
"Lead - citire si creare (pentru captarea lead-urilor din formular contact)",
|
|
"Item - doar citire (pentru afisarea catalogului de servicii)",
|
|
])
|
|
|
|
doc.add_heading("14.3 Recomandari de Securitate", level=2)
|
|
add_bullet_list(doc, [
|
|
"Schimbati parola implicita 'admin' la prima accesare",
|
|
"Activati autentificarea in doi factori (2FA) pentru contul Administrator",
|
|
"Revizuiti periodic permisiunile rolurilor si utilizatorilor",
|
|
"Monitorizati log-urile de acces pentru activitati suspecte",
|
|
"Actualizati ERPNext la cele mai recente versiuni de securitate",
|
|
"Nu expuneti portul 8080 direct pe internet - utilizati reverse proxy cu HTTPS",
|
|
"Rotiti periodic API Key-urile utilizatorului de integrare",
|
|
])
|
|
|
|
# Save document
|
|
output_path = os.path.join(OUTPUT_DIR, "Ghid_Administrare_ERPNext.docx")
|
|
doc.save(output_path)
|
|
print(f" -> Salvat: {output_path}")
|
|
return output_path
|
|
|
|
|
|
# ==============================================================================
|
|
# DOCUMENT 3: Documentatie API
|
|
# ==============================================================================
|
|
|
|
|
|
def generate_documentatie_api():
|
|
"""Generate Documentatie_API.docx"""
|
|
print("[3/4] Generare Documentatie_API.docx ...")
|
|
|
|
doc = create_document()
|
|
|
|
add_cover_page(
|
|
doc,
|
|
"DOCUMENTATIE TEHNICA API",
|
|
"Integrari Website DiDi",
|
|
)
|
|
|
|
add_header_footer(doc)
|
|
add_toc_placeholder(doc)
|
|
|
|
# =========================================================================
|
|
# CHAPTER 1: Introducere
|
|
# =========================================================================
|
|
doc.add_heading("1. Introducere", level=1)
|
|
|
|
doc.add_heading("1.1 Scopul Documentului", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Aceasta documentatie tehnica descrie in detaliu toate intergrarile API utilizate "
|
|
"de website-ul DiDi. Documentul acopera: rutele API ale website-ului Next.js, "
|
|
"integrarea cu ERPNext, integrarea cu DiDi AI API, integrarea cu Stripe si "
|
|
"integrarea cu Keycloak SSO."
|
|
)
|
|
|
|
doc.add_heading("1.2 Audienta Tinta", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Documentul se adreseaza dezvoltatorilor software, arhitectilor de sistem si "
|
|
"personalului tehnic responsabil cu mentenanta si extinderea platformei DiDi."
|
|
)
|
|
|
|
doc.add_heading("1.3 Conventii", level=2)
|
|
add_bullet_list(doc, [
|
|
"Endpoint-urile sunt descrise in formatul: METODA /cale",
|
|
"Parametrii obligatorii sunt marcati cu * (asterisk)",
|
|
"Raspunsurile sunt in format JSON daca nu se specifica altfel",
|
|
"Codurile de status HTTP urmeaza standardul RFC 7231",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 2: Arhitectura Generala
|
|
# =========================================================================
|
|
doc.add_heading("2. Arhitectura Generala", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Arhitectura de integrari a platformei DiDi urmeaza un model hub-and-spoke, "
|
|
"in care website-ul Next.js actioneaza ca hub central, comunicand cu toate "
|
|
"serviciile externe prin API routes server-side."
|
|
)
|
|
|
|
doc.add_heading("2.1 Diagrama Integrari", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
+-------------------+ +-------------------+
|
|
| | OIDC | |
|
|
| Client Browser +--------->+ Keycloak SSO |
|
|
| (React/Next.js) | JWT | didi365.eu/auth |
|
|
| |<---------+ |
|
|
+--------+----------+ +-------------------+
|
|
|
|
|
| HTTPS (API Routes)
|
|
v
|
|
+--------+----------+ +-------------------+
|
|
| | REST | |
|
|
| Next.js Server +--------->+ ERPNext v15 API |
|
|
| (API Routes) | Token | localhost:8080 |
|
|
| |<---------+ |
|
|
+--------+----------+ +-------------------+
|
|
| |
|
|
| | Webhook
|
|
| v
|
|
| +----+-------------+
|
|
| | |
|
|
| | Stripe API |
|
|
| | Checkout + |
|
|
| | Webhooks |
|
|
| +------------------+
|
|
|
|
|
| REST API
|
|
v
|
|
+---+---------------+ +-------------------+
|
|
| | | |
|
|
| DiDi AI API +--------->+ MinIO Storage |
|
|
| didi365.eu/api | | (Media Upload) |
|
|
| | +-------------------+
|
|
+-------------------+
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("2.2 Principii de Design", level=2)
|
|
add_bullet_list(doc, [
|
|
"Server-side proxy: toate apelurile catre servicii externe se fac din server-ul Next.js, nu din browser. Credentialele (API keys, secrets) nu sunt niciodata expuse in client-side code.",
|
|
"Token-based auth: comunicarea cu ERPNext utilizeaza API Key + Secret, comunicarea cu Keycloak utilizeaza JWT tokens, comunicarea cu Stripe utilizeaza Secret Key.",
|
|
"Webhook verification: toate webhook-urile primite (Stripe) sunt verificate prin semnatura criptografica inainte de procesare.",
|
|
"Error handling: toate erorile sunt tratate graceful cu raspunsuri HTTP corespunzatoare si mesaje descriptive.",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 3: Autentificare
|
|
# =========================================================================
|
|
doc.add_heading("3. Autentificare", level=1)
|
|
|
|
doc.add_heading("3.1 Keycloak SSO", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Server", "https://didi365.eu/didi-auth"],
|
|
["Realm", "didi-website"],
|
|
["Client ID", "didi-website-server"],
|
|
["Client Type", "Confidential (cu client secret)"],
|
|
["Protocol", "OpenID Connect"],
|
|
["Grant Type", "Authorization Code Flow"],
|
|
["Token Endpoint", "/realms/didi-website/protocol/openid-connect/token"],
|
|
["Auth Endpoint", "/realms/didi-website/protocol/openid-connect/auth"],
|
|
["Userinfo Endpoint", "/realms/didi-website/protocol/openid-connect/userinfo"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Autentificarea pe website este gestionata prin Auth.js v5 (NextAuth) cu "
|
|
"provider-ul Keycloak. La autentificarea reusita, Auth.js creeaza o sesiune "
|
|
"server-side care contine: access_token, id_token, refresh_token si datele "
|
|
"utilizatorului (sub, name, email)."
|
|
)
|
|
|
|
doc.add_heading("3.2 ERPNext API Authentication", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Metoda", "Token-based (API Key + API Secret)"],
|
|
["User", "website_api@didi.localhost"],
|
|
["Rol", "Website Integration"],
|
|
["Header", "Authorization: token api_key:api_secret"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Fiecare request catre ERPNext API include header-ul Authorization cu token-ul "
|
|
"format din API Key si API Secret separate prin doua puncte (:). Acest mecanism "
|
|
"este configurat in fisierul src/lib/erpnext.ts."
|
|
)
|
|
|
|
doc.add_heading("3.3 Stripe Authentication", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Utilizare"],
|
|
[
|
|
["Publishable Key (pk_test_*)", "Client-side: initializare Stripe.js (nu se foloseste direct)"],
|
|
["Secret Key (sk_test_*)", "Server-side: creare sesiuni checkout, gestionare plati"],
|
|
["Webhook Secret (whsec_*)", "Server-side: verificare semnatura webhook-uri"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 4: API Routes Website (Next.js)
|
|
# =========================================================================
|
|
doc.add_heading("4. API Routes Website (Next.js)", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul Next.js expune urmatoarele API routes server-side. Toate rutele "
|
|
"sunt definite in directorul src/app/api/ si ruleaza exclusiv pe server."
|
|
)
|
|
|
|
# 4.1
|
|
doc.add_heading("4.1 /api/auth/[...nextauth]", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/auth/[...nextauth]"],
|
|
["Metode", "GET, POST"],
|
|
["Autentificare", "Nu (este endpoint-ul de autentificare)"],
|
|
["Descriere", "Handler Auth.js pentru fluxul de autentificare Keycloak"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Acest endpoint gestioneaza intregul flux de autentificare: redirect la Keycloak, "
|
|
"callback cu authorization code, obtinere tokens, creare sesiune, refresh tokens "
|
|
"si deconectare. Nu necesita implementare manuala - este gestionat complet de Auth.js."
|
|
)
|
|
|
|
# 4.2
|
|
doc.add_heading("4.2 /api/erp/[...path]", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/erp/[...path]"],
|
|
["Metode", "GET, POST, PUT"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
["Descriere", "Proxy server-side catre ERPNext API"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Actioneaza ca un proxy transparent intre client-side si ERPNext. Primeste request-uri "
|
|
"de la browser, adauga header-ul de autentificare ERPNext (API Key:Secret) si "
|
|
"retrimite request-ul catre ERPNext. Raspunsul ERPNext este returnat clientului. "
|
|
"Acest mecanism asigura ca credentialele ERPNext nu sunt niciodata expuse in browser."
|
|
)
|
|
|
|
# 4.3
|
|
doc.add_heading("4.3 /api/checkout", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/checkout"],
|
|
["Metoda", "POST"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
["Content-Type", "application/json"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Request Body", level=3)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
{
|
|
"priceId": "price_xxx", // Stripe Price ID
|
|
"itemCode": "DIDI-TECHNIQUES-TEXT", // Cod articol ERPNext
|
|
"customerName": "John Doe", // Numele clientului
|
|
"customerEmail": "john@example.com" // Email client
|
|
}
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("Response (200)", level=3)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
{
|
|
"sessionId": "cs_xxx", // Stripe Checkout Session ID
|
|
"url": "https://checkout.stripe.com/..." // URL redirect Stripe
|
|
}
|
|
""",
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Creeaza o sesiune Stripe Checkout cu pretul si detaliile serviciului selectat. "
|
|
"Returneaza URL-ul de redirect catre pagina de plata Stripe."
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# 4.4
|
|
doc.add_heading("4.4 /api/webhooks/stripe", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/webhooks/stripe"],
|
|
["Metoda", "POST"],
|
|
["Autentificare", "Stripe Webhook Signature (whsec_*)"],
|
|
["Content-Type", "application/json (raw body)"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Primeste notificari webhook de la Stripe la finalizarea platilor. Procesul de "
|
|
"fulfillment declansat include:"
|
|
)
|
|
|
|
add_numbered_list(doc, [
|
|
"Verificarea semnaturii webhook-ului pentru autenticitate",
|
|
"Extragerea datelor tranzactiei din evenimentul checkout.session.completed",
|
|
"Crearea sau identificarea clientului in ERPNext (pe baza didi_user_id)",
|
|
"Crearea facturii (Sales Invoice) cu articolul achizitionat, auto-submit",
|
|
"Crearea inregistrarii de plata (Payment Entry) pentru reconciliere contabila",
|
|
"Crearea acordului de servicii (Service Agreement) care activeaza analiza",
|
|
"Actualizarea planului clientului (iam_role) daca este necesar",
|
|
"Crearea intrarii in jurnalul de plati (Payment Log) pentru audit",
|
|
])
|
|
|
|
# 4.5
|
|
doc.add_heading("4.5 /api/analyze", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/analyze"],
|
|
["Metode", "GET, POST"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("GET /api/analyze", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Returneaza lista analizelor disponibile (Service Agreements active) ale clientului "
|
|
"curent. Daca se furnizeaza parametrul session_id, returneaza statusul/rezultatul "
|
|
"unei analize in procesare (polling)."
|
|
)
|
|
|
|
doc.add_heading("POST /api/analyze", level=3)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Porneste o noua analiza. Accepta doua formate de input:"
|
|
)
|
|
|
|
add_bullet_list(doc, [
|
|
"JSON body: { text, language, category, mediaType, serviceAgreement } - pentru analize text/URL",
|
|
"FormData (multipart): file + category + mediaType + serviceAgreement - pentru upload fisiere media",
|
|
])
|
|
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
// Exemplu request text:
|
|
POST /api/analyze
|
|
Content-Type: application/json
|
|
{
|
|
"text": "Textul de analizat...",
|
|
"language": "ro",
|
|
"category": "techniques",
|
|
"mediaType": "text",
|
|
"serviceAgreement": "SA-00001"
|
|
}
|
|
|
|
// Exemplu request media (upload fisier):
|
|
POST /api/analyze
|
|
Content-Type: multipart/form-data
|
|
- file: [fisier imagine/audio/video]
|
|
- category: "ai_detection"
|
|
- mediaType: "image"
|
|
- serviceAgreement: "SA-00002"
|
|
""",
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# 4.6
|
|
doc.add_heading("4.6 /api/analysis-reports", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/analysis-reports"],
|
|
["Metode", "GET, POST"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"GET: Returneaza lista rapoartelor de analiza salvate ale clientului curent. "
|
|
"POST: Creeaza un nou raport de analiza in ERPNext cu rezultatele obtinute de la DiDi API. "
|
|
"Raportul include: titlu, client, factura, session_id, result_json, status."
|
|
)
|
|
|
|
# 4.7
|
|
doc.add_heading("4.7 /api/analysis-report-pdf", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/analysis-report-pdf"],
|
|
["Metoda", "GET"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
["Parametri", "?report=REPORT_NAME"],
|
|
["Response", "application/pdf"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Genereaza si returneaza un fisier PDF cu raportul complet al analizei, "
|
|
"formatat profesional cu rezultatele, scorurile si recomandarile."
|
|
)
|
|
|
|
# 4.8
|
|
doc.add_heading("4.8 /api/customer/me", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/customer/me"],
|
|
["Metoda", "GET"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Identifica si returneaza clientul ERPNext asociat sesiunii Keycloak curente. "
|
|
"Cautarea se face pe baza campului didi_user_id (UUID Keycloak) din fisa clientului ERPNext."
|
|
)
|
|
|
|
# 4.9
|
|
doc.add_heading("4.9 /api/leads", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/leads"],
|
|
["Metoda", "POST"],
|
|
["Autentificare", "Nu (endpoint public)"],
|
|
["Content-Type", "application/json"],
|
|
],
|
|
)
|
|
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
{
|
|
"name": "Ion Popescu",
|
|
"email": "ion@example.com",
|
|
"message": "Doresc o demonstratie a platformei",
|
|
"utm_source": "google",
|
|
"utm_medium": "cpc",
|
|
"utm_campaign": "launch_2026"
|
|
}
|
|
""",
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Creeaza un Lead in ERPNext CRM cu datele din formularul de contact. "
|
|
"Include parametrii UTM pentru tracking-ul sursei de trafic."
|
|
)
|
|
|
|
# 4.10
|
|
doc.add_heading("4.10 /api/invoice-pdf", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Cale", "/api/invoice-pdf"],
|
|
["Metoda", "GET"],
|
|
["Autentificare", "Sesiune Auth.js obligatorie"],
|
|
["Parametri", "?invoice=SINV-XXXXX"],
|
|
["Response", "application/pdf"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Descarca factura in format PDF de la ERPNext, folosind print format-ul "
|
|
"personalizat DiDi Invoice. Verifica ca factura apartine clientului curent "
|
|
"inainte de returnare."
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 5: Integrare DiDi API
|
|
# =========================================================================
|
|
doc.add_heading("5. Integrare DiDi API", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"DiDi API este serviciul de inteligenta artificiala care proceseaza analizele de "
|
|
"continut. API-ul este disponibil la adresa https://didi365.eu/didi-api si ofera "
|
|
"endpoint-uri pentru upload media si 4 tipuri de analiza."
|
|
)
|
|
|
|
doc.add_heading("5.1 Upload Media", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Proprietate", "Valoare"],
|
|
[
|
|
["Endpoint", "POST /v3/media/upload"],
|
|
["Content-Type", "multipart/form-data"],
|
|
["Camp fisier", "file"],
|
|
["Raspuns", "{ public_url: 'https://...' }"],
|
|
],
|
|
)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Incarca un fisier media (imagine, audio, video) in storage-ul MinIO si returneaza "
|
|
"URL-ul public al fisierului. Acest URL este apoi utilizat in request-urile de analiza."
|
|
)
|
|
|
|
doc.add_heading("5.2 Endpoint-uri de Analiza", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Endpoint", "Categorie", "Descriere"],
|
|
[
|
|
["POST /v3/techniques/analyze", "Detectie Tehnici", "Identificare tehnici manipulare si propaganda"],
|
|
["POST /v3/ai-tampered/analyze", "AI Detection", "Detectie continut generat/modificat de AI"],
|
|
["POST /v3/claims/analyze", "Fact-Checking", "Verificare afirmatii si informatii"],
|
|
["POST /v3/domain/analyze", "Evaluare Surse", "Analiza credibilitate domenii web"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("5.3 Payload pentru Text", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
POST /v3/techniques/analyze
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"text": "Textul de analizat pentru detectarea tehnicilor de manipulare...",
|
|
"language": "ro"
|
|
}
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("5.4 Payload pentru Media", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
POST /v3/ai-tampered/analyze
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"media_type": "image", // "image" | "audio" | "video"
|
|
"media_url": "https://storage.didi365.eu/uploads/file.jpg"
|
|
}
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("5.5 Raspuns Sincron (Text/URL/Imagine)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pentru analizele de tip text, URL si imagine, API-ul returneaza rezultatul "
|
|
"direct in raspunsul HTTP cu status 200:"
|
|
)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
HTTP 200 OK
|
|
{
|
|
"risk_score": 0.78,
|
|
"confidence": 0.92,
|
|
"risk_category": "high",
|
|
"techniques": [
|
|
{ "name": "appeal_to_emotion", "score": 0.85 },
|
|
{ "name": "cherry_picking", "score": 0.72 }
|
|
],
|
|
"verdict": "Continutul prezinta indicii puternice de manipulare...",
|
|
"claims": [...],
|
|
"ai_tampered": { "probability": 0.15, "verdict": "authentic" },
|
|
"domain": { "credibility_score": 0.45, "category": "unreliable" }
|
|
}
|
|
""",
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
doc.add_heading("5.6 Raspuns Asincron (Audio/Video)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Pentru analizele de tip audio si video, API-ul returneaza un status 202 "
|
|
"cu un session_id pentru polling ulterior:"
|
|
)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
HTTP 202 Accepted
|
|
{
|
|
"session_id": "sess_abc123def456",
|
|
"status": "queued",
|
|
"message": "Analysis queued for processing"
|
|
}
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("5.7 Polling pentru Rezultate", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Dupa primirea unui raspuns 202, clientul trebuie sa faca polling pentru "
|
|
"a verifica statusul procesarii:"
|
|
)
|
|
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
// Pasul 1: Verificare status
|
|
GET /v3/pipeline/{session_id}/queue-status
|
|
|
|
Raspunsuri posibile:
|
|
{ "status": "queued" } // In coada de procesare
|
|
{ "status": "processing" } // In curs de procesare
|
|
{ "status": "completed" } // Procesare finalizata
|
|
|
|
// Pasul 2: Obtinere rezultat (dupa status "completed")
|
|
GET /v3/pipeline/{session_id}/result
|
|
|
|
Raspuns: aceeasi structura ca la raspunsul sincron (5.5)
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("5.8 Structura Rezultat", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Camp", "Tip", "Descriere"],
|
|
[
|
|
["risk_score", "float (0-1)", "Scorul de risc de dezinformare (0=fara risc, 1=risc maxim)"],
|
|
["confidence", "float (0-1)", "Nivelul de incredere al algoritmului in rezultat"],
|
|
["risk_category", "string", "Categorie: low / medium / high / critical"],
|
|
["techniques", "array", "Lista tehnicilor de manipulare detectate cu scoruri individuale"],
|
|
["verdict", "string", "Concluzia generala a analizei in text descriptiv"],
|
|
["claims", "array", "Lista afirmatiilor verificate (fact-checking)"],
|
|
["ai_tampered", "object", "Rezultat detectie AI: probability, verdict"],
|
|
["domain", "object", "Evaluare domeniu: credibility_score, category"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 6: Integrare Stripe
|
|
# =========================================================================
|
|
doc.add_heading("6. Integrare Stripe", level=1)
|
|
|
|
doc.add_heading("6.1 PRICE_MAP - Mapare Servicii", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Fiecare serviciu DiDi este mapat la un Stripe Price ID prin constanta PRICE_MAP "
|
|
"definita in configuratia aplicatiei. Aceasta mapare asociaza 16 combinatii de "
|
|
"categorii si tipuri de media cu price ID-urile corespunzatoare din Stripe:"
|
|
)
|
|
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
const PRICE_MAP = {
|
|
"DIDI-TECHNIQUES-TEXT": "price_techniques_text",
|
|
"DIDI-TECHNIQUES-IMAGE": "price_techniques_image",
|
|
"DIDI-TECHNIQUES-AUDIO": "price_techniques_audio",
|
|
"DIDI-TECHNIQUES-VIDEO": "price_techniques_video",
|
|
"DIDI-AI_DETECTION-TEXT": "price_ai_detection_text",
|
|
"DIDI-AI_DETECTION-IMAGE": "price_ai_detection_image",
|
|
"DIDI-AI_DETECTION-AUDIO": "price_ai_detection_audio",
|
|
"DIDI-AI_DETECTION-VIDEO": "price_ai_detection_video",
|
|
"DIDI-CLAIMS-TEXT": "price_claims_text",
|
|
"DIDI-CLAIMS-IMAGE": "price_claims_image",
|
|
"DIDI-CLAIMS-AUDIO": "price_claims_audio",
|
|
"DIDI-CLAIMS-VIDEO": "price_claims_video",
|
|
"DIDI-SOURCE-TEXT": "price_source_text",
|
|
"DIDI-SOURCE-IMAGE": "price_source_image",
|
|
"DIDI-SOURCE-AUDIO": "price_source_audio",
|
|
"DIDI-SOURCE-VIDEO": "price_source_video"
|
|
};
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("6.2 Checkout Flow", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Fluxul de checkout Stripe se desfasoara in 3 etape principale:"
|
|
)
|
|
|
|
add_numbered_list(doc, [
|
|
"Creare sesiune: POST /api/checkout creeaza un Stripe Checkout Session cu price ID-ul, datele clientului si URL-urile de redirect (success/cancel)",
|
|
"Redirect Stripe: utilizatorul este redirectionat la checkout.stripe.com unde completeaza datele de plata in mediul securizat Stripe",
|
|
"Webhook fulfillment: dupa plata reusita, Stripe trimite evenimentul checkout.session.completed la /api/webhooks/stripe care declanseaza procesul de fulfillment (creare factura, plata, acord servicii)",
|
|
])
|
|
|
|
doc.add_heading("6.3 Webhook Events", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Eveniment", "Actiune"],
|
|
[
|
|
["checkout.session.completed", "Fulfillment complet: factura + plata + acord servicii + payment log"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("6.4 Fulfillment (Procesare Automata)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"La primirea evenimentului checkout.session.completed, webhook-ul declanseaza "
|
|
"urmatoarele operatiuni in ordine secventiala:"
|
|
)
|
|
|
|
add_numbered_list(doc, [
|
|
"Creare/identificare customer - Cautare client ERPNext dupa didi_user_id (Keycloak UUID). Daca nu exista, se creeaza automat cu datele din sesiunea Stripe.",
|
|
"Creare factura (Sales Invoice) - Se genereaza automat cu articolul achizitionat, pret, TVA 19%. Factura se valideaza automat (auto-submit) pentru a fi considerata emisa.",
|
|
"Creare incasare (Payment Entry) - Se inregistreaza plata in contabilitate, reconciliata cu factura emisa. Contul de incasari: Stripe.",
|
|
"Creare acord servicii (Service Agreement) - Se activeaza dreptul clientului de a utiliza serviciul achizitionat. Status: Activ.",
|
|
"Actualizare plan client - Se actualizeaza campul iam_role al clientului (paid_tier daca era free_tier).",
|
|
"Creare Payment Log - Se inregistreaza tranzactia in jurnalul de plati cu toate detaliile Stripe pentru audit complet.",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 7: Integrare ERPNext
|
|
# =========================================================================
|
|
doc.add_heading("7. Integrare ERPNext", level=1)
|
|
|
|
doc.add_heading("7.1 DocTypes Custom", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Aplicatia custom didi_custom adauga 4 DocTypes noi in ERPNext, specifice "
|
|
"functionalitatilor platformei DiDi:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["DocType", "Modul", "Descriere"],
|
|
[
|
|
["Service Agreement", "DiDi", "Acord prestare servicii - activeaza dreptul de a rula o analiza"],
|
|
["Payment Log", "DiDi", "Jurnal plati Stripe - audit trail complet al tranzactiilor"],
|
|
["Website Content", "DiDi", "Continut website CMS - texte pagini bilingv RO/EN"],
|
|
["Analysis Report", "DiDi", "Raport analiza AI - rezultate complete analiza cu JSON si PDF"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("7.2 Custom Fields pe DocTypes Existente", level=2)
|
|
|
|
doc.add_heading("Customer (Client)", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Fieldname", "Label", "Tip", "Descriere"],
|
|
[
|
|
["didi_user_id", "ID Utilizator DiDi", "Data", "UUID Keycloak pentru legatura cu contul de autentificare"],
|
|
["iam_role", "Rol IAM", "Select", "Nivelul de acces: free_tier / paid_tier / enterprise_tier"],
|
|
["active_plan", "Plan Activ", "Data", "Planul de abonament curent"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Lead", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Fieldname", "Label", "Tip", "Descriere"],
|
|
[
|
|
["utm_source", "UTM Source", "Data", "Sursa traficului (google, facebook, etc.)"],
|
|
["utm_medium", "UTM Medium", "Data", "Mediul de marketing (cpc, organic, email)"],
|
|
["utm_campaign", "UTM Campaign", "Data", "Campania specifica"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("Sales Invoice (Factura)", level=3)
|
|
add_table_with_header(
|
|
doc,
|
|
["Fieldname", "Label", "Tip", "Descriere"],
|
|
[
|
|
["analysis_consumed", "Analiza Consumata", "Check", "Indica daca analiza asociata a fost rulata"],
|
|
["analysis_session_id", "Session ID Analiza", "Data", "ID-ul sesiunii de analiza DiDi API"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("7.3 Endpoint-uri ERPNext Utilizate", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Endpoint", "Metoda", "Descriere"],
|
|
[
|
|
["/api/resource/{DocType}", "GET", "Listare si cautare documente"],
|
|
["/api/resource/{DocType}/{name}", "GET", "Obtinere detalii document"],
|
|
["/api/resource/{DocType}", "POST", "Creare document nou"],
|
|
["/api/resource/{DocType}/{name}", "PUT", "Actualizare document existent"],
|
|
["/api/method/upload_file", "POST", "Upload fisier (atasament)"],
|
|
["/api/method/frappe.client.submit", "POST", "Validare (submit) document"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 8: Fisiere Cheie Cod Sursa
|
|
# =========================================================================
|
|
doc.add_heading("8. Fisiere Cheie Cod Sursa", level=1)
|
|
|
|
doc.add_heading("8.1 Librarii Partajate (src/lib/)", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Fisier", "Descriere"],
|
|
[
|
|
["src/lib/auth.ts", "Configurare Auth.js v5 cu Keycloak provider, callbacks JWT/session"],
|
|
["src/lib/erpnext.ts", "Client ERPNext API: functii CRUD, autentificare token, error handling"],
|
|
["src/lib/stripe.ts", "Initializare Stripe SDK cu secret key"],
|
|
["src/lib/stripe-fulfillment.ts", "Logica completa de fulfillment: creare customer, invoice, payment, SA"],
|
|
["src/lib/api.ts", "Client DiDi API: upload media, analiza, polling, parsing rezultate"],
|
|
["src/lib/analysis-report-pdf.ts", "Generator PDF rapoarte analiza cu formatare profesionala"],
|
|
["src/lib/analysis-report-store.ts", "CRUD operatii pentru Analysis Report in ERPNext"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("8.2 API Routes (src/app/api/)", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Fisier", "Route", "Descriere"],
|
|
[
|
|
["src/app/api/auth/[...nextauth]/route.ts", "/api/auth/*", "Handler Auth.js complet"],
|
|
["src/app/api/erp/[...path]/route.ts", "/api/erp/*", "Proxy ERPNext server-side"],
|
|
["src/app/api/checkout/route.ts", "/api/checkout", "Creare Stripe Checkout Session"],
|
|
["src/app/api/webhooks/stripe/route.ts", "/api/webhooks/stripe", "Procesare webhook Stripe"],
|
|
["src/app/api/analyze/route.ts", "/api/analyze", "Rulare si polling analize AI"],
|
|
["src/app/api/analysis-reports/route.ts", "/api/analysis-reports", "CRUD rapoarte analiza"],
|
|
["src/app/api/analysis-report-pdf/route.ts", "/api/analysis-report-pdf", "Download PDF raport"],
|
|
["src/app/api/customer/me/route.ts", "/api/customer/me", "Identificare client curent"],
|
|
["src/app/api/leads/route.ts", "/api/leads", "Creare Lead CRM"],
|
|
["src/app/api/invoice-pdf/route.ts", "/api/invoice-pdf", "Download PDF factura"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 9: Variabile de Mediu
|
|
# =========================================================================
|
|
doc.add_heading("9. Variabile de Mediu", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Urmatoarele variabile de mediu trebuie configurate in fisierul .env.local "
|
|
"pentru functionarea corecta a website-ului:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Variabila", "Descriere", "Exemplu"],
|
|
[
|
|
["NEXTAUTH_URL", "URL-ul de baza al website-ului", "https://didi365.eu"],
|
|
["NEXTAUTH_SECRET", "Secret pentru criptarea sesiunilor Auth.js", "[random string 32+ chars]"],
|
|
["KEYCLOAK_ISSUER", "URL-ul issuer-ului Keycloak", "https://didi365.eu/didi-auth/realms/didi-website"],
|
|
["KEYCLOAK_CLIENT_ID", "Client ID pentru Keycloak", "didi-website-server"],
|
|
["KEYCLOAK_CLIENT_SECRET", "Client Secret pentru Keycloak", "[UUID from Keycloak]"],
|
|
["ERPNEXT_URL", "URL-ul instanta ERPNext", "http://localhost:8080"],
|
|
["ERPNEXT_API_KEY", "API Key utilizator integrare", "[from ERPNext]"],
|
|
["ERPNEXT_API_SECRET", "API Secret utilizator integrare", "[from ERPNext]"],
|
|
["STRIPE_SECRET_KEY", "Stripe Secret Key", "sk_test_..."],
|
|
["STRIPE_PUBLISHABLE_KEY", "Stripe Publishable Key", "pk_test_..."],
|
|
["STRIPE_WEBHOOK_SECRET", "Secret verificare webhook", "whsec_..."],
|
|
["DIDI_API_URL", "URL-ul DiDi AI API", "https://didi365.eu/didi-api"],
|
|
["DIDI_API_KEY", "Cheie acces DiDi API", "[API key]"],
|
|
],
|
|
)
|
|
|
|
add_note_box(
|
|
doc,
|
|
"Fisierul .env.local nu trebuie niciodata comis in repository-ul Git. "
|
|
"Asigurati-va ca este inclus in .gitignore. Valorile secrete trebuie "
|
|
"stocate intr-un manager de secrete (ex: Docker secrets, Vault).",
|
|
"warning",
|
|
)
|
|
|
|
# Save document
|
|
output_path = os.path.join(OUTPUT_DIR, "Documentatie_API.docx")
|
|
doc.save(output_path)
|
|
print(f" -> Salvat: {output_path}")
|
|
return output_path
|
|
|
|
|
|
# ==============================================================================
|
|
# DOCUMENT 4: Arhitectura Detaliata
|
|
# ==============================================================================
|
|
|
|
|
|
def generate_arhitectura():
|
|
"""Generate Arhitectura_Detaliata.docx"""
|
|
print("[4/4] Generare Arhitectura_Detaliata.docx ...")
|
|
|
|
doc = create_document()
|
|
|
|
add_cover_page(
|
|
doc,
|
|
"ARHITECTURA DETALIATA",
|
|
"Platforma DiDi Website + ERP/CRM",
|
|
)
|
|
|
|
add_header_footer(doc)
|
|
add_toc_placeholder(doc)
|
|
|
|
# =========================================================================
|
|
# CHAPTER 1: Prezentare Generala
|
|
# =========================================================================
|
|
doc.add_heading("1. Prezentare Generala", level=1)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma DiDi este o solutie digitala complexa dezvoltata in cadrul proiectului "
|
|
"PNRR Contract 11.1.i3.c9/10.05.2024, care integreaza multiple componente tehnologice "
|
|
"pentru a oferi servicii de detectare si combatere a dezinformarii."
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run("Platforma este compusa din urmatoarele componente principale:")
|
|
|
|
add_bullet_list(doc, [
|
|
"Website Next.js 16 - interfata publica si dashboard client, cu e-commerce integrat",
|
|
"ERPNext v15 ERP/CRM - sistem de management resurse, facturare, CRM si gestiune clienti",
|
|
"Keycloak SSO - server de autentificare centralizata cu OpenID Connect",
|
|
"Stripe - procesator de plati online pentru e-commerce",
|
|
"DiDi AI API - motor de inteligenta artificiala pentru analiza continutului digital",
|
|
"SendGrid - serviciu email transactional pentru notificari automate",
|
|
])
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate componentele sunt integrate prin API-uri REST si comunica prin protocoale "
|
|
"securizate (HTTPS, JWT, API tokens). Arhitectura urmeaza principiile microserviciilor, "
|
|
"cu fiecare componenta avand responsabilitati bine definite si independenta operationala."
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 2: Diagrama Componente
|
|
# =========================================================================
|
|
doc.add_heading("2. Diagrama Componente", level=1)
|
|
|
|
doc.add_heading("2.1 Diagrama de Nivel Inalt", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
+===========================================================+
|
|
| CLIENT LAYER |
|
|
| +-----------------------------------------------------+ |
|
|
| | Client Browser (Desktop/Mobile) | |
|
|
| | React Components + Tailwind CSS | |
|
|
| +---------------------------+-------------------------+ |
|
|
+===========================================================+
|
|
|
|
|
| HTTPS
|
|
v
|
|
+===========================================================+
|
|
| APPLICATION LAYER |
|
|
| +-----------------------------------------------------+ |
|
|
| | Next.js 16 Website (App Router) | |
|
|
| | | |
|
|
| | +-------------+ +------------+ +--------------+ | |
|
|
| | | Public Pages| | Dashboard | | API Routes | | |
|
|
| | | (SSR/SSG) | | (Auth Req) | | (Server-side)| | |
|
|
| | +-------------+ +------------+ +--------------+ | |
|
|
| +-----------------------------------------------------+ |
|
|
+===========================================================+
|
|
| | | |
|
|
v v v v
|
|
+==============+ +=============+ +============+ +============+
|
|
| Keycloak SSO | | ERPNext v15 | | Stripe API | | DiDi AI API|
|
|
| (didi365.eu | | (Docker) | | (Payments) | | (didi365.eu|
|
|
| /didi-auth) | | | | | | /didi-api) |
|
|
+==============+ +=============+ +============+ +============+
|
|
| |
|
|
v v
|
|
+=============+ +============+
|
|
| MariaDB | | MinIO |
|
|
| Redis x2 | | RabbitMQ |
|
|
| Workers x3 | | Redis |
|
|
| Scheduler | | PostgreSQL |
|
|
+=============+ +============+
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("2.2 Fluxul de Comunicare", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate comunicarile intre componente se realizeaza prin protocolul HTTPS, cu exceptia "
|
|
"comunicarilor interne intre containerele Docker din acelasi stack (ERPNext <-> MariaDB, "
|
|
"DiDi API <-> PostgreSQL) care utilizeaza retele Docker interne. Fiecare integrare "
|
|
"utilizeaza mecanisme de autentificare specifice (JWT, API tokens, webhook signatures)."
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 3: Componenta Website
|
|
# =========================================================================
|
|
doc.add_heading("3. Componenta Website (Next.js 16)", level=1)
|
|
|
|
doc.add_heading("3.1 Stack Tehnologic", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Tehnologie", "Versiune", "Utilizare"],
|
|
[
|
|
["Next.js", "16", "Framework React cu App Router, SSR, SSG, API Routes"],
|
|
["TypeScript", "5.x", "Tipizare statica pentru calitate si mentenabilitate cod"],
|
|
["Tailwind CSS", "3.x", "Framework CSS utility-first pentru styling rapid si consistent"],
|
|
["Auth.js", "v5 (NextAuth)", "Librarie autentificare cu provider Keycloak"],
|
|
["Stripe SDK", "Latest", "SDK oficial pentru integrarea platilor Stripe"],
|
|
["React", "19.x", "Librarie UI componente reactive"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("3.2 Autentificare (Auth.js v5 cu Keycloak)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Autentificarea este gestionata prin Auth.js v5 (fostul NextAuth.js) cu provider-ul "
|
|
"Keycloak. Configurarea include:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Keycloak Provider cu OpenID Connect flow (Authorization Code)",
|
|
"JWT callback pentru extragerea si stocarea tokens-urilor in sesiune",
|
|
"Session callback pentru expunerea datelor utilizatorului catre componente",
|
|
"Refresh token rotation pentru reinnoirea automata a sesiunilor expirate",
|
|
"Configurare realm: didi-website, client: didi-website-server (confidential)",
|
|
])
|
|
|
|
doc.add_heading("3.3 Structura Routing", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Aplicatia Next.js utilizeaza App Router cu grupuri de rute (route groups) "
|
|
"pentru organizarea logica a paginilor:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Grup", "Prefix", "Autentificare", "Pagini"],
|
|
[
|
|
["(public)", "/", "Nu", "Homepage, Servicii, Despre, Pricing, Contact, Privacy, Terms"],
|
|
["(auth)", "/auth/*", "Nu (redirect daca autentificat)", "Login, Register, Callback"],
|
|
["(dashboard)", "/dashboard/*", "Da (redirect la login daca nu)", "Overview, Analize, Achizitii, Facturi, Profil"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("3.4 API Routes Server-Side", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate intergrarile cu serviciile externe (ERPNext, Stripe, DiDi API, Keycloak) "
|
|
"se realizeaza prin API routes server-side. Acest design asigura ca:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Credentialele (API keys, secrets, tokens) nu sunt niciodata expuse in codul client-side",
|
|
"CORS nu este o problema deoarece request-urile se fac server-to-server",
|
|
"Logica de business complexa (fulfillment, polling, PDF generation) ruleaza pe server",
|
|
"Se poate implementa rate limiting si validare la nivel de server",
|
|
])
|
|
|
|
doc.add_heading("3.5 Internationalizare (i18n)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul suporta doua limbi (RO/EN) implementate prin:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Continut pagini gestionat prin CMS ERPNext (Website Content) cu campuri bilingve",
|
|
"Etichete UI stocate in fisiere de traducere locale (JSON)",
|
|
"Selectorul de limba persista preferinta in localStorage",
|
|
"Limba implicita: Romana (RO)",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 4: Componenta ERP/CRM
|
|
# =========================================================================
|
|
doc.add_heading("4. Componenta ERP/CRM (ERPNext v15)", level=1)
|
|
|
|
doc.add_heading("4.1 Infrastructura Docker", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"ERPNext ruleaza intr-un stack Docker Compose cu 8 containere configurate "
|
|
"pentru performanta si fiabilitate:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Container", "Imagine", "Resurse", "Rol"],
|
|
[
|
|
["erpnext", "frappe/erpnext:v15", "Web + API", "Serveste interfata web si raspunde la API requests"],
|
|
["mariadb", "mariadb:10.11", "Baza de date", "Stocheaza toate datele ERPNext (documente, configurari)"],
|
|
["redis-cache", "redis:7", "Cache", "Cache pentru sesiuni, metadata si date frecvent accesate"],
|
|
["redis-queue", "redis:7", "Message Queue", "Coada de mesaje pentru job-uri asincrone (Frappe RQ)"],
|
|
["worker-default", "frappe/erpnext:v15", "Background Jobs", "Proceseaza job-uri standard (email, notificari)"],
|
|
["worker-short", "frappe/erpnext:v15", "Background Jobs", "Proceseaza job-uri rapide (sub 5 minute)"],
|
|
["worker-long", "frappe/erpnext:v15", "Background Jobs", "Proceseaza job-uri de durata lunga (rapoarte, export)"],
|
|
["scheduler", "frappe/erpnext:v15", "Task Scheduler", "Planifica si declanseaza taskuri recurente"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("4.2 Aplicatie Custom: didi_custom", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Aplicatia Frappe custom didi_custom extinde ERPNext cu functionalitatile specifice "
|
|
"platformei DiDi. Include 4 DocTypes noi si custom fields pe DocTypes existente:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["DocType", "Tip", "Campuri Principale"],
|
|
[
|
|
["Service Agreement", "Custom", "customer, item, invoice, status, created_date, expiry_date"],
|
|
["Payment Log", "Custom", "customer, event_type, status, amount, stripe_payment_id, stripe_session_id, invoice, raw_data"],
|
|
["Website Content", "Custom", "page_slug, content_ro, content_en, section, published"],
|
|
["Analysis Report", "Custom", "title, customer, invoice, session_id, analysis_type, media_type, result_json, status, pdf_attachment"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("4.3 Configurare Companie", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Companie", "TOP CLOSSERS SRL"],
|
|
["CUI", "36193026"],
|
|
["Adresa", "Str. Targovistei 15, Ploiesti, 100299, Prahova"],
|
|
["Plan Conturi", "Romania Standard"],
|
|
["TVA", "19% (conform legislatie romaneasca)"],
|
|
["Moneda", "RON (Leu Romanesc)"],
|
|
["Serie Facturi", "DIDI-INV-YYYY-#####"],
|
|
["An Fiscal", "Ianuarie - Decembrie"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("4.4 API User pentru Integrare", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Utilizator", "website_api@didi.localhost"],
|
|
["Tip", "System User (fara Desk Access)"],
|
|
["Rol", "Website Integration"],
|
|
["Autentificare", "API Key + API Secret"],
|
|
["Principiu", "Least Privilege - acces minim necesar"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 5: Integrari Externe
|
|
# =========================================================================
|
|
doc.add_heading("5. Integrari Externe", level=1)
|
|
|
|
doc.add_heading("5.1 Keycloak SSO", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Server", "https://didi365.eu/didi-auth"],
|
|
["Realm", "didi-website"],
|
|
["Protocol", "OpenID Connect (OIDC)"],
|
|
["Client", "didi-website-server (Confidential)"],
|
|
["Flow", "Authorization Code Flow"],
|
|
["Token Format", "JWT (JSON Web Token)"],
|
|
["Token Lifetime", "Access: 5 min, Refresh: 30 min, Session: 8 ore"],
|
|
],
|
|
)
|
|
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Keycloak gestioneaza identitatea utilizatorilor, procesul de inregistrare, "
|
|
"autentificare si managementul sesiunilor. Fiecare utilizator primeste un UUID "
|
|
"unic care este utilizat ca didi_user_id in ERPNext pentru corelarea conturilor."
|
|
)
|
|
|
|
doc.add_heading("5.2 Stripe (Plati Online)", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Tip Integrare", "Stripe Checkout (Hosted Payment Page)"],
|
|
["Tip Plati", "One-time (plata unica per serviciu)"],
|
|
["Moneda", "RON"],
|
|
["Webhook", "/api/webhooks/stripe"],
|
|
["Verificare", "Stripe Webhook Signature (HMAC SHA-256)"],
|
|
["Certificare", "PCI DSS Level 1"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("5.3 DiDi AI API", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["URL", "https://didi365.eu/didi-api"],
|
|
["Versiune", "v3"],
|
|
["Autentificare", "API Key in header"],
|
|
["Endpoint-uri", "4 categorii analiza + upload media"],
|
|
["Storage", "MinIO (object storage S3-compatible)"],
|
|
["Queue", "RabbitMQ (procesare asincrona audio/video)"],
|
|
["Baza de date", "PostgreSQL + Redis"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("5.4 SendGrid (Email Transactional)", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Parametru", "Valoare"],
|
|
[
|
|
["Provider", "SendGrid (Twilio)"],
|
|
["Protocol", "SMTP over TLS"],
|
|
["Server", "smtp.sendgrid.net:587"],
|
|
["Expeditor", "noreply@didi365.eu"],
|
|
["Utilizare", "Notificari automate: facturi, confirmari plata, expirari"],
|
|
],
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 6: Flux de Date
|
|
# =========================================================================
|
|
doc.add_heading("6. Flux de Date", level=1)
|
|
|
|
doc.add_heading("6.1 Flux Autentificare", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
[Browser] --click Login--> [Next.js]
|
|
[Next.js] --redirect--> [Keycloak Login Page]
|
|
[User] --credentials--> [Keycloak]
|
|
[Keycloak] --authorization code--> [Next.js callback]
|
|
[Next.js] --exchange code--> [Keycloak Token Endpoint]
|
|
[Keycloak] --JWT tokens--> [Next.js]
|
|
[Next.js] --create session--> [Auth.js Session]
|
|
[Next.js] --GET /api/customer/me--> [ERPNext]
|
|
[ERPNext] --customer data (by didi_user_id)--> [Next.js]
|
|
[Next.js] --render Dashboard--> [Browser]
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("6.2 Flux Achizitie Serviciu", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
[Browser] --selecteaza serviciu--> [Dashboard Achizitii]
|
|
[Dashboard] --POST /api/checkout--> [Next.js API]
|
|
[Next.js] --create Checkout Session--> [Stripe API]
|
|
[Stripe] --session URL--> [Next.js]
|
|
[Next.js] --redirect--> [Stripe Checkout Page]
|
|
[User] --completeaza plata--> [Stripe]
|
|
[Stripe] --redirect success--> [Website Success Page]
|
|
[Stripe] --webhook POST--> [/api/webhooks/stripe]
|
|
[Webhook] --create customer--> [ERPNext]
|
|
[Webhook] --create invoice (auto-submit)--> [ERPNext]
|
|
[Webhook] --create payment entry--> [ERPNext]
|
|
[Webhook] --create service agreement--> [ERPNext]
|
|
[Webhook] --update customer plan--> [ERPNext]
|
|
[Webhook] --create payment log--> [ERPNext]
|
|
[ERPNext] --send invoice email--> [SendGrid] --> [Client Email]
|
|
""",
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
doc.add_heading("6.3 Flux Analiza Text (Sincron)", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
[Browser] --selecteaza analiza--> [Dashboard Analize]
|
|
[Browser] --introduce text--> [Formular Analiza]
|
|
[Browser] --POST /api/analyze--> [Next.js API]
|
|
[Next.js] --POST /v3/techniques/analyze--> [DiDi API]
|
|
[DiDi API] --procesare AI--> [Rezultat]
|
|
[DiDi API] --200 OK + result JSON--> [Next.js]
|
|
[Next.js] --mark SA consumed--> [ERPNext]
|
|
[Next.js] --create Analysis Report--> [ERPNext]
|
|
[Next.js] --result JSON--> [Browser]
|
|
[Browser] --afiseaza rezultat--> [Dashboard]
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("6.4 Flux Analiza Media (Asincron)", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
[Browser] --upload fisier--> [FormData]
|
|
[Browser] --POST /api/analyze--> [Next.js API]
|
|
[Next.js] --POST /v3/media/upload--> [DiDi API]
|
|
[DiDi API] --stocare MinIO--> [public_url]
|
|
[DiDi API] --public_url--> [Next.js]
|
|
[Next.js] --POST /v3/ai-tampered/analyze { media_url }--> [DiDi API]
|
|
[DiDi API] --202 Accepted { session_id }--> [Next.js]
|
|
[Next.js] --session_id--> [Browser]
|
|
[Browser] --polling GET /api/analyze?session_id--> [Next.js]
|
|
[Next.js] --GET /v3/pipeline/{id}/queue-status--> [DiDi API]
|
|
[DiDi API] --"completed"--> [Next.js]
|
|
[Next.js] --GET /v3/pipeline/{id}/result--> [DiDi API]
|
|
[DiDi API] --result JSON--> [Next.js]
|
|
[Next.js] --persist result--> [ERPNext Analysis Report]
|
|
[Next.js] --result--> [Browser]
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("6.5 Flux CMS (Continut Website)", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
[Admin] --editare continut--> [ERPNext Website Content]
|
|
[ERPNext] --salveaza RO + EN--> [MariaDB]
|
|
[Browser] --acceseaza pagina--> [Next.js]
|
|
[Next.js] --GET /api/erp/Website Content?slug=homepage--> [ERPNext API]
|
|
[ERPNext] --content_ro / content_en--> [Next.js]
|
|
[Next.js] --selecteaza limba curenta--> [Render pagina]
|
|
[Next.js] --HTML--> [Browser]
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("6.6 Flux CRM (Lead Capture)", level=2)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
[Vizitator] --completeaza formular contact--> [Browser]
|
|
[Browser] --POST /api/leads { name, email, message, utm_* }--> [Next.js]
|
|
[Next.js] --POST /api/resource/Lead--> [ERPNext API]
|
|
[ERPNext] --create Lead (status: Open)--> [MariaDB]
|
|
[ERPNext] --notify sales team--> [Email Notification]
|
|
""",
|
|
)
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 7: Securitate
|
|
# =========================================================================
|
|
doc.add_heading("7. Securitate", level=1)
|
|
|
|
doc.add_heading("7.1 Transport Layer Security (TLS)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate comunicarile externe utilizeaza HTTPS cu certificate TLS valide. "
|
|
"Conexiunile HTTP sunt redirectionate automat catre HTTPS prin configurarea "
|
|
"Nginx reverse proxy."
|
|
)
|
|
|
|
doc.add_heading("7.2 Autentificare si Autorizare", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Mecanism", "Componenta", "Descriere"],
|
|
[
|
|
["JWT Tokens", "Keycloak", "Tokens cu durata limitata, semnate criptografic, refresh automat"],
|
|
["API Token", "ERPNext", "API Key + Secret, utilizator cu permisiuni minimale"],
|
|
["Webhook Signature", "Stripe", "HMAC SHA-256 pentru verificarea autenticitatii webhook-urilor"],
|
|
["API Key", "DiDi API", "Cheie de acces in header pentru autentificarea request-urilor"],
|
|
["Session Cookie", "Auth.js", "Cookie securizat (HttpOnly, Secure, SameSite) pentru sesiuni web"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("7.3 RBAC (Role-Based Access Control)", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Platforma implementeaza 3 niveluri de acces (tiers) pentru utilizatori:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Tier", "iam_role", "Acces", "Descriere"],
|
|
[
|
|
["Free", "free_tier", "Limitat", "Cont creat, fara achizitii. Acces la pagini publice si dashboard de baza"],
|
|
["Paid", "paid_tier", "Standard", "Cel putin o achizitie efectuata. Acces complet la analize si rapoarte"],
|
|
["Enterprise", "enterprise_tier", "Extins", "Client enterprise cu acces la functionalitati avansate si suport dedicat"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("7.4 Server-Side API Proxy", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Toate apelurile catre servicii externe se fac exclusiv din server-ul Next.js. "
|
|
"Credentialele (API keys, secrets, tokens) sunt stocate in variabile de mediu "
|
|
"server-side si nu sunt niciodata incluse in bundle-ul JavaScript trimis la client. "
|
|
"Aceasta arhitectura previne expunerea credentialelor prin inspectia codului sursa "
|
|
"sau interceptarea traficului de retea din browser."
|
|
)
|
|
|
|
doc.add_heading("7.5 Stripe PCI DSS Compliance", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Integrarea cu Stripe utilizeaza Stripe Checkout (hosted payment page), ceea ce "
|
|
"inseamna ca datele de card sunt introduse exclusiv pe serverele Stripe si nu "
|
|
"tranziteaza niciodata serverele platformei DiDi. Aceasta abordare asigura "
|
|
"conformitatea cu standardul PCI DSS fara a necesita certificare PCI pe "
|
|
"infrastructura proprie."
|
|
)
|
|
|
|
doc.add_heading("7.6 GDPR Compliance", level=2)
|
|
add_bullet_list(doc, [
|
|
"Cookie consent: banner de consimtamant la prima vizita cu optiuni granulare (necesar, functional, analitic)",
|
|
"Politica de confidentialitate: document complet GDPR accesibil pe website",
|
|
"Dreptul la acces: utilizatorii pot vizualiza datele personale din profilul dashboard",
|
|
"Dreptul la rectificare: utilizatorii pot edita datele personale din profil",
|
|
"Dreptul la stergere: utilizatorii pot solicita stergerea contului si a datelor asociate",
|
|
"Dreptul la portabilitate: export date in format standard",
|
|
"Baza legala: consimtamant explicit pentru prelucrare date",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 8: Deployment
|
|
# =========================================================================
|
|
doc.add_heading("8. Deployment", level=1)
|
|
|
|
doc.add_heading("8.1 Docker Compose", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Intreaga platforma este containerizata cu Docker si orchestrata prin Docker Compose. "
|
|
"Fiecare componenta ruleaza in containere izolate cu volume persistente pentru date."
|
|
)
|
|
|
|
doc.add_heading("Stack-ul de Containere ERPNext", level=3)
|
|
add_code_block(
|
|
doc,
|
|
"""
|
|
services:
|
|
erpnext:
|
|
image: frappe/erpnext:v15
|
|
ports: ["8080:8080"]
|
|
volumes: [sites:/home/frappe/frappe-bench/sites]
|
|
|
|
mariadb:
|
|
image: mariadb:10.11
|
|
volumes: [mariadb-data:/var/lib/mysql]
|
|
|
|
redis-cache:
|
|
image: redis:7
|
|
|
|
redis-queue:
|
|
image: redis:7
|
|
|
|
worker-default:
|
|
image: frappe/erpnext:v15
|
|
command: bench worker --queue default
|
|
|
|
worker-short:
|
|
image: frappe/erpnext:v15
|
|
command: bench worker --queue short
|
|
|
|
worker-long:
|
|
image: frappe/erpnext:v15
|
|
command: bench worker --queue long
|
|
|
|
scheduler:
|
|
image: frappe/erpnext:v15
|
|
command: bench schedule
|
|
""",
|
|
)
|
|
|
|
doc.add_heading("8.2 Volume Persistente", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Volume", "Container", "Date Stocate"],
|
|
[
|
|
["sites", "erpnext", "Configurari site, fisiere uploadate, backup-uri"],
|
|
["mariadb-data", "mariadb", "Baza de date completa ERPNext"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("8.3 Nginx Reverse Proxy", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Un server Nginx actioneaza ca reverse proxy in fata tuturor serviciilor, oferind:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Terminare TLS/SSL cu certificate Let's Encrypt",
|
|
"Rutare trafic catre serviciile corespunzatoare pe baza path-ului URL",
|
|
"Compresie gzip pentru optimizarea transferului",
|
|
"Buffering si caching la nivel de proxy",
|
|
"Rate limiting si protectie DDoS de baza",
|
|
])
|
|
|
|
doc.add_heading("8.4 Backup Automat Zilnic", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Sistemul de backup include:"
|
|
)
|
|
add_bullet_list(doc, [
|
|
"Backup automat zilnic al bazei de date MariaDB (via ERPNext scheduler)",
|
|
"Backup incrementali ale fisierelor uploadate",
|
|
"Retentie: 7 backup-uri zilnice, 4 saptamanale, 3 lunare",
|
|
"Stocare offsite pe server extern pentru protectie la dezastre",
|
|
"Testare periodica a restaurarii din backup",
|
|
])
|
|
|
|
doc.add_page_break()
|
|
|
|
# =========================================================================
|
|
# CHAPTER 9: Cerinte Non-Functionale Indeplinite
|
|
# =========================================================================
|
|
doc.add_heading("9. Cerinte Non-Functionale Indeplinite", level=1)
|
|
|
|
doc.add_heading("9.1 Performanta", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Website-ul DiDi a fost optimizat pentru performanta si a obtinut urmatoarele "
|
|
"scoruri in testele Google Lighthouse:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Metrica", "Scor / Valoare", "Obiectiv", "Status"],
|
|
[
|
|
["Lighthouse Performance", "78/100", "> 70/100", "Indeplinit"],
|
|
["First Contentful Paint (FCP)", "0.8s", "< 1.8s", "Indeplinit"],
|
|
["Largest Contentful Paint (LCP)", "1.2s", "< 2.5s", "Indeplinit"],
|
|
["Best Practices", "100/100", "> 90/100", "Indeplinit"],
|
|
["Time to Interactive (TTI)", "1.5s", "< 3.8s", "Indeplinit"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("9.2 Accesibilitate", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Metrica", "Scor / Valoare", "Standard", "Status"],
|
|
[
|
|
["Lighthouse Accessibility", "91/100", "WCAG 2.1 AA", "Indeplinit"],
|
|
["Contrast culori", "Conform", "WCAG 2.1 AA (4.5:1)", "Indeplinit"],
|
|
["Navigare keyboard", "Complet", "WCAG 2.1 AA", "Indeplinit"],
|
|
["Alt text imagini", "Complet", "WCAG 2.1 AA", "Indeplinit"],
|
|
["ARIA labels", "Complet", "WCAG 2.1 AA", "Indeplinit"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("9.3 SEO", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Metrica", "Scor / Valoare", "Status"],
|
|
[
|
|
["Lighthouse SEO", "100/100", "Indeplinit"],
|
|
["sitemap.xml", "Generat automat", "Indeplinit"],
|
|
["robots.txt", "Configurat", "Indeplinit"],
|
|
["Meta tags (title, description)", "Unice per pagina", "Indeplinit"],
|
|
["Open Graph tags", "Complete", "Indeplinit"],
|
|
["Structured data", "Schema.org", "Indeplinit"],
|
|
["URL-uri semantice", "Curate si descriptive", "Indeplinit"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("9.4 Securitate", level=2)
|
|
add_table_with_header(
|
|
doc,
|
|
["Metrica", "Valoare", "Status"],
|
|
[
|
|
["npm audit vulnerabilitati", "0 vulnerabilitati", "Indeplinit"],
|
|
["HTTPS/TLS", "Certificate valide pe toate endpoint-urile", "Indeplinit"],
|
|
["Headers securitate", "CSP, HSTS, X-Frame-Options, X-Content-Type-Options", "Indeplinit"],
|
|
["Cookie flags", "HttpOnly, Secure, SameSite=Lax", "Indeplinit"],
|
|
["Input validation", "Server-side validation pe toate API routes", "Indeplinit"],
|
|
["SQL Injection", "Protectie prin ORM (Frappe/ERPNext)", "Indeplinit"],
|
|
["XSS", "Protectie prin React auto-escaping + CSP", "Indeplinit"],
|
|
],
|
|
)
|
|
|
|
doc.add_heading("9.5 Sumar Lighthouse", level=2)
|
|
p = doc.add_paragraph()
|
|
p.add_run(
|
|
"Rezultatele complete ale auditului Google Lighthouse pentru pagina principala "
|
|
"a website-ului DiDi confirma indeplinirea tuturor cerintelor non-functionale "
|
|
"stabilite in caietul de sarcini al proiectului PNRR:"
|
|
)
|
|
|
|
add_table_with_header(
|
|
doc,
|
|
["Categorie Lighthouse", "Scor", "Calificativ"],
|
|
[
|
|
["Performance", "78/100", "Bun"],
|
|
["Accessibility", "91/100", "Excelent"],
|
|
["Best Practices", "100/100", "Perfect"],
|
|
["SEO", "100/100", "Perfect"],
|
|
],
|
|
)
|
|
|
|
# Save document
|
|
output_path = os.path.join(OUTPUT_DIR, "Arhitectura_Detaliata.docx")
|
|
doc.save(output_path)
|
|
print(f" -> Salvat: {output_path}")
|
|
return output_path
|
|
|
|
|
|
# ==============================================================================
|
|
# MAIN
|
|
# ==============================================================================
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 70)
|
|
print(" Generator Documente Livrabile PNRR - Platforma DiDi")
|
|
print(f" TOP CLOSSERS SRL | CUI: {COMPANY['cui']}")
|
|
print(f" Proiect: {COMPANY['project_ref']}")
|
|
print("=" * 70)
|
|
print()
|
|
|
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
|
|
|
results = []
|
|
|
|
try:
|
|
results.append(generate_manual_utilizare())
|
|
except Exception as e:
|
|
print(f" EROARE Document 1: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
try:
|
|
results.append(generate_ghid_erpnext())
|
|
except Exception as e:
|
|
print(f" EROARE Document 2: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
try:
|
|
results.append(generate_documentatie_api())
|
|
except Exception as e:
|
|
print(f" EROARE Document 3: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
try:
|
|
results.append(generate_arhitectura())
|
|
except Exception as e:
|
|
print(f" EROARE Document 4: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
print()
|
|
print("=" * 70)
|
|
print(f" Finalizat! {len(results)} documente generate cu succes.")
|
|
print("=" * 70)
|
|
for r in results:
|
|
print(f" - {r}")
|
|
print()
|