Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .devcontainer/dead-reckoning_beginner/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "🧭 Dead Reckoning | 🟢 Beginner (Laying the Keel)",
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/adventures/dead-reckoning/beginner",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "22"
}
},
"postCreateCommand": "bash /workspaces/${localWorkspaceFolderBasename}/.devcontainer/dead-reckoning_beginner/post-create.sh",
"postStartCommand": "bash /workspaces/${localWorkspaceFolderBasename}/.devcontainer/dead-reckoning_beginner/post-start.sh",
"customizations": {
"codespaces": {
"openFiles": [
"adventures/dead-reckoning/README.md"
],
"permissions": {
"codespaces": "write"
}
}
},
"forwardPorts": [3000, 7007, 30110],
"portsAttributes": {
"3000": {
"label": "Backstage",
"onAutoForward": "notify"
},
"7007": {
"label": "Backstage Backend",
"onAutoForward": "silent"
},
"30110": {
"label": "Gitea",
"onAutoForward": "notify"
}
},
"otherPortsAttributes": {
"onAutoForward": "ignore"
}
}
44 changes: 44 additions & 0 deletions .devcontainer/dead-reckoning_beginner/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -e

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
CHALLENGE_DIR="$REPO_ROOT/adventures/dead-reckoning/beginner"

# shellcheck disable=SC1091
source "$REPO_ROOT/lib/scripts/tracker.sh"
set_tracking_context "dead-reckoning" "beginner" "06" "07" "2026"
track_container_created

"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0

"$REPO_ROOT/lib/github-cli/init.sh" --version v2.96.0 # https://github.com/cli/cli/releases

"$REPO_ROOT/lib/kubernetes/init.sh" \
--kind-version v0.32.0 \
--kubectl-version v1.36.2 \
--kubens-version v0.11.0 \
--k9s-version v0.51.0 \
--helm-version v4.2.2

"$REPO_ROOT/lib/gitea/init.sh" --version 12.6.0

# Create the Gitea organization that vessel repositories are published into.
# The scaffolder's publish:gitea action can only create repos under an existing
# organization, so this must exist before the commissioning template runs.
echo "✨ Creating Gitea organization 'fleet'"
GITEA_URL="http://localhost:30110"
until curl -sf "$GITEA_URL/api/v1/version" >/dev/null 2>&1; do sleep 3; done
# Idempotent: a re-run returns 422 (org already exists), which we ignore.
curl -sf -X POST "$GITEA_URL/api/v1/orgs" \
-H "Content-Type: application/json" \
-u "admin:a-super-secure-password" \
-d '{"username": "fleet", "visibility": "public"}' >/dev/null || true

echo "✨ Installing Backstage dependencies"
# Disable corepack's interactive "download Yarn x.y.z?" prompt. Without this the
# first yarn invocation blocks post-create waiting for stdin that never comes.
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
corepack enable
(cd "$CHALLENGE_DIR/backstage" && yarn install --immutable)

echo "✅ Post-create complete"
29 changes: 29 additions & 0 deletions .devcontainer/dead-reckoning_beginner/post-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -e

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

cat <<'EOF'

✨ Dead Reckoning — 🟢 Beginner (Laying the Keel)

The platform is ready:
• Gitea (the archives) is running in the cluster on port 30110
• The vessel commissioning template is loaded into Backstage

▶ Start Backstage (the commission office):
make backstage

The UI comes up on port 3000 (first start compiles for ~30-60s).
In a Codespace, port 7007 is made public automatically so the
browser can reach the Backstage backend.

✅ When you think you've fixed the template, verify your work:
make verify

EOF

# shellcheck disable=SC1091
source "$REPO_ROOT/lib/scripts/tracker.sh"
set_tracking_context "dead-reckoning" "beginner" "06" "07" "2026"
track_container_initialized
12 changes: 12 additions & 0 deletions adventures/dead-reckoning/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 🧭 Dead Reckoning

The Grand Fleet's commission office is buried in complaints. Manifests are filed but nothing comes of them. Vessels that do sail arrive at port with the wrong cargo, and no one along the route can explain why. As the fleet's engineer, your mission is to restore order from keel to quayside and find out what the records are hiding.

**Technologies:** Backstage, Gitea, Argo Workflows, Argo CD, OpenTelemetry, Jaeger, Kubernetes

The entire **infrastructure is pre-provisioned in your Codespace**
**You don't need to set up anything locally. Just focus on solving the problem.**

## 🚀 Ready to Start?

[Choose your level](https://offon.dev/adventures/dead-reckoning/) and begin learning!
27 changes: 27 additions & 0 deletions adventures/dead-reckoning/beginner/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.DEFAULT_GOAL := help

.PHONY: help backstage verify

help:
@echo "Dead Reckoning - Beginner: Available Commands:"
@echo " make backstage Start Backstage (the commission office)"
@echo " make verify Run the verification script"

# Foreground start so you get live logs and can restart with Ctrl-C + make backstage.
# In a Codespace two ports must be public: 7007 so the browser SPA can reach the
# backend, and 30110 so both the browser and the scaffolder backend can reach Gitea
# at its forwarded URL. 30110 (Gitea) is already up, so it flips immediately; 7007
# only forwards once Backstage is listening, so that one retries. We also layer the
# Codespaces config overlay so the baseUrls point at forwarded URLs.
backstage:
@echo "⚓ Starting Backstage. First start compiles for ~30-60s, then open port 3000."
@configs="--config $(CURDIR)/backstage/app-config.yaml"; \
if [ -n "$$CODESPACE_NAME" ]; then \
configs="$$configs --config $(CURDIR)/backstage/app-config.codespaces.yaml"; \
( until gh codespace ports visibility 30110:public -c "$$CODESPACE_NAME" >/dev/null 2>&1; do sleep 3; done; \
until gh codespace ports visibility 7007:public -c "$$CODESPACE_NAME" >/dev/null 2>&1; do sleep 3; done ) & \
fi; \
cd backstage && COREPACK_ENABLE_DOWNLOAD_PROMPT=0 yarn start $$configs

verify:
@./verify.sh
1 change: 1 addition & 0 deletions adventures/dead-reckoning/beginner/backstage/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
playwright.config.ts
3 changes: 3 additions & 0 deletions adventures/dead-reckoning/beginner/backstage/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
root: true,
};
56 changes: 56 additions & 0 deletions adventures/dead-reckoning/beginner/backstage/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# macOS
.DS_Store

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Coverage directory generated when running tests with coverage
coverage

# Dependencies
node_modules/

# Yarn files
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Node version directives
.nvmrc

# dotenv environment variables file
.env
.env.test

# Build output
dist
dist-types

# Temporary change files created by Vim
*.swp

# MkDocs build output
site

# Local configuration files
*.local.yaml

# Sensitive credentials
*-credentials.yaml

# vscode database functionality support files
*.session.sql

# E2E test reports
e2e-test-report/

# Cache
.cache/
4 changes: 4 additions & 0 deletions adventures/dead-reckoning/beginner/backstage/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
dist-types
coverage
.vscode
Loading
Loading