216 lines
6.2 KiB
Python
216 lines
6.2 KiB
Python
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()
|
|
|