Skip to content

Spec: Astro landing page

Requirements for the workshop website. To be built in web/ in this repo.

Superseded: the page copy is English

This note originally specified Norwegian page copy. That decision was reversed on 2026-09-03: all material is English, including the rendered site, even though the workshop is still delivered in Norwegian. The Norwegian drafts below are kept as a record of the original intent — the built site does not use them.

Two further changes since this spec was written:

  • The route is /prepare, not /forbered.
  • The visual direction comes from the design canvas, not from this document. Where the two disagree, the canvas wins for layout and the repo wins for anything a participant would actually type.

Sections 1 and 4.1's preparation, not registration rule still stand, and the built site honours them.

1 · Purpose

The landing page has one job: make sure participants show up with a prepared laptop.

Everything else — marketing, speaker bios, the agenda — is secondary. The key conversion on this page is not registration (the conference owns that). It's someone actually running make preflight at home. See P1 and P2.

Success criteria

Goal Measure
Participants did the prep Share arriving with a green preflight (show of hands)
Nobody arrives without a laptop Informal count in the room
The content outlives the day Traffic to /docs after the conference

2 · Architecture: two sites, one domain

Recommendation

Astro at root, the MkDocs documentation under /docs/, one GitHub Pages deploy.

We already have a MkDocs Material site holding the lab content. The options:

Option Assessment
Astro at root + MkDocs at /docs/ Chosen. Marketing and docs each get their own form. One deploy.
Astro Starlight for everything Means rewriting the labs. Much work, little gain now.
MkDocs only Works, but a docs homepage doesn't sell a workshop.
Two separate domains Two deploys, split link graph, confused participants. No.

In practice: the workflow builds Astro to dist/ and MkDocs to dist/docs/, then publishes dist/ as one artifact. mkdocs.yml gets site_url: https://<domain>/docs/.

3 · Site map

Route Content Priority
/ Landing page — the whole story on one page Must
/forbered The preparation instructions, as a shareable URL Must
/docs/ The MkDocs documentation (built separately) Must
/404 Simple, links to / and /docs/ Should

One page plus one subpage. Don't build more.

4 · Sections on /

The order is deliberate: what → for whom → prepare → what we do → who we are. Preparation comes before the agenda, because it's the most important action.

4.1 Hero

  • Eyebrow: Cloud Native Days Norway 2026 · Bergen · 26.–27. oktober
  • H1: Agentic Cloud Ops
  • Subtitle: Praktisk AI-drevet Kubernetes-drift
  • Lede (draft, Norwegian):

    Fra Infrastructure as Code til Infrastructure as Agents. To timer der vi slipper AI-agenter løs på et ekte Kubernetes-cluster — og finner ut hva som faktisk skal til for å tørre det i produksjon.

(From Infrastructure as Code to Infrastructure as Agents. Two hours turning AI agents loose on a real Kubernetes cluster — and working out what it actually takes to dare do this in production.) - Metadata chips: Workshop · 2 timer · Norsk · Intermediate · Hands-on - Primary CTA: Forbered laptopen din → (Prepare your laptop) → /forbered - Secondary CTA: Se innholdet (See the content) → /docs/

Critical detail

The primary CTA is not "register". The conference owns registration. Our CTA is preparation, and it must be the most prominent element above the fold.

4.2 Warning banner — "bring a laptop"

A visually distinct strip directly under the hero. Impossible to miss.

Dette er en hands-on workshop. Du trenger en laptop med Docker og ~10 GB ledig disk, og du må gjøre forarbeidet hjemme. Konferanse-wifi er ikke et byggesystem.

(This is a hands-on workshop. You need a laptop with Docker and ~10 GB of free disk, and you must do the prep at home. Conference Wi-Fi is not a build system.)

Addresses P8 and P1 directly.

4.3 Takeaways

Three cards, taken verbatim from the proposal:

  1. Agentic vs. GitOps — understand what's genuinely new, and what's just hype.
  2. Hands-on experience — deployment, debugging and security hardening with agents in K8s.
  3. Risk management — the success criteria for autonomous systems in production.

4.4 "Is this for me?"

Two columns, honest in both directions. Undersell rather than oversell.

Yes, if you… No, if you…
use kubectl daily have never seen a Kubernetes manifest
want to watch agents make real changes want an overview presentation
are curious where the limits are can't bring a laptop
are a developer, architect or SRE expect finished product recommendations

State explicitly that no ML background is needed.

4.5 Preparation (short version)

Three steps with a copyable command. Links onward to /forbered.

git clone https://github.com/leffen/agentic-cloud-ops.git
cd agentic-cloud-ops
make preflight

Every line must say OK. Its own component, with a copy button.

4.6 Schedule

A vertical timeline of the six blocks with durations. Use the revised schedule, not the proposal version. Each block links to the corresponding page under /docs/.

4.7 "What we actually do"

Three lab cards, one concrete and honest sentence each:

  • Lab 1 · Den første agenten — "Deploy en Nginx med 3 replicas." Så planter vi en feil, og lar agenten finne den selv.
  • Lab 2 · Hardening — clusteret er bevisst usikkert. Agenten strammer det inn uten å brekke applikasjonen. Det er vanskeligere enn det høres ut.
  • Lab 3 · Kaos — vi brekker noe. Ingen får bruke kubectl. Agenten må finne det.

4.8 Speakers

Two cards: name, short bio, links. Lars Effenberger and Lars Søraas.

Links to the conference, the repo, /docs/, and the Code of Conduct. No newsletter.

5 · Technical stack

Choice Rationale
Astro 5, static output No SSR need. Plain HTML to Pages.
No UI framework The page is static. No React/Vue/Svelte islands.
Tailwind via @tailwindcss/vite Fast iteration, no separate config file needed
@astrojs/sitemap SEO
Content Collections Schedule, labs and speakers as typed data
Fontsource, self-hosted No third-party font requests
TypeScript strict

No JavaScript islands

The only interactivity is the copy button and the theme. Both are ~20 lines of inline script. If someone proposes a client component, ask why.

6 · Project structure

web/
├── astro.config.mjs
├── package.json
├── src/
│   ├── content.config.ts        # collection schemas
│   ├── content/
│   │   ├── schedule/            # one file per block
│   │   ├── labs/                # one file per lab
│   │   └── speakers/            # one file per speaker
│   ├── layouts/
│   │   └── Base.astro           # <head>, meta, theme, skip link
│   ├── components/
│   │   ├── Hero.astro
│   │   ├── LaptopBanner.astro
│   │   ├── TakeawayCards.astro
│   │   ├── FitCheck.astro
│   │   ├── PrepSteps.astro
│   │   ├── CodeBlock.astro      # with copy button
│   │   ├── Timeline.astro
│   │   ├── LabCards.astro
│   │   ├── SpeakerCards.astro
│   │   └── Footer.astro
│   ├── pages/
│   │   ├── index.astro
│   │   ├── forbered.astro
│   │   └── 404.astro
│   └── styles/global.css        # design tokens
└── public/
    ├── og.png
    └── favicon.svg

7 · Content collections

src/content.config.ts
import { defineCollection, z } from 'astro:content';

const schedule = defineCollection({
  type: 'content',
  schema: z.object({
    order: z.number(),
    title: z.string(),
    minutes: z.number(),
    summary: z.string(),
    docsHref: z.string(),          // → /docs/labs/...
    format: z.enum(['presentation', 'hands-on', 'demo', 'buffer']),
  }),
});

const labs = defineCollection({
  type: 'content',
  schema: z.object({
    order: z.number(),
    title: z.string(),
    hook: z.string(),              // one honest sentence
    docsHref: z.string(),
  }),
});

const speakers = defineCollection({
  type: 'content',
  schema: z.object({
    name: z.string(),
    role: z.string().optional(),
    bio: z.string(),
    links: z.array(z.object({ label: z.string(), href: z.string().url() })).default([]),
  }),
});

export const collections = { schedule, labs, speakers };

The schedule must come from the schedule collection, not be hardcoded in markup. It will keep changing right up to the dress rehearsal.

8 · Design

Tokens

Define the complete light palette on bare :root. Redefine only tokens under @media (prefers-color-scheme: dark) and [data-theme="dark"]. No colour may have its only definition inside a media query.

:root {
  --bg: #fbfbfa;
  --surface: #ffffff;
  --border: #e4e4e1;
  --text: #16161a;
  --text-muted: #5f5f68;
  --accent: #0f766e;       /* teal — matches the MkDocs site */
  --accent-contrast: #ffffff;
  --warn-bg: #fff7ed;      /* the laptop banner */
  --warn-border: #f97316;
  --code-bg: #f4f4f2;
}
  • Accent: teal #0f766e — the same as the MkDocs theme, so / and /docs/ feel like one site.
  • Signal colour: orange, used only for the laptop banner. Used nowhere else, so it actually means something.

Typography

  • Headings and body: one good sans (Inter or similar), self-hosted.
  • Code: monospace. Commands should look like commands.
  • Max measure ~68ch.

Tone

Restrained and technical. No gradient blobs, no AI clichés, no stock photos of robots. The audience is sceptical operations people — the page should read like something written by someone who has been up at three in the morning.

9 · Performance and accessibility

Non-negotiable acceptance criteria:

  • No render-blocking JS. Page weight < 100 kB (excluding fonts)
  • Lighthouse ≥ 95 across all four categories
  • Works entirely without JavaScript (the copy button degrades to a plain code block)
  • Contrast ≥ 4.5:1 in both themes
  • Full keyboard navigation, visible focus ring, skip link
  • prefers-reduced-motion respected
  • One <h1>, correct heading hierarchy
  • No horizontal scroll at 320px width
  • lang="no" on the document (the copy is Norwegian)

10 · SEO and sharing

<title>Agentic Cloud Ops — Workshop, Cloud Native Days Norway 2026</title>
<meta name="description" content="Praktisk AI-drevet Kubernetes-drift. To timers hands-on workshop i Bergen, 26.–27. oktober 2026.">
  • OG image 1200×630: title, subtitle, date, location. Static PNG in public/.
  • JSON-LD of type Event with date, location and performer.
  • sitemap.xml and robots.txt.

11 · Analytics

No cookies, no third party requiring consent. If anything is needed: a self-hosted Plausible/Umami, or nothing at all. We don't need to know more than whether /forbered gets read.

12 · Deployment

Extend .github/workflows/docs.yml to build both sites into a single artifact:

- run: pip install -r requirements.txt
- run: mkdocs build --strict          # → site/
- run: npm ci --prefix web
- run: npm run build --prefix web     # → web/dist/
- run: mkdir -p out && cp -r web/dist/* out/ && cp -r site out/docs
- uses: actions/upload-pages-artifact@v3
  with:
    path: out

Astro gets base: '/', MkDocs gets a site_url pointing at /docs/. A link check in CI is a worthwhile addition: a broken link to the preparation page costs more than it looks.

13 · Out of scope

Deliberately excluded — don't build these:

  • Registration or ticketing (the conference owns this)
  • Newsletter, CMS, comments, blog
  • i18n / an English version (the workshop is in Norwegian)
  • A dark/light toggle beyond prefers-color-scheme (only if it's free)
  • Animation beyond simple hover states

14 · Definition of done

  • / and /forbered deployed on the same domain as /docs/
  • The schedule reads from a content collection, not hardcoded
  • Every acceptance criterion in §9 is green
  • Tested on mobile — half the audience reads this on a phone on the way to work
  • Link sent to the organisers for the conference programme listing