Skip to content

Feature Injection Guide

Feature Injection Guide

Audience: Developers who want to add capabilities to a generated project Goal: Understand how to enable Commerce, Auth, Admin, and Tunnel features at generation time and after Version: Seed & Source CLI (sscli) v2.6.13+


Table of Contents

  1. What is Feature Injection?
  2. How the Injection System Works
  3. Quick Decision Tree
  4. Feature Reference
  5. Injection Modes: Flag-based vs AST-based
  6. Recipes by Template
  7. After Injection: What Changed?
  8. Verifying Injection
  9. Combining Features
  10. Troubleshooting Injection
  11. FAQ

1. What is Feature Injection?

Feature injection is the process of adding a capability to a generated project without manually writing boilerplate code. When you pass a flag like --with-commerce or --with-auth during project generation, sscli writes the necessary imports, wires up routes, and installs the right dependencies for that feature — automatically.

Think of it like installing a plugin, but instead of configuring it through a UI, the CLI does it surgically at the code level.

Key benefits:

  • No manual copy-paste of boilerplate
  • Feature-specific files land in the right folders
  • Dependencies added to the right config file (pyproject.toml, package.json, Gemfile)
  • Result is clean code that looks hand-written

2. How the Injection System Works

sscli supports two injection modes:

Standard Mode (default)

Copies pre-built feature stubs into your project and wires them via direct file manipulation. Fast and predictable.

AST Mode (experimental, --use-ast-injection)

Uses Abstract Syntax Tree (AST) codemods to insert imports, routes, and function calls at the correct locations in existing code. More precise — works on code that has already been modified.

Standard mode is recommended for most users.

Internal flow:

sscli new --template <template> --with-commerce --with-auth
Generator validates license tier
inject_features() runs per-feature
• Copies feature stubs into project
• Adds dependencies to config file
• Sets up secrets strategy (.env or Doppler)
Project is ready

3. Quick Decision Tree

Use this to figure out which flags you need:

What do I want to add?
├─ Online store / Shopify integration?
│ └─ → Use --with-commerce
├─ User login / signup / sessions?
│ └─ → Use --with-auth
├─ Staff-only admin panel?
│ └─ → Use --admin
│ (python-saas only; automatically adds NiceGUI admin routes)
├─ External webhook receiver / ngrok tunnel?
│ └─ → Use --with-tunnel
│ (opens a secure tunnel for local Shopify/Stripe dev)
├─ Local SQLite database for prototyping?
│ └─ → Use --with-sqlite
│ (python-saas only; configures SQLAlchemy to use SQLite)
├─ Data ingestion / ETL pipeline hooks?
│ └─ → Use --ingestor
│ (python-saas only; adds ingestor scaffold)
├─ Stripe subscription payments / checkout?
│ └─ → Use --with-payment
│ (python-saas + rails-api; injects Stripe checkout + webhook handler)
└─ Shopify merchant-facing dashboard?
└─ → Use --merchant-dashboard
(react-client only; adds merchant UI routes)

Template compatibility at a glance:

Feature Flagpython-saasreact-clientrails-apirails-fullstackstatic-landing
--with-commerce
--with-auth
--admin
--with-tunnel
--with-sqlite
--ingestor
--merchant-dashboard
--landing
--with-payment

4. Feature Reference

Commerce (--with-commerce)

What it does: Integrates a Shopify-compatible commerce layer into your project.

  • python-saas: Imports init_commerce from foundry_commerce, calls it during init_ui. Adds nicegui-commerce>=1.0.0 to pyproject.toml.
  • react-client: Adds CommerceProvider import and a /shop route wired to ShopPage.
  • rails-api: Adds commerce route scaffold and Stripe/Shopify webhook receiver.

When to use: You are building a store, marketplace, or any flow that takes payments or syncs inventory.

When NOT to use: Pure internal tooling or admin panels that don’t handle purchasing.


Auth (--with-auth)

What it does: Adds user authentication (login, session management, protected routes).

  • python-saas: Imports AuthManager from foundry_auth, runs AuthManager.setup(ui) during startup.
  • react-client: Adds AuthProvider import and a /login route wired to LoginPage.
  • rails-api: Adds Devise-compatible auth scaffold with JWT support.

When to use: Any multi-user app or anything that requires login.

When NOT to use: Internal single-user scripts or public read-only sites.


Admin (--admin)

What it does: Adds an admin panel accessible to authenticated staff only.

  • python-saas: Imports AdminPanel from nicegui_admin, registers it with AdminPanel.register(ui).

When to use: Internal dashboards (e.g., order management, user oversight).

When NOT to use: Public-facing user flows.


Tunnel (--with-tunnel)

What it does: Configures a secure ngrok-compatible tunnel for receiving webhooks in local development.

When to use: Working on Shopify/Stripe webhooks locally. You need a public HTTPS URL that points to localhost.

When NOT to use: Production environments (tunnels are development tools only).


SQLite (--with-sqlite)

What it does: Configures SQLAlchemy to use a local sqlite:///./dev.db instead of PostgreSQL.

When to use: Rapid local prototyping. You don’t want to spin up a Postgres container.

When NOT to use: Production or any multi-user workload.


Ingestor (--ingestor)

What it does: Adds an ingestion service scaffold (ETL pipeline hooks, queue consumer stub).

When to use: Data-heavy backends that receive external events (webhooks, file uploads, API pulls).


Merchant Dashboard (--merchant-dashboard)

What it does: Adds a Shopify merchant-facing React UI with product, order, and analytics views.

When to use: You are building a white-label merchant tool.


Payment (--with-payment)

What it does: Injects Stripe-hosted Checkout + webhook handler into your backend. You get:

  • A /payments/checkout endpoint that creates a Stripe Checkout session (redirect flow — PCI compliant, no card data in your code)
  • A /payments/webhooks/stripe endpoint that verifies Stripe-Signature and routes events
  • StripePaymentAdapter implementing PaymentGatewayPort (async, uses asyncio.to_thread() to avoid blocking)
  • All Stripe env var stubs added to .env.example
  • stripe Python SDK added as a dependency

For python-saas layout (src/ui/main.py): Router is wired via the SS-FEATURE-ROUTER marker. Routes land at /api/payments/checkout and /api/payments/webhooks/stripe.

For app-rooted projects (app/main.py, e.g. license-server): Files are auto-relocated to app/routes/payments.py and app/payment/, imports fixed automatically, router wired at /api/v1.

When to use: Any backend that needs subscription or one-time payments.

When NOT to use: Free-only apps, or if you are building a custom payment form (this feature uses Stripe-hosted Checkout, not a custom form).

After injecting: Follow → Stripe Dashboard Setup Runbook to get your API keys, register webhook endpoint, and create products/prices in Stripe.


5. Injection Modes: Flag-based vs AST-based

Standard (flag-based, default)

Terminal window
sscli new --template python-saas --with-commerce --with-auth --name my-project
  • Copies stubs from the internal feature library
  • Directly appends/prepends to config files
  • Works on freshly generated projects
  • No external tools needed

AST-based (experimental)

Terminal window
sscli new --template python-saas --with-commerce --with-auth --use-ast-injection --name my-project
  • Uses Python/JS/Ruby codemods to surgically modify existing code
  • Understands code structure — inserts at the right location, not just appended
  • Required if you have already modified generated code and want to inject a feature without overwrites
  • Requires ast-grep to be installed

Install ast-grep (for AST mode):

Terminal window
brew install ast-grep # macOS
cargo install ast-grep # any platform with Rust

6. Recipes by Template

python-saas (FastAPI + NiceGUI)

Minimal API backend:

Terminal window
sscli new --template python-saas --name my-api

Full SaaS with commerce + auth + admin:

Terminal window
sscli new --template python-saas --with-commerce --with-auth --admin --name my-saas

Webhook receiver (Shopify local dev):

Terminal window
sscli new --template python-saas --with-commerce --with-tunnel --name my-webhook-dev

Data ingestor:

Terminal window
sscli new --template python-saas --ingestor --name my-pipeline

Local-only prototype (no Postgres needed):

Terminal window
sscli new --template python-saas --with-sqlite --name my-prototype

SaaS backend with Stripe subscriptions:

Terminal window
sscli new --template python-saas --name my-saas --with-payment

Full SaaS with auth + commerce + payments:

Terminal window
sscli new --template python-saas --name my-saas --with-commerce --with-payment

react-client (React + Vite)

Plain admin UI:

Terminal window
sscli new --template react-client --name my-admin

Store frontend with auth:

Terminal window
sscli new --template react-client --with-commerce --with-auth --name my-store-frontend

Merchant dashboard:

Terminal window
sscli new --template react-client --merchant-dashboard --name my-merchant-ui

rails-api (Ruby on Rails)

API-only backend:

Terminal window
sscli new --template rails-api --name my-api

Full Rails with commerce + auth:

Terminal window
sscli new --template rails-api --with-commerce --with-auth --name my-rails-saas

Webhook receiver:

Terminal window
sscli new --template rails-api --with-commerce --with-tunnel --name my-rails-webhooks

Rails API with Stripe payments:

Terminal window
sscli new --template rails-api --name my-api --with-payment

rails-fullstack (Rails API + React Client, paired)

Note (2026-03-08): rails-fullstack is a fully validated injection target. It accepts the same flags as rails-api on the backend side.

API-only backend with commerce:

Terminal window
sscli new --template rails-fullstack --with-commerce --name my-fullstack-store

Full stack with commerce + auth:

Terminal window
sscli new --template rails-fullstack --with-commerce --with-auth --name my-rails-saas

Webhook receiver:

Terminal window
sscli new --template rails-fullstack --with-commerce --with-tunnel --name my-rails-webhooks

Full-stack with payment + auth:

Terminal window
sscli new --template rails-fullstack --name my-app --with-payment --with-auth

Pairing a Frontend and Backend (Full Stack)

Generate both with matching features enabled:

Terminal window
sscli new --template python-saas --with-commerce --with-auth --name backend
sscli new --template react-client --with-commerce --with-auth --name frontend

Or use the stack CLI interactive mode to wire them together automatically:

Terminal window
sscli interactive

7. After Injection: What Changed?

After running sscli new with feature flags, check these locations:

python-saas changes

AreaWhat changed
pyproject.tomlNew dependency added (e.g., nicegui-commerce, foundry_auth)
src/ui/main.pyImport + setup call added at init
src/features/Feature-specific module stub added
.env.exampleNew required variables added
app/routes/payments.py (app/ layout) or src/ui/api/payments.py (saas layout)Stripe checkout + webhook routes
app/payment/stripe_payment_adapter.pyStripe SDK adapter
app/payment/payment_gateway.pyPaymentGatewayPort ABC

react-client changes

AreaWhat changed
package.jsonNew dependency added
src/App.jsxProvider wrapper added
src/routes/New route entry added
src/components/Feature component stub added
.env.exampleVITE_* variables added

rails-api changes

AreaWhat changed
GemfileNew gem added
config/routes.rbNew route block injected
app/controllers/Feature controller added
.env.exampleNew variables added

After injecting --with-payment or --with-commerce

Your .env.example will contain Stripe variable stubs that must be filled in before the payment flow works. Follow the step-by-step setup guide:

→ Stripe Dashboard Setup Runbook

This guide covers: getting API keys, creating products and prices in Stripe, registering the webhook endpoint, choosing the correct integration mode (Checkout), and verifying everything end-to-end.


8. Verifying Injection

After generation, verify the feature was injected correctly:

Terminal window
# Check for the feature import in Python
grep -r "foundry_commerce\|foundry_auth\|AdminPanel" backend/src/
# Check for the feature route in React
grep -r "CommerceProvider\|AuthProvider\|/shop\|/login" frontend/src/
# Check for the gem in Rails
grep "commerce\|devise" backend/Gemfile
# Run the tests
cd backend && poetry run pytest
cd frontend && npm test

You can also run the full stack in Docker to confirm:

Terminal window
cd my-project
docker compose up

9. Combining Features

Features are additive — you can combine as many as make sense for your project.

Common valid combinations:

Use CaseFlags
SaaS with billing--with-commerce --with-auth
Internal admin only--admin --with-auth
Shopify webhook receiver--with-commerce --with-tunnel
Full merchant platform--with-commerce --with-auth --admin --merchant-dashboard
Local data prototyping--with-sqlite --ingestor

Features that conflict or are redundant:

  • --with-sqlite and a PostgreSQL-configured production environment don’t mix. SQLite is for dev only.
  • --with-tunnel is only meaningful during local development; remove it before production deploy.
  • --merchant-dashboard requires --with-commerce on the backend to have something to talk to.

10. Troubleshooting Injection

”Feature not found in generated project”

Symptom: You passed --with-commerce but don’t see any commerce-related files.

Fix:

  1. Confirm you are on a supported template: python-saas, react-client, rails-api, or rails-fullstack.
  2. Check your license tier — some features require ALPHA or PRO tier.
  3. Run with verbose output: sscli new --template python-saas --with-commerce --name my-project --verbose.

”AST injection failed: ast-grep not found”

Symptom: Error when using --use-ast-injection.

Fix:

Terminal window
brew install ast-grep # macOS
cargo install ast-grep # Linux/Windows with Rust
which ast-grep # confirm it's on PATH

“Feature injected but import not resolving”

Symptom: The code was injected but running the project gives ModuleNotFoundError or similar.

Fix:

  1. Install dependencies first: cd my-project && poetry install (Python) or npm install (React).
  2. The injected dependency may have a placeholder version — update it in pyproject.toml or package.json.
  3. Re-build the Docker image: docker compose build --no-cache.

”Duplicate imports or routes after re-injection”

Symptom: You ran sscli new again and ended up with duplicated code.

Fix: Standard injection is not idempotent on an already-modified project. Options:

  • Delete and regenerate the project (cleanest).
  • Switch to --use-ast-injection which has better idempotency checking via delta_store.
  • Manually remove the duplicate.

”Commerce works locally but fails on Render/production”

Symptom: The feature functions locally but not after deploying.

Fix:

  1. Check that all SHOPIFY_* / STRIPE_* environment variables are set in Render’s dashboard.
  2. Verify .env.example for all required keys and set them in the environment service.
  3. Check logs: render logs <service-id>.

11. FAQ

Q: Can I inject a feature into a project I already modified? A: Yes, but use --use-ast-injection. Standard injection works best on fresh projects.

Q: Can I inject multiple features at once? A: Yes. Pass all relevant flags in one sscli new command.

Q: What license tier do I need for Commerce? A: ALPHA or PRO tier. Free tier users can generate base templates only.

Q: Is the injected code mine to own and modify? A: Yes. Injection creates real source files in your project. There is no runtime dependency on sscli after generation.

Q: How do I add a feature to an existing project (not during generation)? A: Use sscli inject. For payment injection on an existing project:

Terminal window
sscli inject --path ./my-project --features payment --template python-saas

This works on both python-saas (src/ui/main.py) and app-rooted layouts (app/main.py). For other features, use the --with-* flags at generation time. Full inject support for all features is expanding in upcoming releases.

Q: How do I test the Stripe webhook locally after injecting --with-payment? A: Use the Stripe CLI:

Terminal window
stripe listen --forward-to http://localhost:8000/webhooks/stripe
stripe trigger checkout.session.completed
# Expect: POST /webhooks/stripe → 200 {"status":"ok"}

The Stripe CLI forwards real test Stripe events to your local endpoint and handles all signature verification setup automatically.

Q: What happens if I pass a flag that is not supported for my template? A: sscli silently skips unsupported flags. No error, no partial injection. Always verify with grep after generation (see Section 8).

Q: Where is AST injection configured? A: In foundry/codemods/python_codemods.py, js_codemods.py, ruby_codemods.py.


Last updated: March 8, 2026 — Payment injection (—with-payment / Stripe) added; sscli inject command documented For issues or corrections, see TROUBLESHOOTING.md