Cover

PORTFOLIO

Intro

On this page you will find an overview of my Portfolio.

I decided to utilise a front-end that I made a few years ago, with the express intent on developing a backend later (I made everything into re-usable "blocks"). I decided to use my SA development as an opportunity to make this backend this. I wanted to make this as efficiently as possible, noting my core build is to be done in Python; and learning is otherwise mainly around networking and cloud infrastructure. Doing this now, however, would make developing my portfolio "hassle free", so I could populate it as I went along.

An overview of a few of the key/core features/design decisions:

The video to the left shows you an example of the frontend and backend. Please note: It is a long video (12 minutes), and was recorded before I finished - so there are a couple new features, and there's one bug in the video. These are no longer present - but the value for re-recording whilst I have a lot to do is limited. You'll just have to trust me for now until I update it!

Overview architecture

Space for words



---
config:
  layout: elk
  look: handDrawn
  theme: dark
---

flowchart TB
 subgraph Sec["Security + Access (ADR-006)"]
        AccessCF["Cloudflare Access (GitHub OAuth + Org/Team checks + MFA)"]
        Jwt["Session/JWT verification
(shared secrets / keys)"]
  end
 subgraph DNS["DNS Entry"]
        R53["Route53
portfolio.tacsa.co.uk + subdomains"]
  end
 subgraph Admin["Admin UI (Cloudflare Pages)"]
        AdminDev["Admin (dev)
dev.admin.portfolio.tacsa.co.uk"]
        AdminProd["Admin (prod)
admin.portfolio.tacsa.co.uk"]
  end
 subgraph CMS["CMS API Layer"]
        Proxy["Pages Function: /api/*
(adds x-cms-read-key / x-cms-write-key / branch header)"]
        Worker["CMS Worker
(PR-only writes)"]
  end
 subgraph GH["GitHub (Source of Truth)"]
        Repo["Portfolio Repo
(VoodooScience1.github.io)"]
        DevBranch["dev branch
(preview source)"]
        MainBranch["main/master
(prod source)"]
        PR["Pull Request
(review + audit trail)"]
        Actions["GitHub Actions
(build + orchestration)"]
  end
 subgraph CF["Cloudflare Pages (previews)"]
        DevSite["Portfolio preview (dev)
dev.portfolio.tacsa.co.uk"]
  end
 subgraph GHP["GitHub Pages (production)"]
        ProdSite["Portfolio (prod)
portfolio.tacsa.co.uk"]
  end
 subgraph Hosting["Hosting"]
        CF
        GHP
  end
 subgraph Hooks["Rebuild Triggers (ADR-010)"]
        HookDev["Deploy Hook (dev)
Cloudflare Pages"]
        HookProd["Publish (prod)
GitHub Pages"]
        Webhook["Webhook / event trigger
(repo → deploy pipeline)"]
  end
    AdminUser["Admin"] --> AccessCF
    AccessCF --> Jwt
    Jwt --> AdminDev & AdminProd
    AdminDev --> Proxy
    Proxy --> Worker & Worker
    AdminProd --> Proxy
    Worker --> Repo
    Repo --> PR & DevBranch & Actions
    PR --> MainBranch
    DevBranch --> DevSite
    MainBranch --> ProdSite
    Actions --> Webhook & HookProd
    Webhook --> HookDev
    HookDev --> DevSite
    HookProd --> ProdSite
    User["User"] --> R53
    R53 --> DevSite & ProdSite

More space for words

Admin Sequence diagram

space for words



sequenceDiagram
  actor Admin
  participant Access as Cloudflare Access
  participant UI as Admin UI <br> (admin.portfolio.tacsa.co.uk)
  participant Worker as CMS Worker <br> (Cloudflare Worker)
  participant GH as GitHub Repo + API
  participant PR as Pull Request
  participant CI as GitHub Actions / <br> Orchestration
  participant Preview as dev.portfolio.tacsa.co.uk <br> (CF Pages)
  participant Prod as portfolio.tacsa.co.uk <br> (GitHub Pages)

  Admin->>Access: Authenticate <br> (GitHub OAuth + Org/Team)
  Access-->>Admin: Session granted

  Admin->>UI: Open admin portal
  Admin->>UI: Edit content + submit
  UI->>Worker: Write request (/api/*)
  Worker->>GH: Create branch + commit + PR
  GH-->>Worker: PR link/status
  Worker-->>UI: PR created (await merge)

  Admin->>PR: Review + merge
  PR->>CI: Trigger build/deploy
  CI->>Preview: Rebuild dev preview
  CI->>Prod: Publish prod site

space for words

Security/trust-boundaries

space for words



---
config:
  layout: elk
  look: classic
  theme: neo-dark
---
architecture-beta
  service user(logos:users)[User]
  service admin(logos:user)[Admin]

  group dns(logos:aws-route53)[DNS]
    service r53(logos:aws-route53)[Route53] in dns

  group edge(logos:cloudflare-icon)[OAuth]
    service access(logos:cloudflare-icon)[Access Gate] in edge
    service controls(logos:cloudflare-icon)[Security Controls] in edge

  group pages(logos:cloudflare-icon)[Pages]
    service adminprod(logos:cloudflare-icon)[Admin Prod] in pages
    group dev(logos:cloudflare-icon)[Dev Pages]
      service admindev(logos:cloudflare-icon)[Admin Dev] in dev
      service preview(logos:cloudflare-icon)[Portfolio Dev] in dev

  group prod(logos:github-icon)[Production]
    service live(logos:github-icon)[Portfolio Prod] in prod

  group control(logos:cloudflare-icon)[Worker]
    service worker(logos:cloudflare-workers)[CMS Worker] in control

  group gh(logos:github-icon)[GitHub]
    service repo(logos:github-icon)[Portfolio Repo] in gh
    service prs(logos:github-icon)[Pull Requests] in gh
    service actions(logos:github-actions)[Actions] in gh

  user:B --> T:r53
  r53:L --> R:preview
  live:T <-- B:r53

  admin:R --> L:access
  access:R --> L:controls
  controls:T --> L:admindev
  controls:R --> L:adminprod

  admindev:B --> T:worker
  adminprod:R --> L:worker

  worker:R --> L:repo
  repo:R --> L:prs
  prs:R --> L:actions
  actions:T --> B:preview
  actions:R --> L:live

space for words

DevOps + environment promotion with sync + webhooks

space for words



flowchart LR
  subgraph Repo["GitHub Repo"]
    Dev["dev branch"]
    Master["master branch"]
  end

  subgraph Actions["GitHub Actions"]
    Job["Trigger Cloudflare Pages Rebuilds"]
  end

  subgraph Hooks["Deploy Hooks"]
    HookProdAdmin["Prod Admin Deploy Hook\nCLOUDFLARE_PAGES_DEPLOY_HOOK"]
    HookDevCore["Dev Core Deploy Hook\nCLOUDFLARE_CORE_DEPLOY_HOOK_DEV"]
    HookDevAdmin["Dev Admin Deploy Hook\nCLOUDFLARE_PAGES_DEPLOY_HOOK_DEV"]
  end

  subgraph Targets["Targets"]
    AdminProd["admin.portfolio.tacsa.co.uk"]
    AdminDev["dev.admin.portfolio.tacsa.co.uk"]
    PortfolioDev["dev.portfolio.tacsa.co.uk"]
  end

  Master -->|push| Job
  Dev -->|push| Job

  Job -->|if master| HookProdAdmin --> AdminProd
  Job -->|if dev| HookDevCore --> PortfolioDev
  Job -->|if dev| HookDevAdmin --> AdminDev

space for words

Branches

words



gitGraph
  commit id: "baseline"
  branch dev
  checkout dev
  commit id: "change(s)"
  checkout main
  merge dev id: "PR merged"
  commit id: "release"

words