feat: clone tooling — scripts/new-site.sh + README
- scripts/new-site.sh: interactive setup for a fresh clone (prompts identity, writes site.config.json, runs configure, optional git reset + dep install) - README.md: what's inside, quick start, site.config.json/configure workflow, backend setup, directory layout Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYHWLHihq3v9nxNwoPCKSn
This commit is contained in:
parent
fc84d095b8
commit
92fa6c9140
3 changed files with 198 additions and 0 deletions
105
README.md
Normal file
105
README.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# SeedProject base
|
||||
|
||||
A cloneable foundation for building websites — a static [Astro](https://astro.build)
|
||||
frontend with a PHP backend, an AI authoring console, and an autonomous content
|
||||
pipeline. Clone it, set one config file, and build out a new site (a lawyer's
|
||||
office, a roofing company, a niche publication) the way you'd spin up a new
|
||||
WordPress install — but faster to host and safer to run.
|
||||
|
||||
## What's inside
|
||||
|
||||
| Path | Role | "WordPress equivalent" |
|
||||
|------|------|------------------------|
|
||||
| `app/` | Astro theme — layouts, components, content collections, sample post | theme + posts |
|
||||
| `api/` | [SeedProject](api/.memory/documentation.md) PHP framework — the dynamic backend (DB, forms, metrics, agents) | PHP core |
|
||||
| `content-pipeline/` | Autonomous content engine — research, write, review, publish | (no equivalent) |
|
||||
| `astroagent.config.json` + `app/.astroagent/` | AI authoring console — change the site in plain English | wp-admin |
|
||||
| `site.config.json` | **Single source of site identity** — the one file you edit per site | wp-config + Site Settings |
|
||||
|
||||
## Quick start — spin up a new site
|
||||
|
||||
```bash
|
||||
git clone https://repo.carlosarias.com/carlos/seedproject-web.git my-site
|
||||
cd my-site
|
||||
./scripts/new-site.sh # prompts for name/URL/author → writes site.config.json,
|
||||
# stamps every engine, (optionally) resets git + installs deps
|
||||
cd app && npm run build # builds the static site into ./public
|
||||
```
|
||||
|
||||
Then point a web server's document root at `./public` and alias `/api` to `./api`
|
||||
(see [Backend](#backend-api)).
|
||||
|
||||
## The one file you edit: `site.config.json`
|
||||
|
||||
All site identity lives here:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Acme Roofing",
|
||||
"url": "https://acmeroofing.com",
|
||||
"description": "Denver's trusted roofing contractor since 1998.",
|
||||
"tagline": "Roofs done right",
|
||||
"language": "en",
|
||||
"timezone": "America/Denver",
|
||||
"topic": "residential and commercial roofing",
|
||||
"audience": "Denver-area homeowners and property managers",
|
||||
"author": { "slug": "acme", "name": "Acme Roofing", "jobTitle": "...", "avatar": "/avatar-placeholder.png", "bio": "...", "longBio": "...", "knowsAbout": [], "sameAs": [] },
|
||||
"social": { "twitter": "" }
|
||||
}
|
||||
```
|
||||
|
||||
After editing it, run:
|
||||
|
||||
```bash
|
||||
node scripts/configure.mjs
|
||||
```
|
||||
|
||||
This stamps the values into the Astro theme (`app/src/config/site.json`),
|
||||
`content-pipeline/config.json`, and `astroagent.config.json` so all three engines
|
||||
share one identity. `new-site.sh` runs it for you.
|
||||
|
||||
## Backend (`api/`)
|
||||
|
||||
The `api/` directory is the SeedProject PHP framework, meant to be served at
|
||||
`/api` on the same domain (the static frontend calls it same-origin). It needs:
|
||||
|
||||
- **Composer deps:** `cd api && composer install`
|
||||
- **Config:** `api/config.php` with your database credentials (git-ignored). Until
|
||||
the CLI installer ships (see below), create it by hand or use the framework's
|
||||
web installer under `api/install/`.
|
||||
- **A PHP-FPM handler** in your web server for `/api`, with a front-controller
|
||||
rewrite to `api/index.php`. Example Apache/nginx snippets are in
|
||||
[`api/.memory/foundation.md`](api/.memory/foundation.md).
|
||||
|
||||
> **Planned — the Foundation:** a `php console app:install` (DB + config + schema)
|
||||
> and `php console db:migrate`, plus a two-tier auth layer and a `/api/health`
|
||||
> round-trip. Design + implementation plan: [`api/.memory/foundation.md`](api/.memory/foundation.md)
|
||||
> and [`api/.memory/foundation-plan.md`](api/.memory/foundation-plan.md).
|
||||
|
||||
## Content pipeline & authoring
|
||||
|
||||
- **`content-pipeline/`** — autonomous research/write/review/publish scripts driven
|
||||
by `content-pipeline/config.json` (populated from `site.config.json`). Runtime
|
||||
state (`drafts/`, `state/`, `logs/`, queues) is git-ignored and regenerates per site.
|
||||
- **astroagent** — the in-site console for making changes in plain English; its
|
||||
identity comes from `astroagent.config.json`.
|
||||
|
||||
## Directory layout
|
||||
|
||||
```
|
||||
my-site/
|
||||
├── site.config.json ← edit this
|
||||
├── scripts/
|
||||
│ ├── new-site.sh ← one-time setup for a fresh clone
|
||||
│ └── configure.mjs ← stamp site.config.json into every engine
|
||||
├── app/ ← Astro frontend (build → ../public)
|
||||
├── api/ ← SeedProject PHP backend (served at /api)
|
||||
├── content-pipeline/ ← autonomous content engine
|
||||
└── public/ ← build output (git-ignored)
|
||||
```
|
||||
|
||||
## What's git-ignored
|
||||
|
||||
Secrets (`**/.env`, `api/config.php`), dependencies (`node_modules/`, `api/vendor/`),
|
||||
build output (`public/`, `app/dist/`), and per-site runtime state. A fresh clone
|
||||
installs deps and generates the rest.
|
||||
0
scripts/configure.mjs
Normal file → Executable file
0
scripts/configure.mjs
Normal file → Executable file
93
scripts/new-site.sh
Executable file
93
scripts/new-site.sh
Executable file
|
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# new-site.sh — turn a fresh clone of the SeedProject base into a new site.
|
||||
#
|
||||
# Usage (from the repo root, after cloning):
|
||||
# ./scripts/new-site.sh
|
||||
#
|
||||
# Prompts for this site's identity, writes site.config.json, stamps it across
|
||||
# every engine (Astro theme, content-pipeline, astroagent), optionally resets
|
||||
# git history and installs dependencies.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
echo "=================================================="
|
||||
echo " SeedProject — new site setup"
|
||||
echo "=================================================="
|
||||
echo " Press Enter to accept each [default]."
|
||||
echo
|
||||
|
||||
# Current values from site.config.json become the defaults.
|
||||
get() { node -e "process.stdout.write(String((JSON.parse(require('fs').readFileSync('site.config.json','utf8'))$1) ?? ''))"; }
|
||||
ask() { local var; read -r -p "$1 [$2]: " var || true; printf '%s' "${var:-$2}"; }
|
||||
|
||||
NAME="$(ask 'Site name' "$(get .name)")"
|
||||
URL="$(ask 'Site URL' "$(get .url)")"
|
||||
DESC="$(ask 'One-line description' "$(get .description)")"
|
||||
TAG="$(ask 'Tagline' "$(get .tagline)")"
|
||||
TOPIC="$(ask 'Topic / niche' "$(get .topic)")"
|
||||
AUD="$(ask 'Audience' "$(get .audience)")"
|
||||
TZ="$(ask 'Timezone' "$(get .timezone)")"
|
||||
AUTHOR="$(ask 'Author name' "$(get '.author.name')")"
|
||||
TW="$(ask 'Twitter/X URL (optional)' "$(get '.social.twitter')")"
|
||||
|
||||
# Derive a URL-safe author slug from the name.
|
||||
SLUG="$(printf '%s' "$AUTHOR" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g')"
|
||||
|
||||
echo
|
||||
echo "Writing site.config.json ..."
|
||||
NAME="$NAME" URL="$URL" DESC="$DESC" TAG="$TAG" TOPIC="$TOPIC" AUD="$AUD" TZ="$TZ" AUTHOR="$AUTHOR" SLUG="$SLUG" TW="$TW" \
|
||||
node -e '
|
||||
const fs = require("fs");
|
||||
const c = JSON.parse(fs.readFileSync("site.config.json", "utf8"));
|
||||
const e = process.env;
|
||||
c.name = e.NAME; c.url = e.URL; c.description = e.DESC; c.tagline = e.TAG;
|
||||
c.topic = e.TOPIC; c.audience = e.AUD; c.timezone = e.TZ;
|
||||
c.author = { ...c.author, name: e.AUTHOR, slug: e.SLUG };
|
||||
c.social = { ...c.social, twitter: e.TW };
|
||||
fs.writeFileSync("site.config.json", JSON.stringify(c, null, 2) + "\n");
|
||||
'
|
||||
|
||||
echo "Stamping identity across engines ..."
|
||||
node scripts/configure.mjs
|
||||
|
||||
read -r -p "Reset git history for this new site? [y/N]: " RESETGIT || true
|
||||
if [[ "${RESETGIT:-}" =~ ^[Yy]$ ]]; then
|
||||
rm -rf .git
|
||||
git init -q -b main
|
||||
git add -A
|
||||
git commit -q -m "chore: initialize ${NAME} from SeedProject base"
|
||||
echo " fresh git history initialized."
|
||||
fi
|
||||
|
||||
read -r -p "Install dependencies now (npm + composer)? [Y/n]: " DEPS || true
|
||||
if [[ ! "${DEPS:-Y}" =~ ^[Nn]$ ]]; then
|
||||
echo " npm install (app) ..."
|
||||
( cd app && npm install --no-audit --no-fund )
|
||||
if command -v composer >/dev/null 2>&1; then
|
||||
echo " composer install (api) ..."
|
||||
( cd api && composer install --no-interaction ) || echo " (composer install failed — run it manually in api/)"
|
||||
else
|
||||
echo " composer not found — run 'composer install' in api/ manually."
|
||||
fi
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
|
||||
--------------------------------------------------
|
||||
Done — "${NAME}" is configured.
|
||||
|
||||
Next steps:
|
||||
1. Build the site: cd app && npm run build (outputs to ./public)
|
||||
2. Serve it: point your web server's document root at ./public,
|
||||
and alias /api -> ./api for the PHP backend (see README.md).
|
||||
3. Backend (optional): the /api PHP backend needs api/config.php with DB
|
||||
credentials. See README.md > "Backend (/api)".
|
||||
|
||||
Change identity anytime: edit site.config.json, then run
|
||||
node scripts/configure.mjs
|
||||
--------------------------------------------------
|
||||
EOF
|
||||
Loading…
Reference in a new issue