Skip to content
prod e051e98
Browse

1 · Dependencies & assets

Objective — get the frozen vendor snapshot ready to boot: authenticate Composer to dodge the rate limit, install PHP and JS dependencies without clobbering vendor patches, audit .env.example for fail-loud placeholders, then build and commit frontend assets.

The first boot starts with dependencies — but with three traps: Composer’s anonymous rate limit, the vendor’s patched vendor/ tree, and a .env.example full of real-looking placeholders that fail silently instead of loudly.

Give Composer a GitHub token before installing — anonymous pulls hit a 60-request/hour limit that fails large CodeCanyon installs partway through.

  1. Hand Composer a GitHub token so it never hits the anonymous limit.

    Terminal window
    composer config -g github-oauth.github.com "$(gh auth token)"
    # Expected: no output (the token is written to Composer's global auth.json)
    • ✅ The token is set without ever printing on screen.
  2. Confirm it landed with an exit-code check — never by reading the file.

    Terminal window
    composer config -g github-oauth.github.com >/dev/null 2>&1 && echo "✅ token set"
    # Expected: ✅ token set
    • ✅ token set prints.

Pull the locked PHP packages — but gate on vendor patches first if the ZIP shipped a pre-built vendor/.

  1. If a shipped vendor/ exists, diff it before any install (skip if vendor/ came from a prior lock-file install).

    /tech-stack/laravel/codecanyon/build/playbooks/setup-new/02-code-repo/03-extract-and-snapshot/
    if [ -d vendor ] && [ -f composer.lock ]; then
    echo "Shipped vendor/ detected — run the P2 extract diff or P3 page-6 procedure before composer install"
    # or page 6: /tech-stack/laravel/codecanyon/build/playbooks/setup-new/03-local-dev/06-commit-and-secure/
    fi
    • ✅ Either no shipped vendor/ exists, or author patches are documented in _CUSTOMIZATIONS.md before the install below.
  2. Install from the lock file.

    Terminal window
    composer install
    # Expected: "Generating optimized autoload files" with no errors
    • vendor/ is populated and Composer exits cleanly.
  3. If Composer dies with Allowed memory size … exhausted, lift the limit for the run.

    Terminal window
    COMPOSER_MEMORY_LIMIT=-1 composer install
    # Expected: the install completes without the memory error
    • ✅ Install completes under the lifted memory limit (if needed).
  4. Capture the required PHP extensions — the list the server must enable in Phase 4/9.

    Terminal window
    composer check-platform-reqs 2>/dev/null | grep -E "^ext-" | awk '{print $1}' | sort
    # Expected: a sorted list of ext-* requirements — save it for server setup
    • ✅ The ext-* requirements are recorded for staging/production provisioning.

3. Audit .env.example for fail-loud placeholders

Section titled “3. Audit .env.example for fail-loud placeholders”

A .env.example that ships with plausible-but-fake values (APP_KEY=base64:abc…, DB_DATABASE=laravel) is dangerous: a teammate copies it, the app boots against the wrong database, and the failure surfaces hours later as corrupt data. Placeholders must fail loud — empty or obviously-fake — so a missing value crashes immediately.

  1. Surface the risky keys.

    Terminal window
    grep -E "^(APP_KEY|DB_DATABASE|DB_USERNAME|DB_PASSWORD|MAIL_|STRIPE_)" .env.example || true
    # Expected: a line per key — flag any with a real-looking value
    • ✅ The keys carrying plausible-but-fake values are visible.
  2. Replace any real-looking value with a loud placeholder.

    KeyLoud placeholder
    APP_KEY=leave blank — key:generate fills it
    DB_DATABASE="REPLACE_ME_DB_NAME"
    DB_USERNAME="REPLACE_ME_DB_USER"
    DB_PASSWORD="REPLACE_ME_DB_PASS"
    STRIPE_KEY= / STRIPE_SECRET=leave blank
    • ✅ Every placeholder is blank or REPLACE_ME_* — nothing that could silently boot the wrong way.

Frontend assets are built on your machine and committed, so the production server never needs Node.js (the build-locally strategy). Install JS deps, then build.

  1. Install JS deps and build.

    Terminal window
    npm install
    npm run build # outputs to public/build/
    # Expected: a clean build with files written under public/build/
    • ✅ The build finishes and public/build/ is populated.
  2. Force-track the build output — it’s often gitignored by default, but the server relies on it.

    Terminal window
    git add -f public/build/
    ls public/build/manifest.json # must exist
    # Expected: the manifest.json path prints
    • public/build/manifest.json exists and is staged in git.

Capture a vulnerability baseline now — it’s the reference point for Phase 9 hardening. Don’t chase every advisory mid-setup; record the counts and move on unless something is critical in a runtime path.

  1. Record the audit baseline.

    Terminal window
    npm audit --omit=dev || true
    composer audit || true
    # Expected: advisory counts printed — note them, don't chase them all now
    • ✅ A baseline of npm + Composer advisories is recorded.
  2. Confirm composer.json doesn’t autoload dev files in production — a "files" array under autoload-dev breaks the production boot (composer install --no-dev skips it). The full pre-deploy check lives on page 5.

    • ✅ No production-required file is hiding under autoload-dev.

CodeCanyon Laravel apps ship wildly different Stripe wiring — canonical Laravel Cashier subscriptions, ad-hoc invoice-per-cycle code, or both architectures in the same codebase (a “dual-subsystem” pattern found in several Froiden/ResiDoro-family apps). Knowing which pattern is live gates every Stripe decision in Phase 6 (Task 62). Run the greps now, while vendor/ is fresh, and lock the answer into _CUSTOMIZATIONS.md.

  1. Check for canonical Laravel Cashier use (subscription model via the Billable trait).

    Terminal window
    grep -rn "use.*Billable\|->newSubscription\|->subscriptions()\|Cashier::" \
    app/ --include="*.php" | head -20
    # Expected: lines containing Billable trait, newSubscription(), or Cashier:: facade — or no output
    • ✅ If output exists: canonical Cashier is present (at least partially). Note the files.
    • ✅ If no output: no Cashier subscriptions — the app uses ad-hoc invoices only.
  2. Check for ad-hoc / custom Stripe webhook controller (invoice-per-cycle telltale).

    Terminal window
    grep -rn "StripeWebhookController\|stripe.*invoice\|invoice.*stripe" \
    app/ --include="*.php" -i | head -20
    # Expected: custom webhook handler or invoice references — or no output
    • ✅ A custom StripeWebhookController confirms ad-hoc billing is present.
  3. Check for dual-subsystem billing (SuperAdmin operator billing vs tenant-level billing — two separate Stripe flows).

    Terminal window
    grep -rn "SuperAdmin\|superadmin\|super_admin" routes/ app/ \
    --include="*.php" | grep -i "stripe\|subscription\|billing" | head -20
    # Expected: SuperAdmin-namespaced billing routes signal the dual-subsystem pattern
    • ✅ If SuperAdmin-scoped Stripe routes appear alongside non-SuperAdmin Cashier use: dual-subsystem confirmed.
  4. Record the findings in _CUSTOMIZATIONS.md.

    Use the decision table below to classify what you found, then replace the PROVISIONAL block (written in Phase 1B) with a VERIFIED block:

    What greps showedArchitectureStripe account strategy
    Cashier traits throughout, no custom webhook controllerSingle-tenant CashierOne Stripe account; restricted key rk_test_app_* safe
    Custom StripeWebhookController, no Cashier traitsAd-hoc invoices onlySingle Stripe account; standard key; webhook endpoint required
    Both Cashier traits AND custom controllerDual-subsystemPrefer a single Stripe account (Option C); both subsystems share one account
    SuperAdmin-scoped + non-SuperAdmin CashierDual-subsystem (operator + tenant)Prefer Option C; scope rk_test_app_* carefully
    No Stripe references foundNo StripeSkip; note no_stripe: true
    # Run from the project root — updates _CUSTOMIZATIONS.md in-place
    import pathlib, datetime
    today = datetime.date.today().isoformat()
    f = pathlib.Path("_CUSTOMIZATIONS.md")
    if not f.exists():
    print("⚠️ _CUSTOMIZATIONS.md missing — create it first (Phase 1/2), then re-run.")
    raise SystemExit(1)
    text = f.read_text()
    old = "## Stripe account strategy — PROVISIONAL"
    new = f"## Stripe account strategy — VERIFIED {today}"
    if old in text:
    text = text.replace(old, new)
    # Append verification note after the header line
    note = (
    f"\n\n> **Verified {today}** via Phase-3 architecture detection greps.\n"
    "> Grep results: <!-- paste summary here -->\n"
    "> Architecture class: <!-- Cashier / Ad-hoc / Dual-subsystem / None -->\n"
    )
    text = text.replace(new, new + note, 1)
    f.write_text(text)
    print(f"✅ Updated: PROVISIONAL → VERIFIED {today}")
    else:
    print("⚠️ No PROVISIONAL block found — add the Stripe strategy block manually.")
    # Expected: "✅ Updated: PROVISIONAL → VERIFIED <date>"
    • _CUSTOMIZATIONS.md now has a VERIFIED Stripe strategy block with the grep summary and architecture class filled in.

Do not mark this step done until every box below is checked.

  • 🤖 Composer authenticated — no rate-limit failures.
  • 🤖 Dependencies installedcomposer install and npm install succeeded.
  • 🤖 Vendor patches noted — any shipped-vendor/ patches flagged for the page-6 comparison.
  • 🤖 Placeholders loud.env.example values are blank or REPLACE_ME_*.
  • 🤖 Build force-trackedpublic/build/manifest.json built and git add -f’d.
  • 🤖 Audit baseline recordednpm audit / composer audit counts captured.
  • 🤖 Stripe architecture verified_CUSTOMIZATIONS.md updated with VERIFIED strategy, or skipped and no_stripe: true noted.