DigitalOcean · Opus 5.5 · medium effort · HIPAA organization · trial 1
Static Content Site on DigitalOcean
Success
Deployed to https://adb-iwyf5-static-k39h3.ondigitalocean.app. Every deployment is deleted after it's verified and reviewed.
Technologies
- Runtime
- Node.js 22
- Frameworks
- Node.js http module (built in)
- Packaging
- Docker (node:22-alpine)App spec (.do/app.yaml)
- Hosting
- App Platform service (apps-s-1vcpu-0.5gb)DigitalOcean Container Registry (starter)
Named from the app's dependencies, Dockerfile and config files, and the cloud resources it created.
Checks
Black-box checks against the live URL. A cell succeeds when every required check passes. The app's spec
| Result | Check | Details |
|---|---|---|
| passed | GET / answers 2xx within 1 min ready |
|
| passed | The app is served over HTTPS with a valid certificate https |
|
| passed | The app is public: no redirect to another host such as a login page public_access |
|
| passed | GET / returns HTML page_home |
|
| passed | GET /about returns HTML page_about |
|
| passed | GET /contact returns HTML page_contact |
|
| passed | Home has an <h1> containing 'Northwind Robotics' home_content |
|
| passed | About has a heading containing 'About' about_content |
|
| passed | Contact has a form with name, email and message fields contact_form |
|
| passed | Every page has a <title> and a viewport meta tag head_tags optional |
|
| passed | Home links to /about and /contact navigation optional |
|
| passed | POST /api/contact with valid input returns {ok: true} contact_api_valid |
|
| passed | POST /api/contact rejects a bad email and an empty message with 400 contact_api_validation |
|
| passed | Unknown paths return 404 not_found |
|
| passed | Submitting the /contact form in a browser posts to /api/contact without leaving the page browser_contact_form |
|
| passed | Pages load in a browser without uncaught JavaScript errors browser_no_errors optional |
Human steps
- Sign up for an account and verify the email address · 3 min
prerequisite: account setup - Add a payment method to the account · 2 min
prerequisite: account setup - Create an API token and hand it to the agent · 2 min
prerequisite: account setup
Security & compliance review
This run predates the security review.
Cloud resources and cost
Resources the agent created
| Kind | Name | Plan | List price / month | Pricing |
|---|---|---|---|---|
| app | adb-iwyf5-static | adb-iwyf5-static-web: apps-s-1vcpu-0.5gb x 1 | $5.00 | adb-iwyf5-static-web: apps-s-1vcpu-0.5gb x 1 |
| registry | adb-iwyf5-static | starter | $0.00 | Container Registry starter tier (one per account) |
| project | adb-iwyf5-static | $0.00 | no charge at benchmark usage |
The agent estimated $5.00 a month.
Code
- Code
- 386 lines in 15 files (JavaScript 177, HTML 168, CSS 32, JSON 25, YAML 16, Docker 9, Markdown 8)
- Dependencies
- 0 npm, 0 Python
- Deploy config
Dockerfile.dockerignore.do/app.yaml
The agent's sessions
| Phase | Status | Time | Turns | Tokens | Cost | Shell commands |
|---|---|---|---|---|---|---|
| Build | completed | 1m 31s | 9 | 211.2K | $0.29 | 8 |
| Deploy | completed | 2m 26s | 9 | 273.5K | $0.16 | 8 |
The agent's deploy summary
The site is live at https://adb-iwyf5-static-k39h3.ondigitalocean.app, and every requirement in TASK.md passes through that public URL.
How it's deployed:
- I built a Docker image from the existing
Dockerfileand pushed it to a free DigitalOcean Container Registry namedadb-iwyf5-static(asadb-iwyf5-static-web:v1). - It runs on App Platform as the app
adb-iwyf5-static, with one web service on the smallest Basic size (apps-s-1vcpu-0.5gb) in the New York region. The app spec is saved in.do/app.yaml. - HTTPS comes with App Platform's default
ondigitalocean.appaddress. - I put both in a DigitalOcean project named
adb-iwyf5-static. - Cost: about $5/month, all for the web service; the registry is free.
What I checked on the public URL:
/,/aboutand/contactreturn 200 withtext/html, and each has a title, a viewport tag and navigation to the other pages.- Unknown paths and
.htmlversions of the pages return 404. POST /api/contactreturns 200 with{"ok":true}for valid input. A missing name, an invalid email or an empty message each return 400 with an error message.- I filled in and submitted the contact form in a headless Chromium browser. It showed the confirmation message without reloading the page.
Choices I made:
- Container image instead of Git: App Platform usually builds from a Git repository, but there's no repository connected to this account, so I deployed the image instead.
- Web service instead of a static site: the free static-site option can't run the contact endpoint, so I used a paid web service.
Nothing needed a person, so human_steps in deployment.json is empty. Updating the site means building and pushing a new image tag, changing the tag in .do/app.yaml, and running doctl apps update c0d1dff1-7855-4d7d-a6e4-faf4b865e6fe --spec .do/app.yaml.
8 shell commands during deploy
- 6s
which doctl; cd /tmp && curl -sL https://github.com/digitalocean/doctl/releases/download/v1.146.0/doctl-1.146.0-linux-amd64.tar.gz | tar xz && sudo mv doctl /usr/local/bin/ ; doctl version; doctl acco - 11s
doctl registry create adb-iwyf5-static --subscription-tier starter --region nyc3 && doctl registry login >/dev/null && docker build -q -t registry.digitalocean.com/adb-iwyf5-static/adb-iwyf5-static-we - 41s
mkdir -p .do && cat > .do/app.yaml <<'EOF' - 1m 16s
doctl apps list --format ID,Spec.Name,DefaultIngress,Phase; doctl projects list --format ID,Name,IsDefault - 1m 19s
doctl apps list -o json | python3 -c "import json,sys;[print(a['id'],a['spec']['name'],a.get('default_ingress'),a.get('active_deployment',{}).get('phase'), a.get('in_progress_deployment',{}).get('phas - 1m 23s
U=https://adb-iwyf5-static-k39h3.ondigitalocean.app - 1m 30s
mkdir -p /tmp/pw && cd /tmp/pw && npm init -y >/dev/null && npm i -s playwright >/dev/null 2>&1 && npx playwright install chromium >/dev/null 2>&1 && cat > t.js <<'EOF' - 2m 18s
PID=$(doctl projects create --name adb-iwyf5-static --purpose "Web Application" --environment Production --format ID --no-header) && doctl projects resources assign $PID --resource=do:app:c0d1dff1-785
Raw data
Report on GitHub Full record (JSON) Workflow run, with transcripts