feat: add modular setup CLI for optional feature removal#58
feat: add modular setup CLI for optional feature removal#58matheuskafuri wants to merge 21 commits into
Conversation
Wrap feature-specific code blocks in container.go, router.go, auth.go, admin.go, middleware/auth.go, user.go, AppSidebar.tsx, config.yaml, routenames/names.go, and Makefile with start/end markers for the 5 optional features: payment, chat, mail, tasks, and files. These markers are inert comments that enable the setup CLI to surgically remove deselected features.
Interactive TUI tool (cmd/setup/) that lets developers opt-out of features they don't need when bootstrapping a Pagode project. Supports removing: Payment (Stripe), Chat (WebSocket), Mail (Resend), Background Tasks (Backlite), and File Upload. The tool deletes feature files, patches shared files via comment markers, regenerates Ent ORM, runs go mod tidy, and verifies both Go and frontend builds before cleaning itself up. Usage: make setup (or go run cmd/setup/main.go)
- Add FeatureName field to Module struct, replacing hardcoded name map in featureNamesFromModules so new features need no changes to main.go - Remove 6 unused Module fields (UserEdges, NavItems, RouteNames, etc.) - Always warn visibly when frontend build verification is skipped - Use filepath.Join/Dir instead of manual string slicing in projectRoot - Tighten isGitClean to only exempt untracked files in cmd/setup/
There was a problem hiding this comment.
Pull request overview
This PR introduces a one-shot “setup” CLI to remove optional features from the template (via [feature:<name>] markers), along with Ent regeneration/cleanup improvements and dedicated documentation/test coverage for the removal flow.
Changes:
- Added
cmd/setupTUI tool + removal pipeline (delete feature-owned files/dirs, patch marked blocks, regenerate Ent, tidy deps, verify builds, self-delete). - Added/expanded
[feature:*]markers across Go/TSX/YAML/Makefile so optional feature removal can safely excise shared references. - Added documentation (SETUP guide + design/test plan) and tests for marker patching and Ent cleanup behavior.
Reviewed changes
Copilot reviewed 29 out of 30 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| resources/js/components/ui/shape-landing-hero.tsx | Refactors motion easing values into shared constants. |
| resources/js/components/AppSidebar.tsx | Adds feature markers around optional nav items and icon imports. |
| resources/js/Pages/Plans.tsx | Adds icon import used by plan UI. |
| pkg/ui/layouts/primary.go | Adds feature markers around optional menu links. |
| pkg/services/container.go | Adds feature markers around optional services, imports, init/shutdown wiring. |
| pkg/routenames/names.go | Adds feature markers around optional route-name constants. |
| pkg/middleware/auth.go | Adds feature markers around payment-only imports and middleware. |
| pkg/handlers/router.go | Adds feature markers around optional WebSocket routing hooks. |
| pkg/handlers/auth.go | Adds feature markers around mail-only wiring and email behaviors. |
| pkg/handlers/admin.go | Adds feature markers around tasks/admin UI wiring (Backlite). |
| go.sum | Updates module checksums for new setup CLI dependencies. |
| go.mod | Adds indirect dependencies needed for the setup CLI. |
| ent/schema/user.go | Adds feature markers around optional edges (payment/chat). |
| ent/admin/types.go | Normalizes acronym casing for generated admin structs (e.g., IPHash). |
| ent/admin/handler.go | Updates generated admin UI column labels + casing. |
| ent/admin/extension_test.go | Adds tests for field-name/label acronym normalization. |
| ent/admin/extension.go | Adds acronym normalization helpers for admin generation. |
| docs/plans/2026-03-27-modular-setup-cli-test-plan.md | Adds a detailed manual regression test plan for feature removal. |
| docs/plans/2026-03-27-modular-setup-cli-design.md | Documents the setup CLI architecture and marker strategy. |
| config/config.yaml | Adds feature markers around optional config sections. |
| cmd/web/main.go | Adds feature markers around tasks startup wiring. |
| cmd/setup/remover_test.go | Adds regression test ensuring marker scan skips cmd/setup but patches cmd/web. |
| cmd/setup/remover.go | Implements marker scanning + block removal + small cleanup passes. |
| cmd/setup/modules.go | Declares optional feature manifests (files/dirs/schemas per feature). |
| cmd/setup/main.go | Adds TUI orchestration and end-to-end removal pipeline. |
| cmd/setup/cleanup_test.go | Adds tests for Ent stale artifact cleanup and pre-regeneration admin cleanup. |
| cmd/setup/cleanup.go | Implements Ent regen, stale Ent cleanup, build verification, and self-cleanup. |
| SETUP.md | Adds a dedicated setup guide (usage, internals, maintainer checklist). |
| README.md | Links to SETUP guide and documents optional feature setup entrypoint. |
| Makefile | Adds setup target + feature markers around chat-specific make target. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Remove the huh dependency and run go mod tidy again. | ||
| if err := c.runCmd("go", "get", "-u", "github.com/charmbracelet/huh@none"); err != nil { | ||
| // Ignore error — go mod tidy will clean it up anyway. | ||
| if c.verbose { | ||
| fmt.Printf(" note: could not remove huh dependency directly: %v\n", err) | ||
| } | ||
| } |
There was a problem hiding this comment.
Using go get -u github.com/charmbracelet/huh@none during self-cleanup risks upgrading unrelated dependencies due to -u. Prefer a dependency removal approach that doesn’t trigger upgrades (e.g., go mod edit -droprequire or go get github.com/charmbracelet/huh@none without -u), then run go mod tidy.
| func (r *Remover) PatchFeatureMarkers(featureNames []string) (int, error) { | ||
| filesPatched := 0 | ||
|
|
||
| for _, name := range featureNames { | ||
| files, err := r.findFilesWithMarker(name) | ||
| if err != nil { | ||
| return filesPatched, err | ||
| } | ||
|
|
||
| for _, f := range files { | ||
| patched, err := r.removeMarkerBlocks(f, name) | ||
| if err != nil { | ||
| return filesPatched, fmt.Errorf("failed to patch %s for feature %s: %w", f, name, err) | ||
| } | ||
| if patched { | ||
| filesPatched++ | ||
| if r.verbose { | ||
| fmt.Printf(" patched: %s (removed [feature:%s] blocks)\n", relPath(r.root, f), name) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
PatchFeatureMarkers increments filesPatched per (feature, file) patch. If a single file contains markers for multiple removed features, it will be counted multiple times, so the reported “files patched” total can be misleading. Track unique file paths patched across all features (e.g., a set) and return the unique count.
| "testing" | ||
| ) | ||
|
|
||
| func TestCleanStaleEntFilesRemovesGeneratedAdminFiles(t *testing.T) { |
There was a problem hiding this comment.
This test name suggests it removes generated admin files, but the assertions verify ent/admin/handler.go and ent/admin/types.go still exist; it’s actually validating removal of orphaned entity artifacts (e.g., paymentcustomer) while preserving shared/admin files. Rename the test to reflect what it’s asserting to avoid confusion when maintaining the ent cleanup logic.
| func TestCleanStaleEntFilesRemovesGeneratedAdminFiles(t *testing.T) { | |
| func TestCleanStaleEntFilesRemovesOrphanedEntArtifactsPreservesAdminFiles(t *testing.T) { |
| ### Module Manifest Structure | ||
|
|
||
| Each optional feature is described declaratively as a `Module` struct: | ||
|
|
||
| ```go | ||
| type Module struct { | ||
| Name string // Display name in TUI (e.g., "Payment (Stripe)") | ||
| Description string // One-liner description | ||
| Files []string // Standalone files to delete | ||
| Dirs []string // Directories to delete recursively | ||
| EntSchemas []string // Ent schema files to remove (triggers ent-gen) | ||
| UserEdges []string // Edge names to remove from ent/schema/user.go | ||
| NavItems []string // Sidebar nav item titles to remove from AppSidebar.tsx | ||
| RouteNames []string // Constants to remove from routenames/names.go | ||
| ConfigKeys []string // Top-level keys to remove from config.yaml | ||
| GoDeps []string // Go module paths to expect removal via go mod tidy | ||
| MakeTargets []string // Makefile targets to remove | ||
| } | ||
| ``` |
There was a problem hiding this comment.
The design doc’s Module struct (with UserEdges, NavItems, RouteNames, etc.) doesn’t match the current implementation in cmd/setup/modules.go (which only has Name, FeatureName, Description, Files, Dirs, EntSchemas). The flow diagram also references go generate ./ent, but the implementation runs go run -mod=mod entc.go from ent/. Please update this doc section to reflect the actual code so maintainers don’t follow a stale contract.
| github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect | ||
| github.com/charmbracelet/bubbletea v1.3.6 // indirect | ||
| github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect | ||
| github.com/charmbracelet/huh v1.0.0 // indirect | ||
| github.com/charmbracelet/lipgloss v1.1.0 // indirect | ||
| github.com/charmbracelet/x/ansi v0.9.3 // indirect |
There was a problem hiding this comment.
github.com/charmbracelet/huh is imported directly by cmd/setup/main.go, but it’s currently listed as // indirect in go.mod. This makes dependency intent unclear and can get flipped unexpectedly by go mod tidy. Update go.mod so huh is a direct requirement (i.e., remove the // indirect classification by re-tidying with cmd/setup present).
Summary
[feature:X]comment markers to 10 shared files across the codebase, wrapping all code blocks belonging to the 5 optional features (Payment, Chat, Mail, Tasks, File Upload)cmd/setup/) usingcharmbracelet/huhthat lets developers uncheck features they don't need — the tool deletes files, patches shared files via markers, regenerates Ent ORM, and verifies both Go and frontend buildsHow it works
After cloning, developers commit and run
make setup. A TUI checklist presents all 5 optional features pre-checked. Unchecking a feature triggers surgical removal: standalone files deleted, marker-delimited blocks stripped from shared files, Ent ORM regenerated, dependencies cleaned, and builds verified. The tool removes itself on success.Test plan
See
docs/plans/2026-03-27-modular-setup-cli-test-plan.mdfor full verification commands.Q&A
https://drive.google.com/file/d/10A74uX7UwIqCtiWhSCRvNttdO7F8hZAT/view?usp=sharing