523 lines
15 KiB
Markdown
523 lines
15 KiB
Markdown
# ToolCTRL Boilerplate Plan
|
|
|
|
> **Status: Historical planning artifact (pre-Architecture Closure).**
|
|
> This document captures the original target direction. Many sections have
|
|
> been implemented or superseded by later milestones (Architecture Closure, Auth API, Body-Release Docs
|
|
> baselines). Use the following sources for current state instead:
|
|
>
|
|
> - `docs/architecture-migration-status.md` — boundary status and intentional deferrals
|
|
> - `docs/feature-inventory.md` — core/plugin/remove classification per feature
|
|
> - `docs/archive/architecture-handoff-summary.md` — official Architecture Closure record
|
|
> - `docs/feature-manifests/*.json` — machine-readable feature contracts
|
|
> - `docs/agent-entrypoints.md` — recommended entry point for substantial feature work
|
|
>
|
|
> Refer to this file only to recover original intent or rationale not preserved elsewhere.
|
|
|
|
---
|
|
|
|
This document defines the target direction for the ToolCTRL standard boilerplate. It is intentionally a planning artifact first: implementation starts only after the relevant section has been discussed and accepted.
|
|
|
|
## Principles
|
|
|
|
- Build a whitelabel boilerplate, not a lightly edited source template fork.
|
|
- Prefer explicit deployable boundaries over a large all-in-one app.
|
|
- Keep changes atomic and commit each completed step separately.
|
|
- Make i18n mandatory for user-facing UI. German is the default language.
|
|
- Keep provider integrations optional unless ToolCTRL explicitly standardizes them.
|
|
- Optimize for replacing implementation details later, especially UI components and external providers.
|
|
|
|
## Package Manager
|
|
|
|
Decision: move to `pnpm` and use `pnpm workspaces`.
|
|
|
|
Rationale:
|
|
|
|
- Workspaces are first-class and predictable for monorepo packages.
|
|
- Dependency installation is faster and less duplicated.
|
|
- Package boundaries become easier to enforce once `apps/*` and `packages/*` exist.
|
|
- CI and Docker can install deterministically with `pnpm-lock.yaml`.
|
|
|
|
Planned migration:
|
|
|
|
1. Add `packageManager` to `package.json`.
|
|
2. Add `pnpm-workspace.yaml`.
|
|
3. Generate `pnpm-lock.yaml`.
|
|
4. Remove `package-lock.json`.
|
|
5. Update README, Dockerfile, CI and local commands from `npm` to `pnpm`.
|
|
6. Verify with `pnpm install`, `pnpm typecheck`, `pnpm test`, and `pnpm build`.
|
|
|
|
Open question:
|
|
|
|
- Should we pin via Corepack only, or also document a global `pnpm` install fallback?
|
|
|
|
## Target Monorepo
|
|
|
|
Target structure:
|
|
|
|
```txt
|
|
apps/
|
|
web/
|
|
api/
|
|
worker/
|
|
packages/
|
|
auth/
|
|
config/
|
|
db/
|
|
i18n/
|
|
mail/
|
|
queue/
|
|
shared/
|
|
ui/
|
|
```
|
|
|
|
Historical note: this was the intended structure before Architecture Closure.
|
|
Use `docs/architecture-migration-status.md` for the current workspace/package
|
|
snapshot before planning moves or imports.
|
|
|
|
Initial interpretation:
|
|
|
|
- `apps/web`: React Router app for authenticated app UI.
|
|
- `apps/api`: versioned API server at `api.<domain>/v1`.
|
|
- `apps/worker`: BullMQ workers and scheduled/background jobs.
|
|
- `packages/db`: Prisma schema/client initially, with ORM decision isolated later.
|
|
- `packages/config`: typed env/config loading for web, api and worker.
|
|
- `packages/auth`: session/auth helpers shared by web and api where appropriate.
|
|
- `packages/i18n`: locale config, translation loading and key conventions.
|
|
- `packages/mail`: MailerSend default provider and mail abstractions.
|
|
- `packages/queue`: BullMQ queue names, producers and payload schemas.
|
|
- `packages/ui`: replaceable UI adapter layer.
|
|
- `packages/shared`: cross-cutting types and utilities that are not app-specific.
|
|
|
|
Migration approach:
|
|
|
|
1. Introduce workspaces and package boundaries.
|
|
2. Move code only when the target ownership is clear.
|
|
3. Avoid massive path churn before config, API and worker boundaries are agreed.
|
|
4. Keep the current app working between phases.
|
|
|
|
Current-state contract: `docs/architecture-migration-status.md` is the active workspace/package snapshot, and `docs/feature-inventory.md` plus `docs/feature-manifests/*.json` classify features as keep, plugin-candidate or remove-candidate. Implementation phases should use those documents as the pruning contract and cleanly remove or extract replaced features instead of adding permanent legacy adapters.
|
|
|
|
## Domains And Routing
|
|
|
|
Target domains:
|
|
|
|
- Public/marketing site: out of this boilerplate.
|
|
- Web app: `app.<domain>`.
|
|
- Admin app: `admin.<domain>`.
|
|
- API: `api.<domain>/v1`.
|
|
|
|
Tenant routing:
|
|
|
|
- Current standard `/app/:tenant/...` should be replaced.
|
|
- Target app tenant route: `https://app.<domain>/<tenant_slug>/...`.
|
|
- Admin should not be tenant-prefixed by default unless a specific admin workflow requires tenant context.
|
|
|
|
Planned routing migration:
|
|
|
|
1. Add host-aware routing/config helpers.
|
|
2. Introduce canonical URL builders for app/admin/api.
|
|
3. Replace hardcoded `/app/:tenant` generation.
|
|
4. Add redirects from old `/app/:tenant/...` to new `/<tenant>/...` where useful.
|
|
5. Ensure auth redirects understand host and tenant slug.
|
|
|
|
Open questions:
|
|
|
|
- Should `admin.<domain>` allow tenant-scoped admin pages via query/context, or use paths like `/tenants/:tenant`?
|
|
- Should local development use `localhost` paths only, or local hostnames such as `app.localhost` and `api.localhost`?
|
|
|
|
## API
|
|
|
|
Recommendation: use Hono for `apps/api`.
|
|
|
|
Rationale:
|
|
|
|
- Small, explicit and fast.
|
|
- Works well as a dedicated Node/Docker API.
|
|
- Clean versioning: `/v1`.
|
|
- Pairs well with Zod request/response schemas and OpenAPI generation.
|
|
- Avoids dragging the web framework into API concerns.
|
|
|
|
Second choice: Fastify, if we prefer a more traditional Node server with a larger plugin ecosystem.
|
|
|
|
Initial API target:
|
|
|
|
- `GET /v1/health`
|
|
- auth/session validation primitives
|
|
- account/tenant/user endpoints currently living under web routes
|
|
- public API key validation and entity endpoints
|
|
|
|
Planning rules:
|
|
|
|
- No API extraction until route ownership is mapped.
|
|
- New API endpoints should use typed schemas.
|
|
- Web should consume API only where it makes architectural sense; server-rendered web loaders can still use packages directly if that is the agreed boundary.
|
|
|
|
Open questions:
|
|
|
|
- Do we want OpenAPI as a required artifact for every endpoint?
|
|
- Should internal web-to-api calls use HTTP in production, or should web import package functions directly for trusted server-side paths?
|
|
|
|
## Worker And Queues
|
|
|
|
Decision basis: Redis/BullMQ and Docker, matching the HiveGrid operating model.
|
|
|
|
Target:
|
|
|
|
- `apps/worker` runs on a dedicated server or container.
|
|
- Redis is the queue backend.
|
|
- Queue definitions live in `packages/queue`.
|
|
- Job handlers live either in `apps/worker` or domain packages, depending on ownership.
|
|
|
|
Candidate queues:
|
|
|
|
- `mail`
|
|
- `newsletter`
|
|
- `webhooks`
|
|
- `imports`
|
|
- `exports`
|
|
- `notifications`
|
|
- `analytics`
|
|
- `ai`
|
|
- `cleanup`
|
|
|
|
Planned worker discussion:
|
|
|
|
1. Deployment model: Docker Compose, single worker image, or multiple worker processes.
|
|
2. Redis topology: shared Redis, dedicated Redis, persistence expectations.
|
|
3. Retry policy and dead-letter handling.
|
|
4. Job payload versioning.
|
|
5. Admin/observability UI for queues.
|
|
6. Scheduling strategy for cron-like work.
|
|
|
|
Open questions:
|
|
|
|
- Do we want Bull Board or another queue dashboard?
|
|
- Do we split worker processes per queue or run one worker with configurable queues?
|
|
- What is the standard production Docker Compose layout?
|
|
|
|
## Environment And Config
|
|
|
|
Goal: replace the current broad `.env` surface with typed, app-specific configuration.
|
|
|
|
Target files:
|
|
|
|
- `.env.example`
|
|
- `.env.local.example`
|
|
- `.env.production.example`
|
|
- optional app-specific sections for web, api and worker
|
|
|
|
Target package:
|
|
|
|
- `packages/config`
|
|
|
|
Classification for every variable:
|
|
|
|
- required core
|
|
- required per app
|
|
- optional provider
|
|
- local development only
|
|
- production only
|
|
- deprecated/remove
|
|
|
|
Planned audit:
|
|
|
|
1. List every current env variable.
|
|
2. Identify which code path consumes it.
|
|
3. Decide keep/remove/provider-optional.
|
|
4. Rename variables to stable ToolCTRL naming.
|
|
5. Add typed validation.
|
|
6. Update Docker and CI examples.
|
|
|
|
## Mail
|
|
|
|
Decision: MailerSend is the default provider.
|
|
|
|
Scope:
|
|
|
|
- Transactional email.
|
|
- Newsletter/bulk email where MailerSend supports the required workflow cleanly.
|
|
|
|
Target package:
|
|
|
|
- `packages/mail`
|
|
|
|
Planned migration:
|
|
|
|
1. Define mail provider interface.
|
|
2. Implement MailerSend adapter.
|
|
3. Move existing templates behind the interface.
|
|
4. Remove legacy transactional provider defaults and adapters.
|
|
5. Keep MailerSend as the only transactional runtime provider.
|
|
6. Replace env variables and admin settings.
|
|
|
|
Open questions:
|
|
|
|
- Do newsletters go through MailerSend directly, or do we keep a CRM/list abstraction?
|
|
- Should all mail be queued through BullMQ by default?
|
|
- Do we need per-tenant sender identities in the boilerplate?
|
|
|
|
## i18n
|
|
|
|
Decision: German is the default language. i18n is mandatory.
|
|
|
|
Target:
|
|
|
|
- Add `de` locale.
|
|
- Make `de` default.
|
|
- No new user-facing hardcoded strings.
|
|
- Language setup lives in `packages/i18n` after monorepo migration.
|
|
|
|
Planned migration:
|
|
|
|
1. Add German locale file.
|
|
2. Switch default locale to German.
|
|
3. Audit missing translation keys.
|
|
4. Add guidance for new UI copy.
|
|
5. Remove stale languages if not needed.
|
|
|
|
Open questions:
|
|
|
|
- Keep English as fallback or German as both default and fallback?
|
|
- Do we keep Spanish/French from the source app?
|
|
|
|
## Affiliate System
|
|
|
|
Decision: remove affiliate/rewardful as standard boilerplate functionality.
|
|
|
|
Scope:
|
|
|
|
- Routes.
|
|
- Sidebar links and commands.
|
|
- Rewardful scripts.
|
|
- Env vars.
|
|
- App configuration fields.
|
|
- Pricing/admin UI references.
|
|
- Tests and docs.
|
|
|
|
Potential future:
|
|
|
|
- Affiliate support may return later as an optional package/plugin, not as default boilerplate code.
|
|
|
|
## Whitelabel Cleanup
|
|
|
|
Goal: remove all source-product references and source-product assumptions.
|
|
|
|
Scope:
|
|
|
|
- Package metadata.
|
|
- README/docs.
|
|
- Legal copy.
|
|
- Email templates.
|
|
- UI copy.
|
|
- Images/logos.
|
|
- Surveys/fake data.
|
|
- Changelog/default data.
|
|
- External links.
|
|
- Env examples.
|
|
- Comments that imply source-product ownership.
|
|
|
|
Target naming:
|
|
|
|
- Project/product: ToolCTRL Boilerplate where a concrete name is needed.
|
|
- Generic output: application, workspace, tenant, organization, account.
|
|
|
|
## Marketing Removal
|
|
|
|
Decision: marketing is not part of this boilerplate.
|
|
|
|
Implication:
|
|
|
|
- Root domain belongs to a separate marketing site/project.
|
|
- This repo should focus on app, admin, API and worker.
|
|
|
|
What stays for now:
|
|
|
|
- Minimal legal/auth pages if needed for app flows.
|
|
- Header/footer UI primitives only if still used by app pages.
|
|
|
|
What should be removed or made optional:
|
|
|
|
- Landing-page-oriented routes.
|
|
- Changelog/newsletter/contact public marketing surfaces, unless kept as app support features.
|
|
- Marketing-specific page block examples.
|
|
|
|
Open question:
|
|
|
|
- Should `/contact` and `/newsletter` be removed entirely, or converted into authenticated support/admin features?
|
|
|
|
## Components And UI Adapter
|
|
|
|
Goal: make the component library hotswappable later.
|
|
|
|
Target:
|
|
|
|
- `packages/ui` becomes the import boundary for application UI primitives.
|
|
- App code should not import randomly from mixed component folders long term.
|
|
- Domain components live near domains, primitives live in `packages/ui`.
|
|
|
|
Planned consolidation:
|
|
|
|
1. Inventory current UI imports.
|
|
2. Define primitive categories: buttons, inputs, dialogs, tables, layout, navigation, feedback.
|
|
3. Create adapter exports.
|
|
4. Migrate app code gradually to adapter imports.
|
|
5. Remove duplicate components.
|
|
6. Add rules for future components.
|
|
|
|
Open questions:
|
|
|
|
- Do we want shadcn/Radix as the first adapter implementation?
|
|
- Should `packages/ui` publishable/private package conventions be used from day one?
|
|
|
|
## ORM Strategy
|
|
|
|
Current state:
|
|
|
|
- `prisma`: `6.18.0`
|
|
- `@prisma/client`: `6.18.0`
|
|
|
|
Decision: do not combine ORM migration with monorepo/API/worker split.
|
|
|
|
Recommended sequence:
|
|
|
|
1. Keep Prisma during structural migration.
|
|
2. Move Prisma ownership to `packages/db`.
|
|
3. After boundaries are stable, run a dedicated ORM decision phase:
|
|
- Prisma 7 upgrade
|
|
- Drizzle migration
|
|
- stay on Prisma 6 temporarily
|
|
|
|
Prisma 7 consideration:
|
|
|
|
- Major upgrade should be isolated.
|
|
- Expect config/client generation/schema changes to touch build and deployment.
|
|
- Worth evaluating once `packages/db` exists.
|
|
|
|
Drizzle consideration:
|
|
|
|
- Pros: SQL-nearer, lightweight, easier explicit queries, attractive for package boundaries.
|
|
- Cons: large migration cost from current Prisma-heavy codebase, rewrite of generated types and query layer.
|
|
|
|
Recommendation for now:
|
|
|
|
- Use Prisma while splitting.
|
|
- Revisit Prisma 7 vs Drizzle only after `packages/db` exists and the API/worker boundary is clear.
|
|
|
|
## Quality And Performance
|
|
|
|
Target areas:
|
|
|
|
- Dependency cleanup.
|
|
- Bundle size.
|
|
- Server loader performance.
|
|
- Database query count and indexes.
|
|
- Auth/session overhead.
|
|
- Analytics overhead.
|
|
- Background job offloading.
|
|
- Docker build speed.
|
|
- Test speed and coverage around routing/auth/config.
|
|
|
|
Planned approach:
|
|
|
|
- No broad performance rewrite before architecture boundaries.
|
|
- Add measurements where possible.
|
|
- Convert slow or long-running work into queued jobs.
|
|
|
|
## Proposed Phase Order
|
|
|
|
### Phase 1: Planning And Tooling
|
|
|
|
- Commit this plan.
|
|
- Switch to pnpm workspaces.
|
|
- Update commands, lockfile, Docker and CI.
|
|
- Verify current app still works.
|
|
|
|
### Phase 2: Config Audit
|
|
|
|
- Inventory `.env`.
|
|
- Define typed config package.
|
|
- Remove unused service variables.
|
|
- Document standard local/prod env files.
|
|
|
|
### Phase 3: Monorepo Skeleton
|
|
|
|
- Add `apps/*` and `packages/*` structure.
|
|
- Move only low-risk shared modules first.
|
|
- Keep app running.
|
|
|
|
### Phase 4: Domain And Routing Plan Implementation
|
|
|
|
- Introduce host-aware URL helpers.
|
|
- Support `app.<domain>/<tenant>`.
|
|
- Introduce `admin.<domain>`.
|
|
- Plan redirects from legacy `/app/:tenant`.
|
|
|
|
### Phase 5: API Split
|
|
|
|
- Add Hono-based `apps/api`.
|
|
- Add `/v1/health`.
|
|
- Move selected API routes behind schemas.
|
|
- Add API Docker target.
|
|
|
|
### Phase 6: Worker Split
|
|
|
|
- Add `apps/worker`.
|
|
- Add BullMQ/Redis configuration.
|
|
- Add queue package.
|
|
- Move mail/webhook jobs first.
|
|
|
|
### Phase 7: MailerSend
|
|
|
|
- Add MailerSend provider.
|
|
- Queue mail by default if agreed.
|
|
- Remove legacy transactional provider defaults and adapters.
|
|
|
|
### Phase 8: i18n German Default
|
|
|
|
- Add German locale.
|
|
- Make German default.
|
|
- Audit missing/hardcoded strings.
|
|
|
|
### Phase 9: Remove Affiliate And Marketing
|
|
|
|
- Remove affiliate/rewardful.
|
|
- Remove marketing routes and config.
|
|
- Keep only app-required public pages.
|
|
|
|
### Phase 10: Whitelabel Cleanup
|
|
|
|
- Remove source-product mentions.
|
|
- Replace source copy/assets/default data.
|
|
- Update docs and examples.
|
|
|
|
### Phase 11: UI Consolidation
|
|
|
|
- Introduce `packages/ui` as adapter.
|
|
- Migrate imports gradually.
|
|
- Remove duplicate primitives.
|
|
|
|
### Phase 12: ORM Decision
|
|
|
|
- Evaluate Prisma 7 upgrade vs Drizzle migration.
|
|
- Decide based on the stable package boundaries.
|
|
- Execute as isolated phase.
|
|
- Foundation note: `packages/db/ORM-DECISION.md` preserves Prisma for now and defines later Prisma 7 vs Drizzle criteria.
|
|
|
|
### Phase 13: QoL And Performance
|
|
|
|
- Dependency cleanup.
|
|
- Bundle and server performance.
|
|
- Query optimization.
|
|
- Developer workflow polish.
|
|
- Foundation note: `docs/qol-performance-backlog.md` tracks verified warnings for bundle chunks, Prisma 7 deprecation, sourcemaps, lint config and Docker platform.
|
|
|
|
## Immediate Next Decisions
|
|
|
|
Before implementation beyond this plan:
|
|
|
|
1. Confirm local dev domain strategy: plain localhost paths or `app.localhost` / `api.localhost`.
|
|
2. MailerSend-only transactional mail is the migration target; legacy provider defaults and adapters are removed rather than retained.
|
|
3. Public `/contact` and `/newsletter` were removed as default marketing surfaces.
|
|
4. Confirm whether Spanish/French locales should stay after German is added.
|
|
5. Confirm worker dashboard preference.
|