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
95 changes: 95 additions & 0 deletions .github/workflows/api-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: api-ci

on:
push:
branches: [main]
paths:
- "apps/api/**"
- "infra/migrations/**"
- "infra/migrate.py"
- ".github/workflows/api-ci.yml"
pull_request:
paths:
- "apps/api/**"
- "infra/migrations/**"
- "infra/migrate.py"
- ".github/workflows/api-ci.yml"

jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_USER: newstack
POSTGRES_PASSWORD: newstack
POSTGRES_DB: newstack
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U newstack"
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:7-alpine
ports: ["6379:6379"]
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgresql://newstack:newstack@localhost:5432/newstack
REDIS_URL: redis://localhost:6379
WEB_ORIGIN: http://localhost:5173
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: apps/api/package-lock.json

- name: Install dependencies
working-directory: apps/api
run: npm ci

# No lint tool configured for apps/api yet (ARCHITECTURE §12 wants lint -> type-check
# -> test -> build; this step is a placeholder for when one is added).
- name: Lint
working-directory: apps/api
run: echo "no lint tool configured for apps/api yet — skipping"

- name: Type-check
working-directory: apps/api
run: npx tsc --noEmit -p tsconfig.json

# Migrations are the only schema authority (ARCHITECTURE §12) — applied by the same
# Python script every environment uses, not a copy.
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Apply migrations
run: |
pip install "psycopg[binary]"
python infra/migrate.py

- name: Test
working-directory: apps/api
run: npm test

- name: Build
working-directory: apps/api
run: npm run build

deploy:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
# No hosting target configured yet (mvp-todo.md "Hosting/domain topology" — needs a
# real Render/Railway/Fly.io account per ARCHITECTURE §2). Fill in here once one exists;
# the job is kept as a no-op placeholder so the pipeline shape matches §12 now.
- run: echo "deploy target not configured yet"
86 changes: 86 additions & 0 deletions .github/workflows/ingestion-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: ingestion-ci

on:
push:
branches: [main]
paths:
- "apps/ingestion/**"
- "infra/migrations/**"
- "infra/migrate.py"
- ".github/workflows/ingestion-ci.yml"
pull_request:
paths:
- "apps/ingestion/**"
- "infra/migrations/**"
- "infra/migrate.py"
- ".github/workflows/ingestion-ci.yml"

jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_USER: newstack
POSTGRES_PASSWORD: newstack
POSTGRES_DB: newstack
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U newstack"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgresql://newstack:newstack@localhost:5432/newstack
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
cache-dependency-path: apps/ingestion/requirements.txt

# sentence-transformers downloads the embedding model from HuggingFace on first use
# (torch + fasttext-wheel are large wheels too) — cached across runs so this isn't a
# multi-minute download every time.
- name: Cache HuggingFace / torch model cache
uses: actions/cache@v4
with:
path: |
~/.cache/huggingface
~/.cache/torch
key: ingestion-models-${{ hashFiles('apps/ingestion/requirements.txt') }}

- name: Install dependencies
run: pip install -r apps/ingestion/requirements.txt

# No lint/type-check tool configured for apps/ingestion yet (ARCHITECTURE §12 wants
# lint -> type-check -> test -> build; these steps are placeholders for when one's added).
- name: Lint
run: echo "no lint tool configured for apps/ingestion yet — skipping"
- name: Type-check
run: echo "no type-check tool configured for apps/ingestion yet — skipping"

- name: Apply migrations
run: python infra/migrate.py

- name: Test
working-directory: apps/ingestion
run: python -m pytest tests -v

# No bundling step for Python — "build" here means the deployable artifact actually
# builds (ARCHITECTURE §2's worker runs from this image, per infra/docker-compose.yml).
- name: Build
run: docker build -t newstack-ingestion-ci apps/ingestion

deploy:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
# No hosting target configured yet (mvp-todo.md "Hosting/domain topology" — needs a
# real small VM per ARCHITECTURE §2). Fill in here once one exists; the job is kept as
# a no-op placeholder so the pipeline shape matches §12 now.
- run: echo "deploy target not configured yet"
57 changes: 57 additions & 0 deletions .github/workflows/web-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: web-ci

on:
push:
branches: [main]
paths:
- "apps/web/**"
- ".github/workflows/web-ci.yml"
pull_request:
paths:
- "apps/web/**"
- ".github/workflows/web-ci.yml"

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: apps/web/package-lock.json

- name: Install dependencies
working-directory: apps/web
run: npm ci

- name: Lint
working-directory: apps/web
run: npm run lint

- name: Type-check
working-directory: apps/web
run: npx tsc --noEmit -p tsconfig.app.json

- name: Test
working-directory: apps/web
run: npx vitest run

# Re-typechecks via `tsc -b` on the way to bundling — harmless overlap with the
# standalone type-check step above, which exists so a type error is caught before the
# (slower) test run, not after it.
- name: Build
working-directory: apps/web
run: npm run build

deploy:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
# No hosting target configured yet (mvp-todo.md "Hosting/domain topology" — needs a
# real Vercel/Netlify account per ARCHITECTURE §2). Fill in here once one exists; the
# job is kept as a no-op placeholder so the pipeline shape matches §12 now.
- run: echo "deploy target not configured yet"
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
*.DS_Store
.idea/
.vscode/

docs/
validation/
.superpowers/
.claude/

CLAUDE.md

# backend (Python)
apps/ingestion/models/*.bin
__pycache__/
*.py[cod]
.pytest_cache/
.venv/
venv/
*.egg-info/
.mypy_cache/
.ruff_cache/

# frontend (apps/web, not built yet but planned)
node_modules/
dist/
build/
.next/
.turbo/
*.local

# env/secrets
.env
.env.*
!.env.example
14 changes: 14 additions & 0 deletions .spectral.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
extends:
- spectral:oas

rules:
# ARCHITECTURE §10/§12: every timestamp (*At) and count (*Count) field needs a
# `description` — this is what keeps docs/openapi.yaml's pinned meanings from drifting.
timestamp-count-fields-need-description:
description: Every timestamp (*At) and count (*Count) field must have a description.
message: "'{{property}}' is a timestamp/count field and must have a `description` (ARCHITECTURE §10 pinned meanings)."
severity: error
given: "$.components.schemas.*.properties[?(@property.match(/(At|Count)$/))]"
then:
field: description
function: truthy
8 changes: 8 additions & 0 deletions apps/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# apps/api/Dockerfile
FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["npm", "start"]
Loading
Loading