docs: add architecture documentation and slides
This commit is contained in:
215
docs/diagrams/generate.py
Normal file
215
docs/diagrams/generate.py
Normal file
@@ -0,0 +1,215 @@
|
||||
from pathlib import Path
|
||||
|
||||
from diagrams import Cluster, Diagram, Edge
|
||||
from diagrams.generic.blank import Blank
|
||||
from diagrams.onprem.database import Mongodb
|
||||
from diagrams.onprem.inmemory import Redis
|
||||
from diagrams.onprem.network import Internet
|
||||
from diagrams.onprem.queue import Rabbitmq
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
OUT = ROOT / "docs" / "assets" / "diagrams"
|
||||
|
||||
|
||||
def graph_attr() -> dict[str, str]:
|
||||
return {
|
||||
"bgcolor": "transparent",
|
||||
"pad": "0.35",
|
||||
"ranksep": "0.8",
|
||||
"nodesep": "0.55",
|
||||
"fontname": "Inter",
|
||||
}
|
||||
|
||||
|
||||
def node_attr() -> dict[str, str]:
|
||||
return {
|
||||
"fontname": "Inter",
|
||||
"fontsize": "13",
|
||||
"style": "rounded,filled",
|
||||
"fillcolor": "#111827",
|
||||
"fontcolor": "#E5E7EB",
|
||||
"color": "#334155",
|
||||
}
|
||||
|
||||
|
||||
def edge_attr() -> dict[str, str]:
|
||||
return {"fontname": "Inter", "fontsize": "11", "color": "#64748B", "fontcolor": "#475569"}
|
||||
|
||||
|
||||
def render_service_architecture() -> None:
|
||||
with Diagram(
|
||||
"Service Architecture",
|
||||
filename=str(OUT / "service_architecture"),
|
||||
show=False,
|
||||
direction="LR",
|
||||
graph_attr=graph_attr(),
|
||||
node_attr=node_attr(),
|
||||
edge_attr=edge_attr(),
|
||||
):
|
||||
browser = Internet("Browser")
|
||||
demo = Blank("demo-app\nFastAPI UI")
|
||||
auth = Blank("auth-service\ngRPC")
|
||||
worker = Blank("sms-worker")
|
||||
mongo = Mongodb("MongoDB")
|
||||
redis = Redis("Redis")
|
||||
rabbit = Rabbitmq("RabbitMQ")
|
||||
providers = Blank("Kavenegar / SMS.ir")
|
||||
|
||||
browser >> Edge(label="HTTPS / local HTTP") >> demo
|
||||
demo >> Edge(label="gRPC") >> auth
|
||||
auth >> Edge(label="users + refresh sessions") >> mongo
|
||||
auth >> Edge(label="OTP hash + rate limits") >> redis
|
||||
auth >> Edge(label="SMS job") >> rabbit >> worker >> providers
|
||||
|
||||
|
||||
def render_clean_architecture() -> None:
|
||||
with Diagram(
|
||||
"Clean Architecture Layers",
|
||||
filename=str(OUT / "clean_architecture"),
|
||||
show=False,
|
||||
direction="TB",
|
||||
graph_attr=graph_attr(),
|
||||
node_attr=node_attr(),
|
||||
edge_attr=edge_attr(),
|
||||
):
|
||||
with Cluster("Transport"):
|
||||
grpc = Blank("gRPC servicer")
|
||||
demo = Blank("Demo BFF")
|
||||
with Cluster("Application"):
|
||||
auth = Blank("AuthService\nuse cases")
|
||||
security = Blank("Token + OTP helpers")
|
||||
with Cluster("Domain"):
|
||||
entities = Blank("Entities")
|
||||
ports = Blank("Ports")
|
||||
with Cluster("Infrastructure"):
|
||||
mongo = Blank("Mongo repositories")
|
||||
redis = Blank("Redis OTP store")
|
||||
rabbit = Blank("RabbitMQ publisher")
|
||||
sms = Blank("SMS strategies")
|
||||
|
||||
grpc >> auth
|
||||
demo >> grpc
|
||||
auth >> entities
|
||||
auth >> ports
|
||||
auth >> security
|
||||
ports >> mongo
|
||||
ports >> redis
|
||||
ports >> rabbit
|
||||
ports >> sms
|
||||
|
||||
|
||||
def render_otp_flow() -> None:
|
||||
with Diagram(
|
||||
"OTP Login Flow",
|
||||
filename=str(OUT / "otp_login_flow"),
|
||||
show=False,
|
||||
direction="LR",
|
||||
graph_attr=graph_attr(),
|
||||
node_attr=node_attr(),
|
||||
edge_attr=edge_attr(),
|
||||
):
|
||||
user = Blank("User")
|
||||
demo = Blank("demo-app")
|
||||
auth = Blank("auth-service")
|
||||
redis = Redis("Redis")
|
||||
rabbit = Rabbitmq("RabbitMQ")
|
||||
worker = Blank("sms-worker")
|
||||
sms = Blank("SMS provider")
|
||||
mongo = Mongodb("MongoDB")
|
||||
|
||||
user >> Edge(label="mobile") >> demo >> Edge(label="RequestOtp") >> auth
|
||||
auth >> Edge(label="store OTP hash") >> redis
|
||||
auth >> Edge(label="publish job") >> rabbit >> worker >> sms
|
||||
user >> Edge(label="code") >> demo >> Edge(label="VerifyOtp") >> auth
|
||||
auth >> Edge(label="compare hash") >> redis
|
||||
auth >> Edge(label="upsert user + session") >> mongo
|
||||
auth >> Edge(label="token pair") >> demo >> user
|
||||
|
||||
|
||||
def render_refresh_flow() -> None:
|
||||
with Diagram(
|
||||
"Refresh Token Rotation",
|
||||
filename=str(OUT / "refresh_rotation_flow"),
|
||||
show=False,
|
||||
direction="LR",
|
||||
graph_attr=graph_attr(),
|
||||
node_attr=node_attr(),
|
||||
edge_attr=edge_attr(),
|
||||
):
|
||||
client = Blank("Client")
|
||||
auth = Blank("auth-service")
|
||||
mongo = Mongodb("MongoDB")
|
||||
old = Blank("Old session\nrevoked")
|
||||
new = Blank("New session\nactive")
|
||||
|
||||
client >> Edge(label="refresh token") >> auth
|
||||
auth >> Edge(label="hash lookup") >> mongo
|
||||
mongo >> Edge(label="active session") >> auth
|
||||
auth >> old
|
||||
auth >> new
|
||||
new >> Edge(label="new token pair") >> client
|
||||
|
||||
|
||||
def render_sms_strategy() -> None:
|
||||
with Diagram(
|
||||
"SMS Provider Strategy",
|
||||
filename=str(OUT / "sms_provider_strategy"),
|
||||
show=False,
|
||||
direction="LR",
|
||||
graph_attr=graph_attr(),
|
||||
node_attr=node_attr(),
|
||||
edge_attr=edge_attr(),
|
||||
):
|
||||
worker = Blank("sms-worker")
|
||||
factory = Blank("create_sms_client")
|
||||
port = Blank("SmsClient port")
|
||||
kav = Blank("Kavenegar")
|
||||
smsir = Blank("SMS.ir")
|
||||
debug = Blank("Debug local")
|
||||
|
||||
worker >> factory >> port
|
||||
port >> kav
|
||||
port >> smsir
|
||||
port >> debug
|
||||
|
||||
|
||||
def render_production_deployment() -> None:
|
||||
with Diagram(
|
||||
"Production Deployment",
|
||||
filename=str(OUT / "production_deployment"),
|
||||
show=False,
|
||||
direction="LR",
|
||||
graph_attr=graph_attr(),
|
||||
node_attr=node_attr(),
|
||||
edge_attr=edge_attr(),
|
||||
):
|
||||
internet = Internet("Internet")
|
||||
caddy = Blank("Caddy\nHTTPS")
|
||||
demo = Blank("demo-app")
|
||||
auth = Blank("auth-service")
|
||||
private = Blank("Private Docker network")
|
||||
mongo = Mongodb("MongoDB")
|
||||
redis = Redis("Redis")
|
||||
rabbit = Rabbitmq("RabbitMQ")
|
||||
worker = Blank("sms-worker")
|
||||
|
||||
internet >> Edge(label="gapido.amiirkhl.ir") >> caddy >> demo >> auth
|
||||
auth >> private
|
||||
private >> mongo
|
||||
private >> redis
|
||||
private >> rabbit >> worker
|
||||
|
||||
|
||||
def main() -> None:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
render_service_architecture()
|
||||
render_clean_architecture()
|
||||
render_otp_flow()
|
||||
render_refresh_flow()
|
||||
render_sms_strategy()
|
||||
render_production_deployment()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user