Erik Van Craddock personal website
  • TypeScript 99.1%
  • Shell 0.6%
  • Makefile 0.1%
Find a file
Erik Craddock 604309779b
All checks were successful
CI / build-lint-test (push) Successful in 48s
Web Release / Build and publish Docker image (push) Successful in 4m50s
Merge pull request 'Add the About page' (#16) from task-2acaa558-about-page into main
Reviewed-on: #16
2026-07-30 14:58:18 -05:00
.forgejo/workflows Validate Hono JSX in production images 2026-07-28 19:27:54 -05:00
.pi/skills/web-release Validate fixed homepage profile copy 2026-07-29 05:58:18 -05:00
docs Move follow action into the profile sidebar 2026-07-30 14:27:30 -05:00
e2e Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
scripts Verify profile emphasis in release image 2026-07-29 05:59:34 -05:00
src Add About navigation to the site header 2026-07-30 14:56:43 -05:00
.dockerignore Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
.env.example Honor APP_PORT from local environment 2026-07-26 00:55:08 -05:00
.gitignore Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
.slugkit-site.json Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
docker-compose.yml Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
Dockerfile Validate Hono JSX in production images 2026-07-28 19:27:54 -05:00
eslint.config.js Run CI checks for every branch push 2026-07-27 06:58:47 -05:00
garage.toml Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
Makefile Honor APP_PORT from local environment 2026-07-26 00:55:08 -05:00
package-lock.json Run CI checks for every branch push 2026-07-27 06:58:47 -05:00
package.json Run web releases on remote CI runner 2026-07-27 08:09:08 -05:00
playwright.config.ts Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
Procfile.dev Honor APP_PORT from local environment 2026-07-26 00:55:08 -05:00
README.md Run web releases on remote CI runner 2026-07-27 08:09:08 -05:00
tsconfig.json Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00
vitest.config.ts Initialize erikvancraddock.com Slugkit site 2026-07-26 00:05:43 -05:00

Erik Van Craddock

This is a standalone Slugkit-compatible website generated from the Slugkit source template. You own this repository and can customize its routes, templates, styles, assets, content model, and deployment while retaining the Slugkit API contract when you want to use the slug CLI.

Required first-run setup

Run these steps from this generated repository. The site remains private until you complete the owner setup flow.

1. Install dependencies

npm install

2. Configure the environment

cp .env.example .env

For local development, edit .env and set ADMIN_EMAIL to the owner email. Keep AUTH_DEV_MODE=true so sign-in links are written to the app logs. The included defaults use a local SQLite database, localhost URLs, and a local Garage container.

3. Initialize the database

npm run db:migrate
npm run db:status

4. Start local services

Install Overmind and Docker if needed, then start the app, Tailwind watcher, and local Garage container defined in Procfile.dev:

make dev
make dev-status

Configure the local media bucket after Garage starts, then restart the environment so the app loads the generated credentials:

make garage-setup
make dev-stop
make dev

Use make dev-logs to open the process logs. The site runs at http://localhost:3000 by default. Set APP_PORT in .env to use a different local port; the development process preserves that value.

5. Complete owner and actor setup

Open http://localhost:3000/login and sign in with ADMIN_EMAIL. With AUTH_DEV_MODE=true, copy the magic link from the app output available through make dev-logs.

Open http://localhost:3000/setup. Set the public site identity and create the primary actor. Choose the actor username carefully because it becomes part of public actor URLs and is difficult to change after federation begins. Completing this explicit first-run setup creates the actor and signing keys and makes the public site available.

6. Connect the Slugkit CLI

Use a clear local name for this target. The examples below use erikvancraddock.com, matching the generated package name.

slug --site erikvancraddock.com login http://localhost:3000/api/v1
slug --site erikvancraddock.com doctor

The browser-assisted login creates an API key for the named site. Every API-backed example below includes --site erikvancraddock.com so the target is explicit.

7. Verify the site

Open the following URLs and confirm that setup is complete:

  • http://localhost:3000/
  • http://localhost:3000/feed
  • http://localhost:3000/api/v1/health
  • http://localhost:3000/settings/actor

Run the local checks before changing or deploying the site:

npm run format
npm run lint
npm test
npm run build

Publish your first post with the CLI

Create an article. post create saves a draft; it does not publish automatically.

slug --site erikvancraddock.com post create \
  --type article \
  --slug hello-world \
  --title "Hello world" \
  --content "This is my first post."

Inspect the draft and confirm that its content and target site are correct:

slug --site erikvancraddock.com post show hello-world

Publish only after reviewing the draft:

slug --site erikvancraddock.com post publish hello-world
slug --site erikvancraddock.com post show hello-world

Publish your first post from Markdown

Create content/imported-hello.md with YAML frontmatter. slug, type, and—for an article—title are required. Omit date and publishedAt when you want the import to remain a new draft.

---
title: Imported hello
slug: imported-hello
type: article
excerpt: A first post imported from Markdown
tags:
  - introduction
---

This post started in a Markdown file.

Import the file into the explicitly named site. The import creates or updates a draft when no publication date is supplied.

slug --site erikvancraddock.com post import ./content/imported-hello.md

Inspect the imported draft before publishing it:

slug --site erikvancraddock.com post show imported-hello

Publish explicitly, then inspect the published result:

slug --site erikvancraddock.com post publish imported-hello
slug --site erikvancraddock.com post show imported-hello

Both creation methods leave the post as a draft until the explicit post publish command succeeds.

Customize the site

This repository is intended to be changed. Start with:

  • src/config/site.ts for fallback site identity, homepage copy, navigation, and footer links.
  • /settings for persisted site configuration.
  • /settings/actor for actor profile details and images.
  • src/templates/ and src/styles/ for public layout and styling.
  • src/assets/ for public images.
  • src/routes/ and src/api/ for site-owned behavior.

The API documentation for a running site is available at /api/v1/docs.

Optional federation setup

Federation is not required for local use or ordinary publishing. Leave ACTIVITYPUB_ENABLED=false until the site has a stable public HTTPS origin and the actor identity is final.

Before enabling federation:

  • Set the persisted site URL to the stable public HTTPS origin.
  • Set ACTIVITYPUB_PUBLIC_ORIGIN when it must differ from the site URL.
  • Confirm the primary actor username, display metadata, and signing keys in /settings/actor.
  • Set ACTIVITYPUB_ENABLED=true only in the deployed environment.
  • Verify WebFinger, the actor URL, and slug --site erikvancraddock.com doctor after deployment.

Deployment checklist

Deployment is optional during first-run setup. Before making the site public:

  • Replace localhost site and ActivityPub URLs with the stable public HTTPS origin.
  • Set AUTH_DEV_MODE=false and configure SMTP for magic-link delivery.
  • Use persistent storage for DATABASE_PATH=/app/data/slugkit.sqlite and include migrations in the release process.
  • Configure durable S3-compatible media storage with S3_ENDPOINT, S3_BUCKET, credentials, and S3_PUBLIC_URL.
  • Store secrets in the deployment environment or secret manager, never in the image or repository.
  • Run npm run format, npm run lint, npm test, and npm run build.
  • Back up the database and media storage.

Docker deployment

The included Dockerfile builds the CSS and application, installs production dependencies, exposes port 3000, and runs npm start.

docker build --build-arg APP_VERSION=local -t erikvancraddock.com:local .
docker run --rm -p 3000:3000 \
  --env-file .env \
  -e DATABASE_PATH=/app/data/slugkit.sqlite \
  -v erikvancraddock.com-data:/app/data \
  erikvancraddock.com:local

Run migrations against the same persistent volume before starting a new deployment or after updating the image. APP_VERSION is exposed as SLUGKIT_VERSION in the image so /health and /api/v1/health report the deployed version.

Publish a web release with Forgejo Actions

The publishing workflow at .forgejo/workflows/web-release.yml runs on the remote Debian CI runner and publishes evcraddock/erikvancraddock-web for linux/amd64 and linux/arm64 only for approved web-v* tags. Manual dispatch validates the remote Docker build with publishing disabled. Use /skill:web-release <version> to run the project release gates and request explicit approval before pushing a web-v<version> tag.

See docs/web-release.md for versioning, image tags, required repository secrets, and non-publishing validation.

Environment reference

The complete local defaults are documented in .env.example.

Required for local ownership and login:

  • DATABASE_PATH
  • ADMIN_EMAIL
  • AUTH_DEV_MODE

Optional runtime settings:

  • APP_PORT controls the application port and defaults to 3000 when unset.
  • APP_HOST controls the bind host and defaults to 0.0.0.0 when unset.

Required in production when AUTH_DEV_MODE=false:

  • SMTP_HOST, SMTP_PORT, SMTP_SECURE, and SMTP_FROM_EMAIL
  • SMTP_USERNAME and SMTP_PASSWORD when required by the provider

Optional media settings include S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE, and S3_PUBLIC_URL.

Optional federation settings include ACTIVITYPUB_ENABLED and ACTIVITYPUB_PUBLIC_ORIGIN.

Useful commands

make dev
make dev-status
make dev-logs
make dev-stop
make garage-setup
npm run db:migrate
npm run db:status
npm run format
npm run lint
npm test
npm run build