diff --git a/README.md b/README.md new file mode 100644 index 0000000..a09ea27 --- /dev/null +++ b/README.md @@ -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. diff --git a/scripts/configure.mjs b/scripts/configure.mjs old mode 100644 new mode 100755 diff --git a/scripts/new-site.sh b/scripts/new-site.sh new file mode 100755 index 0000000..9796d3e --- /dev/null +++ b/scripts/new-site.sh @@ -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 < ./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