# Infra

> Infra — Index

- Skill: `persimmon-automation-labs/infra` (Agent Skill)
- Install (CLI): `npx skillmds@latest add persimmon-automation-labs/infra`
- Raw SKILL.md: https://api.skillmd.com/api/skills/persimmon-automation-labs/infra/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: Persimmon-Automation-Labs (https://skillmd.com/u/persimmon-automation-labs)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/persimmon-automation-labs/infra

---


# Infra — Index

Persimmon infra = Railway (app + DB + bucket in one project), S3-compatible storage with presigned uploads, resumable background jobs, and a minimal GitHub Actions CI. This mother is a map; follow the child for the actual work.

## Trigger

- "Deploy this" / "custom domain" / "env vars"
- "File upload" / "presigned URL" / "bucket CORS"
- "Background job" / "long-running task" / "queue / cron"
- "Set up CI"

## The child skills

| Skill | When to use | Owns |
|---|---|---|
| `infra-railway-deploy` | Project creation, deploy, domains | Railway project setup, env vars, custom domain, container port (8080), staged-config drift recovery |
| `infra-s3-uploads` | Any file upload flow | Presigned PUT flow, bucket CORS, multipart, content-type validation (Tigris/R2/S3) |
| `infra-background-jobs` | Work that can't finish in a request | Idempotent resumable pipelines on Railway (pg-boss / Inngest / cron) |
| `infra-github-ci` | CI pipeline | Minimal Next.js CI — lint, typecheck, `prisma validate`, build |

## How to route

1. **Deploying / hosting?** → `infra-railway-deploy`.
2. **Uploads?** → `infra-s3-uploads` (presigned PUT — never proxy bytes through Next).
3. **Long job?** → `infra-background-jobs` (idempotent + resumable).
4. **CI?** → `infra-github-ci`.

## Persimmon infra defaults — one-screen summary

- **Railway container port is `8080`** (from `PORT`). Public domain `targetPort` must match — not 3000.
- **Uploads**: server issues presigned URL → client PUTs directly to the bucket.
- **Bucket CORS** must include every uploading origin (`http://localhost:3000`, preview URLs, prod domains) via `PutBucketCorsCommand`, or uploads fail silently with `net::ERR_FAILED`.
- **Railway managed bucket** stays staged until the dashboard "Deploy" is committed once.
- **Staged-config drift**: committing an older draft reverts live mutations; Settings → Source → Disconnect → Reconnect drains the draft.
- **CD**: Railway auto-deploys on push to `main`. **CI**: lint, typecheck, `prisma validate`, build.

## Anti-patterns banned

- Public domain `targetPort` mismatched with `8080`
- Proxying upload bytes through Next instead of presigned PUT
- Missing CORS origins on the bucket
- Non-idempotent background jobs that can't resume
- Committing secrets — use Railway/GitHub env, never code

## Relationship to other mothers

| Mother | Connection |
|---|---|
| `stack` | Deployed app code follows `stack` conventions |
| `data` | Railway hosts Postgres + pgvector |
| `security` | `infra-github-ci` runs the checks `security-review` relies on |

