digraph gcp_architecture { rankdir=TB node [shape=box, style=rounded, fontname="Helvetica"] edge [fontname="Helvetica", fontsize=10] labelloc="t" label="MPR - GCP Architecture (Cloud Run Jobs + GCS)" fontsize=16 fontname="Helvetica-Bold" graph [splines=ortho, nodesep=0.8, ranksep=0.8] // External subgraph cluster_external { label="External" style=dashed color=gray browser [label="Browser\nmpr.mcrn.ar", shape=ellipse] } // Nginx reverse proxy subgraph cluster_proxy { label="Reverse Proxy" style=filled fillcolor="#e8f4f8" nginx [label="nginx\nport 80"] } // Application layer subgraph cluster_apps { label="Application Layer" style=filled fillcolor="#f0f8e8" django [label="Django Admin\n/admin\nport 8701"] fastapi [label="GraphQL API\n/graphql\nport 8702"] timeline [label="Timeline UI\n/\nport 5173"] } // Data layer (still local) subgraph cluster_data { label="Data Layer" style=filled fillcolor="#f8e8f0" postgres [label="PostgreSQL\nport 5436", shape=cylinder] } // GCP layer subgraph cluster_gcp { label="Google Cloud" style=filled fillcolor="#e8f0fd" cloud_run_job [label="Cloud Run Job\nFFmpeg container\ntranscoding"] gcs [label="GCS Buckets\n(S3-compat API)", shape=folder] bucket_in [label="mpr-media-in/\ninput videos", shape=note] bucket_out [label="mpr-media-out/\ntranscoded output", shape=note] } // Connections browser -> nginx [label="HTTP"] nginx -> django [xlabel="/admin"] nginx -> fastapi [xlabel="/graphql"] nginx -> timeline [xlabel="/"] timeline -> fastapi [label="GraphQL"] django -> postgres fastapi -> postgres [label="read/write jobs"] fastapi -> cloud_run_job [label="google-cloud-run\nrun_job() + payload\nexecution_name"] cloud_run_job -> gcs [label="S3 compat (HMAC)\ndownload input\nupload output"] cloud_run_job -> fastapi [label="POST /jobs/{id}/callback\nupdate status"] fastapi -> postgres [label="callback updates\njob status"] gcs -> bucket_in [style=dotted, arrowhead=none] gcs -> bucket_out [style=dotted, arrowhead=none] }