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
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly

- package-ecosystem: npm
directory: /frontend
schedule:
interval: weekly

# Backend Python dependencies are updated via the python-copier-template
# sync (uv.lock is regenerated on each render), so uv is not listed here.
43 changes: 43 additions & 0 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Checks for backend/, which is rendered from python-copier-template
# (see docs/backend-sync.md). Kept as a thin repo-owned workflow because the
# rendered workflows assume the project sits at the repository root.
name: Backend

on:
push:
branches: [main]
paths: ["backend/**", ".github/workflows/backend.yml"]
pull_request:
paths: ["backend/**", ".github/workflows/backend.yml"]

jobs:
backend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v5
with:
# setuptools_scm derives the version from git history
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
working-directory: backend

- name: Install dependencies
run: uv sync

- name: Lint
run: uv run ruff check .

- name: Check formatting
run: uv run ruff format --check .

- name: Type check
run: uv run ty check app tests

- name: Test
run: uv run pytest
45 changes: 45 additions & 0 deletions .github/workflows/contract.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Verifies the API contract between frontend and backend by booting the real
# backend and hitting the endpoints the frontend uses (frontend/src/api/backend.ts).
# This is what makes automated backend syncs from python-copier-template safe:
# a template change that breaks the contract turns this check red.
name: Contract

on:
push:
branches: [main]
paths: ["frontend/**", "backend/**", ".github/workflows/contract.yml"]
pull_request:
paths: ["frontend/**", "backend/**", ".github/workflows/contract.yml"]

jobs:
contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
working-directory: backend

- name: Start backend
working-directory: backend
run: |
uv sync
uv run uvicorn app.api:app --port 7000 &
timeout 30 bash -c 'until curl -sf http://localhost:7000/ > /dev/null; do sleep 1; done'

- name: "Contract: GET / returns version info"
run: |
body=$(curl -sf http://localhost:7000/)
echo "$body"
echo "$body" | jq -e 'to_entries[0].value | test("version")'

- name: "Contract: POST /predict echoes the input"
run: |
body=$(curl -sf -X POST http://localhost:7000/predict \
-H "Content-Type: application/json" -d '{"input": 5}')
echo "$body"
echo "$body" | jq -e '.output == 5'
61 changes: 61 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Builds both container images and runs the composed stack, checking the same
# contract as contract.yml but through nginx — catches images that build but
# cannot start (missing runtime deps, broken CMD, bad base tags) and proxy
# misconfiguration. Complements the docker.yml that python-copier-template
# renders into standalone backend repos.
name: Docker

on:
push:
branches: [main]
paths:
[
"frontend/**",
"backend/**",
"compose.yaml",
".github/workflows/docker.yml",
]
pull_request:
paths:
[
"frontend/**",
"backend/**",
"compose.yaml",
".github/workflows/docker.yml",
]

jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Build and start the stack
run: docker compose up -d --build

- name: Wait for the stack (nginx up and backend responding through it)
run: timeout 60 bash -c 'until curl -sf http://localhost:8080/api/ > /dev/null; do sleep 2; done'

- name: "Frontend served"
run: curl -sf http://localhost:8080/ | grep -q "<title>React Template</title>"

- name: "Contract via nginx: GET /api/ returns version info"
run: |
body=$(curl -sf http://localhost:8080/api/)
echo "$body"
echo "$body" | jq -e 'to_entries[0].value | test("version")'

- name: "Contract via nginx: POST /api/predict echoes the input"
run: |
body=$(curl -sf -X POST http://localhost:8080/api/predict \
-H "Content-Type: application/json" -d '{"input": 5}')
echo "$body"
echo "$body" | jq -e '.output == 5'

- name: Container logs
if: always()
run: docker compose logs

- name: Tear down
if: always()
run: docker compose down
38 changes: 38 additions & 0 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Frontend

on:
push:
branches: [main]
paths: ["frontend/**", ".github/workflows/frontend.yml"]
pull_request:
paths: ["frontend/**", ".github/workflows/frontend.yml"]

jobs:
frontend:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v5

- uses: actions/setup-node@v5
with:
node-version-file: frontend/.nvmrc
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Check formatting
run: npm run format:check

- name: Test
run: npm test

- name: Build
run: npm run build
108 changes: 5 additions & 103 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,104 +1,6 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
build/
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
# Root-level ignores only; frontend/ and backend/ have their own .gitignore.
.DS_Store
.idea/
.vscode/*
!.vscode/extensions.json
.env
.env.test

# parcel-bundler cache (https://parceljs.org/)
.cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port
33 changes: 33 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# CLAUDE.md

Fullstack template: React frontend (`frontend/`) + FastAPI backend (`backend/`).

## Ownership model — IMPORTANT

- `backend/` is a **rendered mirror** of
[python-copier-template](https://github.com/Komorebi-AI/python-copier-template)
(answers in `backend/.copier-answers.yml`). Do NOT edit files under
`backend/` in this repo: a sync job re-renders the template and replaces the
whole directory, wiping local changes. Backend changes belong in
python-copier-template. Exceptions applied by the sync itself: rendered
`.github/` is dropped, and `[tool.setuptools_scm] root = ".."` is set in
`backend/pyproject.toml`. Files marked `TEMPORARY` carry patches for known
upstream bugs. See `docs/backend-sync.md`.
- `frontend/` and everything at the repo root are owned by this repo and
edited normally.

## Commands

- Frontend (`cd frontend`): npm. `npm run dev` (port 5173), `npm test`,
`npm run lint`, `npm run build`.
- Backend (`cd backend`): uv, never pip. `uv run python app/api.py` (port
7000), `uv run pytest`, `uv run ruff check .`, `uv run ty check app tests`.
- Full stack: `docker compose up --build` (port 8080). Root `Makefile` has
delegating targets.

## API contract

The frontend example calls `GET /api/` (version) and `POST /api/predict`;
both proxies (Vite dev, nginx) strip the `/api` prefix before the backend.
If a template sync changes `backend/app/api.py`, update
`frontend/src/api/backend.ts` and its tests to match.
34 changes: 34 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.PHONY: install dev-frontend dev-backend test lint build up down

# Convenience targets delegating to the two projects. See frontend/README.md
# and backend/README.md for the full command reference of each side.

install:
npm --prefix frontend install
cd backend && uv sync

# Run these in two terminals for local development
dev-frontend:
npm --prefix frontend run dev

dev-backend:
cd backend && uv run python app/api.py

test:
npm --prefix frontend test
cd backend && uv run pytest

lint:
npm --prefix frontend run lint
npm --prefix frontend run format:check
cd backend && uv run ruff check . && uv run ruff format --check . && uv run ty check app tests

build:
npm --prefix frontend run build

# Full stack in containers
up:
docker compose up --build

down:
docker compose down
Loading