Skip to content
Merged
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
12 changes: 0 additions & 12 deletions .context/architecture/repository-layout.md

This file was deleted.

34 changes: 0 additions & 34 deletions .context/decisions/tooling.md

This file was deleted.

1 change: 0 additions & 1 deletion .context/failures/.gitkeep

This file was deleted.

5 changes: 0 additions & 5 deletions .context/failures/README.md

This file was deleted.

11 changes: 0 additions & 11 deletions .context/runbooks/local-dev.md

This file was deleted.

1 change: 0 additions & 1 deletion .context/summaries/.gitkeep

This file was deleted.

5 changes: 0 additions & 5 deletions .context/summaries/README.md

This file was deleted.

1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.github
.context
.cursor
.claude

.env
.env.*
Expand Down
24 changes: 12 additions & 12 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,32 @@ WEB_HOST=127.0.0.1
# WEB_PORT=8730
# WORKER_HEALTH_PORT=8735

# Docker-published infra ports. Leave unset locally to use deterministic worktree ports.
# Optional worktree orchestrator reservations. Leave unset for path-hashed ports.
# Use WORKTREE_PORT_BLOCK_START when the orchestrator reserves a small range.
# Use WORKTREE_PRIMARY_PORT when the orchestrator reserves one public port.
# WORKTREE_PRIMARY_PORT_TARGET can be WEB_PORT or API_PORT.
# WORKTREE_PORT_BLOCK_START=
# WORKTREE_PORT_BLOCK_SIZE=10
# WORKTREE_PRIMARY_PORT=
# WORKTREE_PRIMARY_PORT_TARGET=WEB_PORT

# Docker-published example infra ports. Leave unset locally to use deterministic worktree ports.
POSTGRES_HOST_BIND=127.0.0.1
# POSTGRES_HOST_PORT=8740
REDIS_HOST_BIND=127.0.0.1
# REDIS_HOST_PORT=8750
MINIO_HOST_BIND=127.0.0.1
# MINIO_API_HOST_PORT=8760
# MINIO_CONSOLE_HOST_PORT=8761

# Postgres
# Example database
POSTGRES_DB=app
POSTGRES_USER=app
POSTGRES_PASSWORD=app
POSTGRES_URL=postgresql://app:app@127.0.0.1:8740/app
DATABASE_URL=postgresql://app:app@127.0.0.1:8740/app

# Redis
# Example cache/queue
REDIS_URL=redis://127.0.0.1:8750/0
REDIS_QUEUE_NAME=jobs.default

# Optional object storage
MINIO_ENDPOINT=http://127.0.0.1:8760
MINIO_ROOT_USER=internal
MINIO_ROOT_PASSWORD=change-me
MINIO_INTERNAL_BUCKET=internal-transfers

# Observability
SENTRY_DSN=
OTEL_EXPORTER_OTLP_ENDPOINT=
Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Summary

-
- <!-- What changed and why. Replace this line. -->

## Validation

Expand Down
111 changes: 67 additions & 44 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ concurrency:

permissions:
contents: read
Comment thread
michaelmwu marked this conversation as resolved.
pull-requests: read

jobs:
changes:
runs-on: ubuntu-latest
outputs:
typescript: ${{ steps.filter.outputs.typescript }}
Comment thread
michaelmwu marked this conversation as resolved.
python: ${{ steps.filter.outputs.python }}
web: ${{ steps.filter.outputs.web }}
infra: ${{ steps.filter.outputs.infra }}
workflow: ${{ steps.filter.outputs.workflow }}
steps:
Expand All @@ -30,37 +29,37 @@ jobs:

- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
# paths-filter runs with token: "" below, so it needs enough history
# to compare commits locally instead of calling the PR files API.
fetch-depth: 0
persist-credentials: false

- id: filter
uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
with:
# Keep the workflow at contents:read. Empty token forces git-based
# detection and avoids requiring pull-requests:read.
token: ""
filters: |
python:
- "apps/api/**"
- "packages/shared/**"
- "tests/**"
- "pyproject.toml"
- "uv.lock"
- "scripts/*.sh"
- "scripts/*.py"
web:
- "apps/web/**"
typescript:
- "stacks/typescript/**"
- "package.json"
- "bun.lock"
- "bunfig.toml"
- "biome.json"
- "scripts/*.sh"
python:
- "stacks/python/**"
infra:
- "compose.yml"
- "docker-compose.yml"
- ".env.example"
workflow:
- ".github/workflows/**"

python:
typescript:
needs: changes
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.workflow == 'true'
if: needs.changes.outputs.typescript == 'true' || needs.changes.outputs.workflow == 'true'
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2
Expand All @@ -71,31 +70,28 @@ jobs:
with:
persist-credentials: false

- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
enable-cache: true

- name: Install Python
run: uv python install 3.12
bun-version: 1.3.13

- name: Install dependencies
run: uv sync --locked
run: bun install --frozen-lockfile

- name: Ruff
run: uv run ruff check apps packages tests
- name: Biome
run: bun run lint

- name: Ruff format
run: uv run ruff format --check apps packages tests
- name: Typecheck
run: bun run typecheck

- name: MyPy
run: uv run mypy
- name: Tests
run: bun run test

- name: Pytest
run: uv run pytest
- name: Build
run: bun run build

web:
python:
needs: changes
if: needs.changes.outputs.web == 'true' || needs.changes.outputs.workflow == 'true'
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.workflow == 'true'
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2
Expand All @@ -106,24 +102,19 @@ jobs:
with:
persist-credentials: false

- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
bun-version: 1.3.13

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Biome
run: bun run format:check && bun run lint
enable-cache: true

- name: Typecheck
run: bun run typecheck
- name: Install Python
run: uv python install 3.12

- name: Tests
run: bun run test
- name: Install dependencies
working-directory: stacks/python
run: uv sync --locked

- name: Build
run: bun run build
- name: Check Python stack
run: ./stacks/python/scripts/check-all.sh

compose:
needs: changes
Expand All @@ -140,3 +131,35 @@ jobs:

- name: Validate Compose config
run: docker compose -f compose.yml --env-file .env.example config

ci-passed:
if: always()
needs:
- changes
- typescript
- python
- compose
Comment thread
michaelmwu marked this conversation as resolved.
runs-on: ubuntu-latest
steps:
- name: Check required jobs
run: |
changes_result='${{ needs.changes.result }}'
typescript_result='${{ needs.typescript.result }}'
python_result='${{ needs.python.result }}'
compose_result='${{ needs.compose.result }}'
if [ "$changes_result" != "success" ]; then
echo "The changes job did not pass: changes=${changes_result}" >&2
exit 1
fi
# Component jobs may be skipped by the path filter. That is healthy
# only when path detection itself succeeded, which is checked above.
for result in "$typescript_result" "$python_result" "$compose_result"; do
case "$result" in
success|skipped)
;;
*)
echo "A required CI job did not pass: changes=${changes_result}, typescript=${typescript_result}, python=${python_result}, compose=${compose_result}" >&2
exit 1
;;
esac
done
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.DS_Store
.env
.venv/
.context/
.claude/
__pycache__/
.mypy_cache/
.pytest_cache/
Expand All @@ -14,5 +16,3 @@ build/
.next/
.turbo/
*.log
.context/artifacts/
.context/screenshots/
17 changes: 3 additions & 14 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: local
hooks:
- id: mypy
name: mypy
entry: ./scripts/typecheck.sh
language: system
pass_filenames: false
files: ^(apps/api/src|apps/worker/src|packages/shared/src)/
- id: biome
name: biome
entry: bun run format:check
language: system
pass_filenames: false
files: ^(apps/web/|packages/|scripts/|biome\.json$|package\.json$)
# Keep the hook scoped to root tooling and the TypeScript stack. Add
# stack-specific hooks only after selecting that stack for a target repo.
files: ^(stacks/typescript/|stacks/.*/package\.json$|scripts/|biome\.json$|package\.json$)
Loading