Skip to content

Commit 1bdf4bb

Browse files
authored
5.0 (#2)
* skills * agents.md * Update site * SwiftWASM app BytesizedCafe * hummingbird backend impl * fix wasm app * bytesized cafe
1 parent 9fb70a8 commit 1bdf4bb

95 files changed

Lines changed: 3366 additions & 211 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ENV.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copy this file to `.ENV` and fill in your real values before running repo commands.
2+
#
3+
# `just backend` and `just local` use all values below except `AWS_S3_BUCKET`.
4+
# `AWS_S3_BUCKET` is only used by `just site-deploy`.
5+
AWS_REGION=us-east-1
6+
AWS_S3_BUCKET=your-site-bucket
7+
GENERATED_IMAGES_BUCKET=your-generated-images-bucket
8+
OPENAI_API_KEY=your-openai-api-key
9+
AWS_ACCESS_KEY_ID=your-aws-access-key-id
10+
AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key
11+
OPENAI_IMAGE_MODEL=gpt-image-1.5
12+
IMAGE_GEN_PREFIX=generated/v2
13+
14+
BACKEND_HOST=127.0.0.1
15+
BACKEND_PORT=8080
16+
SITE_HOST=127.0.0.1
17+
SITE_PORT=8000

.github/workflows/deploy.yml

Lines changed: 102 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,112 @@ name: Build and Deploy
22

33
on:
44
push:
5-
branches: [ master ]
6-
5+
branches:
6+
- main
7+
8+
concurrency:
9+
group: deploy-production
10+
cancel-in-progress: true
11+
712
jobs:
8-
build:
9-
runs-on: macos-latest
10-
steps:
11-
- uses: actions/checkout@v4
12-
- name: Build
13-
run: swift run -c release bytesized
14-
- uses: actions/upload-artifact@v4
15-
with:
16-
name: bytesized
17-
path: Output/
18-
deploy:
19-
needs: build
13+
deploy_backend:
14+
name: Deploy Backend
2015
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
env:
19+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
20+
AWS_REGION: ${{ vars.AWS_REGION }}
21+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
22+
GENERATED_IMAGES_BUCKET: ${{ vars.GENERATED_IMAGES_BUCKET }}
23+
IMAGE_GEN_PREFIX: ${{ vars.IMAGE_GEN_PREFIX }}
24+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
25+
OPENAI_IMAGE_MODEL: ${{ vars.OPENAI_IMAGE_MODEL }}
26+
RAILWAY_PROJECT_ID: ${{ vars.RAILWAY_PROJECT_ID }}
27+
RAILWAY_ENVIRONMENT_NAME: ${{ vars.RAILWAY_ENVIRONMENT_NAME }}
28+
RAILWAY_RUNTIME_HOST: "0.0.0.0"
29+
RAILWAY_RUNTIME_PORT: "8080"
30+
RAILWAY_SERVICE_NAME: ${{ vars.RAILWAY_SERVICE_NAME }}
31+
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
2132
steps:
22-
- uses: actions/download-artifact@v4
23-
with:
24-
name: bytesized
25-
path: Output/
26-
# Sync HTML content
27-
- uses: jakejarvis/s3-sync-action@master
33+
- uses: actions/checkout@v4
34+
35+
- name: Set up Node
36+
uses: actions/setup-node@v4
2837
with:
29-
args: --acl public-read --follow-symlinks --exclude '*' --include 'posts/*' --include 'page/*' --include 'index.html' --content-type 'text/html'
30-
env:
31-
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
32-
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
33-
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
34-
SOURCE_DIR: 'Output/'
35-
# Sync resources
36-
- uses: jakejarvis/s3-sync-action@master
38+
node-version: "22"
39+
40+
- name: Validate Railway configuration
41+
run: |
42+
set -euo pipefail
43+
44+
: "${AWS_ACCESS_KEY_ID:?AWS_ACCESS_KEY_ID is required}"
45+
: "${AWS_REGION:?AWS_REGION is required}"
46+
: "${AWS_SECRET_ACCESS_KEY:?AWS_SECRET_ACCESS_KEY is required}"
47+
: "${GENERATED_IMAGES_BUCKET:?GENERATED_IMAGES_BUCKET is required}"
48+
: "${IMAGE_GEN_PREFIX:?IMAGE_GEN_PREFIX is required}"
49+
: "${OPENAI_API_KEY:?OPENAI_API_KEY is required}"
50+
: "${OPENAI_IMAGE_MODEL:?OPENAI_IMAGE_MODEL is required}"
51+
: "${RAILWAY_PROJECT_ID:?RAILWAY_PROJECT_ID is required}"
52+
: "${RAILWAY_ENVIRONMENT_NAME:?RAILWAY_ENVIRONMENT_NAME is required}"
53+
: "${RAILWAY_SERVICE_NAME:?RAILWAY_SERVICE_NAME is required}"
54+
: "${RAILWAY_TOKEN:?RAILWAY_TOKEN is required}"
55+
56+
- name: Sync Railway backend variables
57+
run: ./Scripts/sync-railway-backend-variables.sh
58+
59+
- name: Deploy backend to Railway
60+
run: |
61+
set -euo pipefail
62+
63+
npx -y @railway/cli up Backend \
64+
--ci \
65+
--path-as-root \
66+
--project "${RAILWAY_PROJECT_ID}" \
67+
--environment "${RAILWAY_ENVIRONMENT_NAME}" \
68+
--service "${RAILWAY_SERVICE_NAME}" \
69+
--message "GitHub Actions ${GITHUB_SHA}"
70+
71+
deploy_site:
72+
name: Deploy Site
73+
runs-on: macos-latest
74+
needs: deploy_backend
75+
env:
76+
AWS_REGION: ${{ vars.AWS_REGION }}
77+
BYTESIZED_CAFE_API_URL: ${{ vars.BYTESIZED_CAFE_API_URL }}
78+
steps:
79+
- uses: actions/checkout@v4
80+
81+
- name: Set up just
82+
uses: extractions/setup-just@v3
83+
84+
- name: Validate site API URL
85+
run: |
86+
set -euo pipefail
87+
88+
: "${AWS_REGION:?AWS_REGION is required}"
89+
: "${BYTESIZED_CAFE_API_URL:?BYTESIZED_CAFE_API_URL is required}"
90+
91+
- name: Set up SwiftWasm
92+
uses: swiftwasm/setup-swiftwasm@v2
93+
94+
- name: Configure AWS credentials
95+
uses: aws-actions/configure-aws-credentials@v4
3796
with:
38-
args: --acl public-read --follow-symlinks --include '*' --exclude 'posts/*' --exclude 'page/*' --exclude 'index.html'
97+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
98+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
99+
aws-region: ${{ vars.AWS_REGION }}
100+
101+
- name: Install Binaryen
102+
run: brew install binaryen
103+
104+
- name: Build SwiftWASM app
105+
run: just wasm
106+
107+
- name: Build site
108+
run: just site-release
109+
110+
- name: Deploy site
39111
env:
40112
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
41-
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
42-
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
43-
SOURCE_DIR: 'Output/'
44-
# Invalidate CloudFront cache
45-
- name: Invalidate CloudFront cache
46-
uses: chetan/invalidate-cloudfront-action@v2
47-
env:
48-
DISTRIBUTION: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
49-
PATHS: '/index.html /page/* /feed.rss /css/styles.css'
50-
AWS_REGION: 'us-east-1'
51-
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
52-
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
113+
run: just site-deploy

.github/workflows/validate.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Validate
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
validate_deployment_config:
11+
name: Validate Deployment Config
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Set up just
19+
uses: extractions/setup-just@v3
20+
21+
- name: Validate Docker and workflow YAML
22+
run: just validate-deployment

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
.DS_Store
2+
.ENV
23
Output/*
4+
/bytesized-cafe-app/
35
/fonts/*
46
/.swiftpm/*
57
/.publish
68
/.build
9+
**/.build
710
.vscode/settings.json
811
/CLAUDE.md
12+
.railway/
13+
.swiftpm
14+
/Package.resolved
15+
/BytesizedCafe/Package.resolved

.swift-format

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"indentation": {
3+
"spaces": 4
4+
}
5+
}

AGENTS.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# AGENTS.md
2+
3+
Instructions for coding agents working on this repo.
4+
## General
5+
- When adding new dependencies, check Github to make sure that you’re adding them at the latest release.
6+
- When naming files/targets, prefer non-project namespaced names (eg Server vs BytesizedServer)
7+
## Validating Changes
8+
- Run the swift-format skill
9+
- Run `./Scripts/validate-deployment-config.sh` when changing `Backend/Dockerfile`, `.github/workflows`, or deployment-related scripts
10+
- Keep `SPEC.md` up-to-date when making changes.
11+
- You don't need to run swift-format and swift-test to validate changes to markdown files.
12+
13+
## Build & Run Commands
14+
- List available recipes: `just help`
15+
- Build the WebAssembly app: `just wasm`
16+
- Build site: `just site`
17+
- Build with release config: `just site-release`
18+
- Build site against a configured local cafe API: `just site-local`
19+
- Run local stack: `just local`
20+
- Run backend only: `just backend`
21+
- Validate deployment config: `just validate-deployment`
22+
- Deploy site to S3: `just site-deploy`
23+
24+
`just` loads environment variables from `.ENV` automatically.
25+
26+
## Project Structure
27+
- `Sources/bytesized/`: Swift source files
28+
- `Content/posts/`: Markdown blog posts
29+
- `Resources/`: Static assets (CSS, fonts, images)
30+
- `Output/`: Generated site (not checked in)
31+
32+
## Content Writing
33+
- Use Markdown for all content in the Content/posts directory
34+
- Include proper metadata with title, date, and path
35+
36+
## Code Style Guidelines
37+
- Swift 6.2+ codebase using the Publish framework
38+
- Use descriptive variable/function names in camelCase
39+
- Consistent 4-space indentation
40+
- Prefer `Struct` to `Enum` for general data structures
41+
- Group extensions with the type they extend
42+
- Use Swift's strong type system
43+
- Organize imports alphabetically: Foundation first, then third-party
44+
- Keep functions small and focused on a single responsibility
45+
- Use Swift's error handling with do/try/catch
46+
- Follow CommonMark for Markdown content
47+
- Use the `swift-concurrency` skill for Swift concurrency guidance.
48+
- Always mark @Observable classes with @MainActor.
49+
- Assume strict Swift concurrency rules are being applied.
50+
- Prefer Swift-native alternatives to Foundation methods where they exist, such as using replacing("hello", with: "world") with strings rather than replacingOccurrences(of: "hello", with: "world").
51+
- Prefer modern Foundation API, for example URL.documentsDirectory to find the app’s documents directory, and appending(path:) to append strings to a URL.
52+
- Never use C-style number formatting such as Text(String(format: "%.2f", abs(myNumber))); always use Text(abs(change), format: .number.precision(.fractionLength(2))) instead.
53+
- Prefer static member lookup to struct instances where possible, such as .circle rather than Circle(), and .borderedProminent rather than BorderedProminentButtonStyle().
54+
- Never use old-style Grand Central Dispatch concurrency such as DispatchQueue.main.async(). If behavior like this is needed, always use modern Swift concurrency.
55+
- Filtering text based on user-input must be done using localizedStandardContains() as opposed to contains().
56+
- Avoid force unwraps and force try unless it is unrecoverable.
57+
58+
## Tools
59+
- Prefer `ast-grep` for syntax-aware searches; only use `rg` for plain-text matching when needed.
60+
- Use the `gh` CLI for GitHub operations when available (e.g., creating repos and pushing).

Backend/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.build
2+
.swiftpm
3+
.DS_Store

Backend/Dockerfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM swift:6.2.4-bookworm AS build
2+
3+
WORKDIR /app
4+
5+
RUN apt-get update \
6+
&& apt-get install -y --no-install-recommends libssl-dev \
7+
&& rm -rf /var/lib/apt/lists/*
8+
9+
COPY Package.swift Package.resolved ./
10+
COPY Sources ./Sources
11+
12+
RUN swift build -c release --product Server
13+
14+
FROM swift:6.2.4-bookworm-slim AS runtime
15+
16+
WORKDIR /app
17+
18+
COPY --from=build /app/.build/release/Server /usr/local/bin/Server
19+
20+
ENV HOST=0.0.0.0
21+
ENV PORT=8080
22+
23+
EXPOSE 8080
24+
25+
CMD ["Server"]

0 commit comments

Comments
 (0)