diff --git a/.github/workflows/export-excalidraw.yml b/.github/workflows/export-excalidraw.yml index f1b6502..7ce627e 100644 --- a/.github/workflows/export-excalidraw.yml +++ b/.github/workflows/export-excalidraw.yml @@ -1,17 +1,21 @@ -name: Export Excalidraw Diagrams +name: Export Diagrams # Testing the triggering of this workflow: on: - # Runs on any PR (any target branch) that touches .excalidraw files → validate only + # Runs on any PR (any target branch) that touches diagram source files → validate only pull_request: paths: - '**/*.excalidraw' + - '**/*.puml' + - '**/*.plantuml' - # Runs when .excalidraw files land on main (PR merged) → export + commit + # Runs when diagram source files land on main (PR merged) → export + commit push: branches: [main] paths: - '**/*.excalidraw' + - '**/*.puml' + - '**/*.plantuml' workflow_dispatch: @@ -31,41 +35,25 @@ jobs: with: node-version: '20' - - name: Install excalidraw-brute-export-cli - # Local install so npx resolves playwright from the same node_modules, - # guaranteeing the Firefox cache path matches what the CLI expects - run: npm install excalidraw-brute-export-cli + - name: Install PlantUML + run: | + sudo apt-get update -q + sudo apt-get install -y --no-install-recommends default-jre-headless plantuml + + - name: Install Excalidraw CLI + run: npm install -g @swiftlysingh/excalidraw-cli - - name: Install Playwright + Firefox - # Uses the locally installed playwright (correct version) to install Firefox - run: npx playwright install --with-deps firefox + - name: Install diagram-sync + run: npm install -g diagram-sync - # On PR → validates every .excalidraw can be exported (job fails = PR blocked) + # On PR → validates every diagram can be exported (job fails = PR blocked) # On push → same step, but followed by the commit step below - - name: Export .excalidraw files → diagrams/ - run: | - set -eo pipefail - find . -name "*.excalidraw" \ - -not -path "./.git/*" \ - -not -path "./node_modules/*" \ - | while IFS= read -r file; do - rel="${file#./}" - out="diagrams/${rel%.excalidraw}.svg" - mkdir -p "$(dirname "$out")" - echo "Exporting: $rel → $out" - npx excalidraw-brute-export-cli \ - -i "$file" \ - --format svg \ - --scale 1 \ - --background 1 \ - --embed-scene 0 \ - --dark-mode 0 \ - -o "$out" - done + - name: Export diagram files → diagrams/ + run: diagram-sync # Commits back on push to main (PR merged) or manual workflow_dispatch # Skipped entirely during PR validation runs - - name: Commit exported SVGs to main + - name: Commit exported diagrams to main if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' run: | git config user.name "github-actions[bot]" @@ -74,7 +62,7 @@ jobs: if git diff --staged --quiet; then echo "No diagram changes to commit." else - git commit -m "chore: auto-export excalidraw diagrams [skip ci]" + git commit -m "chore: auto-export diagrams [skip ci]" git pull --rebase origin main git push fi diff --git a/diagrams/docs/architecture/00-baseline/v1/URLShortenerV1.svg b/diagrams/docs/architecture/00-baseline/v1/URLShortenerV1.svg new file mode 100644 index 0000000..0e87d40 --- /dev/null +++ b/diagrams/docs/architecture/00-baseline/v1/URLShortenerV1.svg @@ -0,0 +1,84 @@ +URL Shortener v1 - High Level Design (Single Region)Dot Executable: /opt/local/bin/dotFile does not existCannot find Graphviz. You should try@startumltestdot@endumlorjava -jar plantuml.jar -testdotColorPathBlueRead Path (GET /{code})RedWrite Path (POST /shorten) \ No newline at end of file diff --git a/diagrams/docs/architecture/00-baseline/v1/url-shortener-v1-hld.svg b/diagrams/docs/architecture/00-baseline/v1/url-shortener-v1-hld.svg index ef5e321..65eb1f4 100644 --- a/diagrams/docs/architecture/00-baseline/v1/url-shortener-v1-hld.svg +++ b/diagrams/docs/architecture/00-baseline/v1/url-shortener-v1-hld.svg @@ -1,4 +1,6 @@ - - URL Shortener v1 — High Level Design (Single Region)AWS Region (Single Region)Entry LayerAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)Application TierNginx(TLS Termination + ReverseProxy + Rate Limiting)URL Shortener App(Stateless Instances)Data TierPostgreSQLPrimary DBWriteReadLookup short_codeReturn original_urlINSERT mappingConfirm WriteWriteReturn Short URLHTTP 301/302 RedirectReadUserPublic InternetResolve DNSgo.buffden.comtinyurl.buffden.com/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UILocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFrontCloudflare(DDoS AbsorptionWAF Rate LimitingDNS Proxy) \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }URL Shortener v1 — High Level Design (Single Region)AWS Region (Single Region)Entry LayerAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)Application TierNginx(TLS Termination + ReverseProxy + Rate Limiting)URL Shortener App(Stateless Instances)Data TierPostgreSQLPrimary DBWriteReadLookup short_codeReturn original_urlINSERT mappingConfirm WriteWriteReturn Short URLHTTP 301/302 RedirectReadUserPublic InternetResolve DNSgo.buffden.comtinyurl.buffden.com/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UILocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFrontCloudflare(DDoS AbsorptionWAF Rate LimitingDNS Proxy) +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }URL Shortener v1 — High Level Design (Single Region)AWS Region (Single Region)Entry LayerAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)Application TierNginx(TLS Termination + ReverseProxy + Rate Limiting)URL Shortener App(Stateless Instances)Data TierPostgreSQLPrimary DBWriteReadLookup short_codeReturn original_urlINSERT mappingConfirm WriteWriteReturn Short URLHTTP 301/302 RedirectReadUserPublic InternetResolve DNSgo.buffden.comtinyurl.buffden.com/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UILocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFrontCloudflare(DDoS AbsorptionWAF Rate LimitingDNS Proxy) +>>>>>>> main diff --git a/diagrams/docs/architecture/00-baseline/v2/URLShortenerV2.svg b/diagrams/docs/architecture/00-baseline/v2/URLShortenerV2.svg new file mode 100644 index 0000000..2a82f90 --- /dev/null +++ b/diagrams/docs/architecture/00-baseline/v2/URLShortenerV2.svg @@ -0,0 +1,102 @@ +URL Shortener v2 - High Level Design (Scale + Abuse Safety + Reliability)Dot Executable: /opt/local/bin/dotFile does not existCannot find Graphviz. You should try@startumltestdot@endumlorjava -jar plantuml.jar -testdotColorPathBlueRead Path (GET /{code})RedWrite Path (POST /shorten) \ No newline at end of file diff --git a/diagrams/docs/architecture/00-baseline/v2/url-shortener-v2-hld.svg b/diagrams/docs/architecture/00-baseline/v2/url-shortener-v2-hld.svg index 506c292..02d21cc 100644 --- a/diagrams/docs/architecture/00-baseline/v2/url-shortener-v2-hld.svg +++ b/diagrams/docs/architecture/00-baseline/v2/url-shortener-v2-hld.svg @@ -1,4 +1,6 @@ - - HTTP 301/302 RedirectOR HTTP 404Return Short URLURL Shortener v2 — High Level Design (Scale + Abuse Safety + Reliability)UserAWS Region (Single Region)Entry LayerApplication TierNginx (TLS Termination + Reverse Proxy + Rate Limiting)URL Shortener App(Stateless Instances+ Token Bucket RL)Cache LayerRedis(Cache-Aside)+ Negative CachingData TierPostgreSQLPrimary DBObservabilityMetrics(P95, P99, QPS)Structured LogsWriteWriteWriteINSERT mappingConfirm WriteReturn MappingLookup short_codeCache populate (TTL) or stores NULLWarm cacheCache hit\nor NULL (negative cache)Cache Miss LookupReadStructured LogsEmit Latency/RPSReadReadReadPublic InternetLocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)Resolve DNSgo.buffden.comtinyurl.buffden.com/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UIAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFrontCloudflare(DDoS AbsorptionWAF Rate LimitingDNS Proxy) \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAACm0AA4AAAAASxAAACldAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGigbkhYcgkAGYACBJBEICvVE1loLgQwAATYCJAOCFAQgBYMYByAbKTqzERFsHEACiDfI/i8JVA7X8nTgA6CRVByFBe0V3dTZuy/SZ+3VVD+TL+BTGWtl9mXaj09wj8SkAkoSFP8rTBkhyezw/Nx6P7dmazYGrGFUjl40NbJGCyItiAF4h4hBWYV9JWHknViHXliBUVdh1Z08/3Fvnnd/o11c/gaZgFSrXaw00ExEVyiEoVb+fk5Tm1wdIj0YqJ6ftpMzkj/oNcB/f3jQwQnJkON4fM76/6nze6nVtHdmFDC8gBA4bjDPb9cbQkCwofKP1RbVT9DiVgMSyfazhIi2zxobO7/sTWGk+aGof//jsIOHf+haG7Z7p9F4IDz6n05dJgdga/W/BwDFQ52V82XS0jFVD4jJ5dv7/otebqV2wJB1FmQ7tJxsFu544Qgk+f9f61f3gceHnK4aqodEt1Jm78qZO29N5zfSCqbTVhDTkDbEEUzfkP73WXTasAlINEKBJprKpk9otGohBFKlNmya6hVIN9dFnbEQ8uPf+/3UjPl3Zi4eJfRqYIue2D0BgABAJWBVGIqIyDMyyUE8RFMdPfA8GrIAGujCYkI6EO60N9YC4UFjeQ0QnpY01wEhFACgJlnjZK+xDhAlIlhNCA+9cDBCLxnuPTllXP4VLoLR0fgLuNvm1aN5dX5ePVyz119tsyQeJQY7Su6uHsGUxkx1TumM7d8fppv9EoEKvKDIyZGBqj4Wc4mmClKbCcQVuyaPMTsB26E3AXIkfIQnc5rbzI1tx8T20gZlICwGA31losC5K1tUYpMzcGSj6u83V4DBYRpT2F95Du50PUbqc/+2lAMQYFCh6pdcfY85vzfkvkYgAIgEhoCMhoWNg4tHSMSVGzEJKRk5D568ePPhL1CIUGEiRYmmJS5EVGgkgJGWJxKgYIRZV0F4OpQMgWGLK2YfRTGPckFAHiOEj8hLQiJUMwRENHwcdM6cMABEmCJwIuQvxhEAy5MBQFB1GQyBnhUxAOASjQAgIaOgot0t0nEA6d4yhVkojGMeL0zFw+cM8BiTfPNwSZEra0PJvrJUd4NGoVALVXm/+sorYkHh5/NSfxKmVJ4khnZOmIgTI14jGRRGoRAGRTAphk1hrhTmTmFSivIQGqmKF3qDUvlSghBKFE7JopASKQZmEFZfGGEWQBExDOpnUYBlJbHD3HUECZVCVvzHiv7/RkjejGh+Q+SHENduenpUWQKkF41lBmSxEwAOACACgjAPlM3oItgNisUKQGd5jbYmHSqOZsmgPA1dKRzC3BDSCfjQsyBnW0TpIKYAyShiwBohR4aAaJBVBoqB0HUNd2cuHMHkAWbk4A7jKLAkdArxAXT/kQKA+nmKuEiQ6M3RpNcADDF9yQZA/LY2tC7IO7BgJwCQqxqWzElgEohHDtL6J9jVsFpHADYDAAB0KScszjzBmIyjBmwpamCUmBjaylARrDJkyVekWr1W7TrMGzkfYRLP4VoJU5eo0ajt3dlMu+Gi8350zpRvnXHaKSedmC+AQBH6D9zvayR9rvxB7Lskbz7dhspZrtgePh4HQ65L7+4E7vv6/vPSfvmCIDIE3Ttz288/UaNyYymkfP/s9MK6AE4GV8dj2/RuTYmphaVRZQWuqghJePCslOT0Bs/AYI6SHxpNV3HSMvVCUYIiQS9w83IK1eTFm/OsWUlB7mSeO9er4MFrlpLZJTtP8i47gKu444LfaMsFHgB0L+gffnGYSNPgYe+e12d9vNhOQM+WtYGcVup1yqc/G8ui6CiKiSDxn79RMfwwRJdfI1m1Ejp83rzSgETJRK8/XWQDIzrFapUpvZNliAyMmPLraT7F7UZTHpupJDGrsvPmXgR78DQxsZHhvhr0FE+er7xWFqp/lJkrREr+dpIUVWuOA+VB0q+HUzoJV5SQ+7Si+lKh7OH00XrAMDLGIFD0WNFyxxZH9kA2nSbljeYG5WadcKNJhwiMzMUBT5jAS/NAtTTODGj8LiNexyuMB8GH6I7b0D0kZZhMbJ3JUl06XD3wosdweLtnwywZy/97NY1X4maTHlUdWvlCyIFGPGvkXiHYG6VvjIu08zWpzycTIfwFMxMHoESgt8XHryQYQU80r8cvLH2naBmegJpuwHpXf12TRNbkkWxS/v9SJc2/SegLY5mysLhJWeqHMNGTpEJBLYRZbevDAR2IN9UpbvPlcD+1cP9Z6U/8nho4NVN1argK6BN96cU73797YJHDh8uzcisR7P3Sy444WOckMtNvVczKiaLuIXEKzp2tybj7+DCzG+PmO/6EaRpha/Gz0Y1vPSbq1mok2rZYCH/8XTFT9NaFnbl4ha+mOD2Ijr8dq8Go943PIc1P3sdzb9xWZwvmoUm9HqVKpcrNo/Wyy1Gj1qhsyHMx1x7m+6qZmAyod5OYqyFzJER9HfGmClG9TguOT818rKIKsKIGan9GjOCchHLgSq5WQyyyrQuHZONZUvwOifZNtb7q1kE+vRrOXd2JXxh0M3oZyrGizODmcumsP+vHxDd8WuI5pspUzMKVi9Nc2lZFWsO3On7s8opVF6BwzFE9B09XDtrq4Hy8sBgljBoqJ0Yi9PbLDhxB9OX+yf5naSBWH2ieRrnL6LWksuaVXanlZQ7/ggWNN5op6nYnygcA7mbtmyS0WKdt4uuk1Hye1opIGc7OAH4AKc+W2g90mcXu/r7hb5Ch1VB9tQmbLsxtcokhAsYYRgfg9ks1kljbcwH+oKYhujekjbOl66nlMOIAbE0WZUyy7oDMWzni9Z/QrOjHsQ4zvVCW4qoJBkT5XVLbTaNHUmYtzPECONhebWWlRgzfrL0KT3cNR9njOCWXIcIC7AvnVRDQA93fKS7Ft/bJ4o1q/MJ2nEwuZnfy71VUQCvcpLmGGuJ7RsJVrqmDN7kRERp0QU78njMCgxYRK1GyVR5hLENvqakXozkOp2gQ4Iub3VSrEtppxHLaEUka0nrdqXc9RuBaiu0/2qKNgNsDWON5gV0hGt9+WxLMl5TlVie+eMFR2eEwUi1aZ6gKqLYyAqBnSW+368IoUUeepTgM6YSqafg95aspCvn3asgY9hyf0AU4AH4EVePNURkKkfZc6wBvqWEaDpWbAM3hZ5+VpmI9XKe5QH9EDwDGPA0PHzpgQloDQrKX88XOu1Ox8oQxnCKwOlfRBdBKxIFDU7FQ9cozCn+HKPwyCwszbQNw0Dwtj6B8AUzQ20rDV1BrkCRlBO2qkeN18WHBjAZvpmNt5bXd3QV/4h/5Z84PYHAuen0iVgrtozh2DRpGYuE0CDAiJzBP8aOoAdgbwY37FMW6g6rjeGAHOjMw5lOlJUrN+pA2eJv623Ja6chm18pzYRmAtzTBEFfmQTOP0enIr+xakwVxPZ4QjuRutjjglteCNDtea7x4tp3bJ4wiRoomilVEsiRdWrlZySkPaY4rHNbrDFfSsQq+7zjVqqK0hHOgyJGqkd6mqwmGi6YKWMJ/GVzQBQnvgnLOli/4D9dkDGblWtn91PxSwV1h+JUa6dIpQjOBWQ7gtgHzKcIq1lgPWIAxYEyS3PT/0CXZzh0SxTrFuk8iJe5x6C1vJ/HM2wbgS6bakD0VGcNXWewKI748HQRO+xoyXGsJzIKul6g5pCrANexjjHBY1iziPYw9W+rJElcob8htEd4GD+muMOsjxzw8E83gFkYv1CxptON9sSGov20sWPk9VXAQDpwygQ6HlazO0KCxU0oLYeRuQuC2VWPaP8q46LjQ58pemBiZjySKsZQoF4wAQymhXnR4+vMDfxFbip/dUPQc9CTfP1JvAriOi/F6eN7P9e1t2WSKhWJGBkZ0SZarmYi26BufrfeYC6Pbmzw9vrWbAADXU2cX0HFcuPllLiwOq06MK3H9LHXJRpyRXQegBcC1ivp/lexT9JtOStH9AYypDJ18RwZxKhFzb5hT6+9OEaZFCwFXhTfG9io8B/5T9Jke2osSypwdI57Lc3gPc71J14tut6EoC/VehMNVTphhUlXZfmUQzz6nyIjsa3D+Vl5dTafW8OvMY3LaUcA28ySOGOGZRHBGxvp8saCoxMOQNtaM+Huzj/eSCr+H6IsYjSXmphT7QU84eH2cRmatVlNSrq+JtgvwR0MZ2ZZHQzrNYW7rdRWJ9B09iomjjcFsdDNeVVMUhuHpRPz+1dA/fMQ8VxplZFfxvg+ag0l43nGELa4mOnz54UMvkiB+TP3tik7ENZoAm8uP/WQU64J5GlIVBJYSJRSPsug5GBzIqmk5UYo40YwYIolFM56TBdFfk7fc6HYxEYYvaHtFySHGsQp7Lafou1va4rmZIihPwwroZjkWlKrM6H5HHq1OczgG2Cqrgs+DCbrvLoCtZ+sk142k6CcT2SdL8aXJC2/h9RktxDWkDV4q/DEYTc7mUZJakuShYCwvracWSu88XVeGX6dHM5nfgSZwZ35FHRWMA/jorhpkIUMkm60Pbhzxa9DsZcHxv6LZtbi49t9XaDAgV4hERryS/qqC63nj/hj3/2OHkSpUsOVANvSLSmPdrFSC8MqaipKa0grijxB7zvxI0YVSVH2lcPiEp6Vv63iW2iEiLde9XGV6B2FjwKCWYvQPeRHXWsfRW+S4EalHRSNIWU/GD8L+RoOt8sNovrfQX9slh0K4HYubudJdM2Kmw1WDw5UDi7cnUSLc62UNGdn4fuaieA8cDKzMwD68Z9ekekjcbKnUffDiHZHPj/u50FMDkH6NJIQOYfzLvGh5OHw7jaw29qXy7bEtddDK2CgVGieR1jjZPlnfbm7QWMhjC49xeL0p4ijjaU9yQ0c4BFCUuV28mzCbXeqcI2jB0FV+C8Pz4tWCGyHek9E5/ppW9M4FV9qK3py8ezF8M9e8s+VzpmXIcYocC9bX0f7SiN+5UD3qZQ+1yHCtIM7miQtHQ5MP6PWk1P10uMpT2prgeo1HeC4EGRqQbFn6ZIMXTLTNueRRFntpXYyX5hSlPVVqRZpw/D8/pqw70BMrV1fc65uK5vui0RB3qT1vbMfJBbG6g3hZgFBE6I3saJQFAMeQYrprt/jZX7Qr6UKtPsNVA529+VEa1mRmKdZdSv/Q4zC6DYoWSTaNSp12xZ1YX4hvnqV6vc4YknAPFkR0reAckbsVXbcB4chNvoTudyTrGPGpiXUGWhifxxb8q2cH5M8KIWmYR020vS0sWq4kMP2OsPi0HiKkMQly+/DUgc4Pb1lEK8f9Qu+WIxoQPxxbrXbSY30pxc2mHDpy3omFj838SRFF3lCymd0CckSncUdei9S8uBEjcoLhFkqbnBte1G5rCGCPdWrIaRPRx4eD6w/CQ33HTBe8oTCWrUlu1Q7abboa+CTTqdGp3ZFHiu0JH1Q/rULPAd0lJKdKDQzA2rvliItRR+WBossXiKtB5vNSLKivk2yGWGmhVG5J9d1dysMhHa5wMGaaNexyW/IAfHv/42Qn2aYK3SntIKKXbcUATPzHJSVEmBqN2oA4U6ABerCpgtuW2Binn4OTk67myI8rgoxafn83bxye9ivo8DfG8QtlwSWOodr7Ui0VNHj82mYhfGYrn365vnrnzYNuXypDT1GXlMfZSyOAEcxq6DluXEnRhX49QWuN2OIAI5PKdrvepHtDPDgIrhAWN0kWE4dcokGS1T8KVsG6ra2bycqHzsT3AVy8FeWsUS7sqt7G2sYsfd0xXDxORkSDnJBUYZo26CfTNxvyMN/XMMLn86sw/94k0WtGZLlcrc4biAUMLAakfs7YZKYdnoVR74e3YLImu11CjZqVIh8YuQa1CxLdaQg5yGntJg8pH6AXvV51JG0uYMAQcwWf3Kh/IijMzeN+QkCnHM3MZMGWNTK4v+hC0SuJgdTKocXnmsXDntfHSPmyvlsfNmmcWp9jE1EtIyXcLfWKOADUpVq1IbNklHiV32VhUGNA7vtKPMcIxvBljHKIOquZYT2UIRYzSaJxZS9tAHALzbxt9RBEmvyulm2hqrLpnQH8Avo/VbIkp7ulWKTuClOz28Wosi2MLgL3VcjO2uG5yeGwuZsKoGMq0fhsff+lpuNKDocOfwIcx1WD9A16Zzu+EQka79OomNkPmlM3BLmKfBpczK6lupc/z/FpCGtDtMVhL605LwRtHPb7+NYTwVv9mbCVhZ4Lo+v2iN/iGkKY1nan77orOULMxRcX5HZyvuTyHQyXUO5kKCaDDs3JQ/P4+FybKSdGXGIHp25UAz+ddSdZ/BVjn3na3EejguZ/zRo6HMFDU7/JZm4YWvkUQTLkoL8ME79bo0zzaWj5fK1muQ1Br/BNxYkrbjp+53wpWB9h/XKWv+6qmmP/Z8QYPYfYxouF6oi/tVBSQverYeEpeJiBfoDcH98vvq/IgVyX7Zs7RtW6yH93Ba5NZjzHgeo1UIpiIWiCktv2jr+9TKDUxISBtAScO7PyPGGtn+bm0jpTJqo37OxMTUXh1dQqsv295e9lFbK0Vr7fEcrrPiADtXs/dFjwTikiX/X892KcgZKmdLd+sax6lUGOZ/bEHUtNWq1VKJiF3TFIDMeSaWguqj0ca1xC0tGKDTtejjFOJvzAWHXmk8XULjBrivASZxMhcx8k3zTj4W6XEYKOud49syGz72vDB8Bk3D8sAHhdNTRrOrjA1VArKRWsImW7+n85nl4J3uCBEnagfUEZ7FE0MMpBP7/qip/rPjMkX5O5WhskmvggcolfvYJmdQvEDmAtlByvbsIeSqoYv3na8P15vVj6GVMbhNl5Q23dmekdIIALhNGECmmwJ12agfTQyBzNSMPW1Eeu1DtI2MREZx+O58sUmREwFYErkKXMB0+YW6++VJw3Fyk+uirLcLq5itVKPARMH15JiYhntCA/cmECFihCKWwPtbsn7XRTDBfx5NQz2E1bofzwqk80gAGqrzLXfe7Ktzznc16PER4Vb9nqOJXzsKJziFfsMXDWAJYoOjfNlPLiofbSX5TDyZSiolPAd+feb5wLvlyEbi4chIUGsPSbHNdQpqXx2fAeSsqb64sVWV6RLaa+2pPq3IsBQUSAi14lWu/KZhRE91LI/Dyf2R3ha3QUpqY53QgpiFiqwv7RdP2GJMV74eiGYMe+9AL3+Itgt2pEKPX3P7tq74pOdR+hkJB++/0p4Mxk/wkZoEk3ONODgntXLjP4eS9sIrZsOfi2K9YnbSKt9F3ZMEYODRgi3CWkoMkU5Iy1HQXLiKv+yeJ+FWY6AK8Y2NYLViz5oF32yxOXkZ0bzw3lyyAepICCxalaTchRhX9JY9TlTHHEg/2/n3lVnjOvJPqI17/TT7Tq2XXY4Ko8N/YvTkF1A+gwxvh2+ZCJU0pLgBtTgC+MGFFHZjXvoQNR4HGZvY7ubOnjFI5VEHC2SK27sNVKKDGm9kWOVFIba11s8tuiOgviENj2xPo9fB5T/Pvww2ccK3UrNZdcfaQqSm10dkxSGv80zn7UWk30ztQbhWCpLOhG8MdHfKoPpTZux5Zkzo8tA7lCAoC6wsrye3cvfXRiaZDmaFxCATbiRM0YKx1ogiEIYuCI/2u0CRtp8hAX4cksN2nada76gJxTJrCuHt3F2Dx5DWbAy5RKXp+3N84LBH9L2DtLnQ0HkO3XI8q2lDA//jfvM2vrFXpDWpqImClr+/qJ0fambTZfMHUlI9pJ+xZ19oJLKdREFIULx28wqau3JpEtuqqa158KUtM4f3pKD6VYMQ8GWk7DbnlEO2nrGTaSwNG8Nn5CcsfRncYFjp/9szPcU13BR3ZxBzTH9QEJ0tWEgMM7ykLfjYzty3dxIjeRz/fl2hgZVeQj0qU2AhG/sASuhXDeK5RpM5Vebz2Qrzn27L0rVF0lBoQ+z6AkSB7jyc4CgmDa/j+brdRLIvKqDGiFoZe3lkOhPsaDjpSV7WLslrHtVwqzXrWMvNjka9S/5eRD3dCs+jHOUUCodpK54RAEO4Rr6TBr8NQiBUSBPvslIDiRacWI6ex153bgL/F6sa7pxr6yAD+Q5fdWor8TkFO/EeiBTpNgwAlGTCNpqU/47ng0j7S0HTlJn6Qgy4AJrStz514lIyzig8HTel8sGL6njYfsQY209ly22f1lbTpuWGjN17oxlEwd64g6ff2heoMOs9MYhV1Dnv/Ig7gMfQWnfbYZkZLWCxjr1CJOGdJhe90FD6cGnE4VxC3imlryIt/FNZMoFvgWWAlFf+p56ZAuYxO3Om9Il6sVVTaJcbiVgcKPJcY3dQs85p1Nho8Lq/RMBoCu7DNWpS8puMQk5//17ytj7poke4i2TjQMkFR8BcKmmzLaBW0pnfHOwCp5SjzcU3Z1Ah6zN6Tu3YtjzJZ3uZVkE0zmE0+aSachIEvg2z0mIu66ULa90Yt7lfTelAxTqkmmOVx0y/zg8q3iM4+07mXMpU7y2aa/OzaTK2KDWKYMApYSaMsq7cmrExEMYccgbSyUi+rY1jqbkpR2DGyhcj5mxNvxZTGEHKKeSMjJKAp+hGkMStIBhvkS9/fd+4ZP7ukRblGErVq95jwWFz61NVAxPgs18bfrefv+KydU1leofJBCkcFpjDw2qT/1Y2XYdOp89EYLP9lFkSo71GVBr5Y0aGB3O84oa8GxJCTd6epvsXN2DSx3ulR8Lmdb58wU0MLYmsDBC6gn3tvw4zskttZUgvjyXifnHfyOrKjrpycO7Uq399DOm0qXw91rf4hLLCMVs4tJ8ExXmYFAEYQJAv/6tZjeMN0jUSDFTMLPGXjh9wSXr3aDDFXJ1FOma6JG1SvKAy21YYlGh3pmamVN6wzLnugUOd5g+IVD3pYEE5qPvVvkNbhbaHAUoBZNmoEZ2sets0p14adAEVqKacF+uduxeiigd3EGYSgdSR8yiBeQmdVKq43o+RaMZXaT7Aqk2KrD5sh/MJE5RFxzsSmuSs7txqq8ne1tDGl+bLY/JQdKhScR9nbGK0FtI5FOMkvcIANEO8Qi6rjgrZ9oHmLh++dV2+XhZQLeF1MQAmfNcoGS6SSjiyqZ3TwhBjmC8LmDlYJ0393Mw0anBsvPdKKB3Exn7ksMIYZ4lyxI4AJGZv34Jp+R9MCLAw+crfdSr1UqJp7gbEQYhDD0DAQyQN3iP+uJGhyFz9praUxo6GTo5wTPvpLpRg4WgARgXIf7KuAF3jBIPfTxcuKgBfX72xogzw1t49oCvQt9iHgR9PtqXwp7G82286/sF6oCEZuUU/eHXALl4llbUpekzgNMl4r5JKTGD3xnufT4e5v9tfpzdslaX0JmMyCokE4D31hU15Qt1Yb5R0Ikp0wXe/SI1ASOSM4h14OKuV2r2keS4mVpRK4hX88e/uYxhXDN3PstPFeuiP0JafzcPStvNZ7Nq+cBtHFwhLHdeJCkgcB4N6EmfDMPxcxRIMHXZf7ffXHOuXAbTPQfXuR92l1vq7HaXy+EzLYQbjO1v4T7KIHbqpy3prlYqTuby7YeZ2XHcpcTl/z5MGY5zDUjWCKxVTZv6eGY9UVDj5TGS0d+XS4/L21K6YH7rvCO5pKUmE22F0RBBcNFjESPHu90V4ujrdsLKuB1DufwRLje4KeB/IgrZYJ4qaWiINE31d2WTVcaz5c8bOMHnncxXPLOShpoFwbUK2ugnZ9ljiX6cDfGJSr9t1e2d04+BxXsAl9IR861uSxP+AVO8zzcrlaHCmn7MzZk4BvwmWyHvN/bVMjdGw+yTG8en3Mum6WTLwt2TojiAzENj4sfhMF4L6uJ+Vjz8lQr/1NAAaaU6FGmfMh/G6p9GCp7AKhCB0x2AX8tFe30C9KfOP4TQFDxi0sZdJVi19iUk/ZvvypfXFJRRbSGV0+UKXJ4gogD6UGfeGbwLB3B1cWUnQ6FNu0NwvZJOf0n67n90jNLBbOhRI7wVnmM+rNMr4YcoVXf6zftl015FkYV/naO7gZwr6Ce3RrBZxnVWeXAkJcWDuZCxGuhd36pyrA3JZjesSVn/l8tuazmii/+TxtRfO4/z+uOT4iWxX4amU0l1aE7YCw+VCxmc58jX5SQW4ijsPkoZJBynJoytP+iqpLg/RXxmF1mx7pkub4Z5tBbIqcv9779ozeIMq3DuvDsnli7OcawlgVB4opOjKEylgMB3AQnSXd9nidj+D1Urg6EPn+h1EA20h8Dq9OMgRkzPTqinW5sHGuwB0AdyKEHSzrNoHHone7ESkePhoIN9MD5kJ1dFbBnbsj+RBEZP7E+3r1pIDQu6dPCl9romeVgXKAPLoeSMDZ6zo+eH2A3MJKh+Q1uH7tlXKdo13cO1eo0fj5Bg5V/imypZ2D1ZAv00IZ64yaJOxFay6gfqafuoLIxzWMN9gchC1wkkknrtiLOC6RHGWeAHy46meQsOs7OLcb7ZiKKeiWiCgvu+3fyVWsgV/fmLolAtrvbehR1v3+vkv42TA2ra6uouKfq3yabZ+PDyV5sJjyJrFGhDYtVAnqGX7GPZ3/LspeVi+n6iVb+frCKoohdYmW7hlej5byCajfvVw6DIeTtK3ptqMAeYhIXf25VfBJgSjuYtWzzoDNryfffyJiVCQGt5Ce/xZnf/HpanryGBkPBEA4e/cfn0ppDiZ6DFZPLPQQWF5PaIosPJz2++Eqf5UgxdPQqS5LQRQFqW8Kyf77/HrC/WhF8cOSNSP+8AVoLeFHWxr/Ym3b8Of7LSyhN3HqOQQ8tpJ5pT6ov87c6Q2UxwLeG2s7k/xAMBWBKiuTBpeeay110C4bFl7ttg8MZkdRkG0NFycCi4Zew9WI1/jyRdhZTgpP4Y62zctmMm8kZXC/Iy3jYp0w6aHFKJjCr16l/yM9bzk/iS/Ocl9GT0fcA83bsNp2Sh3zG03roG9J1Bcwb0NxyC9JGCLGhwcPZe+vRaiEgU8rMKpsfKR9Km4enu3D/oXFn3GGuJoueYE6LRE5LEXun/Dc3yzp3P7tUXb94dUJIYE4mY2rO2al0pvnFH5t85Mmk46Z7Gd8zc0E+bVKY8qyUcfsdbqrr7+YVefymmZJUXIpTTE0il19GXF75++BTz5CjsC5q+/Og94nQRA3WGEJwbisAO1mB56b3vMVTYgik5IVzkqgPbZ6xCAFpJ+ABvLIkFqMQjj70JNVldQiwK6g1cvdEuabEP0vkorG5/RlK4Mz8R1BX52S2npoK2V6/X8J/neUTs5I7AptJ6eXBwCPztLxiRmxKgvOz0smGlDglmpKD8LjBtffO0Xc5Ehayu6Zu6xsVUs6jHjsvJRnVqQyy3D9mY00vtWRXOO2n4OUNXM73QZUjYJw8+GZRt2oOl6XvnLMrh7tA5s4YiNwL1fAEKX3OIXubhhvtcMfOhZ+/ZmG1geMP/i05Ld+SBrUGRIY20pKIlsvfWueyX19ZHesNnnNd9NwtSr6glYgR1aIFFMKdRMBpZZvCc2eu1wiSSviso4ah11IETHeTEgtZaAq8PCwwalGkhRyaXfU6KdwMMEoABZt9wGj/71mNSWqIirJ+XnGEeVsu1nGK3ImtG5FdPXLgot6Q7F5Nny0uW3/H5zfwlEtUXvVu5DvpfzuqqgmxVtGo1yn8XilAUJp/cAAcz0LyYB79g4qNqXWDxWMQ+HgeEy5An8cRSky59anBPJ7EwnHP3izK9oLCWcYG0H/i0VtXMXlndwmbaU9dqekNmiNrhyKYWcxFzj9sBzRXF4KdkE0Quv6uPHOBO3PWFV+i1B+C/VUzwC6XW6XGpdqAX3ZSmXglgpvenGy2n1oI/pqKKc61up786tJ8I103Dbd6lJRJvQ5BMBGHCwKv+xinFv2P1HiyiO0E11CkFjKRlwcckGNwMl6tyJNBWy2gi82fugfNc6YRyJSzQphy3qedJ3KHF2CImUzzpR0mrLRCiFE8uo02ZwrMAduL5Zvg55E86mBeUeiG94+zVYdecsKb2DFpD2+OrrBNEnOgrOOu65XU2SfTP9aN+nznwqWkwDRDG3Nj8sbghL+H4TtxWZQmOBCEJQQXLQF7YbKAVVHJ0uYr91j4Upwo0YaHprL9khpGDMfcrZSVrlgiQmLon4hPzfCmh0P6iWuyzFmyaY1k24yBmgk3cwYrBTkBCf8QV4E7qFf1N9b3aPUMr+o9Ws81cbbeuKlg01dxM+eJXpbXB4jjPTN5VrWJot1SCUnT/Xzczxxhpg8aiB7eFIg888lEDdjQWF8/nfk108NM3kUEFUIoNZ9kWPDkHNtIIwy3uAVY/qPO/6cuVjqdGrIRJcE9EsKMyLKhtWGrvol24VotpvQ9ileUeKfN8+hzQL9smG7gYONSKj9YSoO2beHvWJrXXcTBSMJlFg51t3neYjJb0QcaebSlEVE7Hl6KoSNWhAcbgNbIvqZQB/3pun1cQxF9Nxza6rspUZch1IaaHJdd8Jm/5svTMFiCPA3ca2i1cFM/xVKe7Gt5f+Pqp6//3ZvxNDtcV/iIwGyQzJ8POOpLeYrLBxSUDiXHkqk/eZPkOu64/UAfwc6mTqorD1Xxtvt5IPUVisDpce2lHV+ArpLXJsY4v8DkpCYnjwr/Lw8JeG7fq/3EOLt6rhlt4eyZvHQ3RVPcEZ5obxDPB9NUnBCpXfzbgnLnVDi2o91dvH2iJzR496AzZKRk0HC/V2xpYJcZEfvBckWkf+oFh+cpkusxW4XI5qn+8SsCghZvo0v8vZVqNIZmfvaBlQPuEZinDp9TFwjso7P5rl1ACkmA3P4SBCF6Qc2iRYc2PX/8QeqctWWj8Hre1V/S8DXjYnQywYnwQK1tM6QbC5aG39XuZJZJ9AFanAAsMSPJ62rQ6vju5AqdekXO0/LMB8O+vNmZRLRhmNH7RXRaiQbZ0pyqi9CvXDWPe43BTBUbWWEQAnsZdlTkxWiMXJ5FzWwXO64Gv/MRvp1M6V7Rn6P7g0GGeWf69BnOt/3BvSbxSoWEWhix/MuYocs3TRESQek1l7xabQnZwu/0ZL7uNOPeT5Biuo/54py1D25kfYhIrkQN0cvS5jqLpIlzYhtC/oEjFfXOY7FfBYVHkmJlQjJIffAo/GZxl4LCir/36Ok/6dl0qG09feJNw4oTnE9WeeIet+sZ63+79vlPzNSfrSOrX1J+P68RcfzzlOkB9i2O85cW/33MgKTEjrz55X9pjtfexI9n/c2TaYnHEBjyWvIbyL4QWIenuocyvOaG+oX7dhGMv+qLgqvC4xQ+4d6p5WhHyI9NDS6LuOfuOwnoWQKw7sLfQyv80q5EVQiufzAwJhQ23bz9poVL9DEdeIhHzXTKbOfXVp/ULDeg35/6RtEU0nCFq+hRSWfr13dL7rp0w4FLjjPYoZpsB/M+ifAFra55a8SpLApSSmsl/0vmLZ3e9v3aBbGBXy+PvyUgDu6jY7tk446lTHB/377SCISSFf8p4YIT6xNmjxzUM/8V5XBVZm3/yFP+oZH5ROwfv8jDx+ZDNHHJdicu17rgy9thlCGw53JnP9o5332bGwm5e5eABZHidPV0mjRLS3NxTPoCt3k27KeKQFJWLZmMraFj067IDxdQ8ljV5Nd3iTQkoelXMQ6UkyNnTfsGoVqKrnWm7WETQT6h5re+h9Fu3Gig8dsyO572or44zk4ZeLD/QvgN5qcbkt+s0qwlwznPQ4NpaupPrT8zctTxynmD5fUbRrxlgf4315xineo+AAFo/gifrl+fLnKKfiVayG8AAPCw3csAAACPtv75t4+ftAP9A+0CgAgW8P6vONKxjEH/Aa5KwVnGxsFYAwA051NDPEMDrlFyKwgoaz12segSCM0a0fUFXo7hpZggVrLMIE4L/2wH4E+UUZ3fUAEtp0BQVlKNmh+fIe9IuMV9z9n/46SNSz5i5QhtA4AsD4AtdUhNDijTwK9hiU4iAD8iR0MZb6H1hjgFVBFwqae9TZ53woV6gREuXw9BSFa33DsdRCRbQATCa4PAuPOMChR54qUBWpI5hSWo3siJmKB2Ei11m124rRuXWvVfFT0GGmV0A+BFGADQdUoDNiXIhYBa0ji81uUxEI5vxsDoxsYgvPSMQck5xmBiyREnQKxnm1IlalWrMEudZr5SlavUolaJRpnKNWpSzVpTLJCfgCIbxWzn29WrSsIuCcYgRU8mQScPp5I+E3GptJUN0pglpcpCpZPKTNRrtl67gdUuVoWEng5UaTZIwAtDKjrM7cWiWObOl5jNj1C7ErCtWJw1nWG5knJsJSxzxRGwuI+FAQA=); }HTTP 301/302 RedirectOR HTTP 404Return Short URLURL Shortener v2 — High Level Design (Scale + Abuse Safety + Reliability)UserAWS Region (Single Region)Entry LayerApplication TierNginx (TLS Termination + Reverse Proxy + Rate Limiting)URL Shortener App(Stateless Instances+ Token Bucket RL)Cache LayerRedis(Cache-Aside)+ Negative CachingData TierPostgreSQLPrimary DBObservabilityMetrics(P95, P99, QPS)Structured LogsWriteWriteWriteINSERT mappingConfirm WriteReturn MappingLookup short_codeCache populate (TTL) or stores NULLWarm cacheCache hit\nor NULL (negative cache)Cache Miss LookupReadStructured LogsEmit Latency/RPSReadReadReadPublic InternetLocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)Resolve DNSgo.buffden.comtinyurl.buffden.com/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UIAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFrontCloudflare(DDoS AbsorptionWAF Rate LimitingDNS Proxy) +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }HTTP 301/302 RedirectOR HTTP 404Return Short URLURL Shortener v2 — High Level Design (Scale + Abuse Safety + Reliability)UserAWS Region (Single Region)Entry LayerApplication TierNginx (TLS Termination + Reverse Proxy + Rate Limiting)URL Shortener App(Stateless Instances+ Token Bucket RL)Cache LayerRedis(Cache-Aside)+ Negative CachingData TierPostgreSQLPrimary DBObservabilityMetrics(P95, P99, QPS)Structured LogsWriteWriteWriteINSERT mappingConfirm WriteReturn MappingLookup short_codeCache populate (TTL) or stores NULLWarm cacheCache hit\nor NULL (negative cache)Cache Miss LookupReadStructured LogsEmit Latency/RPSReadReadReadPublic InternetLocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)Resolve DNSgo.buffden.comtinyurl.buffden.com/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UIAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFrontCloudflare(DDoS AbsorptionWAF Rate LimitingDNS Proxy) +>>>>>>> main diff --git a/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg b/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg index 97ffab9..434f717 100644 --- a/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg +++ b/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg @@ -1,4 +1,6 @@ - - EventBridge SchedulerStop — 11 PM dailycron(0 4 * * ? *)EventBridge SchedulerStart — 7 AM Mon–Fricron(0 12 ? * MON-FRI *)Lambda FunctionPython / boto3stop_instances / start_instancesstop_db_instance /start_db_instanceIAM RoleLeast-privilegeScoped to specificinstance ARNsEC2 Instanceems-prod-appt2.microEC2 Instancetinyurl-prodt3.microRDS PostgreSQLtinyurl-proddb.t4g.microCloudWatch LogsFull executionhistory30-day retentionCloudWatch AlarmLambda errors > 05-minute windowSNS TopicAlert channelEmail / Slack webhookEmail AlertScheduler failurenotificationLambda error metricOn any resultOn Lambda error(two independentpaths)SQS Dead Letter QueueCaptures failedinvocations4-day retentionFailed event payload Trigger & ExecutionObservability & Alerting \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Comic Shanns; src: url(data:font/woff2;base64,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); }EventBridge SchedulerStop — 11 PM dailycron(0 4 * * ? *)EventBridge SchedulerStart — 7 AM Mon–Fricron(0 12 ? * MON-FRI *)Lambda FunctionPython / boto3stop_instances / start_instancesstop_db_instance /start_db_instanceIAM RoleLeast-privilegeScoped to specificinstance ARNsEC2 Instanceems-prod-appt2.microEC2 Instancetinyurl-prodt3.microRDS PostgreSQLtinyurl-proddb.t4g.microCloudWatch LogsFull executionhistory30-day retentionCloudWatch AlarmLambda errors > 05-minute windowSNS TopicAlert channelEmail / Slack webhookEmail AlertScheduler failurenotificationLambda error metricOn any resultOn Lambda error(two independentpaths)SQS Dead Letter QueueCaptures failedinvocations4-day retentionFailed event payload Trigger & ExecutionObservability & Alerting +======= + @font-face { font-family: Comic Shanns; src: url(data:font/woff2;base64,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); }EventBridge SchedulerStop — 11 PM dailycron(0 4 * * ? *)EventBridge SchedulerStart — 7 AM Mon–Fricron(0 12 ? * MON-FRI *)Lambda FunctionPython / boto3stop_instances / start_instancesstop_db_instance /start_db_instanceIAM RoleLeast-privilegeScoped to specificinstance ARNsEC2 Instanceems-prod-appt2.microEC2 Instancetinyurl-prodt3.microRDS PostgreSQLtinyurl-proddb.t4g.microCloudWatch LogsFull executionhistory30-day retentionCloudWatch AlarmLambda errors > 05-minute windowSNS TopicAlert channelEmail / Slack webhookEmail AlertScheduler failurenotificationLambda error metricOn any resultOn Lambda error(two independentpaths)SQS Dead Letter QueueCaptures failedinvocations4-day retentionFailed event payload Trigger & ExecutionObservability & Alerting +>>>>>>> main diff --git a/diagrams/docs/hld/database/v1/db-design.svg b/diagrams/docs/hld/database/v1/db-design.svg index f20b3fb..49b8e2c 100644 --- a/diagrams/docs/hld/database/v1/db-design.svg +++ b/diagrams/docs/hld/database/v1/db-design.svg @@ -1,4 +1,2 @@ - - URL Shortener — Database Design v1 (PostgreSQL)Schemaurl_mappingsid BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULLWITH (fillfactor = 90) → 10% page space reserved for HOTupdatesTOAST: original_url > ~2KB stored in TOAST table (avg 100chars is safe)Sequence cache = 100 → reduces contention at high create QPSIndex Strategypk_url_mappings · B-tree · PRIMARY KEYColumn: id | Implicit from PRIMARY KEY constraintUsed for Base62 short code generationuq_short_code · B-tree · UNIQUE (full table)Column: short_code | Implicit from UNIQUE constraintPrimary redirect lookup index in v1No separate redirect index in v1uq_short_code is sufficient at projected scaleAdd a covering hot-path index only in v2No url_hash index in v1`url_hash` is introduced in v2Repeated URLs still create distinct short codesNo cleanup index in v1Expired links are filtered in application logicBatch cleanup starts in v2 if neededConstraints (DB-enforced)uq_short_code → short_code UNIQUE across ALL rowschk_original_url_length → length(original_url) <= 2048chk_short_code_format → short_code ~ '^[0-9a-zA-Z_-]{4,32}$'Connection Pool (PgBouncer)AppPgBouncer(transaction mode)PostgreSQL(Primary)max_client_conn=1000 | pool_size=20–40 | pg max_connections=100 \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }URL Shortener — Database Design v1 (PostgreSQL)Schemaurl_mappingsid BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULLWITH (fillfactor = 90) → 10% page space reserved for HOTupdatesTOAST: original_url > ~2KB stored in TOAST table (avg 100chars is safe)Sequence cache = 100 → reduces contention at high create QPSIndex Strategypk_url_mappings · B-tree · PRIMARY KEYColumn: id | Implicit from PRIMARY KEY constraintUsed for Base62 short code generationuq_short_code · B-tree · UNIQUE (full table)Column: short_code | Implicit from UNIQUE constraintPrimary redirect lookup index in v1No separate redirect index in v1uq_short_code is sufficient at projected scaleAdd a covering hot-path index only in v2No url_hash index in v1`url_hash` is introduced in v2Repeated URLs still create distinct short codesNo cleanup index in v1Expired links are filtered in application logicBatch cleanup starts in v2 if neededConstraints (DB-enforced)uq_short_code → short_code UNIQUE across ALL rowschk_original_url_length → length(original_url) <= 2048chk_short_code_format → short_code ~ '^[0-9a-zA-Z_-]{4,32}$'Connection Pool (PgBouncer)AppPgBouncer(transaction mode)PostgreSQL(Primary)max_client_conn=1000 | pool_size=20–40 | pg max_connections=100 \ No newline at end of file diff --git a/diagrams/docs/hld/database/v1/er-db.svg b/diagrams/docs/hld/database/v1/er-db.svg index 3a63d63..f7cb52a 100644 --- a/diagrams/docs/hld/database/v1/er-db.svg +++ b/diagrams/docs/hld/database/v1/er-db.svg @@ -1,4 +1,2 @@ - - URL_MAPPINGS id BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULLIndexes:- PK(id)- UNIQUE(short_code) \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }URL_MAPPINGS id BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULLIndexes:- PK(id)- UNIQUE(short_code) \ No newline at end of file diff --git a/diagrams/docs/hld/database/v2/db-design.svg b/diagrams/docs/hld/database/v2/db-design.svg index 3d2e52f..e84305b 100644 --- a/diagrams/docs/hld/database/v2/db-design.svg +++ b/diagrams/docs/hld/database/v2/db-design.svg @@ -1,4 +1,2 @@ - - URL Shortener — Database Design v2 (PostgreSQL)Schemaurl_mappingsid BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)url_hash CHAR(64) NOT NULL──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULL──────────────────────────────────────────is_deleted BOOLEAN NOT NULL DEFAULT falsedeleted_at TIMESTAMPTZ NULLcreated_ip INET NULLuser_agent TEXT NULLWITH (fillfactor = 90) → 10% page space reserved for HOTupdatesTOAST: original_url > ~2KB stored in TOAST table (avg 100chars is safe)Sequence cache = 100 → reduces contention at high create QPSIndex Strategypk_url_mappings · B-tree · PRIMARY KEYColumn: id | Implicit from PRIMARY KEY constraintUsed for Base62 short code generationuq_short_code · B-tree · UNIQUE (full table)Column: short_code | Implicit from UNIQUE constraintCovers ALL rows — deleted codes permanently reserved (namespacereservation)idx_short_code_active · PARTIAL · COVERING ★ HOT PATHshort_code INCLUDE (original_url, expires_at) WHERE is_deleted= FALSEIndex-only scan on redirect path — no heap fetch neededidx_url_hash · B-tree · NON-UNIQUEColumn: url_hash | Full-table indexSpeeds lookup and analysis while allowing duplicate URLsidx_expires_at · B-tree · PARTIALColumn: expires_at | WHERE expires_at IS NOT NULLCleanup job scan only — not on hot pathConstraints (DB-enforced)uq_short_code → short_code UNIQUE across ALL rows(incl. deleted)chk_original_url_length → length(original_url) <= 2048chk_short_code_format → short_code ~ '^[0-9a-zA-Z_-]{4,32}$'chk_deleted_consistency → deleted_at IS SET iff is_deleted =TRUEConnection Pool (PgBouncer)AppPgBouncer(transaction mode)PostgreSQL(Primary)max_client_conn=1000 | pool_size=20–40 | pg max_connections=100 \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }URL Shortener — Database Design v2 (PostgreSQL)Schemaurl_mappingsid BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)url_hash CHAR(64) NOT NULL──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULL──────────────────────────────────────────is_deleted BOOLEAN NOT NULL DEFAULT falsedeleted_at TIMESTAMPTZ NULLcreated_ip INET NULLuser_agent TEXT NULLWITH (fillfactor = 90) → 10% page space reserved for HOTupdatesTOAST: original_url > ~2KB stored in TOAST table (avg 100chars is safe)Sequence cache = 100 → reduces contention at high create QPSIndex Strategypk_url_mappings · B-tree · PRIMARY KEYColumn: id | Implicit from PRIMARY KEY constraintUsed for Base62 short code generationuq_short_code · B-tree · UNIQUE (full table)Column: short_code | Implicit from UNIQUE constraintCovers ALL rows — deleted codes permanently reserved (namespacereservation)idx_short_code_active · PARTIAL · COVERING ★ HOT PATHshort_code INCLUDE (original_url, expires_at) WHERE is_deleted= FALSEIndex-only scan on redirect path — no heap fetch neededidx_url_hash · B-tree · NON-UNIQUEColumn: url_hash | Full-table indexSpeeds lookup and analysis while allowing duplicate URLsidx_expires_at · B-tree · PARTIALColumn: expires_at | WHERE expires_at IS NOT NULLCleanup job scan only — not on hot pathConstraints (DB-enforced)uq_short_code → short_code UNIQUE across ALL rows(incl. deleted)chk_original_url_length → length(original_url) <= 2048chk_short_code_format → short_code ~ '^[0-9a-zA-Z_-]{4,32}$'chk_deleted_consistency → deleted_at IS SET iff is_deleted =TRUEConnection Pool (PgBouncer)AppPgBouncer(transaction mode)PostgreSQL(Primary)max_client_conn=1000 | pool_size=20–40 | pg max_connections=100 \ No newline at end of file diff --git a/diagrams/docs/hld/database/v2/er-db.svg b/diagrams/docs/hld/database/v2/er-db.svg index a18d8ac..fe2bc58 100644 --- a/diagrams/docs/hld/database/v2/er-db.svg +++ b/diagrams/docs/hld/database/v2/er-db.svg @@ -1,4 +1,2 @@ - - URL_MAPPINGS (v2)id BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)url_hash CHAR(64) NOT NULL──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULL──────────────────────────────────────────is_deleted BOOLEAN NOT NULL DEFAULT falsedeleted_at TIMESTAMPTZ NULLcreated_ip INET NULLuser_agent TEXT NULLIndexes:- PK(id)- UNIQUE(short_code)- INDEX(url_hash)- INDEX(expires_at) \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }URL_MAPPINGS (v2)id BIGSERIAL PK · NOT NULLshort_code VARCHAR(32) NOT NULLoriginal_url TEXT NOT NULL (≤ 2048 chars)url_hash CHAR(64) NOT NULL──────────────────────────────────────────created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()expires_at TIMESTAMPTZ NULL──────────────────────────────────────────is_deleted BOOLEAN NOT NULL DEFAULT falsedeleted_at TIMESTAMPTZ NULLcreated_ip INET NULLuser_agent TEXT NULLIndexes:- PK(id)- UNIQUE(short_code)- INDEX(url_hash)- INDEX(expires_at) \ No newline at end of file diff --git a/diagrams/docs/lld/c4-deployment.svg b/diagrams/docs/lld/c4-deployment.svg index 59bc3cb..84dce42 100644 --- a/diagrams/docs/lld/c4-deployment.svg +++ b/diagrams/docs/lld/c4-deployment.svg @@ -1,4 +1,6 @@ - - C4 Deployment Diagram — TinyURL (Docker Compose)Maps containers to infrastructure nodes — shows ports, networks, volumes, health checks, and secrets managementInternet(End Users)<<deployment node>> Docker Host (Linux VM / EC2)docker-compose.yml (bridge network: tinyurl-net)<<container>> nginxImage: nginx:1.25-alpinePorts: 80:80, 443:443 (host-mapped)Volumes: ./nginx/nginx.conf → /etc/nginx/nginx.conf ./certs/ → /etc/nginx/certs (TLS)Health check: curl -f http://localhost/actuator/health<<container>> app (Java 21 + Spring Boot 3)Image: tinyurl-app:latest(Gradle multi-stage → eclipse-temurin:21-jre-alpine)Port: 8080 (internal only — not host-mapped)Env: BASE_URL, LOG_LEVELSecrets: /tinyurl/prod/* via AWS SSM Parameter Store (IAM Role)Depends on: pgbouncer (healthy), redis (healthy) (v2)Health check: GET http://localhost:8080/actuator/health<<container>> prometheusImage: prom/prometheus:latestPort: 9090:9090Volumes: ./prometheus.yml → /etc/prometheus/Scrape target: app:8080/metricsRetention: 15d<<container>> pgbouncerImage: edoburu/pgbouncer:latestPort: 6432 (internal only)Mode: transaction pooling | max_client_conn=100 | pool_size=20Depends on: postgres (healthy)<<container>> redis (v2 only)Image: redis:7-alpinePort: 6379 (internal only)Volumes: redis-data:/dataHealth check: redis-cli ping<<container>> postgresImage: postgres:16-alpinePort: 5432 (internal only — exposed 5433:5432 for dev)Volumes: pg-data:/var/lib/postgresql/data ./migrations/ → /docker-entrypoint-initdb.d/Env: POSTGRES_DB=tinyurl, POSTGRES_USER, POSTGRES_PASSWORDHealth check: pg_isready -U tinyurl<<container>> flyway (run-once)Image: flyway/flyway:10-alpineVolumes: ./migrations/ → /flyway/sqlCommand: -url jdbc:postgresql://postgres:5432/tinyurl migrateDepends on: postgres (healthy)Restart: on-failureNamed volumes: pg-data (PostgreSQL WAL + data), redis-data (AOF persistence v2). Network: tinyurl-net (bridge, all containers)proxy :443proxy_pass :8080HikariCP → :6432Lettuce :6379 (v2)TCP :5432scrape /metricsDDL :5432AWS Managed Services<<AWS managed service>>SSM Parameter Store (SecureString)Path: /tinyurl/prod/*KMS-encrypted secrets: spring.datasource.password spring.redis.passwordGetParametersByPath (IAMRole)SPA Delivery<<AWS managed service>>CloudFront Distribution (SPA)tinyurl.buffden.comDefault -> S3 origin403/404 -> /index.html (200)API Entry<<AWS managed service>>AWS ALBgo.buffden.comHTTP -> HTTPS redirectForwards HTTPS to Nginx :443Static Hosting<<AWS managed service>>S3 Bucket (static-assets)Angular dist/ assetsOAC-only accessCI sync + CDN invalidationHTTPS —go.buffden.comHTTPS — tinyurl.buffden.comOAC fetchS3 BucketDeploy Flow (SPA)CI: ng build -> s3 sync static-assetsThen invalidate CloudFront paths /*Frontend deploy stays independent of backend/Redis \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Deployment Diagram — TinyURL (Docker Compose)Maps containers to infrastructure nodes — shows ports, networks, volumes, health checks, and secrets managementInternet(End Users)<<deployment node>> Docker Host (Linux VM / EC2)docker-compose.yml (bridge network: tinyurl-net)<<container>> nginxImage: nginx:1.25-alpinePorts: 80:80, 443:443 (host-mapped)Volumes: ./nginx/nginx.conf → /etc/nginx/nginx.conf ./certs/ → /etc/nginx/certs (TLS)Health check: curl -f http://localhost/actuator/health<<container>> app (Java 21 + Spring Boot 3)Image: tinyurl-app:latest(Gradle multi-stage → eclipse-temurin:21-jre-alpine)Port: 8080 (internal only — not host-mapped)Env: BASE_URL, LOG_LEVELSecrets: /tinyurl/prod/* via AWS SSM Parameter Store (IAM Role)Depends on: pgbouncer (healthy), redis (healthy) (v2)Health check: GET http://localhost:8080/actuator/health<<container>> prometheusImage: prom/prometheus:latestPort: 9090:9090Volumes: ./prometheus.yml → /etc/prometheus/Scrape target: app:8080/metricsRetention: 15d<<container>> pgbouncerImage: edoburu/pgbouncer:latestPort: 6432 (internal only)Mode: transaction pooling | max_client_conn=100 | pool_size=20Depends on: postgres (healthy)<<container>> redis (v2 only)Image: redis:7-alpinePort: 6379 (internal only)Volumes: redis-data:/dataHealth check: redis-cli ping<<container>> postgresImage: postgres:16-alpinePort: 5432 (internal only — exposed 5433:5432 for dev)Volumes: pg-data:/var/lib/postgresql/data ./migrations/ → /docker-entrypoint-initdb.d/Env: POSTGRES_DB=tinyurl, POSTGRES_USER, POSTGRES_PASSWORDHealth check: pg_isready -U tinyurl<<container>> flyway (run-once)Image: flyway/flyway:10-alpineVolumes: ./migrations/ → /flyway/sqlCommand: -url jdbc:postgresql://postgres:5432/tinyurl migrateDepends on: postgres (healthy)Restart: on-failureNamed volumes: pg-data (PostgreSQL WAL + data), redis-data (AOF persistence v2). Network: tinyurl-net (bridge, all containers)proxy :443proxy_pass :8080HikariCP → :6432Lettuce :6379 (v2)TCP :5432scrape /metricsDDL :5432AWS Managed Services<<AWS managed service>>SSM Parameter Store (SecureString)Path: /tinyurl/prod/*KMS-encrypted secrets: spring.datasource.password spring.redis.passwordGetParametersByPath (IAMRole)SPA Delivery<<AWS managed service>>CloudFront Distribution (SPA)tinyurl.buffden.comDefault -> S3 origin403/404 -> /index.html (200)API Entry<<AWS managed service>>AWS ALBgo.buffden.comHTTP -> HTTPS redirectForwards HTTPS to Nginx :443Static Hosting<<AWS managed service>>S3 Bucket (static-assets)Angular dist/ assetsOAC-only accessCI sync + CDN invalidationHTTPS —go.buffden.comHTTPS — tinyurl.buffden.comOAC fetchS3 BucketDeploy Flow (SPA)CI: ng build -> s3 sync static-assetsThen invalidate CloudFront paths /*Frontend deploy stays independent of backend/Redis +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Deployment Diagram — TinyURL (Docker Compose)Maps containers to infrastructure nodes — shows ports, networks, volumes, health checks, and secrets managementInternet(End Users)<<deployment node>> Docker Host (Linux VM / EC2)docker-compose.yml (bridge network: tinyurl-net)<<container>> nginxImage: nginx:1.25-alpinePorts: 80:80, 443:443 (host-mapped)Volumes: ./nginx/nginx.conf → /etc/nginx/nginx.conf ./certs/ → /etc/nginx/certs (TLS)Health check: curl -f http://localhost/actuator/health<<container>> app (Java 21 + Spring Boot 3)Image: tinyurl-app:latest(Gradle multi-stage → eclipse-temurin:21-jre-alpine)Port: 8080 (internal only — not host-mapped)Env: BASE_URL, LOG_LEVELSecrets: /tinyurl/prod/* via AWS SSM Parameter Store (IAM Role)Depends on: pgbouncer (healthy), redis (healthy) (v2)Health check: GET http://localhost:8080/actuator/health<<container>> prometheusImage: prom/prometheus:latestPort: 9090:9090Volumes: ./prometheus.yml → /etc/prometheus/Scrape target: app:8080/metricsRetention: 15d<<container>> pgbouncerImage: edoburu/pgbouncer:latestPort: 6432 (internal only)Mode: transaction pooling | max_client_conn=100 | pool_size=20Depends on: postgres (healthy)<<container>> redis (v2 only)Image: redis:7-alpinePort: 6379 (internal only)Volumes: redis-data:/dataHealth check: redis-cli ping<<container>> postgresImage: postgres:16-alpinePort: 5432 (internal only — exposed 5433:5432 for dev)Volumes: pg-data:/var/lib/postgresql/data ./migrations/ → /docker-entrypoint-initdb.d/Env: POSTGRES_DB=tinyurl, POSTGRES_USER, POSTGRES_PASSWORDHealth check: pg_isready -U tinyurl<<container>> flyway (run-once)Image: flyway/flyway:10-alpineVolumes: ./migrations/ → /flyway/sqlCommand: -url jdbc:postgresql://postgres:5432/tinyurl migrateDepends on: postgres (healthy)Restart: on-failureNamed volumes: pg-data (PostgreSQL WAL + data), redis-data (AOF persistence v2). Network: tinyurl-net (bridge, all containers)proxy :443proxy_pass :8080HikariCP → :6432Lettuce :6379 (v2)TCP :5432scrape /metricsDDL :5432AWS Managed Services<<AWS managed service>>SSM Parameter Store (SecureString)Path: /tinyurl/prod/*KMS-encrypted secrets: spring.datasource.password spring.redis.passwordGetParametersByPath (IAMRole)SPA Delivery<<AWS managed service>>CloudFront Distribution (SPA)tinyurl.buffden.comDefault -> S3 origin403/404 -> /index.html (200)API Entry<<AWS managed service>>AWS ALBgo.buffden.comHTTP -> HTTPS redirectForwards HTTPS to Nginx :443Static Hosting<<AWS managed service>>S3 Bucket (static-assets)Angular dist/ assetsOAC-only accessCI sync + CDN invalidationHTTPS —go.buffden.comHTTPS — tinyurl.buffden.comOAC fetchS3 BucketDeploy Flow (SPA)CI: ng build -> s3 sync static-assetsThen invalidate CloudFront paths /*Frontend deploy stays independent of backend/Redis +>>>>>>> main diff --git a/diagrams/docs/lld/c4-level1-system-context.svg b/diagrams/docs/lld/c4-level1-system-context.svg index 93481d0..a900d61 100644 --- a/diagrams/docs/lld/c4-level1-system-context.svg +++ b/diagrams/docs/lld/c4-level1-system-context.svg @@ -1,4 +1,6 @@ - - C4 Level 1 — System Context DiagramTinyURL — Shows the system in its environment with external actorsEnd User[Person]Creates short URLs andaccesses redirects via browserTinyURL System[Software System]Accepts long URLs, generatesunique short codes, and redirectsusers to original URLs withlow latency (<100ms P95)CloudFront CDN[External System]S3 Bucket[External System]HTTPS requestsOrigin fetch(SPA assets)API calls + redirect requests301 Redirect \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Level 1 — System Context DiagramTinyURL — Shows the system in its environment with external actorsEnd User[Person]Creates short URLs andaccesses redirects via browserTinyURL System[Software System]Accepts long URLs, generatesunique short codes, and redirectsusers to original URLs withlow latency (<100ms P95)CloudFront CDN[External System]S3 Bucket[External System]HTTPS requestsOrigin fetch(SPA assets)API calls + redirect requests301 Redirect +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Level 1 — System Context DiagramTinyURL — Shows the system in its environment with external actorsEnd User[Person]Creates short URLs andaccesses redirects via browserTinyURL System[Software System]Accepts long URLs, generatesunique short codes, and redirectsusers to original URLs withlow latency (<100ms P95)CloudFront CDN[External System]S3 Bucket[External System]HTTPS requestsOrigin fetch(SPA assets)API calls + redirect requests301 Redirect +>>>>>>> main diff --git a/diagrams/docs/lld/c4-level2-container.svg b/diagrams/docs/lld/c4-level2-container.svg index 9676cdb..fb87606 100644 --- a/diagrams/docs/lld/c4-level2-container.svg +++ b/diagrams/docs/lld/c4-level2-container.svg @@ -1,4 +1,6 @@ - - C4 Level 2 — Container Diagram (v2)TinyURL — Shows the containers (deployable units) within the system boundaryHTTP 301/302 RedirectOR HTTP 404Return Short URLUserAWS Region (Single Region)Entry LayerAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)Application TierNginx(TLS Termination + Reverse Proxy)URL Shortener App(Stateless Instances+ Token Bucket RL)Cache LayerRedis(Cache-Aside)+ Negative CachingData TierPostgreSQLPrimary DBObservabilityMetrics(P95, P99, QPS)Structured LogsWriteWriteWriteINSERT mappingConfirm WriteReturn MappingLookup short_codeCache populate (TTL) or stores NULLWarm cacheCache hit\nor NULL (negative cache)Cache Miss LookupReadStructured LogsEmit Latency/RPSReadReadReadPublic InternetResolve DNS/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UILocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFront \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAACowAA4AAAAATAAAACnaAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGigbkhwcgkAGYACBHBEICvcw2AQLgQ4AATYCJAOCGAQgBYMYByAb1TojA8HGASCg+CbJ/vpAuyznw1YjPCgTw6LYohm/EB/bHb213DGI0P5pO2osNEFF/R1aRkgyOzw/t97PrdmajVrDyFEyetHUWNAhiLQgBuKJmJRV2FdW34l16IUnZl6FVXfwzz9Hv9/3vIkL6Bm0AsnHmQNJcBSLNLL++Pdzmtrk6hDpwUD1/LSdnJH8QS8AKCb3xolSEbQz4VaKGWaYwDgeD/t++6zTjrO2+3L6Jc3c7Lc3wxAmSwR2vNe/9z3cu69V16ougSMHWpIpbAjwDwxBS/o/VS2gxbR/ZhAYHAiCVLJ3T7R8lkPelBg2VLpYbVFdklqqBUiAFBWRSIqSnkWJUnaWQ94B5kJR3/8/52vz/li+wfH0yf0Jy0LNkzHpLd68EqVxU4Xx57iedEAoVIVsMsrvOP0KKB3G9VRtU3MTZnOAynz1J9ycJSHElJ11s2lqjSOcbK6LOmMh5Me/y3DL2s3ihfgjVdqtAAQAKgEZGIoIflicSQbiL5HqGaDI4yFT0UD39lNdQHjW2VwPhFfNlXVAeF/a2gCEUAAAR9Lu7qK5ARAxIji0hjdL4WCEXil4HVAwjf9aNypBXz4ZDGxlKwsra11ZT/s86LR2CU6SJLAnX7z7aiQFZdUl6GO2a3ycE+djXgWFokDJ2SOj1Yli6CJIAetEApGJTDQZCY0CMJxzBogFrEiyzndjw65a7SAJNaAWswJTwEAE5jnuUIwTHIODAHDh6ydWgKfjnFCKXcZz9InajRHfBo5rmF8ACMCTgunnLX2PvsKfDL7iqw+IBIaAjIaFjYOLR8ibD18iYhJSMv4CBAoSLEy4KNEmiRMvQSJd6EJEkU0SF6l7JgEKkQBryQe/zyFD4FnywXxE75BBeSEggxHCF+QRT4SqTkBEw8dB54mcBwZAEt4ReBEqyGkIgO7ZACDQuxGGQOcQI4bjvBoAJGQUVLS1OToOgN3RqACLCOOwyAHIQyOfJwAEGTMEZ+CRkDPrICO+Xqz7QQuk4IoKXF+4CXvEgsxVzJEAxGB0ZUiS6LaEiTgz4jKSQWEUCmFQBJNi2BTmQ2F+FCahKH++kCoFYhAoVQgliKJEMZQsASmBYmAGkZoCizASUUQSg35FFEgpBZHIbHk+CZU8Jf+fokL/ORCSIy1a1SgF/oVwe9/fVJcCyVNzhQGpbCvAAQBEgA8uAk3TumRniSQqdJSTae3pUBraLoOSNfThQBSyO6TbEzrn4wxzKD2EFYBZ8oaTYjI1Z1BVH6sJFANJPqLWLlkoMfkzj5HVO4ATgS6jP7NgUgEwpQCgriISLv6tP2RorhmAIbawHACkDItDhyK8h9W7AUTXcGBOB6NEWw7S/g+w/qrTvgVgIwAAesETEKWfwEzGoQOGFNXHfBUK6Y5HFS2WlVu2AsVqNerUZeaWMxEBIgFiaaWimkrVaX5XObfDbrUYdFqNWqXcUAjkoP/qcYqJLOYKZ7K/Y/yd5wC14J6gbHd4SmHIXuBneFJa3hVatwf4XSkjSAqCjmsUFRqWplH6suQSfliOq6hBxXFzdTy2Te/bkuYoKo+vKPRRxopjIqdmZriaAsIjOQp+dAJdyXFm6YXeqfJUvcA30CNak59izsi3ZqdH+JF5ftzAwsmoWUJml24/zbt8XXo9+0b2FdO4tthzgGBswb5653CRjsPnwwdO22rjnVaCwhLUOqKv63Uq+2+1PV4uKYqJoEl//saMpoMAzd9HslpI6LMR92o6JEolauuDRdbRon2Mk0LN51nWkLEWU7mTFlLca8dirKeCx0b97JP7CIfwQWJeYguP5CCUDPlo5c3lqPpHyH7ZEF+vpIwE1ZppQm2c0vVgQOfBBHLx1XYd20JHOTh9MutZmC3LgkCCpxKM90tqpzQW9XyTykJzgUqzTqTRpBOEmC0bByzhAq02QtXKLDum8ReC8A6fYN7ydmIsLpK/TWrU75dsNksP6GTy0cuOhcOLwxINGW3vf7eoRUWaTfqiKRMjHw0ZmFWWc0JAsLGaeTIrm7V7pLWVSjj3Vyy7VgPIU+h9C7/7VIIT9L7mo/jq7gsJxuk81VQHhffg/RQQqImRqNP6f2nfsmcJe6TtUeGGNKlIEqEeqyJ4nc5znTBnS3a7Q8f8E9zHPTnubqa3H14Ct++GciDUZNWsQQfsnrp77erlF48W5nniHDOXEsHGuzA3ZVA455GePpc5B30J/G1SKnjrfApi/+l29i4mzS3+hGka4cLCt9ogvvAeGb9WI9GKIZz74xflTIJPV3aH4wk5GeB0K9p93pOD1fCZyyAtzL/iQ6fXkjeK7mFJqxWlfV+ffbFVK3OmUWvMLIgDPtybFEaym7gMyddJzjfZMoU61mcRfoIBagutON7X857MMsG+HMijpFqFtwBqgS0ESpOxynVXFmRxyUhmjUSbOh51T7YK6Ul3+Ctn8dWxn7XjkM8kyI7P7lXelGftmGhNU1+GhaJOmYkTq8t82pJVxsJvbfzU5a2BDVR8iWSP8HLisY1bh73RnSjh6CixpyVc7X3SoR14XOk/efgsjfnkU83LKP8lduYEpXjKFvpSVuM/C6fxQjNtfL8vOSC4zhZvQMxYy6wQrRqpZVnGSkBqdHAA9ApATM71nuqy8PXNTU0vkInRxrbcoUUbNheZwAg9y7Iwm0AXXyUjgVuODfQHHAQY24C23/TXRGIwZUDWFJQhJpnfIVtGjvDOn+pJWcexDgtdqYFwNd4ALb9PWnTT6ImU2QI2WZFMXFyLyn4OOh7MPQn217WSsqdxCsYpwgqKFymg59FH3T8r78YXHqjAJxBfPY1T1kXnrPC9Onq0Lk2aK4z2+MZ4KZAWtsNociYipuMD9N3QXAWHBTJG3rCtnmCehuFe1Y5FwxIM0GqKV0/HqAXErDVi0U94ynRpq1WqdzVGiJspLv6xKBYRskMAN54XuBOi8dvf9iqWYyriC0l8dLWkGuMwkgssnKGsoNHNCIEdMmqvJ1zzzbyYpCUI6JziIHhJ5WSApPC9JlsW9sgl5ghKILYDDefNUT3nPO3pawufyGGGtqUHAZbBzzoSlnw2mKU5RxWyAwQzlqHHjx3UJ90xMaIRn/168sWST7zPHAwQYjyU2QbaK8ESHKoSQcNTScS/Y/T4ZVYW6mkLiIFlGdiB2krDBb3NDP1KtQZJ0k7QnRqVfMS/qVjQ6h/SnrJ/+263YvvujntgvgKHm9GdOZ+otM/EsWvc0BKDB56HGTHHMsDvRh3Qxio8uaUoVktokOlAMbDZsbaV9nepada7tC0rVK+Ivp4X9bqR58NpIDanKAvhif7YzHW0DemZdWM+qsqxhDKFYHGOAS85c2BnW3RnY2/2cuu4VsWMBH2JJCBZyhwbuV7PqXRpjusS1OsWrqc9mVzXNKtVCTIAb5EEpmBGWou2oixcNdGzLP7LYIMtAnyXpFmutmIfT0EMblW2sofprXMVD7imZ2pkQJcIFRfYYEB2C7iQIjSqNdc9y8PsWZbgBZn/k0+ytWUSxaqJVU0iKdhgMBw/teLJbzuA05qqQ/ZxpE1uCV/nWtw9G4Q4bSts4WZXYeH0qGKaXYoebnIbc4TDaaVAfoA5LIGanJMZKgtiWVBWYIQMJsRqI7YcvB4leQmzo2qmtHvxJl/gVK9o20b+QFYMlAmvuUCfwX7OZk2nsdZIE2nVXoTAbsnOpD9CXC650ud6znWO9Hclqp7wkio6AY5sQrXoZP/tI38V240vLSS4TKFg3R35HMg2bcynw8N2flQ6FVkm2y5nZKxFx8FyG51Rigr9HLhj2TC9eMwyswt3CQKyHXljlE3ThvNfcm5IYDphmdFrPZ8s4iz4JtAcEFNqC/9fJQ8UfVCNVMtegTMha/ZekHGcTvjw5yzpoy+WCPUCCwiYrJweLq7KMeF/SOu0hz1bxzeG57V4OM/zAyz1Jj0ql7uFBDlybOPIdijhhla1xOnNcTz0EUVaZPchhYsCngwGxuRe9j1yWlHkluUIDjnC64nggMzUrXJFUUW6AW0favFLfYTvk4i/x6hAjnoC2zbFerB9Bt4Ip5HebDZR+NJIUS0b6I+OMnIqRl26zHP+5A5GPH2lRjEpadEZis7GkzhA0g323zwvX3X9hx+xYwvTLPiScV2wDFzCC3cjXOBBos/G33nYMcOJjqlemVENKRsdguPx9/xGq9YVyyCg6HkG8grzJ1l2TEwmZNUM9KWanoQD7Au2ipIe5Ui0p+BCObosJ1zTnMYrcgkw92TamBOKtr2k7BzqKUIqg8AAbQljD9/0jFU9L0aTy3ziqf3StKzYCLFg7K6BSnaoZcT2i0lZpxLRpPz4WJfRZ/j0uhLiJtO2nKv8MRi1zpWz4PUFL0Si7Z07Sm9XvvOdFmq6Tl9MZH4HisL9kX15WnQOYqv35SBHWUOyodb4zAu6Bp1hjkz3VzN0GJcP/3vTdDrky4ZEWjyRvpfJdpxeu4dH/ymFkaxkKkFH1PQX9Tbq9XoanBhLXsEBrTP+EWOPRqYSHEk1cKUasT7LgFuy8ZCJQzy0Kns8KfQKYYk9C5opZvkI72DWivaCcdyKtKKyE4TG++OnYb3gsUu8Wh0Zjo6m7qhENtyL+dlU6b4FYbLPZIeTiUcLP5tHiXAjzDkyxPhhtpN9SSYma9oC6/C9HfrVbVLOdiuDR9eueCHfbedDRw4A3BpJiNmG2bsRNefg8LM0MnrcFtTFWQn2wQBjza80ziOl/WrvVVlpLtCYi7HBuzg83VF6lPSe/1aq6wiHQBJkL8vXCbe5o/4hQlox+VK5cLzFb1XczvG9jG6y21aCz1cCYTP6ZP7Fav5Jrnjn42+5lqOSU8SWNzuL8mMt/nwFdsLcc13DuAGQ0mZIGY66umzRtaQy+GEyKQPanWO3ZkQ5NgRZ0yHZOLhkwYouGnOufzfLoV33xPvKJMh4z3n9SFGm++f3KPM7amKk6rIHbR1pvsm9hueOh3L3NE5t88kzhDcUKAmIuZvtrOYIyGSkJ720mr/1V+16OtpsrTPZQX9jZJqhKcjuxmqZsq9CBtOLJMGYEXVjpk4HfDlWt+Ozb5p6vW5ZCEP5AlR0quIcYf4iOl0ElBHd5hfyX5BsXov3da5boIb5Cs/Bf+3QmPxZQSWvWmBFtZwlrOZsoULbM27Ifj1AKPSCoGEXPnCw+erTAtnI8ag4vFCS6RCtjgOW+5mZupuWZlOUefHZJOY+0fOPVBR5Q6HLpQioJuYby+I2T2/xMzHCvLJwl4UNxowwarUUBirNVNMQ/RhhGz8fnH4anqhnejrqTbi2Z8zzB6Wg1WI9ckmmmsZ8bVmMJArFGDR+2qDQBOsTI/o1Aw5oamtpUsbMvKY6Eiy+QEwOsj/3Y061akTdxaiEgpoTZH2dSrdLJxPi9SylMLqqJYRAbunhY28t1TMz9KxyhjC6UVQcUN99WkHOw6bRqHVIaQJYoBCOZbJbAvdw+hOZKek2Jel4hgcj6bcvcu/wrD+FPrs7i6/WFBMchvLwFzxX0fjp7eNi+PuTQvrL0eTVJ4/dkaBgKIFParPcF6dAq7ChsGPaYQsJjtS1BAPVYkM8zJagSj1p0vshb215JwgNaZIsJgK5ToMkk/+oGL1ZXpu3noPHZt91gWx8EuULQxXvVG8xtRgy9+a1Mh6nImIB+sRWVGwW6E+Wn7T9SWGkcITfzk+CwvfmiaEfScF4w5y7qVH2DAGkfoOxLpby/AZMw1efUn8KfJ+YRo1LQQeLoU7tiETLDS6K6Juz0qWyhVparjEVNkbZsxAOV/zqwP0EkWwrx6OEgv50lFzPUQlqZPxwrAxFNxON0AAnhhwqBT4fOm3MVI7r6/Vuk8bpo2HRGTkZISFuIcwiQJCtVkvg1tLz42h5WX1BN8RBqs3UuV7NNva8MMlIuuu0HW/S+BO0HMfBOworq5NH3C+/k2tS9+gokUwZ3pE+IoeU3dV8mZQvhGum0SG3vkOyEMIh+SWOngwd+ya79UBmG2IJQlwgH2YcEO6yHgduG4LKGNcXmSWmKtnwAOgd2P9Uya7o71Vinr4WJgydlqOZFa4NEOKRTLmNUnioS9BtrjsWOM4VqLEPZHS9Q7ZADPrsPJmmLQeZJ+bz0/hMxFsUjsoHCmyQknB1HXHcORo6TA+O3w7LfgBzA5TiMMxYxgpBC4ftNr44H3w6SoZzOQptmJ4ujvwcNxnCjC0dQ5adyBHy4fjoiFymtipl/niF4/K1rInJeJ7m3kh1d/dQWZ9OTJnAW80YyoGbyfx+jt9jbluOsvnttGjZX7OGSjvwjgkfRD08CYx8gCBob9NznPquX6NC9+HAMKBiHdWCICye+DhznQev75xflNVGaPzlTfd6p2ol67cIe+jdIbfwTrExZWWzFeSq1uvsB+BhBm0P8R+/v/b9GnTEts/f9C76gvD4d5fj5jzpkQmNr5JUW5MAOiTFypPjb63xVgJWALwgj0sTIy94wK5pfjNjszXP94bdSDYxCk4GRpUdbYz/HqqQZax0uoivXvcpOWje/NDzFZ9VInLm6L8t6+aUPqa79YtlxWs3OYXZm3zCkb5SK5czi3oSkUSOJcvQWlx/NMm4iKSjlRi2vdrDOJ36PWPFuU8WUOeAqWOEVzibCJkXQrINkx/t9Boh6Jhr/bKashZ+ZfgImIwHRwUAb6iFpt6OLPQx1IvLBStIOT5hX+x1VYO3eLiYHW6fXQH7Fw/s5qCfXfXBL/ScG5KtylqpjfDe99HbK2XlMprVNxw7hLVRcgN7CLsoDhF+86zhu4t6keRTpjYCs/OGOnqyXF1AxQXCBEKVJDKALnEjvTQyRzPStNnx2Id6F5m0b1/3QhwvkMqzYmEqAlchi5kPnzI3X30lv2gulk/4KCpwurmG1U48AkwfX0uISECCoCBubioW7o1S2P5qvwDa2ZZELhLAaWSwWzZDBTE1n2gAA9ReZa75zIdvecHnvNlDeFyyaXPZmdxHVd1DvBL/gfMGsEjevWGKhJcCdZb/ohjOoBQXnwEh2/d/7Vn4xXx0Y9EgLDSAxV/n+kQzLc3Ph3dRMt9eXyDPDoxrMy2sP63Ou6SKIALc+3Wa9Z50cmFCH4XMzw+e1hWzSkdhalpdRkhOxBxy+4Tp9A1xZtDc3esiyw64Cv1SLoGdyhGhJCzs/Ir9y7rVCwlFBNedD2eAJ5P9J2SARn3hLH8KHlS9xBAaNLeF2Lbp8Ls5ScHOfc7y9xXDGDlaNUS4R8hEMyjIOWsnCpYQV/yTzf1ykukQvGxgSx9YtuijdskvT71Gtq+/MFQghXiQHIoUObSaqOPysNLm+MtZotiHB38/97oyd2ZpwrHAf28/1aqnNWCDK/J92b94RDQMoMMY45ulQyZOOS0Vbs4EITBiRMuyanmPyhA5npzVV9aTI3mSybEKVOeL1bofN1sJpUbHwriRampzvZdNdse7wYKUCWy7kkIfvUgs+X340XOOlbqZmkeuPVYTrzZ6lo1Smv80TnvcXksMytIbhWCxNOJG5MRjPjWYUp+8bVMG54e2gTwhAUBzJlUU9O1c/PjU4gjN8eTUQmzEg+reUz7QAkMQxMCRsDdoCzbS4i8qxjNYvhLnda76kIxTIbCu3L2DsXH0GsyAlygUvIVBQTgvHPwtZm8v9zQcQrZej63YVMqc+G8reOrmK/Qmp9ObmCXt+Oqp0fa2YxpfMHbFneChfYd6BsLlFGoaisJFe28wqSs3p5Mtupq6N/MEDifnzwDJkUwr5s9AK2nYLf8ED20jw0YSlLWuTtknvlvW4+SCsp/Dctx+Dh8wwS7pgqb7PCRBuroocHRbRfT7kT0HCrw8yC3kiwvzbAx3DfmYZLGNQMR/XATXQzjvNcq0mcqvtx8q0Jx4/sEHqq0RAcLCgIh0SJYYwM4GgkjawT9brdRxb/IKN7TM0MdbzaFQn+ARxyoqdjB2Stn2K0XZr9tGXm4IMerfcQqgHmhq4x7OcUCo9ZD64hAElwlX02HW4Jn5cogCffqLKjKNacWILvaaC9vwV3ijSNdy40CFKhRkh74T6++qchvXAz3QaVINOMGIacRtjanfnkzgkRZ3IqfpoxRkCTChDRV+3KtkhEV8OHhWH4JFwve1KZA9opnWmcc2+72qd+GGudYCrS9DwdSxjqlda480GnSYncYomjMU8I8sgsvQV3E6p5kRCWmtgLFG7c2pQLpsb+bAww7VWYcgeT7X1JYf9z65lUSxwLfAcihhXsD4EZ17A7c2f0iXp/WubhHhcDsDhZ+IjW8bZvvPPJ8BnxTW6JkMAF05YKxxLSocZ5IL/vr3tTFvVbo9StvgPQwQB74MYdNN7k5BR2Z3iiewip8Rj/ZWXN0H77E3OfbvxzFm2/u8arIJJvOJp82ksxCQpvLt/vti73lRtrzVi/oU9L5Mt8lhkmqOFt8yP7x8q+TcY61fBXOxh2ya6e+ujeSqpAiWyU3AMsNt2eW9+Q3eBMOkE5A2CcpDdWxrg01Bcp4Am6icCXe8FV+SSMgl6omEXHdx5GNMY1CQDjHM49zfdx4YPr2rV7hJPmnFylUXseSYsc3h8r1TURN/q5534L9KQnVjlTIYKfI2eOwh7xnVn/mhetJtxyz0Rhs/w0vukB6ZY0GvljZpYD87zqhow7F0xOVx9bek6TsGlnqMl1zI3dI9JRO0MTancvBC6qkPNvzkNrGt3UEQXd7v4bmN35Udf/3sviM7XPZe2kVT+VK4Z/X3yWkVpBJ2CQme4iM1ECiCSYLwv34toTfd7hXLkRIm4Wc3XvQdwevLncCtLB17xvRJ0yj7vPNBW/2kNGOZeoqjuq59smVXQqYMbzL8wiFvSYcJrSfezw8c3Ck0lBWiFo3TwIxeyG2wSnQxZ0AxWo5pwUGZ74lGSNW3wE0YciGuIYNoNplZq7DaiAHvwJ6sHpJdjpRYddh02fcmMoeIay61JNfIuD1YTZCnvYMhKUjKCaPkQg54FGFvZbwW1DcT6SSz2BcyQLQjLKKOC96Fes9ELPyw/Fq7LKZCwPt8DELg7KleUAadZPRSZrBb94lAriBmxmC1wBWyk3nU6NFk+ZlONJBb6cwDaVHEqKDS2alcwMhq3LsheMQVfmngoaf1vuNatXzfU5yNCCMQhp6BQAaoR/RnI1GDo/B5ez2NCQ2djv6MELCw9HYzB1MhKoxb5rcCBIK3DFIvfW8lcdCChv5tVcnyoju4tvCgomAiXgz9vjKEwt5Cs23/K+elstCbTcpt+EMmhvLw7E2ORY6ZgOlVNYuE1IWCby3jT76z2d+oP2OXrg4hZLUCghLpNvCNxQ0tORLtpLA4iOSR5WVPGJGYwDHxBeR6RAl3zorOkfQUqZPINRTo2cNfP6EQrpn7voFnyORJPyHNn/ll56/Ec3iNPIA2D44wthoPkzQQ2NtDqIvZyEMxczxIDfGa9ffCZM88uAMmhg3PDzrrp7fVWe1v5kJmWxS3ldpfyn2cym1XzFzVWqLQnc9jW0+ycpK4S4mL/nyUuBTmmhEsjdgunbn4aOLa4qHHCuP4sV+Xyi5KWjJ74YVXeMfzSArMJt0P4qHC4WJGmn9vkMvHUtbREwgV8rqHc3neuN4QqoFCiculghSJpaowLcThZ8uhK4wXSx918MMvehnGg7LTBzqFqkZFHbT906w9acHc9clpirCt1Z3doy9AFbswBNKR82xeS1N/gZ0BRzvV6mgh7aB7nRtfh09hl8n6g0xF3P0pINv09skFz4qpOtmSSM/UeD4Q0fDklEEY7O1jtTCfaF6daefPAxRgykzYzZQNhW1BtY+ipQ8BVVgGk73AX4u9t4dG6E+d/AkgqOjluJuulO/YM+ah/Tu0JgQXV9UQrTG1+yrkuTxB7CFXxCcBbp6lK7K2hLK9TK51vkXYwZln/2S9sI8/t1Qxm0plCG+F/+4wlun1UFl0zXf6DQelYwFF8UW/XaD7AjwwonenRvCpuza7EhjynTFgBkS8Fn33lxq3vSXV9J4tPvf/SvFlNVd06X/aiPyzsJmBd4OjtCz2s7gcKqkB3QZjKdEiEZv7Avm8lNxG3A2bj0MGCcejxa39F1WWRh6sSsHsUjs2R5oX4jZH3/L2+GL/uz/6Iii3ddgcPKc3yW5ONKxmQZCoqhtjKI2VQAC3wOmSHZ/lSxmhjxQrw6HPXio0kI30x8BKpzHcPcW/K8Hjxvo9TXYV1IUcebio2wyah97rTi0v69VQsIFeuACys2tUu2ZEHUzzJuOn1qb4tQxEJ6fPK3qlTZhSCfYK9JGVUDrGRi+E0gtUdgMjA5rV5DvRI+V6JPi8L1OudPILCBqsch6yqZGBNZIt0CMbGoSbxH5EaDWjcaSRuo3KxjRPNNgfhGxwiUgmrdmMeM6WHGecA6G49+l0T++T7LwSfOEURN6oQJSTIhf+O/q6PZyre3uPRCDb/Wy98obfv1NKfhumTmroqKq6r+zfIp1p48MZgWwmPIqsUqJNC5QCuju0JDigv23Jq+oFdP2+dv5BsIIiT1pkZfvE1KKVvMJa36DXZQZD1LvX9PpogT3KJCr5zCr/RGVyHs5esnHQk7Xou6+lzOpUVTv56W/J5re/npVlrKLBUCSEg8f/8bm01mhiwGDV6FJ/gcXLpLZIU2JITy691meXZRq6+hSl6eh8ldqWuuSf774D7C+XRR4eeeutf9EErQa8eGvzX+wN2/7c+8sryClqv8CgRxdRz3WmN1aEWT2hikQQUkftZPK/j4RUmIIifjj+QnN5Dt2CYSmVvlvgGEYcNcPGUFLcWAL8CrZeqsVfpNHOYwpwGn+i9VQsmXwzw80NhAKNR4MrJIMWjwwCs3aN+vuC/KX8dL4k33MJPQP9ALCgsp2mM7KoT3laf32TS1fIvAHNqLQgHYQoGxo5nLO/Ea0VAjKlwqy0hZIKIOdM3OXF/YfGnXyXuZLs/RTzmO/tsRixd8t+87Ws8Qu1S9SNC1amRoXnZjHGpp8fczHNL//YECzLIJ003Xd/x8wDBbRRYebzcsad97ipob+HV+z/m2ZMXDWeLB8bRS6/ir28/PfBZwFRx2Fd/NYXER/SoH11WHMUwbOjEGxnhV+4vesdnplIIGXMnZ5OfWQLSEIISCcBV/Eq0lmMIjjhyFOH18ooYJdT62R+aTJNaVi2t5fG5vtnNIEz5R9BQ4OH2XpmLGpr40Ex/012cOJy7ghsJrkqI4F/1llZ1eSkzFTP5+WjTZnJCjQzF+FxI+vvX6DvKEudy54zdkffLJdwHvfaeZkZqE5pkOb9MQ1reaUl+8DOnyKXNnE530VUj4C95MG383uU07ksfff0Hbnc2VI/xkDcfqiOJ8hc6Bm1v2W42Q53bZ/72RsWVh++9+G/pWdlm5xQuyouupmWTrRc/sY6g/3mysqkIPCC66XnblLwBe1EjKj2nk0h3E0DnHa2KSZvylqNIL2UzzpuGHojQcDtHlJaEQvNhJdOCo+fH2chR+fUvEmPMQOMoqJg0w4Z7f89rzNJDPHx1s+qjjHvyEQ6TrEfsX09sqNXBrzU6zL8aunTRBVr7wb/Bp5xiYqrQc18D/1vx5V1UdYaGvU6hd8nAQhKC4tUwSksJB/m0T8q2ZhaN1iyBwITFzHhbPRFMqHUlNfoiOTxxBaOX85G75xAKIZlbAL9px6/8xGRt/eUspl2x3JNX8R0aScUy8xmzvf8fiug+XgR7IQcgtDnd8W5H7lTpl4JIUrCIDhMORns8LpVblysVf2yncrEqxHc9PZ0q/3MXPDXWGJJntXn9Jfjs4x03W243b+0QhJ4BIKJOFwYfj3YODb/f6QugEXsJPhEI/WQibxUdUiGwRl4rTxfCm22gDls/th9aKYnjUCmnBfClIvBnTxvP3g2hpjJtBDaUcJyK4QYRbu30KaPgelga4lsA/wijkcdzC+OXvfhSY7yyCtOTAs70fno5u5ltlFiLpR90metgjrttGuiYXVhyAy4nBTuNHQw12esj0z9exi+m5xNaYHDwaTUyOJFYD9MFrCqqlnaAsUuC1+CE8XamGgHOzS9acRwws9KWe6DpSEkhv6p6MzkIHoMpN93TZo1VXpbI94yeaBun6/ZzcpETkHCP0Q14C4aWPu19QNaOzmwdpc2YFWyrS95LNL0ZfKUmd6vKhtVopSALJ5VbaJoN1VDEldosN+5Y0zXoIHoH0SByFOe7qsD65obG29nfcX0N5N3EEGVEHIUkAyzn15gG2mE4TZfleU/6qx/GpIktx1R61ES3CsmTI6rGFo9acXXCV5cq8Xk2iV/TUnx2DiTPh30S4fpBg62V0LlR0po0JZN/G2L83uKORhJuMTCoe40z1xAZssXgmYebXFs/LZH44l0xIrwYAPQGtnX5OqIP3227tVQvL8djm4P2ZCmcwu10aayy174lF8LZE4MFiPPwvcb2i1cxzws8+mBtg83rs578+9+97OcGF3RYwKzSTxrFuCox/Pllw/JKV0KjiVLf/omyWdv2Z2H+lh2DnVUXX2khrc11B9prJKH396rHd/2OZhT+sbE2MsvNHmoyRm7hf9XRqle2PdrPzFOq51hRts4u0bH72VqSrpi0uxNolngNhUnxGkX/Da70tMBJ3V1+om27uuNjtw56AkZKW4aHvqaLQmfY0ZEobBMHhfm+LEs4AzJ54StytsWoP7hSwKClmyhi8OCFGo0kWZ+/pGVC+4TmGeOXlAXCuy7p/F95gAJJAYy+ysQgegFdfPnH9nw4slHiWf2pvXC6/lXf3Hiq/aK0NFUD8JDtbbD4DIWLo65p93OrBDrVVqcAL6hIyLKFd2jmpXzpkbGQ+tgXEFjBkmY2d2Edqar0GemCVseqM9O0TZXPVYgVr04BQ9i+ZwLrVwX7twX+xO00f2sVDOwy9wUZZPokkwXH3GneTniaoAlcSRjTR1am9KTUaVTL8t9Vpn1cDiENy2LiDYNM/o+T3CWapBNrQ5drH75ipncawymQ2RkTYIQONCwrSo/UWPk8ixqZqeo7Grk+2Dhu9HMnmX9ubo/GGSYd26h3u15JwzcbxEtl4upRbFLv0gcunzTFCsWlF/zyq/XlpIt/O4A5ptuMx70FCmhB5svTV/98Eb2x9iMatSQsMQ5w9NbkjY9qSnqHzhO3ui5J+nLiJg4UpJUSAaOh49jbpbMkVNYKfcfP/vHlUOHOtbS971tWnaK88mKANz/TiNj7W/XPvuJ6fjZOrLyFeX3ixpvTli+wqWybyq7OL7g7xMGJDNp5O0v/0tyA/enTZwPM486004gMBS46DeQ82N4A+7wi2YEzogOjQmZQzD+qi+OrIlJlgfHBDkq0a6oH1qavOZzLzzwENCzBWDNj38PLQt1XomvElz/aGDsk9t0Mw+a5i7SJ3bhUf51tzOneb6xBjuyfYH+oOOtvCWq6QpX3quUTNOv7RHf8+qBwxedZLCjNTllzAckwue0htbNsWeyKUg5rZ38L5m3+PaW83ZXxAZ+vfz6LQFx8GAd2ysHL1vMBA8OHCiPRSjZKfMIP3qwPmH2ykAj81/vXK7SrO0fqeUfGllPRWEp8/2DbcFEE5ds9+ByrbO/uDOJMgR2Xe7uR7tn+W3xJSH37hGwCFKy7ixJB7chl/ZIXuJQAMLeVBVOyoYW0fZko3vohzg/nKr0Ca2xr+4FaL84/L+KcaCSHMdrOTAI1Yf+Yuc6HrUQZLSQ/9a3ZHcPbgQDzd9U2HHnv+pLe9mZAw/3vxSeGf10owpalZrVZDj3x6FBp5r6U/vPjFx1imLmYGXjupEgaXjYzVVnlnerFwLwQp+P8Z/IuPRij4RXRAry20oBAB49jwEAAB5/vl0+8S70j2UXACK4guPO5+CKZcz8P8JSPtSWaVHGOAMA9CV4hgREAz4pfAcCilmLPSxd4WirJMzneJ3Aq4QgK2mTiWoT1lYA/kFZSvMXVEDrjIiWUy6qE19iUGLf/K5q+3+cOng10W7HaBcASHvIVgPSIhfUbaELVkJpAPyKnIaioOh5S1QhZQKvefb/XUFBxUR7yYgb4pGoVpY8OB3ElkOVIGbWCc8vICWUjAZCA7QOCimDR6yIeSs3kWC28+5qLnbgLn29ZsV/p9POpIUmN+AIE4OW4xrQmyAPAlqSlnn1LjdCOL5uhNHtaUQE6m1EyZQ1YpLIEOdqA2DUoVyperWqTNWgVQiHStXa1CvVLEulZi1qUe1FwoVSZWI8s53p1KiG+EsSiRGKAYlEnD2GEvsSRPnYtjRwMksn5Ur5b8pI1CvcMY/NR7FaDcOTWE6pYgTVC6Milpm7i6pihTtTappQRu2Bx66i6qxlDiuVVGI7Y4UrgoB1TTgM); }C4 Level 2 — Container Diagram (v2)TinyURL — Shows the containers (deployable units) within the system boundaryHTTP 301/302 RedirectOR HTTP 404Return Short URLUserAWS Region (Single Region)Entry LayerAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)Application TierNginx(TLS Termination + Reverse Proxy)URL Shortener App(Stateless Instances+ Token Bucket RL)Cache LayerRedis(Cache-Aside)+ Negative CachingData TierPostgreSQLPrimary DBObservabilityMetrics(P95, P99, QPS)Structured LogsWriteWriteWriteINSERT mappingConfirm WriteReturn MappingLookup short_codeCache populate (TTL) or stores NULLWarm cacheCache hit\nor NULL (negative cache)Cache Miss LookupReadStructured LogsEmit Latency/RPSReadReadReadPublic InternetResolve DNS/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UILocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFront +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Level 2 — Container Diagram (v2)TinyURL — Shows the containers (deployable units) within the system boundaryHTTP 301/302 RedirectOR HTTP 404Return Short URLUserAWS Region (Single Region)Entry LayerAWS ALB(TLS terminationHTTP→HTTPS redirectHealth checks)Application TierNginx(TLS Termination + Reverse Proxy)URL Shortener App(Stateless Instances+ Token Bucket RL)Cache LayerRedis(Cache-Aside)+ Negative CachingData TierPostgreSQLPrimary DBObservabilityMetrics(P95, P99, QPS)Structured LogsWriteWriteWriteINSERT mappingConfirm WriteReturn MappingLookup short_codeCache populate (TTL) or stores NULLWarm cacheCache hit\nor NULL (negative cache)Cache Miss LookupReadStructured LogsEmit Latency/RPSReadReadReadPublic InternetResolve DNS/* /api/*/{short_code}CloudFront CDNEdge routingtinyurl.buffden.comS3 Angular SPAstatic assets / UILocal DNS cache checkORRecursive DNSresolver (ISP /Google DNS)DNS Cloudflarego.buffden.com → ALBtinyurl.buffden.com → CloudFront +>>>>>>> main diff --git a/diagrams/docs/lld/c4-level3-component.svg b/diagrams/docs/lld/c4-level3-component.svg index 6fd0a1f..3c09df4 100644 --- a/diagrams/docs/lld/c4-level3-component.svg +++ b/diagrams/docs/lld/c4-level3-component.svg @@ -1,4 +1,6 @@ - - C4 Level 3 — Component Diagram (URL Shortener App)Shows internal components of the Spring Boot application container — controllers, services, repositories, middlewareNginx[Reverse Proxy]URL Shortener App [Container: Java 21 + Spring Boot 3]Middleware ChainLogging MW[Component]Correlation ID + SLF4JMetrics MW[Component]Prometheus countersRecovery MW[Component]Panic recoveryRate Limit MW v2[Component]Token bucket per-IPFeature Flag Guard v2[Component]Toggles custom aliasesDispatcherServlet[Component]Route dispatch + Filter chainCreate Handler[Component]POST /api/urlsValidates input, returns 201Redirect Handler[Component]GET /{code}Returns 301/302/404/410Health Handler[Component]GET /actuator/healthLiveness + readinessURL Service[Component: Business Logic]Shorten URL, Resolve code, Check expiry,Orchestrates cache + DB via repository interfaceBase62 Encoder[Component: Utility]Encodes sequence IDto short_code stringURL Repository[Component: Data Access]Spring Data JPA queries: save(),findByShortCode(), nextval()Cache Client v2[Component: Cache-Aside]Lettuce GET/SET with TTL.Negative caching for misses.Circuit breaker on failure.Config[Component: Utility]Env-based config.DB, Redis, app settings.PostgreSQL 16[External Container: via PgBouncer]Redis 7 v2[External Container: Cluster]HTTP/1.1POSTGETshortenUrl()resolveCode()encode()SQL queriesGET/SET (v2)JPA + SQLLettuceAngular SPA: CloudFront (app.*) → S3\nThis diagram shows the API/redirect path only.\nNginx is the API entry point(tinyurl.buffden.com). \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Level 3 — Component Diagram (URL Shortener App)Shows internal components of the Spring Boot application container — controllers, services, repositories, middlewareNginx[Reverse Proxy]URL Shortener App [Container: Java 21 + Spring Boot 3]Middleware ChainLogging MW[Component]Correlation ID + SLF4JMetrics MW[Component]Prometheus countersRecovery MW[Component]Panic recoveryRate Limit MW v2[Component]Token bucket per-IPFeature Flag Guard v2[Component]Toggles custom aliasesDispatcherServlet[Component]Route dispatch + Filter chainCreate Handler[Component]POST /api/urlsValidates input, returns 201Redirect Handler[Component]GET /{code}Returns 301/302/404/410Health Handler[Component]GET /actuator/healthLiveness + readinessURL Service[Component: Business Logic]Shorten URL, Resolve code, Check expiry,Orchestrates cache + DB via repository interfaceBase62 Encoder[Component: Utility]Encodes sequence IDto short_code stringURL Repository[Component: Data Access]Spring Data JPA queries: save(),findByShortCode(), nextval()Cache Client v2[Component: Cache-Aside]Lettuce GET/SET with TTL.Negative caching for misses.Circuit breaker on failure.Config[Component: Utility]Env-based config.DB, Redis, app settings.PostgreSQL 16[External Container: via PgBouncer]Redis 7 v2[External Container: Cluster]HTTP/1.1POSTGETshortenUrl()resolveCode()encode()SQL queriesGET/SET (v2)JPA + SQLLettuceAngular SPA: CloudFront (app.*) → S3\nThis diagram shows the API/redirect path only.\nNginx is the API entry point(tinyurl.buffden.com). +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Level 3 — Component Diagram (URL Shortener App)Shows internal components of the Spring Boot application container — controllers, services, repositories, middlewareNginx[Reverse Proxy]URL Shortener App [Container: Java 21 + Spring Boot 3]Middleware ChainLogging MW[Component]Correlation ID + SLF4JMetrics MW[Component]Prometheus countersRecovery MW[Component]Panic recoveryRate Limit MW v2[Component]Token bucket per-IPFeature Flag Guard v2[Component]Toggles custom aliasesDispatcherServlet[Component]Route dispatch + Filter chainCreate Handler[Component]POST /api/urlsValidates input, returns 201Redirect Handler[Component]GET /{code}Returns 301/302/404/410Health Handler[Component]GET /actuator/healthLiveness + readinessURL Service[Component: Business Logic]Shorten URL, Resolve code, Check expiry,Orchestrates cache + DB via repository interfaceBase62 Encoder[Component: Utility]Encodes sequence IDto short_code stringURL Repository[Component: Data Access]Spring Data JPA queries: save(),findByShortCode(), nextval()Cache Client v2[Component: Cache-Aside]Lettuce GET/SET with TTL.Negative caching for misses.Circuit breaker on failure.Config[Component: Utility]Env-based config.DB, Redis, app settings.PostgreSQL 16[External Container: via PgBouncer]Redis 7 v2[External Container: Cluster]HTTP/1.1POSTGETshortenUrl()resolveCode()encode()SQL queriesGET/SET (v2)JPA + SQLLettuceAngular SPA: CloudFront (app.*) → S3\nThis diagram shows the API/redirect path only.\nNginx is the API entry point(tinyurl.buffden.com). +>>>>>>> main diff --git a/diagrams/docs/lld/c4-level4-code.svg b/diagrams/docs/lld/c4-level4-code.svg index 3d02bfc..62b236e 100644 --- a/diagrams/docs/lld/c4-level4-code.svg +++ b/diagrams/docs/lld/c4-level4-code.svg @@ -1,4 +1,6 @@ - - C4 Level 4 — Code Diagram (URL Service Internals)Java interfaces, classes, and dependencies — shows how the URL Service component is implemented in codecom.tinyurl.controller@RestController UrlController────────────────────────urlService UrlService────────────────────────createUrl(@Valid @RequestBody req) → parse JSON body → call urlService.shortenUrl() → write 201 + JSON response@RestController RedirectController────────────────────────urlService UrlService────────────────────────redirect(@PathVariable code) → extract {code} from path → call urlService.resolveCode() → 301/302 or 404/410@Component HealthIndicator────────────────────────dataSource DataSource────────────────────────health() → ping DB → return {"status":"UP"} → 200 or 503com.tinyurl.serviceinterface UrlService───────────────────────UrlMapping shortenUrl(CreateUrlRequest req)Optional<UrlMapping> resolveCode(String code)@Service UrlServiceImpl─────────────────────urlRepository UrlRepositorycacheClient CacheClient // null in v1base62Encoder Base62Encoder───────────────────────implements UrlServicecom.tinyurl.dto (DTOs)class CreateUrlRequest─────────────String urlint expiresInDaysString alias // v2class UrlMapping───────────Long idString shortCodeString originalUrlLocalDateTime expiresAtboolean deletedclass ErrorResponse────────────String codeString messageclass CreateUrlResponse─────────────String shortUrlString shortCodeString originalUrlString expiresAtcom.tinyurl.repositoryinterface UrlRepository extends JpaRepository<UrlMappingEntity, Long>Long nextSequenceVal()UrlMappingEntity save(UrlMappingEntity entity)Optional<UrlMappingEntity> findByShortCode(String code)@Repository JpaUrlRepository────────────────────────────────entityManager EntityManager────────────────────────────────implements UrlRepositorySQL: SELECT nextval('url_seq')SQL: INSERT INTO urls (...)SQL: SELECT * FROM urls WHERE short_code=?1com.tinyurl.cache (v2 only)interface CacheClient─────────────────────────Optional<UrlMapping> get(String code)void set(String code, UrlMapping mapping, Duration ttl)void setNegative(String code, Duration ttl)@Component RedisCacheClientredisTemplate RedisTemplate<String, String>prefix string ("url:")implements CacheClientJSON marshal/unmarshal for mappingCircuit-breaker wraps Redis callscom.tinyurl.encodinginterface Base62Encoder────────────String encode(long id)long decode(String code)charset: 0-9 A-Z a-z@Component Base62EncoderImplimplements Base62EncoderPure function —No external deps.Stateless, thread-safe.Padded to min 4 chars.usesusesimplementsdepends onusesdepends on (v2)depends onimplementsimplementsimplements \ No newline at end of file +<<<<<<< HEAD + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }C4 Level 4 — Code Diagram (URL Service Internals)Java interfaces, classes, and dependencies — shows how the URL Service component is implemented in codecom.tinyurl.controller@RestController UrlController────────────────────────urlService UrlService────────────────────────createUrl(@Valid @RequestBody req) → parse JSON body → call urlService.shortenUrl() → write 201 + JSON response@RestController RedirectController────────────────────────urlService UrlService────────────────────────redirect(@PathVariable code) → extract {code} from path → call urlService.resolveCode() → 301/302 or 404/410@Component HealthIndicator────────────────────────dataSource DataSource────────────────────────health() → ping DB → return {"status":"UP"} → 200 or 503com.tinyurl.serviceinterface UrlService───────────────────────UrlMapping shortenUrl(CreateUrlRequest req)Optional<UrlMapping> resolveCode(String code)@Service UrlServiceImpl─────────────────────urlRepository UrlRepositorycacheClient CacheClient // null in v1base62Encoder Base62Encoder───────────────────────implements UrlServicecom.tinyurl.dto (DTOs)class CreateUrlRequest─────────────String urlint expiresInDaysString alias // v2class UrlMapping───────────Long idString shortCodeString originalUrlLocalDateTime expiresAtboolean deletedclass ErrorResponse────────────String codeString messageclass CreateUrlResponse─────────────String shortUrlString shortCodeString originalUrlString expiresAtcom.tinyurl.repositoryinterface UrlRepository extends JpaRepository<UrlMappingEntity, Long>Long nextSequenceVal()UrlMappingEntity save(UrlMappingEntity entity)Optional<UrlMappingEntity> findByShortCode(String code)@Repository JpaUrlRepository────────────────────────────────entityManager EntityManager────────────────────────────────implements UrlRepositorySQL: SELECT nextval('url_seq')SQL: INSERT INTO urls (...)SQL: SELECT * FROM urls WHERE short_code=?1com.tinyurl.cache (v2 only)interface CacheClient─────────────────────────Optional<UrlMapping> get(String code)void set(String code, UrlMapping mapping, Duration ttl)void setNegative(String code, Duration ttl)@Component RedisCacheClientredisTemplate RedisTemplate<String, String>prefix string ("url:")implements CacheClientJSON marshal/unmarshal for mappingCircuit-breaker wraps Redis callscom.tinyurl.encodinginterface Base62Encoder────────────String encode(long id)long decode(String code)charset: 0-9 A-Z a-z@Component Base62EncoderImplimplements Base62EncoderPure function —No external deps.Stateless, thread-safe.Padded to min 4 chars.usesusesimplementsdepends onusesdepends on (v2)depends onimplementsimplementsimplements +======= + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAADB0AA4AAAAAV3wAADAdAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGigblgwcgkAGYACBFBEICoGJfOVbC4EmAAE2AiQDgkgEIAWDGAcgG8RDIwP1kvMKOopSPXgi+8sDnuzUpB+A5HU6zcTEYT+mk8hWsqBJcnux4bh45HEXvwpXRkgyOzw/t97/f/9vzdYsgLEiaoWMXjS1DUaHgSMFMQAVowgVO++wzrwT69QLO69Cm0uJqlXLrt47wLg1iiA8gTD4/xcGhRJohxHPP750+zviVMKI4gSmxcfjcf/P4/Hh+vs5TW1ycykmJYTxg4Hq+Wk7OaOAPuj9Xzor6ap6e/tVpYChA0IEd9hZaPcOE0IgTDgx8bSHUzRXfJVAIjoIRDB275jkxqGzO00uqTYcztv/AP3g/0+n/0n/d9bZzvAIkyUCO972b79FP9POtBcEjhwYSaY4DwxheJ9H0tV+rzYbltkkwgDKTIQD9PFoxM++m5vZz6CCF0R1IVJUYKEiTNEietIVqq7CtA5QiXxVGVmnK4SqstWu/7t09oRtjTp5XrY7F1YadaQOdS/uEmaUxCiETMPaP4qxflkzVQdKI5xDSN6GOG1TogJdB4GoEV7aYtPqd/MwqwnHvmibPeEJT5BZCQABgAJgJAyHhMSlBWJAVByYxUVBXgyJkh5ucys9BwgOO5snAsFpc80EILiqaG0EAjgAACYJXh43f5lACAMKXjPCBhMoQ4bkXlkQdAbhaeUUIPhkPzXY34/Qrtm6Zr9IYfUs9QywnTQ6YhHUDdTaj0xyfQwIOEZFo8rlrj+uQ6HpoBbUIHx2FAlFQYi2Kl7XYKylJ26B72NGBUWCSmmetQaAV3OwoBQ4k1lMKIf0sKIXKFD0AUBFGtp4O0EPP36SHPEMtNQt7BPfgUxAtk9qyVhIg2lcoutBYBp7Izbji9iEqihwTeD8MFt/NQceXQDo8qZBQuARUfjhExIJECiIhJScQogw4SJEihIthoqaVqxx4iVKkUrPwMLKxi5TKChYFpbOBYADAB7S7BgRylhfcxAfC2HvC8kQJkOGxmtMjHkUcAoViKAKEwA/2D+ZFKghAiLMpOHj8iOAfjoGYTqMGYM4Q9znJAJeGcDCII7KBlImHERhgAfiTBIyCiqasl9COu4QAxOLrEkc5mqeEA8A/2P5BA8gGssCocDFxsyOkJB2yUCyCaseWusiQesOQdFED7H14n1OeSWkcn3MffLMzPrzjax0XIbTGYSEksCG1FinTDDOMUQRbCQPKAijIoSJMBYi+AgTIEaEMAXCQhEWgTiq0ngaWkSxSBWHBClIpEciI5LZKA7GGiMKOIQQEEZCGBlxnABZaNjnwES45FOSBsIaGiOPDRncUK1iO0KbmVfndRVActtcjdR2MSiRBJnhR2PrehDMVTuVS6FEGyKEQOmJpMt4tUDinBXkSPGNQLpjlFs29lzhZEEiSAJF5LC4cmRIEIsWc5EGREFhhZSj9ROwIFlgYgLLgcVCr0CLQMaNHWCNAOBkkDDGoojYN0xO9UMRsiApANLmB0M71P4GjbsByD2bt22ZYJR4ZiPt/wra7dU+C2DDyA096/uBuL1hoGlhXwbNEac7IkJnk+cTkxgngZVTnkJlGnSZPsPHH/ApGyJeErv07AoTPkrj1eu026wWk06rUW8A4tj2McDDJA9sTfClc99OKHjBhyeGQd5aeE1DmsvRWsRXD7LwEfkuQ9XVwh4gawKCW5YHzaL5R8dk6MMCmXIJLyY/p7QxUqRks9lqKS8xmV3J8nKMXJbTFNiSUVrlTqwuCQiLD47TTHZn5SQ11ak0bAUvNokWxs7ONQlE6fJ0Ez8w3C+GEasvSrNlFTnS8jLVQSRuECe85BecTUJi1bk40j3RjXh4iPQhRlkwwS+oE3HtYoT0WBCK+FINRd7pdKg8QB5atmANaNq2WUrvkM9UsuCSP9cWdh0AuF4wT3+xbaxp8W5w2xlYA7zRCkE/r6pD0ZW1GuXlz9omLxQUBkRS4r+/Xtak56Hpr76s5xI6bNU+05CE4Vitv1ulQy1cYp1lSu+kMSIDLaL8epJJcLsRiZGeCA4a3u6b5zHsw7vUNI8W7st+XyLy0cZpxqHytYp9mYgrd8IkqUrVNKEyCMuaN6dTb01z8XHD0wOhKRyc3N/oWhgtywJfUg8kle7kxSI/EGW7QbnT6FBu1AjXG3SINEbLxj4LWTfTEKgUJ7EBjd5lpF/HM4zTbiKu4zr0ZqQCk0nexNJIlw6zl0F0LBxc7+UhSdrm/17FWJEbDXq/REMjuxQwoF0Wt0KAf2M3+sGkQHs/kPpaOObcKZkty7KQI9CtpT/+VIIVdKv5bfDC+LGk0nAVqqqFPPj615IiqiqGoozI/0Vcwx6mzIm2SZkb3KAsGdI6DkVwms07zSBu8mY2pAP+pl7iNp+ODiLrd55V7sTty75Rj1Ixq2YVzE11/OLhk3cvLZ3AHDmYWyH/xi/9+IhB7p36evJIxriaSKo3I4WCF3slFfQezGJnCW5E+B9EEx/nlv5Z6wbXboh61SoJdwzm3IkeF1JJvbUwTkVrfDbHydQ/fDSW/d3+Q5dBkpm+j8fOuCWv5OzZkHo9jLiuvHi/XikKVK/Wyx2xy1PtYaYv25nNgXyUxkQNLVPwdG0D6Te1hxpMS46WejaWUQZ4Jftyf0XswgsFFd8WfKWGWMRbCzMye5Yk2iPhga4x4u1pJjkbpb6yG7ww6MVM2qQnkooNLm4Wn8tajUZEapK6nGKq9Vpu6bXFeSJpySJq4LcmeOBzlpQNkHsAsgN4vnbZ1dPj8aUNP2TBngvVGAeRUvOQp/iJftlHyxbMvUnUgoXN0+wc6Xz/+F+bIStIezWvNmpoUbs+7M1IyuLQ7+/KeBtvlMxNLeZq+5MeLMyF67rk4rMy4NlTzXM/8SV0moJQHGELndz6Ul8wp1GnEaFebyJZADjK50hD8iYSLXUvOY99gKYg+l/QkK5lGekVaALYufwLlojQb+SgsLRzIRyd0o91kU9HSyNbQdvsw14O+qZtCjiwDnX0j5XluF9U1aHaHRm/W9R8bfF3v0N9W66Cey+2QA9mErHxGF+ba7+vpOJ92UDeoqd9tC0IG3pFqlbrxA01uXxCI/6zZ3ASJNVPhIbVulRUl28CNbwc8RBPFbR3oXr1LnLwFEyxTr1eXezezTLlJP9Oo+RMqlhCZ1J0qVyeWjxUWjq/f1X0ZTFUrSscAfsg8qoKzXiv59TwpmPZv1VShYJOVLLk7InH6bmUUsQ6u7cWsUlwgZ6m705gEoQlp7s/Z8oy2tLLQBH4IQr+AGl6yJ8pSLG4BStvg8NHXR+fM+fS6NqyBUgblp58kZ1q6xpTksg1XbAxf/wXRehynXaIVEmqGxY1kiIVODoCeApKjK+0T3WV+f7BgSY7ZGg09EBuwqYNq5tMQKS7lmVhNAGud6svYMuxAb7Sc4+QPdp47i65wGDEAKySKqiApL0hWTMypF//kxcXZBDoKNOFiqpcjZrTYPBwaN5P/PtS5nNYZTkwcX6b116xnOXMO/OW+1pB6YMgo9LgYwH5E2d0t0sv9XC3MA6uXVCOH6jghZ0g7Djy3cz3PI27etygmYIK4mPjgS/N3AI0vhASGvZATdy+uQsWc0SsecoK9zGuQ299LnM5TLE3R4sJXlzMUF0R2qsHohvzMI1ovV6oVzVCGtcSnP9jXs5jYPftvoUEBWdCtH7723bJfEpZvBcHJy8UVEEc+HKOuTeQBVRbKQEwSVLbbeaaS20xjrDn0SnVc+8J5bM54sz3aggf1wGX0AkUAGwBVRvMkJdxno2ENMXbchCFmXQhwDCAmQTCnG94GzTjqER0AGDConDvng0T0hoQEkl8/+vxu3O+dsvozZHG+lhGG+CqsALqQAmg6ogVjX+H6GpQKJa0ABgEFFULqCxUbdhZjULphMJALaAKpgP5yMQG2lrEHVNq1Ea0wTtU7oiubIty38gSwToAayrCQvpMv2xnbJkgWd43ppfETiwkTMHfbDLALacJDi/Wmlx+3s5ejGtlgiQ1kUBSJA3TqZHpXkZ5RDPssVerWdhLxjK4rmlWKpKKKngBkjLLItemrQgLl23dtVzviW0wOQXfBWkSryyYe384owvlI7dKBpH7vNRR8i6uoR/d2puP9jXZERtxWVvTSKKmWtOQHZFHKX1+DPJy9KbUS47lBytbvuAz2Z5VAHZTdNI7kbUrJXe5JstV0qVzpBXrrjAAuwWYSZA2yi3WulYXY9eyBMeP/h96JN3bJmGgUqBKEkr+DQa99E4FTb9dXrcrSjukz4Ta8FXm+1yL3gb5QMlAQQvXWgIzp2+L1BhRnYl0kI+Jg3UlR7yNsZ9XanyFy5Q74hnjHYWQ7hpbA4SWg5f9FdzC6OQ1lEY7OuAdTuWOtm5kt2XBQJjwxLodBq/iJkbD+l4qEWHX3gTfbsnWhK9VUCi41NdexnX09WuJYiw8EDkrwBIjQOlw+fNdp0yMg2dnknoO+oJxF/Ie769qYzwfHA8S/fyOiJmxXkjJQAtPhZCiI0pQbp1HdSwbRte3WHRy7SwFALYjr1xC0wzY+zLjBntFh3PZqs0emQUx1TOhYnlmpnj6/xVyQeFvKkmV9ClYU8Xo5mMyCCIxT33OHHn77hxpPcccfCYLZ4zzW+GY8D9Nz9mUNPUCJtTWolSWwNuYaw36tlAcZpKKQ7lnZ9CEkB3nL4rsvFKOmfyIQi1sUM7sZ/TZfG4Mf4jdUBAxhy3LESyij5dD/hGZqGuFksIijzzaeKNFT/Q+Pk9r/D2seDJ/LNwNRnl+MBMGTh8nvl6r1bTwpb4iWjbA15ZSsiOGIzpPYGL7de3z7KEaBqSg2TAZXoyyeo545C0VedJG+g8/QscWRjHVk8h1wTCwKSc49HGOr0Mdlr46m8vEiQyo3CmrRIpWE2ArfeOQVm5L5rlHdbdraF5Efj+PjonBhLQSVROpYnfcx46g4K84EAdxl9S1YnJQiLkmOa2LmuxhHMtwo2kUt72lbBzrCdKU516RrrOIOJUPPqpsi2F2nsAxwNa6LNgqYLDFEUDJzFQKh0E4Dkyr75FY27Rc7mC0RgXzAS25LGY0m+JABgGOoNlhsmgKAJA3yTqJjftxQYZjkcJudKrzpffw/LIS4BrSBl8pnUiLKK/7o+B0BCdArG1eeRtZL37nO3WtyRq9L3BRFYE7q6/kUc7awHZvyX4cYkTSZH1w4Z6sQrMXB9PNq9kDQtWcg7mtscE/e0+WRsm7n9ZTKQ3eqHyZIpHBh0ifTfV8q70NC+MGtUFFOOs2QL2Hbjl24eOXpXEh4zw9fXlvmmCI6vUkxe42i2ooSvoLr6EDuZd4ZwYsKuo59RD/6F3kwOpIUifSE7k9YFFduXkTJEncEnrveJpleoh0HrsW1BKM11Bs4Fqba+xaTUXUw4JE1I3b6WlUduoKlqe7q71L/dIZFSqj7YhfLBcbtTmUDpMtDtcuLf321A8FN/pxS2UyuhNLJfUemBisdQtCxucXalKZkWIxLnbvvnjIM9nhIBE4sg/KrZKY0Awmv6yKpoODtxPfaONAENcneZUkEgaaW2qc+krjcfsx7zQ6NOJiZOAhDs43hQVnzt1vccg+DgAkFTsoHKXs7ow6x0jTkqEnFSvLa/zVkhsZPpfxVfaakdQ7C76w6r85fXcxezNTnL30C9uxVHCC0OpubKDsVIveWVCLfvxOC5M6wwsPkSIajnSe0qW42P10mOU5bU0xFSHCscGP0ZCkaeWSGcvZeEtm5jqP/SqKBKufpKLOHafjK8J0v72htDdUY6MJaNwe6JpmB7wCJGd0njd2gvA6z+4i/bIAISlCb6SL3TgAmEgGkCDNf3bKrpdcqtWXmWyhc2N1FIWSio0DtciYp30Go+sgqcskynq5Rrt8O1DXg4vPqVarWRYK4Rg5CP9cyRnSiX3/fO4KU/b4EnqPSdrWoqWONQvOiPF5bMJ/TXJAKAh8oRZlUBEtZwuLpi1oJHe5wcuahzQdO3SwC+9sNJ++lSMaGe7netcKoiGRdPw2cic6UccRbjREbovvxwEPsZ79Ufh+MBBamFeE9tr1bXGdR9b4hQjphLBwC4UVxozAb7UUBMhPVKqLboT0AN/1z59Gh+qunlxyhlzbNKaJ13m/1WKDaZekf+nt6rYYSlA3Zz+tGjGrs0dIdCsEFqAUWU6KBLVNDCW1GzCT/djP3YhTqZIoR1grgSCaAu/vUx6N6HCNu2NLyY2WaAkBgJu/eLu5F25Tme4Wd5H2X85rFmDiPihqzqNUr1eHpDAVGCjeThnsloBjnHwOphhWCpJBmVeE/d/fzdzSG34KHfbGJHihIphgMZB7X+orJQ0evLaVC/68nUm+NZfDMucR9xM4M1XyhuKDZba0dPdRvwNpIlvOHXFcN80z9L6Y8ytcow2qSxauMDj88m328M3Lfl8Q0JNUj1Qm8S+OAHZhRUHHtM1ChHOiLsWFWIsM7mK0BJFvc4Oej3E67Z4hbXCDpAEx6Dp1Emf/UbLubuQVvOW4umdOXBfAxtt+IjdE7kwNZqVZkn5oa0UyCofEgJqQssabOvQn8zcb7jDTV9DHL7MzL/O9aajnAIVKV/lggbiEXYMhpXFgpLOl3F2BUf/pWzApqV6PUL36JTMLAzSsnpBwu85FFl26yCPKU5TRnaojYeUSdi2kUyU/7vIXQzz7435IQGfdX1mOQ15VyeDO5SISvhJrMZ1yaPCxkuPdwBlgpHxa26+NGjSKvE2xjoilaIgutO9VAUxZqeSVe5bFz4Tb2+o9WRdLv1qu5ZphDrDjBCuIeLRPG9EBjd7UluM4eENBZXF4lzv8J36Ra13aD9UEwQvpI7IIsbHmcpbfZa5RfUhOQj0FPaSb9iX0E4i6ZLJRzZOqwRYVBI3Zi1oA3EK9TqwGIKLk9kz2LFSRTP8I4Bcw/6mQsehuFiMeORKmSu4UwvIO17pI474M8ZV8cKyzN2rsM1Oj+4VStrD3X2qCLQCDDrsKArdlP9pKRao16C5PfWUoUg7uTchOpJMIYqHvzTnPJis1f9X8wmxYLMoxFen5E6Nc93AZGAcGFZC6UJxNNamU6J2d4ELIseFhobU01hVmUW0LcTA8Sb6JdE9/TvHSU1wPJTjoRw1jJb+Fg8EA71/13+qvBM049G0Ync8v8RGuIQRRk+/d2HEtQ5qnopMTchBeKxbFRlvEzb0YBWTQpplbHHh4eKwsr4dGTMBpvkbZd6NpbxLHXzEOLEdZ/WiUM+z7tK7CAq5M9ZsoU0PPyOZIqXR7i9MwcXtVynTlnlGYV2qKFvj9XNfe8h7Op7/Ol8IaIG385bl9PlONguXPSI/R9RhbeCNXHbHPyqLmqmQY+Q4cjODuIvz6+0vfr6ih2HCJIg7RF7oKqL+7HNemKw6YUP0qSJWlioImSA2GX+OvmbEWK08HuGOTnhsbWcYVT04Sq1ETq7jg9+zKSk373tncKPP9G+nfqwqkUSN1iL57yadkoXb8Q3dL3i2GpG/0/xHALLsQ5fNFXByzFl3lhzclCZey/CsTH22R0IVskXADn5XLz68NB/WXKJPFJIjePpFbQ1SbImCEXxwdNUHTdwdkXjDe+8G+4r2XlMboSz3pyRw2yOWM0t5kJJltzzW3lk08lmJZSDRSy83b3o3Qz6R/Q19xfvZ8Sg+YfAH/DmMRINsCSLZ+/LOdwk14I2NNUG5T7oLPzf8CBv3JMT7AGhugyfc1JQHmicFV/BXE/ICYvftz6sAYpgpmqVwzq+GQsv5P2bjdNwOwS73nB2Urc4cNatGBf0XCtOFlVEegCv0MbSMXhPfiPyF7xNjdc+avL5vEkl0Mgxp1cQc7enNzuoCSAwRJ+FqJJpQm8SJ9VBJbv6lps+d5AOUhMu7Age4FGFYslefGwxQErkUWMZ6+ZGy++U5+2VYm/xigqMZotnpmO+EosP77XkJAQpP4xQmz0lGVCEdmheiCQqnnWpI5SCjbR2e1bIaK4+pn6wEdNNxkrN4dwLO/4bE/jOCfl2/cXHm24Flt9yC3PKT/ohkslHevnyThpkGdVT8ohrLIZWVnQdT2g1/4l+ydi9tQOgALzGDRFwUBsQx78+uhT8jusdvz5XnhCW3WBRPP6AqvKtUEgIneZzgeSceXJM0jk3hFkVO64lYayQx9a44FkhNQj9z10Xr+TrA7YtanazWVh3JKgtKugp1hmwSSmJiLKw4u69YtwJficx78cxb4M1i/QmZoNBDODSFjEXWLzdERs1oIbRuP/NWTEpl9ILvq7+ohlBSrHMQ/wrtxWWTkvKMTBxYTVvyRx9k3zvoZvKx/yzywbOG/hsU/vBRu2r7u0mCxFOJCckgj9hj02hPymIrmxOu54vinh38+/76mYHpF0vHwP++/NOimNKIDK4oCWT/4qRv7cUMo/cslg1Z2FTUdbnaDKBix4CpzG7jPKhE5lpo7r7I3X/LCzXbwlRfLdMYrmx34CotnQcKmOkrzRKFT9kDUaEcq+c5PUqKfvUku/3no2Wu2g7KZUkhqOF6fqLP4V46Sm3+1THne3kCIyDVZBGCRVH1H8/E5jxJJnpi6bWMW+9u2/kIBHkA946qL5+1c9Pz0IrX+RGp6CbrJj+IdqepvgSEIomNIzAdcC7qpJURchmUxAyXZtzm6z2Tsar5j+NMd9A2jt2A6vFih4C6IiMC4KvB7MGt7lb/5M2Tr7fjqjRWMj/+tRU7efIPWlJ0tIuRKOz5/aXGOdUzh8S/c8Cb5Gf7C+YfDVWRKBg4Hl+6/w6AMb84k2Y31Ez7M4Xuy2b+GSo66HWgIHVdDRe+FJPkZfHQnkV/ZuirtQPDDyt5sDqj8PibfG+QJAIkcIzTb/OEDe/7nIndRtyVFVWvJ7RlWhSQ6hFIiuvfToBpV4UR9Lif77WklWWbwSFuT/gi4GWZtd6oLoLvLTvxu/tUd1nZ+hBPnPmQjuzU3gZQLjou/BB9Z5V3Q1ICnRMg4QQuObauO/XvTyKFioR+phXR5QaGT7q0nHZcscuIJ2JWF8EQI477HMZzWqtvtnxXrT77+JwBqqBcD/IJQdSYkSw5l5YEuQu9Kfslv3Yl06i9V+AjI0gnT5gSqR8LThYE7/BSHiHuJUI/tbreeC+ZDo9ulECOvJCw/JM8lKzu7ltpWf/QhzMAXFI2Q5q8v08rmzfdanryegf6mv/tfyT1z4BldLX4XcDVgb9YLWPIL37VCU6gydqJGn+gOFCJ/LDqgGqGXQ74uDv1ZqfH29clrbj0IgXE3cVcwHreGici5yBKtF/Tit/zWMMRCGbOpbveON1mx94nUB3atB77llahzX/jWGTFZe1UlTCcPlwx21/ZPWbVQVFut82bcd5t+lPxjvAJGbra0kIMOUUiXPpXMuTRH0sbIc0zZy/GYKdTITYeH6DCEEXj2vsMSSis1dIbVOjYB1X1z/PjxMvMJrBqVBGru0W7gD8yab54h74Eo7IB5XO4/i51D4MdvTRnsHvGkXi1z2e8Ba6/PJ0vep1GaPqk06QtDGsHkH/r90bFnkNZ6brvvRUF689vk9MyIiEk/B434bNip6Lt+tlcTMFSHYcQYCvlDqt/2yLjCRnZ0dcDg5JxgBzeHNUg+K8q5mE5r6h6ivjJTmSFjpLIIeHFJ7zSB6vJBbf+rRfPPrBvjYNnnB79xOyM2dl0HfA318K+tDso1EWmFF1pmnsddxSZTXmDq49XVO+g7pSzXjdK8922b3q6Pspj+YhdDvdBk3wj7BMA3+EkDMQiCKwWraDBz4OxcOUSGdv2g1GQwHCghh7X60jbsHeYTG1vuHKpWRoO86L+CTQ+VBb51wASM+nQzhreg+uA2X/pXp5K4xEWdyBnaKBlZDKy4xuogzk0SwiQ8HThnikI18GNDGuRSN1M7C1m2oHcTczDzLEexIZCuYBiZx3U5a476zEbURaWX9gyG/iFTc+imWnbnFBsiIa7h01frROxqpMv5oQce8ijPefipcznWtqKEv1NbiWQ7fA8sh5LmhF47avSu5zQUDRoLDaK6FjEGt9Nx8Itgy1jjzJDpF7PgU4J6E4MOoBuHLPU5C0uuMUjFv/353lK4MtOlNTSKhgDiwZYhLJrV28nvcHen+QNH8CvCsb7qmwfgEVeT5+BBDGW0/V1YR7LCJB7hjI14DgLSdJ4r5ED8IyF5y5hJPE9Bm+f2Wj1Wqf5Y2T3b0+v3ys8/NwRVMxb5yaZYf+/aQKpNUTOtXjzqVjnzqvqKGkV487iTkCEFKsQZWY5Gp4KYfRJspLA/eoOt2OJkfAHBRMAXeMs0z1G9WUH8jG67xvl556GhM5/0CTbKx60YXnkZTY27sFkl3z8ZZ+VtNXEP/VeDr/PVhkUipSKz3whpZNR09tu6cfc9M3B32nhZQrlHerTHjrtZ0aSHg1wYvboNQzORHL+bP6VM3dG/xO9a+aWCLd2T3KCNvjmdjZVQTv/jxE5tC3a2e/Di6wf9/LfxuvISb587cHRHjquPetlatQTuXfVNakY1sZxVToQnBUjNeDJ/HF/124/ltKb7fcFypJyB/96LlX6NF+7bCUZye4kuOVLuMKJTZd9YSWwCpr/aklov4/Si9RH+rg66pDglP4ZcAHngUYS1lf6eP7GZQCPaggMhM0Q9yiQYOeCvaNF0xM6LKWpwyeKq+dw9FyAEzpsshLJoRIswLIvVekAMCvhx0wbq+DlROxnHLH5N9u9pBDOplcY4lKElaCMqZqZzAD3Xt3995KYc1dX+p/6Ox55bdfIDLzEWIlAjdBMdgcxQr/hXH0GP4eCLrolUBjR4JnY3PnRBxf1mNqpElCinMmgFCAezluexY4plr/WG196a7MBoM9135qfqFHWVYVLiIrZ4nkFOwocSUPpeOIdhgcQVUDquSrV5vRAfbpeu0TIYTIhuh42sqNGrxCbm7FA5GdfKY6OdLIIDjNGJfbT9NYQBOy76d4dSVhjbwXGqIkojCVgZ9PNwFJm1herc/lv+27ASEYtY0PiLLBgqxPI2ehZ6pgOGsHYGEZkQDb6yX3vxtdP1QbebVbEqCp/bCvBhSLeZZylrbMmXGMbFJEBEv1yhK2mTxAqOB19CbqvLOT0rOjdlpkmzCRxzsYk19MULMv6Wbd6X8DSZPOU7pHl3UF7RMJbP9XEBrnlgE32r5QhRD4H9vfgJcRu4ONSWCNKjhDN+X5DqXwh3wISYobkR54JMzgkO14dZkM2p5bRSllZwnqdz2hXTV7aWK4wXC1mOU8z8FM4SwsJfnyUvgTk2BM0gtEunLzqWvKZs8LnCcu34j0tklyUt7j54wQ3uiUKiAnVKD4JEqGSojJ4R0heRE2Cv7OgNh0q43UMFXBFmMkfroWjCcik/TWKvLcmI8gQ582kKy+WKZx081WWh+VpEXmZ/p0DpU0yAtu/KHcmI5KxLzVDEbK3r7B59A2pZJVGQkVToFC5J/wHODj3WqdPFCqiHvWu92FpsEqtStjTCWso5mAbyrGMvLvlXTzbKFmv80xN5QEzFUtMGYLB/HrOF8UL/7mw7bw4gA6s76VOGbDBmC87wLFb6FFAElTBJCH5bJNoerTadPvUdQHDit9e8tDD5jpELfobfo+ujsODaeoIjruFAtbyAy4//LEc9O9TLtXdpGsrJ2yvlhuwxhBXpPvcr843r2mt7LaOpQoZwV4R8GsO0vh+sjK3/2rT+sPRCaGli6U+XaIEAC1f37dTzd3kb8mqAuSg7DkyDCLdiH/5Q73W1pFv/ZgWf/384+LqOI776P3WTfHfM9PCHkVoDk/UqIZ9CbMRtg9G0WLGYxXmD7KkgtRE+hW0nILOE7dfiNfyJC6vQHK5NQ11SF9ojLYzy2mLvifz2Hvzrl3lq8n0j2oPl96W4bMnmVUwIEtd2o/QwSw3gwy1wpmTH7iIpPfqZYlgF7X6r0ENO4i/9w9kWlXdSSFeS3511I00uJdSFHH26sNsGmgf/Np5eXtmnJ6P9fXAx5GLVKz+Zpj2cISJhp9ekBbX0x6Zmzil9Z0iaVAP2802aGigTZeEuRdOKlS4zPQua0RT4sTfh+CUF/F0ZNpzNK8br0Zo5yEYfHfWR7NAzJy4CswYHEaBVdN8mH2UbhYXqX+jRX/B54CqBRFy9GfGfKTlBPw+iMdGZTH/RKVZhObZgEiL3KZCwcZoFf46+b1dxjGOPiHiSK8jZJ2/8+eswyU9DlHGNHbW1j8OWbpFOd/LgrHAWAx5FVobhmuaH8Wne6PLI0KVti9/VzaeZDrTzDgORoHruYUfHQnXnwAHZ3A7hr+445YeesfJDJ63nIcluSc34wNzLl+o7KkYDM7hOB/U7+PDM16+Pw97I2LTdJ4qP7kVccKjmP7CCLE9Z6GAFxDXgarglDYER7yvNZu1f72kTY/kurVVcvtshn620Zh/JW7xhwJ+58OsvpIy6dGU76eVPqbaxH8/JslZSYUgDYeD5fzwOtTWWEDpQO7okhG8XWnV2aVoc8cXV96a8Sre5a56iIhM3V6lzpi/+4+uvwSkH0ilqGvxrHt28T+JjfON5voTqpBYn+/JPfO5tg04PEb3rJdMFVVOXqTDW6EjVEE1M8pGeN3en9ru3f8tAMWp5zfiXw77spDm1Q+taZuT0KPrmdDZK/zbmMEz4sxUWGCVPqtg/hr5+RQ26+fNA2Jx1PBA1gdLJ4H2jgZSoghz89Nob/fUemh1F02oCt8Bx9ARKlpMeRvaiSfA72HG1AXuTQb2IKsAZ7IXBX7F4/N0sLyccCrcci6yWDNj9svCMhtW6b4qLlvAyeZIi/8W0LNw/AI2o3Gk9K9Pu4hpCTE05xhLGHWhajR3pwGudOM1Q/kEfrkEASORqW5gzmlgMZU/HcoScP6ic8Q8ZwyTRS9RvrshvEeLqlv0UaF8dFO2S6Hzzh9O1qoJc+oWpFy/kMGxvf1kfKcsinrI+9n7NKATF1FGB+3UV/cHfmLVxaS+3LOQn/YXg2mup8gujyPV38deX/zzwKlR7AjYmbn2j/icDOjABbdbi/TtKwHam6tL9T/7C3Ml4YtasqZmUZ87QFASPdOIxJbc6k0kvhZOOvvQIh7XAJadMkAVlyPQVMXkiod4Z+Gssnj3pD35jo5/NcfaCdqvvcDDvQ15k8nLOJthGzKnRgJDcc7La8SnudP/XVaNN7lQFzl2AcDmaiY8v0XZUps9i9Vx4YGqWS9jP+1xcdxbOGGaWFv4yBW15ZyAFwNnfaZY0cdhfq+s2gf2kgbG5vWFTOUxT99QdBZyZ0iB6f8JBaAKX717grz3YMtTsgru2z9r9gYlOVO1/+mfFOdnGbKhdmRDbTM0k2K9/6ZjG+nBjOCUCvOEITZyNCh6/nYASdKKZZPzDDMBuZ1njCiet0fMzK3jME+bBDxIE3O8lZpQycW54yThV4twEOyk2v/5DZpwNoGQlGZ3ymcX13+sJVok5MdGxu/Y444FMbGSXBRHa1yE7+mRAqFubFdRAmyKuXvMw8ifwikNQ3Ixo5vmZfjoRNkHrqKdSbpN58yQAwVFjNEo4jYkUwVzav2EsVGccKB+BwMfLqGAm7k0qvsJa6PNouNxgOzsof4MoPxyKY1qawNLTz/8KEJO291awGC7Pcv089VRpJxTPyGPM9f9mK6AGCPEufD5eEPCz4vwVzqTJN6IIkhgIjgkbD3YI71VZFhmUP2ynMLA6BLOOnWl1nZ0FfruQXF7oCDiz79oMC814H24PqaiWhB+FYAIGl6huR1ouzP0fmRDKJHTiA2KRiZCVtET5mQyFs7AGeZEU2mwHPSzehcfQdH8qnkS+KIDJlyM7uaIgeCaK2EjUKOox/HIHhFjEn26hTr0ApoKt5bL18JsELmWgqCx27T8v8sOOvmPHtbCSs5/d/XSZc5RQAOWdClijoEw5k/OxcXdB1DS4iqjKNncw1mWt06T/PgQ/TM0jt8AqMC5dU7YQHIRJfGZtHdNQrPjEzpNghGBDXKyHFZ3ZtMl8MshBXh6AZiBEuuml+Oz4CFocZDpwS5o7WXpfH7xlfP+EA4E2L9ONnIYEv4jrwUNceMMXjn9wDePDGz4xhK5Mdc5LvaCx7kudNF30rsanFKeF5nIdOivZsLEOkuRERwadP87IGTATQiLIEGnSywMTwNpmn+9+7ueMEBtpBwHUCiBPMdE88+UlloWKH2oLVNr/o8z4ozFFct+jXYcjwn3B+PEJ1YOrxq34IknIcditOZ/I35PT/DZMp00Fqyt/SjtcRCmktiBZ5zN5h+HQ5hNQRXZHEOrWTWX8CPdqHuel41ksjAzjJxP74EPx/BSC7jvw9b1nucb/ICEOl/QPbMVNjoApjnFDYKl0iGZmo/slFJ5GQoW2bORtW1TUW8ZGiYLFdjZlp236fBJLvgA0c6mL4hO3PbuWTEMcCBc2A4OFdUuuU/8asHW/niz6aii2PWp9htErMMRaK68LsUk/FsuyUTgYeaU6aG63czxzUPfLQ23/3Lk558OfB72v8uOMpc/xjKbgGTMAW3etSH79Mzm5S8G255rO3CUG7K988NQUz8qnjOrqjtZzt0aHIL5auer+fsO1bXtAT8UHK30/r8TqpyNlfSr4v0arfOM6aJhtmdIwzYZrY38yeu2RW1/eFZfhahLPAPcpGD7BMP+nmTX+HjilqzNIvPVAX6xm54A/ZCF7qVj0e5ZE1WNDxNGwTJ4Q47lSGXqWGHDSWStyhuq+3YdHcOVbaMExEQodLplqe/0vswA8xjPOHrukK+G7Pp3CC+gBEigYyFzvgBox8SfMnXt0/ZsX/0r88zauE9wuuvlDNrZyvxg3mu6Hf6ozdJhzLCWL4h4ZtjOqg01KA4YHX9IQMfmG8Vn98JzJmkRoLYwpqIwICSOvG9/OyCkJmG5Fl4eb8tIMzbXPFYjDFJyGRTADzkfXrFVlH4j/DtrgfVWh7//E1qR1Sowp1svPOFOEnoR6YE/elLV6Aq4hrTer1qhbVvCqJvfpUBR3Si4B1zREn7cnKbtCj2xs9RjjTctXTOfcojM8YgtzHITA4eZttUXJeguHa9cxOsWVNzV/Rwr+GnX3LltaYPyFToK55xeYvP4PYsDjFvFyeTClNH7J3uTB63et8cH8qlvCoomGCpKd1x3K+NBtwyJeIuW0SNvVqaue3sn7Nz6rDmdOWpw9zV8kyZia0qT9A06Q+/xHUvap4xKIKVIBCRh4bzXEhP1xk/vm/VO/nbSqVtRz2fsyp8L2jbH/NNK/u4zaTn77wxCU9D6q12L4bWWJ8H+LA4F4/2xlNQe+pCsK/BNKb1mJ5xAxfAMRI9+lEN4wgefp87i75T1yMjPt8fNXf+Tk06CONbQDY03LTrNnrwjFQh746Gt+urX7O4bne8em4Xfkny/rReyYIkWO0rWx8vK1+b+fNCPulE1jP/wvKQg/mPHxYoxtNDvjJAJD4Qt/AvlXVI2YJyiWHj4tNjouqgdv+dFUpqmPS5VHxkV4anBd2m9bmoRzOZee+PFpeXyw+srvg8uis28k1vJv/2umH5A7jdMPW2ctNCV3YdqQCffdU/w/OCI9eYHAdNgzJm/RNt3gyPvCJFNMa3qDHwl7YdXCU3RWrD6/kvGEiN9DbWzdHH82j4xUUdtJf5K4i+5v6Qe/INr/4/XpzwTExiKNLGE+VrmIAZ4cOlQVj5Dz0ubgr/gxZzP6ZMDH+FNUwAmzGZZuOss/NHJfimPS5oZEOiMJVg7J5cfhOGbufTCOPAg+ud69FNc9I2hLIBF59AiPqompxnNEI9yGXB2RvMWgUIS1sVZFzIMWUkfycCO0NuFvp6x4cam+zx+JCHuwRHkbS38NKYHbcmgAmihPDjrf8awFL6PKkg++xZ/2YhbQ3/xltQvL/lN3dT/L3f/04FvBDw1fr7a4NUy/igQXXBkcyNZRvmv/nl6gS1NMH6jxrd0UIVXF3F15dnm3bgEAq7+9p/LSyOsyv6R3BDLyEwDOfZ3h5vkjYPOvXR9nW9e6cb9MfQAQwBrinzzOBdNJ/78nAIHX6elKluoHoEcW91nrmMgaFBoqCIhCYEFAUWuwiskYFVxWSqo9uDmZ77YcPw7SjCdOt6C0iSkCMJywEiBoZGJdR+7keeRWAP5C9v/8vKYAas5SZ7mwJItIsMDEIyUINf9jp4MwHzFznKEBkOYpZxoRuwCU+6Ljwm2mpNZjZT1S9BSJEFtjxCkRFj5hvRp/JSUicWK9RQ9HlGe0GZYUGohPPmX44iIUUmupEiQ0YaDIqEIF1BwWlSx+YVInSXCNKYgYv7YTja7ZO3CmQMJaMQwPA9U8jzswwh6gLgD04GZ4hRDQRAQATHR9XQBh+6IARjNSgAjXV4AjU1mASiFjjJ4WAIsOVSpM1KDWZI1aRfGoUadtoyo0y52CzVpcQ40VU4mm9EKJbL7q5FOPpi1oWG0cyqA+eZyw0MsR66GNNMtmk4kLaulqYV82Wcin0+GGkKU+Jg4NcJiF1JSdtY0r3bViXa4OqwpTRBMbPsdOJNa3tGxxjUENt9OYatEQ0NJHgwI=); }C4 Level 4 — Code Diagram (URL Service Internals)Java interfaces, classes, and dependencies — shows how the URL Service component is implemented in codecom.tinyurl.controller@RestController UrlController────────────────────────urlService UrlService────────────────────────createUrl(@Valid @RequestBody req) → parse JSON body → call urlService.shortenUrl() → write 201 + JSON response@RestController RedirectController────────────────────────urlService UrlService────────────────────────redirect(@PathVariable code) → extract {code} from path → call urlService.resolveCode() → 301/302 or 404/410@Component HealthIndicator────────────────────────dataSource DataSource────────────────────────health() → ping DB → return {"status":"UP"} → 200 or 503com.tinyurl.serviceinterface UrlService───────────────────────UrlMapping shortenUrl(CreateUrlRequest req)Optional<UrlMapping> resolveCode(String code)@Service UrlServiceImpl─────────────────────urlRepository UrlRepositorycacheClient CacheClient // null in v1base62Encoder Base62Encoder───────────────────────implements UrlServicecom.tinyurl.dto (DTOs)class CreateUrlRequest─────────────String urlint expiresInDaysString alias // v2class UrlMapping───────────Long idString shortCodeString originalUrlLocalDateTime expiresAtboolean deletedclass ErrorResponse────────────String codeString messageclass CreateUrlResponse─────────────String shortUrlString shortCodeString originalUrlString expiresAtcom.tinyurl.repositoryinterface UrlRepository extends JpaRepository<UrlMappingEntity, Long>Long nextSequenceVal()UrlMappingEntity save(UrlMappingEntity entity)Optional<UrlMappingEntity> findByShortCode(String code)@Repository JpaUrlRepository────────────────────────────────entityManager EntityManager────────────────────────────────implements UrlRepositorySQL: SELECT nextval('url_seq')SQL: INSERT INTO urls (...)SQL: SELECT * FROM urls WHERE short_code=?1com.tinyurl.cache (v2 only)interface CacheClient─────────────────────────Optional<UrlMapping> get(String code)void set(String code, UrlMapping mapping, Duration ttl)void setNegative(String code, Duration ttl)@Component RedisCacheClientredisTemplate RedisTemplate<String, String>prefix string ("url:")implements CacheClientJSON marshal/unmarshal for mappingCircuit-breaker wraps Redis callscom.tinyurl.encodinginterface Base62Encoder────────────String encode(long id)long decode(String code)charset: 0-9 A-Z a-z@Component Base62EncoderImplimplements Base62EncoderPure function —No external deps.Stateless, thread-safe.Padded to min 4 chars.usesusesimplementsdepends onusesdepends on (v2)depends onimplementsimplementsimplements +>>>>>>> main diff --git a/diagrams/docs/use-cases/v1/UC-US-001-shorten-url.svg b/diagrams/docs/use-cases/v1/UC-US-001-shorten-url.svg index 0c72e4a..74b6040 100644 --- a/diagrams/docs/use-cases/v1/UC-US-001-shorten-url.svg +++ b/diagrams/docs/use-cases/v1/UC-US-001-shorten-url.svg @@ -1,4 +1,2 @@ - - UC-US-001: Shorten URL — Sequence Diagram (v1)End UserNginxUrlControllerUrlServiceImplBase62EncoderUrlRepository1. POST /api/urls {url}3. Forward request4. shortenUrl(CreateUrlRequest)5. nextSequenceVal() → SELECT nextval('url_seq')Long id6. encode(id) → Base62String shortCode7. save(UrlMappingEntity) → INSERT INTO url_mappingsUrlMappingEntity8. UrlMapping (domain)9. 201 Created {shortUrl, shortCode, expiresAt}@Valid on DTO fieldsCompute expiresAtCloudFront(API Dist.)2. Forward (pass-through) \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }UC-US-001: Shorten URL — Sequence Diagram (v1)End UserNginxUrlControllerUrlServiceImplBase62EncoderUrlRepository1. POST /api/urls {url}3. Forward request4. shortenUrl(CreateUrlRequest)5. nextSequenceVal() → SELECT nextval('url_seq')Long id6. encode(id) → Base62String shortCode7. save(UrlMappingEntity) → INSERT INTO url_mappingsUrlMappingEntity8. UrlMapping (domain)9. 201 Created {shortUrl, shortCode, expiresAt}@Valid on DTO fieldsCompute expiresAtCloudFront(API Dist.)2. Forward (pass-through) \ No newline at end of file diff --git a/diagrams/docs/use-cases/v1/UC-US-002-redirect-url.svg b/diagrams/docs/use-cases/v1/UC-US-002-redirect-url.svg index 4d02e02..e57e8a0 100644 --- a/diagrams/docs/use-cases/v1/UC-US-002-redirect-url.svg +++ b/diagrams/docs/use-cases/v1/UC-US-002-redirect-url.svg @@ -1,4 +1,2 @@ - - UC-US-002: Redirect URL — Sequence Diagram (v1)CloudFront(API Dist.)NginxRedirectControllerUrlServiceImplUrlRepository2. Cache MISS -> forward3. Forward request4. resolveCode(shortCode)5. findByShortCode(code)Optional<UrlMappingEntity>6. Check expires_at 301 (no explicit) / 302 (explicit)7. UrlMapping (domain)8. 301/302 Redirect — Location: <original_url>Error Flows: • Not found → 404 NOT_FOUND • Expired (expires_at < now()) → 410 GONEEnd User1. GET /{short_code} \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }UC-US-002: Redirect URL — Sequence Diagram (v1)CloudFront(API Dist.)NginxRedirectControllerUrlServiceImplUrlRepository2. Cache MISS -> forward3. Forward request4. resolveCode(shortCode)5. findByShortCode(code)Optional<UrlMappingEntity>6. Check expires_at 301 (no explicit) / 302 (explicit)7. UrlMapping (domain)8. 301/302 Redirect — Location: <original_url>Error Flows: • Not found → 404 NOT_FOUND • Expired (expires_at < now()) → 410 GONEEnd User1. GET /{short_code} \ No newline at end of file diff --git a/diagrams/docs/use-cases/v1/UC-US-003-expire-url.svg b/diagrams/docs/use-cases/v1/UC-US-003-expire-url.svg index b71e907..ac938c9 100644 --- a/diagrams/docs/use-cases/v1/UC-US-003-expire-url.svg +++ b/diagrams/docs/use-cases/v1/UC-US-003-expire-url.svg @@ -1,4 +1,2 @@ - - UC-US-003: Expire URL (Passive) — Sequence Diagram (v1)NginxRedirectControllerUrlServiceImplUrlRepository3. Forward request4. resolveCode(shortCode)5. findByShortCode(code)Entity with expires_at < now()6. Passive expiry check: expires_at < Instant.now() → EXPIRED7. throw UrlExpiredException8. 410 GONE — { error: "URL has expired" }Design: v1 uses passive expiry only (ADR-004). No background cleanup. Row stays in DB until accessed.Data remains soft-queryable. No cache invalidation needed in v1.CloudFront(API Dist.)End User1. GET /{short_code}2. Cache MISS -> forward \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }UC-US-003: Expire URL (Passive) — Sequence Diagram (v1)NginxRedirectControllerUrlServiceImplUrlRepository3. Forward request4. resolveCode(shortCode)5. findByShortCode(code)Entity with expires_at < now()6. Passive expiry check: expires_at < Instant.now() → EXPIRED7. throw UrlExpiredException8. 410 GONE — { error: "URL has expired" }Design: v1 uses passive expiry only (ADR-004). No background cleanup. Row stays in DB until accessed.Data remains soft-queryable. No cache invalidation needed in v1.CloudFront(API Dist.)End User1. GET /{short_code}2. Cache MISS -> forward \ No newline at end of file diff --git a/diagrams/docs/use-cases/v2/UC-US-001-shorten-url.svg b/diagrams/docs/use-cases/v2/UC-US-001-shorten-url.svg index 9f26a84..f4468ef 100644 --- a/diagrams/docs/use-cases/v2/UC-US-001-shorten-url.svg +++ b/diagrams/docs/use-cases/v2/UC-US-001-shorten-url.svg @@ -1,4 +1,2 @@ - - UC-US-001: Shorten URL — Sequence Diagram (v2)NginxRateLimitFilterUrlControllerUrlServiceImplBase62EncoderUrlRepositoryRedis2. POST /api/urls3. Bucket4j check (5/min)OK (pass through)4. Forward to controller5. shortenUrl(request)6. Compute SHA-256 url_hash7. encode(sequenceId)short_code (7 chars)8. save(entity) + url_hashPersisted UrlMappingEntity9. Cache warm: SET url:<code> (TTL 1h ±jitter)ShortenUrlResponse10. 201 Created { short_url, expires_at }v2 additions: RateLimitFilter (Bucket4j, Redis-backed), SHA-256 url_hash for dedup, cache-warm on create (TTL 1h ±10% jitter)Error: 429 Too Many Requests if rate limit exceeded (Retry-After + X-RateLimit-* headers)CloudFrontEnd User1. POST /api/urls \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAAC6QAA4AAAAAU6QAAC43AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGigbk3gcgkAGYACBLBEICoGEOOFWC4EeAAE2AiQDgjgEIAWDGAcgG7NAIwPlXBco2V8ecIfiKz4AtbhcceMOjb3U1skPt0hu0biYLuOj/YxDj4QZjOmj8GSEJLNDNKf3//n/qBCDOGIJUigacSwJBLyIVyiiVaArNaEtFaM+q/k2KjapqG6r6AZFsfx975CNe05QCIOPWSMMwiAMhcJopE8/3t+vtb26O7RTc54g6YbeiZQk9iVzpbPvpbpMqssMR7j7icBe//RV/oN8Ju1Ju6cFtrwwkkzrfWBYpuORdHmaKxDVYIJtDj8/d6zN4VqTn3KaL1011zczkmVYsCw7WIiT/M2W2VA4+eOpxw+cXJ2r0BC0LBkCbZw4qQPLWYKR5kP/A4Tj/Ptpze4/2jrmXxlP6eqEpLkuXDMmebnc7Et2OyWF7hK3u5TsokKpTagTdkMPPfQc17viHA5hwFcjuzoJDilKE8JgLEagPCqyybpBwBsumBS5bLOqLGc1zeSCbwSIIa+OACAAUAmIhxGQkJDfRxBICDNNkQoktUOmpUfY3UvNAqLTjsaRQHTZWDkCiO5Km+uACAEAQJNIt+eNWyQmFAZGhLcrYGCEKgXevEmYgn9sZUn5vtg/LNhfgy/ddioj3V+DzwSNCmfAN3m3lTcMYKI5WmDBElnJBesyK5v0ZbumUXoAWO/gY194gCSsFZgoVkPKJf+wZWSc+Ffi+42vrIbphwRig3JiNU+AoIRdzhzYBCIcN+jnu6CEYL0/PZIZwBHwXY+l48O25hViDR/32ODTqgCrz5BZNHs/CGrBTfZk0NefxLcXl9uZCPgIAu96NRD03b2PijO673hEfGwATLoSRA1DREEnJCImISUjp6SipuEvQKAgIUKF09KJEi1GnHgJEhkYmZg5ra5K4BCAykf6PlCEMhydcigI+wYsdgBZUykW4WgEEjg1lBg2aQIwCQlVxhGh0/jgJZ6VAxmYSkD4zAuEgDYgcAATRlRYv8hGgKiIIIJUEjIKKhoQOMJnqhwWNuXgBnjREX5AwAh9CKjywEcvsj0LDZ4A5EFsj0j+Zma3FTTtB9Z3TR9v6UyFnrAsJOP8moUILGPJFk4wNs4BUkAoIrySISxSGJcifChKRGEqCgugBCH5MWHCEWkpVQTFxVGiBEqURMlMwFZGIaQQnMJIFEamCAuBBCYy7HKAhowISGUy2pDKXVgQ8jLQaAkIDo82SqHPF0SEnHp3XV0KFI+NFQb46ZwQe0ECvIYLTnmsztqkRBIt+qDAL/Si62wcvkXIE0VVEop7uSKkkxjhIsDdaQQpkDuUBBKVKgY4QqYpJCrAToKKgh72ihuzaICPELBISXQIiwS+CZ1CdFzk/OlAAAhJUzHGh7dCQShr5kIRm14uAFJ2RUMHInwB03YCiAua923pYIBsxUVa/wO0TJrWFQCripL4zCYk862BSuRmA3aUYLGsIAPCZfHV4iRIYuXg4pWrWIexxtu2qg2KwOteAaMa2KXw9C/1KuwOm9ViMhr0WrlMKmHesyCgQ4vgPgXpvGC5F9R5+Tu5whcB6o5Dc1XBpuDTfAR8mw1DVke8OfhyahjMD01TcxBAWAs6wvBedCw+NSw8TR/oy1YrBOG5WcPqQiT2GIGvlqvlGxHv5Rn5HKfJtyltWLk3vqJIGjhUPtqdkVWki+RqBNEJ9EBuZrZJJOGrU/39mIS+QYxwVrS+IMWWUeDISY/wIyep+H68oKKsO9sUZI4d4gl0xT6ffsHLrs4IJnSZBORj7ygZcd4qNvQILct+2hRqghWiPGG73ys9v0lk+4ruEtNvKL0/LqJkwvlfK/U6mI7wmSeUraD8LLb5fnZNCU70J9kN8rmKlVzxF9oizwUclC+Yh0/tNtyy+Gp43e2YHbzdjGNQBKsrutK2KY+eqDu8VFIUEUWNL39tSZW+j+bPQlkpJHTZhH3WXRIlk1jjcZ511WiE1QJT/XGW0WSkxpTfS/Mp7jRjMdZSwSHdP/jgKkwBPMbnRTLxUA4CSZOPl04ji9XfQOYrmrhyM6klqFqGAd4oKW1/SOf+nOLi201fdYSWcHF6e9kzMZmmCYEEdySY6RbFYXEkypU65dX6KuW6TbhWp2OkMJkODljc+lPtBKvlWWZE408YqffoHNO+F4vymMf2AfFwMCiaTJbq0/HCjYdcE4fzgyKOaXXn/+/IcGWu1+nrrsZ6Phky0H2WtUJAsNtPP5mV9PbPpLEpCs1XMZvaAZAj0IOlvvpMghX0oPlF9Pr0vgQz+BJaMQuF59mzChCwxEiUKfn/lGvY3bg5VXcoc53rlLXqkNLIFZxW65VWmDVFc9ClI/6BGuEOn/X2Uls3rkBr0ArkQKjXUzUswwLzS2z6xsmDT24slaPM41bmejzYfRpkJwwKxzzU0nsyZWEgQfuAlAo+OKxA1L5zkLmMcj3EXx+ahriw1BO1H83ek25bFok2debcF98vZRJ8uDIdj+f4fIjT/fDo3pYc9IO7LQZpfv4ZnbhbTXm9YG+GNBpRynXl5dcbXpnVNau2tCr2+XhnnB/KdmzTKJ8mKFcn0xB8ZS8j9YHyUZNpxfFIy7dkkhGeyoE8TIg+fADgBY4QKHXCItteWZDFFS3pbRLtaQoT3tvPp+e98a8eRK+P2hkzY2ZmEmRGl3fK70vbpjGRqqQujzNVWsZ+PuZWl7m0KYu0gd+Z6I7TWQMHsPAGyg7i5dxNS+2fbE1uh3EL9laq6jRKVZrHfJwfaDcdMh3B3BqkLVjYOVtYIlUcnvy0FreClG/7dq+uxiu1bvuAZCyLQdCX6Trerpj75Ly29eqKuUP2qRzpafn1zjeZi9yuEg+YBJnjcR7u66rcaf6wWUWoDwGTWzVfaXty8KEpWBQdoVeBzLWK9TnVp6SkaFOvdjykx3e97GF1IjtM05/i1E9bqFHuThpBP8haKkYMFUd0zeoS3W1D7RGDzvfCNHEaYr/DT2ikIoG2pKUSsMULGhXzi5rwWOfTNh4ahy29dXL9WRzxhQvNyzD3ZXIbglAc4QjdAtZU3zOn8Wo9pdvtgWQB4TRToO6S56l4pPnpRQoAG4IIvtddurnASCWwAegUzHZW0UQ/J8eltf1LUe+MfqJzfNYb6XmCHCOAwwIGhmMI1DGPNApPlF42KGvLqhE3UuXoAY35E9voNBqDx0R3rZrSmMsVj5p+gXSE5wo5fajdvos0PgTzIxA91dCbRMa01DAsbSQgHh4fg/EbA2Iy3bnQJeY7e3uqXCVjvak6cgvXHNhYYwIh5ZmmickAnEfAUKCm6wD+Wg39oe/T5vvumosMJgzQrEAJIpK1u2RTz5F6789+UpJRpENMVzyoVi3LIpnoSpsWnTS8LWWmgA1WQAMXl6L8lBUs5/65P9pRS8ruREmYwRALKJ44rzyP3ujeQWkazV5TgU8gen0/SpZc8UH++77yqM91miukED4z3nCkhS5Xk0uR6O1g0AqMPlgskLDiCYu7jWkRBuuMZioaZ3+IVlO8ultODSB6uxaJbsKTukcbjVK9xmKkcD3FxT8WhSKMTkBQkE4Fl0LUf/e7TsV8Rll8LYlOXy/JIxyGcoGFI5QF1NoZQTBjOtbpMFddvSImKfZ9Oqdq6D+gfD5EnP9+HeEbdbBF9CmUgOwQataTIz/nPHXnYvt4Tw7TeCBdCzAM+spHYcmX/WWac1QhuYAwY2m8dcuOA9IeES1q8aVvJJ8s+dwDkz9EqqyEyRHIlXAJZUYJoeaIhMK/JxR10spSWtoEZGBYGg7BW6nZgLORxso5RVGshBoaLhR9kxmpmyl3SnXd7tEmb1K5KbpyRZQ7ep4LFwFZQxEmUufaTSPXcBGS+9J8Ujg7FheGEKw1GNC62wArNVx7NvV+J28yrlZRLcFAQglIltRneq75OeUezbHPvm2b2E+3ZGy1DKNalSAN8AFKYBRFqzVHESauGsoz7eVNOGAKAN9DaZb1VsytClrQ+CQq/UIfAl5Yh0FmcVny1Fa580LnuXxdxngQ78a7mPBJefxNdRrT9EgZzv8Ij4+vwaf5f6Wv0fUTxyNGi9bH2KpABHZZNusulNqcrrjPVblkkT5dIqVY/zoDdJpA+RQpvVqR7ZkeJs80BSdI/x/bJNveIFEU01FMkkgKdhkMZvYNq/CdapY3cJkheyVSx+8w3+Fq3DYMUjjtKGTieltg5vRFWdd7VHm4Th1MIQ4XlQLpOqagCLFkmpcor4rvwrxJJ6Q/x2YHkeniXpigdUyuvFVKsxPv8VVO5aa6pefXZcFAGPCO9XcZPM2ajO7WthNZidh31iBwmrI18TcQlUqu9MnPuUahdidRbAlvLBasAEtawSkdj57c9FXRaXRlIcFVDATTOpQPdd9pHUwXw5NObljcFzFL2yplZKRGZx5MgkYoRUUJde+aDkzmd1l6NnsZR0DHldcnyTAcOPwh5zr7xSfKSyU7vU0WUQbaBlSu984UX/0IZP/tUTT2MUVqVKecP8qr8+FQH/+cuSepTChQ03QFixTiXjw4JrPYZqmiqMw9nzafq/EDbYivEgp/nypTKdwSApT1xgczYOAMcRpq9XpdCV/uKKLpAP7GUkb2xahHlznK7b2nQp46iUURKWnRHYsuxwtqiLjnjya+B1XaH39MriNMMqany7VaYBjYuBMehbjAZ/Eum7m9mSnNiYyo3FyKaVLWWwi7M/c+rVarinnoU+V5uuJl4rcz5BoYDciqaRhIXomIBlhHx4UJB7Oo1hWYLYfHpYSrklPHLp19TFsy7jawsnbWle0TLUWK8tAvbCwwvsNkxjgmV8RoYZnDyoDri7JgE4hBhlPAH2dEt7sWdTIqmQLqSyZMRltbQ80Wd96oejzdeLdL9Okp0UTvUEYqNzy5jlOa93qZizN75NMbh4MMLDiLLh6Gk3TSwQTOua+bVD39pd9Umu+n/rm+5GU1pD7hHxN2cGIiwankQUvykA1YGlpFE41pp8tHA56J5QlSRfJMqKeYeBzdxvjEzKwFVRpRyXVJ1h9GFyG5ag3tH/YnBpPDyiWVVIY6Mb/sGYK9tu0y2eJ47sZSH83DeLjrWdhWsfhGJpPgUzQwmosmdB98dQeD6gEpp9Ny/+YbJzyfH3VyoSsHAC2LJEQfwOzphGi4OPwoDfUOdQQxPyvCmCZRpLqVxnmoNN/uvM2b9VUaczHW6QiHF1uiEDDZefXlcCvEIaDb1I5Kp3G7vqTuCVK0YmxL5dzyJn+n4maOr2Rkg71rJPh4JRA2wg/mn6zmH+SKczjzgW1aKjlFZHrLyyg/U2M7AQ6D7CvtIQvnpU2TMhT1NN6na0m5/814gYe0Pccaw4lwHQgyukuyGWiRBSvYiIO95C5DgRZ2HJGFBGnnFaEbKsJo/e6esnY3lugNk3S63tEUzfe4jvddJg/y/n6U3OILB0i9JUBIQPT72WE/i4AGkp0gRYo/8VUtP52sN3pMttDdnZiksQKZaRQrk+ZhwGAyjxJMaVHWlmza5xtRbCu6/L62bds0EQP7AkR4oeIcqdxReLHwi5JwmR+wfZ9kK2o80sg2oZiYXqMG/M+MjYiOImekxnlSRNNdx6LhCBQJWUT2L+9kQ+qY7pe4mUTwF/h4Ucq21bhUMG252u7UrYhEUeTVPbyXKB43JnZ/OOA6j2wfKa0QMXpDLXi0k/HwwwJJz/GwMJgtKRekLLuWu+lZbJriel3kFfGlJOJe1vKXRRh6QqFNRcekHazUNsQtntrkl2KkcsLEbRLWGTPCsNlUCLA4i+ma6MZIdfCrwcWL0Dh2oKWTzpirO/o896wY3GHLxdgiWWFYsTbESMJAnUHtZzUMDDBtokXX02ABK6FZkDKqV4juSnDd6ZgcZH7hxpzKmBZlDyslFERD4J0dyr0eHc+xt2UqhdEWTSEEbBWv337ZTnb0Ej0oHyAVvlWULeCgdaesOA/pmn/usDQBDGAAuzI6TYG2cPodGvY6oSQZLXETEX3xSf61aIGfQZe9P4te9wQTLIby4Ac1XdHozru7hfBXe/n0d2YqWuI86H4KlyaM3VOyN1qoLOXda0j7GhLuFV5FaZGvjdD+fsmn2aZNXZMs3GJ49MOLhZMPbjpDQcBAgjbxZtkvTQD7sK6QazhG+TOcxtaSUqLGpRsPkymIYofr9GpA+/veOVI610kWkdlZaiRZ+GfFyltWsq7Ry8ItY9BqATp4L8wVhihcqu6ishjTP6+oZSxORsQADIi2akSv0p8uP2i64/xQoRB/mJ/7+e/P4wMrpMBMrSpZQUySpzMgve8g1thUXl2HSfDwQxxUoN3WycDlsIXJUdc6JdFGjYssuvoy9yjvo5Ta1SbC+iR5JlLjFb/dr/qKh9j08DAuoLsYJnpZLIJFRjemymD0dqJGZD3W+UQp8NXQ7WDS6NY7dq9O49SLcdYIVXBCXF2EIIgBgl6tFqH1L8ZXoo2N2GuyJlaqtWRLTVV2sOOECULc26HNeI/GHyjTdV28rZCyOr7Jffwqv8G2R4dxF8nxofQxWcTMVHV5gT9hrupal5x7m74RpCrpyxS2ImplkHq2r9k6mzaCcA0YpC0gbpPmMCaGINK61RZZo+iqZIJjwKdg/lslU9HdKcc8dSpMGNsvRUubXO0jhYcyZteL4YnGfq++U6lBi0KU5jZuyZstdKyagy57CQ3DkYP0E/3xfnQp4imKRqUagLdPWTJ6AXHUPR17nuqfPRnnkc/K9VGKwyBtGMsHTRx2OvjopeDDYSJsZDFwYHKxONA9XCcI06ZYY7Wdy5Hi4/HpKTlObpbLXDPEw9O3MzoioxWa28GMR0cnSm8xPmEC7WenkYNWOmsPsvRMl92LsvHlpGDYH7JaDA/h1oTnohwf+3o+RBSknTPO4KDVtijTddTXS2BRLdGEICh0MB3ap+HY8gdhdpDS//q+fYFGuLyyQY6g9e+1yVciUX7iq3Fl90RX9pCvPOy8q7X9whABeGBZkgeyI9YFR/SlFmRWdFeUI6RuIzVE6gFSvulpc08QUjYLTIJbP1yqasnyCVJb6G5ATbxdqE1Y7PSy4jFZ8eiP4GATrD1Ev/nB2g886IpNV4L+6B6hl5kjxXF9nnDQgNrXUPLWPIAWSh52z/h7avxlcxwCC8/gxETP89Z9+TS3kTYZz6o/YdcTdRX650O9ygx3Z/4AVcjSRur4e/yKL8hC/eyHXq34oByRVsD/z66fLlXCaBOAIa37SiffERqwiLXYPB55TtdMO+8h/1xq7Gy/4daCcge+uncL9+zmWM53Z30ZaHBB3KicBZdmRo15sPocZxTNEIynuCelVRQVMkhnucGmFNsiBm7xcXTubxihWDD1mKbJM/Vn3DHSK64q7Yi58a7PabYfvArSTxivPbYv+uAlp7B6kg960vsMajVrWHciksi1Z5ubi0fuS7LMIBlpJeb177cyD6f+yVx07Ltp1C4w+gT+HuMQIdt0SLVy+L1N4n7cyFrml92QPf0X8zfAYt7ZJwRYXS00+npkkdQ8Ul4uXETKlYb/tC2rGnzCdHKOzjWxAvYvnruFS/jhohQ71X1svmpxdp8hQrL9m0Sc0reA5vDVobvRFkpeUDe+meKRYVePmv84bZIpvmcZIlAXf357d3bWWKDlAVECXqWIDKArvEgPjczV9zes8dyXUm8iQ7Zv75yOYYVKdfZQmIrAVchM1t2/WWsuvlefthWrB6WaCoxuq2G3EvcC67cPCiISkCAsjJuUiuokBArHP9YvgHa0KZGHBHDrmZymNVBhTM13esAEtRdZS3+QCuxvBdyPW/H7JavXlB3Ju1fVOZ9f4j/3pBnMUHeuHKXgp0Ad5Y81vRmU4uIjIHTDjl99in6aQlg1bB4sMoOZv+ZJo1n2xn97N1Pcny5PU+cExbVYp488HJt/VhtBBJjkQ5rjlnJ4UcJUCllQENI2NmaxkcLSN2dZIDUR9ahdg9aLV+Tu4ElblkeW7cwq8ks5CzYF9osU4eEnF+1Y0Bk7HR+GZ934egT4sDgvIDM04Atn+1Ow4OpZ5rDgSU3EltV7PnclhWRuzyz/UtGLkqO18/FbuJuQQUGOOToIYBZx0esc3s9DrLvhBXPXTgULZnwzzHr8t7h/w4pT8wuVEB9SQ5Eyj0EfdUAdXtoYfz5bNvTurmfHPlTmjS9N2B/05vrfhti2OnTeogJfzmNGRN1cQi/KPD57vpVbTkuFG90gFEYshLLsWv69MkSNJWdPLevOVTxwcx1C7cniWOOZNQ681OKZHtdfTW0cKXaqbkjq7EiZ0Lk5Keze28SSZ733/uU6qGuo+eTa/TXxsRafsgFK4wtL2/3WWmJwtskiAjOVEVciB+8LqCGUkcnrV2dw/2qZmy/CAdQ1pKJw6qaZ9w/NjNAfSE4tQvsZVO/W8rlNMARBTAwJ/0hoQvub/GXFWAbbV5F5mRe7W8WtEDr6tmxkrhq4BDPhWRoNf3pwMMbXgVdyzoZyH/NuZN3loRWrS1mD/22GjF5zgd6QmSkhZivbf/nb4vzU3iYQnrjgTWAYPhN8guByCjWNQICHbbvCovatSSfbjTUjPk4WejK5LwIUe90O1J9JqKSh1/wTGIZ6ppMkLGtekrJdfrOsO5MHyh6F53r9PFIQzzNC35k/fuRO+0XiLui0JOmqLNldfTr/eIdYSUJ/2uJXqcsfqc/mZb47pKWoDB5lc8Jr6cVAa6szIg+6uuDAK/MLd2DLsa28GPdOG8UdeREo+WC/7DgQhhirXku7jhcz5f1HgiQMRl5XNbZAnZabmJzJ1KjUroCwiWS2P/VL/n4zIcLXC2chh74/1EjaJg0X7I6r+kPtmc2JV+ucbxfychkBIxErNAUZB8w+UrMxJosHm1oyvHeBleMsXDejoM5WIYvvIm+78s9aTn2/5IkEaV6n3owm3dTkhWuNcNxansEbIbh5qtugyihx4GfY7RYrF8L7f9AqPE8KOgdmwakRbdN7CSvfcMIKwp/h9YUVoktHWfPXQDfhKloVnhIgH7FAvPgXMMgpGQuNkd4lQcYRUWDf+oroL/1bdxaKGeQm8unp+U6mt4a8XzHTiROxMzPgkRDG/0BgOa3ll1t3F+oP/vtVCtXWyAA+PSAiHVIlBnBywFhi92Jh0cvOeCbteTkeDFk6YPpk34itQali340MzU7STySoy3a1U88H06CBDUqIlVMUmOuf41IVH1lOa6nZexNm4XkFW8nTVhZHqaZO81ru/DsBfam/+l/RNbPv4dgq/HvQja99WdvLQVnf0dzujW8zoq+TaDfsUR74klcRkf2gfoURU7WWl8FMSl/R/M6quW1LZkiqKmK9adfdpieKr8YzQBhJ2/Wi2UE9JyEv8kILzFP5S7gU6gMsYn9FxUbmJiXHdWFYzoeW/ncrQy2mz9xCqBsaXb+VewDgtQylLwZBcJloCR1mzzsyRQ1RoO8fayPTWA6UmMVZemo99h6rlxmbruys0IaBnLDPctNNbV79CmACRn2qGcMtqF7eUp/6+28JfNLMDuQwfYCCzAJWQl2FH+8iGWET7847agpFI+HbhhTIFdFI68jn2Pzej8zCzJMchQZfpoZlZO+PzVq2t95sRF005rCu+QGvVRE8pqmK29FmQxSkZULm0lgJtwIZ6/zYBfd6tEc9wuQpPGtLQdyX5GYSxQ5fAwuhhMkB5/YavSt5tQXzjfkGSXWTDINbmQT4gdzyqW6i//iTGfBvohoTiwmgCzstNVkzis6xyIUv33yw5C9Od0UZ6iS9APFgCxAO3ertELa7O1N8gEP+D3FfT8XF7fBWV4Nnxw4MZbV8ya8mW2GygHjYRjoKAWWqwOW/fegtMWXtJ5NsqoY+1e21eqxK/b7ia7a756+VHLtv8KtgzWSo2qyvxq4iVyVFsK1eHHXrnDnlPQV1Etw85CBkSILyCUaOo86pIWUeBKup3EFvtA6blYjnEU1EPM9bHHkf1Zs1pN1M2znes007ew9v7hGtVg9Z1Lf4NJocc2KNTr1tNMEqWGfi7/yvEq+urwoMQYZJzIyt5K0DpiN/VQ+57plAuNIiyBCrPcq9XXbCxdIGPeznwpgVLRiajmQxLj5NGrNx7mzGuZJTeWs7R7lBC3NNKhcroh766sR+Wy93tnpw2fkdDJ/1grE58ZePbt+7McvVQzttLZ8Ndy/5MzmtglTCKSHBo6RKM04RDhHqXj4poTdc75GrkRIW/siLDfsDF/+8CWzN7ia51EiJw4iOUf1pJXOJmP5sU3KNiteN1gT7uNqZisKk3HBKHuSBBxDOOuYH4chGIp1kk/tCZoi2l0008sDnMMl4xC4IL6h1qWIqhPwfT0AInDNaDGXQSRZxYAanebsM5Aljxs2rFmaFbmLtszAa7I/oRDO5mc7amRZFjAounZjKA8zs+m0rQ/qzdGfn3vVx3PZcqlZv/xvjIKIIhGliIpAZ6pa9qCfqMQJ80jWSxoLmH47+AQ+YXnq9kYtqES3KK/NbBILACo3r8JVNt9pPs3YZMhL0/lOxq8ZV5z2rpLD4J3gdeQmaCiWbWye5piYLsgrsm6e9jup6HW75XpiSjT897BrO1fg0TXq1+YFC9QfBlJudmfKVOVf+Q8gqXuuFeUzwiUnqoW+rJM6zE8JeObSq/Oh2nlMXPCyEiBVDz/pCKZy1NOeGl7nvAoskHFJe3XOVHMrHclZ7ZnjGA5a4agIJGREGfrefe/CH0/Ux9gdO6ZJQPLsZ4IFIp1lgKa5rylUYhoTHQSRGttiV0K+wgv3yU8jliBJe16KO/vQUZSaRZy40cXp/fUDBL9mmHofHqdRJD5HGH/xyCvqwXH49HxAa5/Uz11n2kPQQ2NaNj4hZxSegtniQGiqe8Gp6sk8+3A4Tw3unBB/1MzlHOFwfJ0E2ZxSvmTqnlHc/ldeqGb+4uURjPJnPcfzGzk3izSbOeHEvcTbMsyFoGrFVOX7mvsRlxfPvayzn9j+ZrTqtaHL3wNMv8A/kkzSoU7kDxENFvcXMNP+e4Cypvay9Owgq4nf25vElmMkcpofCiAuVwhSFvaooLdTj58ylayynS++1C3SnxeZzwTnpcztE2nrNCGjD99lb00J4K5LTNOHrqjs6B96CKk5RKGQk5zvFs1Mfw5kB+zpiY6NFtF3e5V5sOTaKU6aaE2wdxtuRAnKsnx6c8qkYbVTNivRJjRcAGQ1LTpkHg21T2U2sB/r3R1oFkwEFWN0JW1iq+eFrCYZ70cq7gCoqg8liMA4iXoq++bjG62pKtX7hyI/93yc/H8uTnf2f1q/+IXx80M2QKAOb809cLpVUR1gPoynRMhmH9xb5sZTcQtwC2w5AZgWX0eQ1vCEElkbuqkpBXUoX2qXMD/Xaoq9JGD/t+Px8agTluhHtwnJ7kly2RPMSNgTJqjpRZqClEgjhJjhdsfGHAiUz7J6mTwf98E6jh5yk53P7Mi067yj/sQmMKyu2Nri00Fhk790ZnTbQOP+L8dDCsh49BZ3bAxdCLk6NdvO4qF1pEjJ2aFmKX9Pc6OT0ycPeGxJGVYJtQlNkJZSOcginwuiFWpeZmQFNaPAd7I7xGAnSL2WBfZmCQlyPVk5GVtcz0XqyHbrnJARjVrkfEVrCrO+vp66nclD9Az36HM8BZ4lk0tI1iM9ExQHmMRCGSQ6n+0h+4+SXYNNHIep6DRI4JHL6m4EPrTqe8dMtEk52+Tl71HXP/ghUPO2lDqlrr6q6HThnrXK8UwBnBHFY8ACyOJDQMC1QSPeGlYQEzGmZ9b56Gt20vVWwC4TWQhsn+yoO5NbMYhM6ln3UeaGd/mF3V95nyVn3lP3RZGqLyUOTigNIqSpFG5Q1IXDYkLff0X3c2rqlZxQnhV+QndmRIwZpO0fkp2NXOUJ/1qvKGznw6yj+6Cm7IlUBRX5+SjYIHUHtYAn+jIS0qIYiv3vurf58F92OoimVvmvhGGYcNcPJDKR40QT4Pew4W4u9TaOdRDXgMPbA4KOZNfxqhpcXBAVZ9oVUKObZGRk4q3Zp7J+FBbMF6QJFgc8segbhK0CDyzZZj6iivucb/E0NWcYi1hVoXKUdacejnITI3twd9YRaESBTKmyBzjBSIZQ5HssS817TeMNvsvrIkr9RxhQJYybi6lQ99bUv9QtzKWLrp/WlRunyspknxpw8kcWyvXu+MkSVQfrNetv7BysfFNIGRO5/y5k3vmDWujnd/GL/p/oT8qpzyeoTA8j590PPL3w275+AqAOwMX7d24ivadD2EWhjFO7TXgQ2sHWnrm/+jLkTcVLGpDHp1HvOgCQERzpwTMuvSGczh8EJe//2iPuigEtNHaHyS1PpS8NzJGK90/dFNM4d9VpYV8ewOY6ciFpXv0su+JgTkriQ1w/bSFmVkcA/+6iqaniSO9Xn3/KBBneyhuDOQ/i8yJG3T9E3lqVO4nSduGFqVCu493tcfHcGwRhoVuY/b0Ob3hvIUjjzYeTsBh73j4jqfrCNPO/TlO7AMTy2qXPMxjzeRKUfc27cDmgEX+ie7hO1o6m30QWP3TDph49sdKRu2903pUdVqzOhVm1cdCMtnWg/f9wxjvPxQl9SMHjLE5t4qzUCYSsRJcZKJlLwm2mA28qxxuSPWqYXppcK2AfM8z8qEHC9m5Q2jE1ww7OH6OKnxNnJ0bk1H9NjbAClaClo226L679/R1gV5vh4xw9V+1k3VDIjt9iP2LoC2dijAuLY5Rl+tfQ2WcWymyFPwT88ouZicKOAYXp6IHBElKOGRr1MEUxVAIRAC4/UwilspADm078FctBY47ySrRAYPI2KJhLeJuOl1vx6TySfL7dz/XJXSXKDoBi2pQHMOXT/s1RG3tBdymG5PAv1UyPGKDugoawc1hSfP9cBmlSMu/BcXCR9pjl2hjdq9IVQoiIcgsMDh4PNKw3WYF3xIhffLzLL8MOAj+rEqGYfZjdk4gQeTUuPyEu3u/fx6ZNzaZB5SITfrhn+H+iRtEK6/Sf6p7tLI8Mv+/AzXuSDjeJr5ZaZBu3jDVQWVo1g1k+Hm11HJoGXJxJL8h3Swz+fm2ChG6/Drf6lFYqgvRBMxOAi3eUQy4kp/yMjAtjEDlwajYyErOTZ2t0qFM7AatUFSmiNHXRxBCduQ+N9aDiZclIEU06HdPAlfvBEFLGRaaG0ffhCB4RYZFvW0sacAGPAuhLVSvhtHJ86r6A4evnXB7mBe99zY5o4iZn3rm5Z4Bwg5kE5v0mXaahth7MG6/rTQ8fB5SRdprmdtSJjRWTqq174ZnIOpQnWgSGpkcUzwA6YLGRXVbMNhZrNdoECI8oNMdEeTlh6Q7/5oJ+DslCKpiEkpulv2ZHhwfQYyLT9kjJ7tPK6Xr52+NwR231tXrYbOQSJnstqwE1CUO2vjq+E2uFBtZsNAYuTnVOTT0Raf04eNV7yvrJeK0sJyOY7Yq0Uw+pqSJEVFuJ3bD8ra56Z6B9Mgcij/t4+AixvrK+/nv0Ly99G3kgEVSLIU0gyT/z7FMdCw3tbfLX2/6gTXtclKa57olYQSHCPHB8eVzF/yZBFvyaIeQ67NWuz+gMlhbFqPH0MWFr2NGVXATWf1oRkHEsX7IIDGg9ApZntfqg7dgzrCdwdeTsnFedwMAqMjyb1wDuHCpOIsQ/BH9fuZRv/g8QEQsJX2EoYHQxTHUN6wRxlL93MRbcpqIJIBQ1au1qwfmZBdzEXJYlm2bnUTbbx08gc9XTQyKfNHBq//t65RDriQPiwGRgsnEvq2IgX0nXb9BTJ773RraEr04xekSHaWnZejI16UqjKRGE58o9uh7nVzvNMRt1/72z5euXi5I9vdnj/yY0xDruPsxrkEyYAbuy5AvX53WrKWA3Xnm06fJUk3VZ2465pKCeXOhBbvbeGvy7MH6mvUuuubzOcW/8j6Cr9aGVuExRZGbHkjC2i/yujtG9dOwzfWdpqx9kILdzNA+duufUlY2PSXA2yCeA6FcPjDNOeTqz08cBJYzv8ZOu290RHbprnA1koXhoW9oGj0HXZEFkYrFLHhXvOlAUcIUkPOqskzoDYv37GEULJWro8PFgTS0ik2f79xs4Dt3HWkX2nYouEri1tAmkXUEByoHK9BxGISThiypS9K98++KbwyVm9QnS54OLjTGzxNhlhIJWB3401tJuzLEUzY24ZNrAq5CatAcPBcToio1ww3qvpmzw6Mh5aDmMaGitYwcrpxFtZWUXS8VZ0YZApJ8XQWHVfgzhM8hQsmC09Fla5XJe5fehDaJX3n1L93M22hiinwphkPX2P1yb2xNUAe2J/xtIRhNqU7owqY+yCvH8qs+/2hvLbsomEhl7m1B8TMkv1yOpmj3GoaeGi8bxLTJZHZmEPgRA4yLy+qiBRb+Hx7bGsDlnZxcgvIaLPA+7uBXPyjM+ZZJh/bLrJ63MjHNxuki1Uy6nDhs7+KXH++avWoXJh+SVxwUhDKdku6Axgfey0YcF/IyX0ENvZMUvuXsn5NjSjmmBOmJU5zkeiSBuT1BD1Go5T1/tsTfo5IiaOlKQUkYHn7v2YqyVdago75fb9f15n5dKh9mX07Z8aFhzifrcoAPO/Uc9c9vTSDw9ZnkeO/r73lGen9RJueIEmS+taXXb63LRXB82IO6n/0+P/FXlBO9IGT4bbBjLTDiIwFDTjKcg9o6vDPH7RzKBx0WExoV245YmpOLImJlkdEhPsqSSMjfqrqUE8hXfqDkNIzxGCpWdezV8Qlnkhvkp4+ZuZuV3tNI7fZZ00w5Q4FovyH3Hd3ebz0RHiyfEFpl2eT+qmqIYLPHVPoKLNtKxbfkvcDetm/MbkROtzy1h3SPiPtLrmNUOP5FCQclor+Q2ZP/P62k7VU6Jzn5wf/5MAcbEQI0eci5XNZAH/W9ALVrTcMUrqRY+0+pK4XqabrDQEhMjQC6PFFryTyELEvDAHoRrFvCR/RuIDCtRUCoVn68mMfAaJGcX27HCDhnmnObyRVN8DfhgXoh0TMBrqYfXPxcwQ+fYYvJpHJzvBnZ07y4cilJyUyfgZBvs7Vo8K1LPeSPJ4gTbDnP7E/kUj+29ZeMoU/xBnCNHKI7sYPJ5j4k83hlDmg83nO+cQOif4rfUlIbdu4WgEKdl4lGSEW5CzWxXvMCgA4ayu0pFyoBm0rTmErfTm0WenLX2Q1dm/3HJQgnL351EscyvJcfymnfOgka5PUcfa7zXhKprL89Q3a0s3ZgFzG49XuLDMN7Fnt3Hcc+/ueCdqIX92owqbA/VLyHDemfnzMmOpD1sfMfNiUzTj51XWL+8fQe59XfjV4IjZ2Qbgh+a1+Nt7HA8ZCZ9EC3kKAHDvKcgMAAD33178fVDhYwnP1zsAIIIpCj7tCG+wDe//DW7M0NHS18pYZi6AvPKffUJmvoBoQJqG70BAM8twhs2YDqHFEuZH/A7iV0KYg7LhZHXyKwzcuC5Ti/AhAkMa2k9qfOsA+FeUo/sRrFEBrSMiWiiwRMHJ+VYpLL/o4f0/bu3EDcZuP0N3OatDWssDdV1YzVStRE5PU7Do+ZSsIoEJiecfn8sJLka0d5hjX6jEE+qeqPokRAdDy6VNKCYx/1lOl5+AAkGpJrc0QGuX0DIwYouYT+UlI5wNJGn4Dy3XNuKt+xLPooVjwKG4YrorMOATdLidowepuHwIaJ005Y10fgiE69chMLqtQxBBeoYQqJQNQSVRIZbcLwAW7cqVGqlWldHqNAvlUalay4FWqlH2QmrUZHKTZBmdMNpAjmeztQ71aoQ5JJEY0WEASMThYwQyH4PMzCzeLJNNuqyWyjxZ/Us0dXK9DgNrb4k1EWHADQzs5AjaD0ZVWGZuLKPFittaqTZhCRo2B44koxebLrCyI5XYmmDFrRgCZjbIoQAAAA==); }UC-US-001: Shorten URL — Sequence Diagram (v2)NginxRateLimitFilterUrlControllerUrlServiceImplBase62EncoderUrlRepositoryRedis2. POST /api/urls3. Bucket4j check (5/min)OK (pass through)4. Forward to controller5. shortenUrl(request)6. Compute SHA-256 url_hash7. encode(sequenceId)short_code (7 chars)8. save(entity) + url_hashPersisted UrlMappingEntity9. Cache warm: SET url:<code> (TTL 1h ±jitter)ShortenUrlResponse10. 201 Created { short_url, expires_at }v2 additions: RateLimitFilter (Bucket4j, Redis-backed), SHA-256 url_hash for dedup, cache-warm on create (TTL 1h ±10% jitter)Error: 429 Too Many Requests if rate limit exceeded (Retry-After + X-RateLimit-* headers)CloudFrontEnd User1. POST /api/urls \ No newline at end of file diff --git a/diagrams/docs/use-cases/v2/UC-US-002-redirect-url.svg b/diagrams/docs/use-cases/v2/UC-US-002-redirect-url.svg index 498b83b..10ce933 100644 --- a/diagrams/docs/use-cases/v2/UC-US-002-redirect-url.svg +++ b/diagrams/docs/use-cases/v2/UC-US-002-redirect-url.svg @@ -1,4 +1,2 @@ - - UC-US-002: Redirect URL — Sequence Diagram (v2: Cache-Aside)CloudFront(API Dist.)NginxRedirectControllerUrlServiceImplRedisUrlRepository2. Cache MISS -> forward3. Forward request4. resolveCode(shortCode)5. GET url:<short_code>[alt] CloudFront Cache HIT301/302 from CDN edge5. 301/302 Location: <url>[alt] CloudFront Cache MISS -> Redis/DB flow7. findByShortCode(code) [DB]Optional<UrlMappingEntity>8. Populate cache (1h TTL)Not found → negative cache __NEG__ (60s)9. 301/302 Location: <url>Error: 404 NOT_FOUND (not in cache or DB) • 410 GONE (expired) • Cache down → circuit breaker → fall through to DB__NEG__ sentinel in cache → immediate 404 without DB queryEnd User1. GET /{short_code} \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }UC-US-002: Redirect URL — Sequence Diagram (v2: Cache-Aside)CloudFront(API Dist.)NginxRedirectControllerUrlServiceImplRedisUrlRepository2. Cache MISS -> forward3. Forward request4. resolveCode(shortCode)5. GET url:<short_code>[alt] CloudFront Cache HIT301/302 from CDN edge5. 301/302 Location: <url>[alt] CloudFront Cache MISS -> Redis/DB flow7. findByShortCode(code) [DB]Optional<UrlMappingEntity>8. Populate cache (1h TTL)Not found → negative cache __NEG__ (60s)9. 301/302 Location: <url>Error: 404 NOT_FOUND (not in cache or DB) • 410 GONE (expired) • Cache down → circuit breaker → fall through to DB__NEG__ sentinel in cache → immediate 404 without DB queryEnd User1. GET /{short_code} \ No newline at end of file diff --git a/diagrams/docs/use-cases/v2/UC-US-003-expire-url.svg b/diagrams/docs/use-cases/v2/UC-US-003-expire-url.svg index 8017079..0190310 100644 --- a/diagrams/docs/use-cases/v2/UC-US-003-expire-url.svg +++ b/diagrams/docs/use-cases/v2/UC-US-003-expire-url.svg @@ -1,4 +1,2 @@ - - UC-US-003: Expire URL (Active Cleanup) — Sequence Diagram (v2)@ScheduledExpiryCleanupJobUrlRepositoryRedis1. Trigger (cron: hourly)2. findExpiredBatch(limit=500)List<UrlMappingEntity>[loop] For each expired entity3. softDelete(id) — is_active=false4. DEL url:<short_code> (invalidate cache)5. Done (count cleaned)v2 active cleanup: @Scheduled cron batch job. Soft-deletes expired rows (is_active=false),invalidates Redis cache per key. Batch size 500. Logged via Micrometer counter. \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }UC-US-003: Expire URL (Active Cleanup) — Sequence Diagram (v2)@ScheduledExpiryCleanupJobUrlRepositoryRedis1. Trigger (cron: hourly)2. findExpiredBatch(limit=500)List<UrlMappingEntity>[loop] For each expired entity3. softDelete(id) — is_active=false4. DEL url:<short_code> (invalidate cache)5. Done (count cleaned)v2 active cleanup: @Scheduled cron batch job. Soft-deletes expired rows (is_active=false),invalidates Redis cache per key. Batch size 500. Logged via Micrometer counter. \ No newline at end of file diff --git a/diagrams/docs/use-cases/v2/UC-US-004-custom-alias.svg b/diagrams/docs/use-cases/v2/UC-US-004-custom-alias.svg index 1f392be..5c61353 100644 --- a/diagrams/docs/use-cases/v2/UC-US-004-custom-alias.svg +++ b/diagrams/docs/use-cases/v2/UC-US-004-custom-alias.svg @@ -1,4 +1,2 @@ - - UC-US-004: Custom Alias — Sequence Diagram (v2)CloudFront(API Dist.)NginxRateLimitFilterUrlControllerUrlServiceImplUrlRepositoryRedis2. Forward (pass-through)3. Proxy request4. Bucket4j check (2/min)5. createCustomAlias(dto)6. Check feature flag Validate alias (Base62, 4-32) Check reserved words7. SELECT 1 (advisory pre-check)Not found → available8. INSERT (alias as short_code)9. SET url:<alias> (cache warm, TTL 1h ±jitter)10. 201 Created {short_url: /<alias>}Error Flows: 400 ALIAS_FEATURE_DISABLED — feature flag off 400 INVALID_ALIAS — bad format or reserved word 409 ALIAS_TAKEN — pre-check or UNIQUE constraint violation 429 RATE_LIMIT_EXCEEDED — >2 req/min custom aliasv2 only: Feature-flagged (tinyurl.features.custom-alias). UNIQUE constraint is sourceof truth for alias uniqueness. Advisory pre-check avoids hitting constraint in happy path.Stricter rate limit: 2/min vs 5/min standard. Alias reserved even after expiry.End User1. POST /api/urls {url, alias} \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }UC-US-004: Custom Alias — Sequence Diagram (v2)CloudFront(API Dist.)NginxRateLimitFilterUrlControllerUrlServiceImplUrlRepositoryRedis2. Forward (pass-through)3. Proxy request4. Bucket4j check (2/min)5. createCustomAlias(dto)6. Check feature flag Validate alias (Base62, 4-32) Check reserved words7. SELECT 1 (advisory pre-check)Not found → available8. INSERT (alias as short_code)9. SET url:<alias> (cache warm, TTL 1h ±jitter)10. 201 Created {short_url: /<alias>}Error Flows: 400 ALIAS_FEATURE_DISABLED — feature flag off 400 INVALID_ALIAS — bad format or reserved word 409 ALIAS_TAKEN — pre-check or UNIQUE constraint violation 429 RATE_LIMIT_EXCEEDED — >2 req/min custom aliasv2 only: Feature-flagged (tinyurl.features.custom-alias). UNIQUE constraint is sourceof truth for alias uniqueness. Advisory pre-check avoids hitting constraint in happy path.Stricter rate limit: 2/min vs 5/min standard. Alias reserved even after expiry.End User1. POST /api/urls {url, alias} \ No newline at end of file diff --git a/docs/architecture/00-baseline/v1/url-shortener-v1-hld.excalidraw b/docs/architecture/00-baseline/v1/url-shortener-v1-hld.excalidraw index b430916..8b0bf6a 100644 --- a/docs/architecture/00-baseline/v1/url-shortener-v1-hld.excalidraw +++ b/docs/architecture/00-baseline/v1/url-shortener-v1-hld.excalidraw @@ -2138,8 +2138,8 @@ "frameId": null, "x": -220.66529003471368, "y": -303.5077851544676, - "width": 171.50159565320678, - "height": 128.9607875234742, + "width": 153.29535786023803, + "height": 125.23422502347421, "angle": 0, "strokeColor": "#f08c00", "backgroundColor": "transparent", @@ -2151,8 +2151,8 @@ "groupIds": [], "roundness": null, "seed": 1036090294, - "version": 4124, - "versionNonce": 675132968, + "version": 4179, + "versionNonce": 648276660, "isDeleted": false, "boundElements": [ { @@ -2160,7 +2160,7 @@ "type": "text" } ], - "updated": 1774769149312, + "updated": 1780887497358, "link": null, "locked": false, "points": [ @@ -2170,15 +2170,15 @@ ], [ 0, - 63.59563320416075 + 61.73235195416075 ], [ - 171.50159565320678, - 63.59563320416075 + 153.29535786023803, + 61.73235195416075 ], [ - 171.50159565320678, - 128.9607875234742 + 153.29535786023803, + 125.23422502347421 ] ], "lastCommittedPoint": null, @@ -2255,10 +2255,10 @@ "type": "arrow", "index": "agG", "frameId": null, - "x": -50.10924709348319, - "y": -54.621333771234035, - "width": 308.1567959810417, - "height": 175.36087468829965, + "x": -68.31548488645194, + "y": -58.347896271234035, + "width": 326.36303377401043, + "height": 179.08743718829965, "angle": 0, "strokeColor": "#f08c00", "backgroundColor": "transparent", @@ -2270,8 +2270,8 @@ "groupIds": [], "roundness": null, "seed": 1565690968, - "version": 4831, - "versionNonce": 913617192, + "version": 4887, + "versionNonce": 1655437108, "isDeleted": false, "boundElements": [ { @@ -2279,7 +2279,7 @@ "type": "text" } ], - "updated": 1774769149313, + "updated": 1780887497472, "link": null, "locked": false, "points": [ @@ -2289,19 +2289,19 @@ ], [ 0, - 111.42588623872977 + 115.15244873872977 ], [ - 97.94944876125368, - 111.42588623872977 + 116.15568655422243, + 115.15244873872977 ], [ - 97.94944876125368, - 175.36087468829965 + 116.15568655422243, + 179.08743718829965 ], [ - 308.1567959810417, - 175.36087468829965 + 326.36303377401043, + 179.08743718829965 ] ], "lastCommittedPoint": null, @@ -2337,22 +2337,22 @@ "index": 2, "start": [ 0, - 111.42588623872977 + 115.15244873872977 ], "end": [ - 97.94944876125368, - 111.42588623872977 + 116.15568655422243, + 115.15244873872977 ] }, { "index": 3, "start": [ - 97.94944876125368, - 111.42588623872977 + 116.15568655422243, + 115.15244873872977 ], "end": [ - 97.94944876125368, - 175.36087468829965 + 116.15568655422243, + 179.08743718829965 ] } ], @@ -2401,10 +2401,10 @@ "type": "arrow", "index": "agd", "frameId": null, - "x": -179.99130314362878, - "y": -54.43363240533003, - "width": 0.5090771940789693, - "height": 183.66922976935638, + "x": -198.19754093659753, + "y": -58.16019490533003, + "width": 28.24434257472356, + "height": 188.16026601866412, "angle": 0, "strokeColor": "#f08c00", "backgroundColor": "transparent", @@ -2416,8 +2416,8 @@ "groupIds": [], "roundness": null, "seed": 777376600, - "version": 5581, - "versionNonce": 843957800, + "version": 5651, + "versionNonce": 330421556, "isDeleted": false, "boundElements": [ { @@ -2425,7 +2425,7 @@ "type": "text" } ], - "updated": 1774769151817, + "updated": 1780888335799, "link": null, "locked": false, "points": [ @@ -2434,8 +2434,16 @@ 0 ], [ - 0.5090771940789693, - 183.66922976935638 + 0, + 94.08843335104227 + ], + [ + 28.24434257472356, + 94.08843335104227 + ], + [ + 28.24434257472356, + 188.16026601866412 ] ], "lastCommittedPoint": null, @@ -2451,8 +2459,8 @@ "endBinding": { "elementId": "nR-2GIajiYPMjhAoZLsck", "fixedPoint": [ - 0.49952875878787484, - -0.04326026653429992 + 0.38199112218058967, + -0.0450853090287157 ], "focus": 0, "gap": 0 @@ -3179,8 +3187,8 @@ "type": "rectangle", "index": "ay", "frameId": null, - "x": -209.12305427739824, - "y": -169.6279692219096, + "x": -227.329292070367, + "y": -173.3545317219096, "width": 199.74500710497375, "height": 110, "angle": 0, @@ -3196,8 +3204,8 @@ "type": 3 }, "seed": 1430654040, - "version": 1498, - "versionNonce": 2066601560, + "version": 1553, + "versionNonce": 968050612, "isDeleted": false, "boundElements": [ { @@ -3217,15 +3225,15 @@ "type": "arrow" } ], - "updated": 1774769149311, + "updated": 1780887497357, "link": null, "locked": false }, { "id": "qKIIAMdmMGTIov9tNsvuj", "type": "text", - "x": -197.94049213116136, - "y": -164.6279692219096, + "x": -216.1467299241301, + "y": -168.3545317219096, "width": 177.3798828125, "height": 100, "angle": 0, @@ -3241,11 +3249,11 @@ "index": "az", "roundness": null, "seed": 376619352, - "version": 283, - "versionNonce": 921661992, + "version": 338, + "versionNonce": 2027434292, "isDeleted": false, "boundElements": [], - "updated": 1774769106192, + "updated": 1780887497357, "link": null, "locked": false, "text": "Cloudflare\n(DDoS Absorption\nWAF Rate Limiting\nDNS Proxy)",