Files
HiveGrid-Wireframes/hivegrid-cloud/BOILERPLATE-PLAN.md
T

15 KiB

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:

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.