docs(v1.2): complete project research — stack, features, architecture, pitfalls, summary

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 15:34:46 +02:00
co-authored by Claude Opus 4.6
parent 4a5ca206db
commit 4d4b01d9b7
5 changed files with 1198 additions and 941 deletions
+216 -89
View File
@@ -1,52 +1,189 @@
# Technology Stack
**Project:** Ready2Blob
**Researched:** 2026-03-26
**Confidence note:** External verification tools were unavailable in this session. Version numbers reflect training data (knowledge cutoff August 2025). Verify all versions against npmjs.com before scaffolding.
**Project:** Ready2Blob v1.2 — UI Polish & MD3 Overhaul
**Researched:** 2026-03-31
**Scope:** Stack ADDITIONS for Material Design 3, dark mode, accent colors, responsive improvements
**Existing stack (validated, not re-researched):** Vite 6, React 18, TypeScript 5, Tailwind v4 (@tailwindcss/vite), react-hook-form 7, Zod 4, Vitest 4, JSZip
---
## Recommended Stack
## Recommendation: Zero New Runtime Dependencies
### Core Framework
The v1.2 UI overhaul should be achieved with **Tailwind v4's native theming system + hand-authored MD3 design tokens in CSS**. No component library. No runtime theming library. The existing approach (semantic HTML + Tailwind utilities) is the right foundation -- it just needs a proper token system layered on top.
**Rationale:** The app currently has zero component library dependencies and 159 passing tests. Introducing a component library (Material Tailwind, MUI, shadcn/ui) at this stage would:
1. Require rewriting every existing component to match the library's API
2. Break existing tests that assert on current DOM structure
3. Add bundle weight for a wizard that needs at most 6-8 component types
4. Create upgrade debt for a library the team doesn't control
Instead: define MD3 tokens as CSS custom properties, wire them into Tailwind v4's `@theme` directive, and build the small set of reusable patterns (card, input, button, elevation) as project-owned Tailwind utility compositions.
---
## New Stack Additions
### Design Token Generation (Dev Dependency Only)
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| React | 18.x | Component model, state management, rendering | Largest ecosystem, best-in-class multi-step form libraries all target React first. Hooks (useState, useReducer, useContext) provide exactly the right mental model for a wizard: local step state + shared config accumulator state. No SSR needed — this is 100% client-side rendering. |
| Vite | 5.x | Build tooling, dev server, static asset bundling | Near-zero config for a React SPA. `vite build` produces a static `dist/` folder deployable to GitHub Pages, Netlify, or any CDN with no server required. HMR makes iteration fast. Replaces CRA, which is abandoned. Replaces Webpack, which requires painful configuration for something this simple. |
| TypeScript | 5.x | Type safety | rclone config generation involves composing structured data (backend type, required fields per backend, optional flags) into string templates. TypeScript catches the inevitable "wrong field name" bugs at compile time rather than at user download time. The marginal overhead is worth it for a tool where correctness of generated output is the entire product. |
| `@material/material-color-utilities` | 0.4.0 | Generate MD3 color palettes from seed color | Official Google library. Used at build/dev time via a small script to generate light + dark token sets from a single seed color. NOT bundled into the app -- it produces static CSS custom properties. This is the same algorithm the Material Theme Builder uses. HIGH confidence (official Google package, actively maintained). |
### Styling
**How it works:** Write a one-time Node script (`scripts/generate-theme.ts`) that:
1. Takes a seed color (hex)
2. Uses `themeFromSourceColor()` to generate full MD3 palette (primary, secondary, tertiary, error, surface, outline, etc.)
3. Outputs CSS custom properties in the `--md-sys-color-*` naming convention
4. Writes to `src/theme-tokens.css` which is imported into `src/index.css`
This means the generated tokens are **static CSS** -- zero runtime cost, zero bundle impact from the color library.
### Tailwind v4 Theme Integration (No New Dependency)
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| Tailwind CSS | 3.x | Utility-first styling | No design system to maintain — each step of the wizard is a one-off layout. Tailwind's inline classes mean styling stays co-located with markup, avoiding CSS file sprawl. For a tool likely built by one or two developers, it eliminates the "where does this class live?" question. Avoid CSS Modules (too much file switching) and styled-components (runtime overhead, no benefit here). |
| Tailwind v4 `@theme` directive | Already installed | Map MD3 tokens to Tailwind utility classes | Tailwind v4's `@theme` directive creates utility classes from CSS custom properties. Defining `--color-primary`, `--color-surface`, etc. in `@theme` blocks automatically generates `bg-primary`, `text-on-primary`, `bg-surface` utilities. No config file needed -- pure CSS. HIGH confidence (verified in official Tailwind v4 docs). |
| Tailwind v4 `@custom-variant` | Already installed | Class-based dark mode toggle | Tailwind v4 replaces the old `darkMode: 'class'` config with `@custom-variant dark (&:where(.dark, .dark *));` in CSS. This enables the `dark:` prefix to respond to a `.dark` class on the HTML element. HIGH confidence (verified in official Tailwind v4 dark mode docs). |
### Form & Wizard State
### No Other New Dependencies
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| react-hook-form | 7.x | Per-step form validation and field registration | The standard for React forms. Uncontrolled inputs with ref-based validation means no re-render on every keystroke — important when some wizard steps may have 10+ fields (e.g., S3 config). Native Zod integration via `@hookform/resolvers` allows schema-driven validation that mirrors the rclone backend field spec. |
| Zod | 3.x | Schema definition and runtime validation | Per-backend field schemas (required vs optional, string format, enum values) map directly to Zod schemas. A `backends/azure.ts`, `backends/s3.ts`, etc. pattern lets each backend declare its own schema — react-hook-form validates against it per step. This is the correct abstraction: the schema IS the backend spec. |
| Category | Decision | Rationale |
|----------|----------|-----------|
| Component library | **Do NOT add** | Current semantic HTML + Tailwind is correct. MD3 styling is achieved through tokens + utility classes, not through library components. |
| CSS-in-JS | **Do NOT add** | Tailwind v4 handles everything via CSS. Adding styled-components or Emotion would conflict with the existing Tailwind approach. |
| Theme toggle library (next-themes) | **Do NOT add** | next-themes is Next.js-focused. For a pure Vite SPA, a 15-line React hook (`useTheme`) with `localStorage` + `classList.toggle` is all that's needed. |
| Animation library | **Do NOT add** | MD3 motion tokens (duration, easing) are CSS custom properties. Tailwind v4's `@theme` can define transition tokens. No framer-motion or similar needed for the subtle transitions in a wizard UI. |
| Icon library | **Evaluate later** | If MD3 icons are desired, `@material-design-icons/svg` provides tree-shakeable SVGs. But this is a nice-to-have, not a v1.2 blocker. |
### File Generation & Download
---
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| Native Blob API | — (browser built-in) | Text file download (rclone.conf, .ps1 scripts) | No library needed. `new Blob([content], { type: 'text/plain' })` + `URL.createObjectURL()` + programmatic anchor click is the standard pattern for single-file downloads. Zero dependency, works in all modern browsers. Using a library for this adds complexity without benefit. |
| JSZip | 3.x | ZIP bundling of all generated files | When the user wants to download all files at once (rclone.conf + Intune script + RMM script), a ZIP is far better UX than three separate downloads. JSZip is the de-facto standard for client-side ZIP in browsers, actively maintained, no server required. `file-saver` is often paired with it for the `saveAs()` convenience but the Blob/anchor pattern works fine without it. |
## Detailed Integration Plan
### State Management
### 1. MD3 Color Token System
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| React built-ins (useState / useReducer / useContext) | 18.x | Wizard state, accumulated config object | No external state library needed. The wizard has one primary data structure: the accumulating rclone config object (backend type + per-backend fields + script options). A `useReducer` at the app root with a context provider gives all steps read/write access without prop drilling. This is a solved problem at this scale — Zustand/Redux are overkill. |
The Material Design 3 color system uses ~29 semantic color roles (not raw palette values). These map to CSS custom properties:
### Hosting / Deployment
```css
/* Light theme tokens (generated from seed color) */
:root {
--md-sys-color-primary: #006A6A;
--md-sys-color-on-primary: #FFFFFF;
--md-sys-color-primary-container: #6FF7F6;
--md-sys-color-on-primary-container: #002020;
--md-sys-color-secondary: #4A6363;
--md-sys-color-on-secondary: #FFFFFF;
--md-sys-color-surface: #FAFDFC;
--md-sys-color-on-surface: #191C1C;
--md-sys-color-surface-container: #EFF2F1;
--md-sys-color-surface-container-low: #F4F7F6;
--md-sys-color-surface-container-high: #E9ECEB;
--md-sys-color-outline: #6F7979;
--md-sys-color-outline-variant: #BEC9C8;
--md-sys-color-error: #BA1A1A;
--md-sys-color-on-error: #FFFFFF;
/* ... ~29 roles total */
}
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| GitHub Pages or Netlify (free tier) | — | Static hosting | The output of `vite build` is a folder of HTML/CSS/JS. Any static host works. GitHub Pages is zero-cost and integrates directly with the repository. Netlify adds deploy previews for PRs, which is useful for validating config generation changes. No server needed at either. |
/* Dark theme tokens (same seed, dark scheme) */
.dark {
--md-sys-color-primary: #4EDADA;
--md-sys-color-on-primary: #003737;
--md-sys-color-surface: #101414;
--md-sys-color-on-surface: #E0E3E2;
/* ... all roles overridden */
}
```
### 2. Tailwind v4 Theme Wiring
```css
/* src/index.css */
@import "tailwindcss";
@import "./theme-tokens.css"; /* Generated MD3 tokens */
@custom-variant dark (&:where(.dark, .dark *));
@theme {
/* Map MD3 tokens to Tailwind color utilities */
--color-primary: var(--md-sys-color-primary);
--color-on-primary: var(--md-sys-color-on-primary);
--color-primary-container: var(--md-sys-color-primary-container);
--color-on-primary-container: var(--md-sys-color-on-primary-container);
--color-secondary: var(--md-sys-color-secondary);
--color-on-secondary: var(--md-sys-color-on-secondary);
--color-surface: var(--md-sys-color-surface);
--color-on-surface: var(--md-sys-color-on-surface);
--color-surface-container: var(--md-sys-color-surface-container);
--color-surface-container-low: var(--md-sys-color-surface-container-low);
--color-surface-container-high: var(--md-sys-color-surface-container-high);
--color-outline: var(--md-sys-color-outline);
--color-outline-variant: var(--md-sys-color-outline-variant);
--color-error: var(--md-sys-color-error);
--color-on-error: var(--md-sys-color-on-error);
/* MD3 Shape scale */
--radius-xs: 4px;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 28px;
--radius-full: 9999px;
/* MD3 Elevation (box-shadows) */
--shadow-elevation-0: none;
--shadow-elevation-1: 0 1px 2px 0 rgb(0 0 0 / 0.3), 0 1px 3px 1px rgb(0 0 0 / 0.15);
--shadow-elevation-2: 0 1px 2px 0 rgb(0 0 0 / 0.3), 0 2px 6px 2px rgb(0 0 0 / 0.15);
--shadow-elevation-3: 0 1px 3px 0 rgb(0 0 0 / 0.3), 0 4px 8px 3px rgb(0 0 0 / 0.15);
--shadow-elevation-4: 0 2px 3px 0 rgb(0 0 0 / 0.3), 0 6px 10px 4px rgb(0 0 0 / 0.15);
--shadow-elevation-5: 0 4px 4px 0 rgb(0 0 0 / 0.3), 0 8px 12px 6px rgb(0 0 0 / 0.15);
/* MD3 Motion tokens */
--animate-md3-enter: md3-enter 0.2s cubic-bezier(0, 0, 0, 1);
--animate-md3-exit: md3-exit 0.15s cubic-bezier(0.3, 0, 1, 1);
@keyframes md3-enter {
from { opacity: 0; transform: scale(0.92); }
to { opacity: 1; transform: scale(1); }
}
@keyframes md3-exit {
from { opacity: 1; transform: scale(1); }
to { opacity: 0; transform: scale(0.92); }
}
}
```
**Usage in components** then becomes natural Tailwind:
```tsx
<div className="bg-surface-container rounded-md shadow-elevation-1 dark:shadow-elevation-2">
<h2 className="text-on-surface">Step Title</h2>
<button className="bg-primary text-on-primary rounded-full px-6 py-2">
Next
</button>
</div>
```
### 3. Dark Mode Toggle Hook
No library needed. A simple React hook:
```typescript
// src/hooks/useTheme.ts
function useTheme() {
const [theme, setTheme] = useState<'light' | 'dark' | 'system'>(() => {
return (localStorage.getItem('theme') as 'light' | 'dark') ?? 'system';
});
// Toggle .dark class on <html>, persist to localStorage
// Listen to prefers-color-scheme for 'system' mode
}
```
### 4. Accent Color System
For user-selectable accent colors, the approach is:
1. Offer 3-5 preset seed colors (not arbitrary color picker)
2. Pre-generate token sets for each seed color at build time
3. Switch accent by swapping a CSS class on `<html>` that loads a different set of `--md-sys-color-*` variables
This avoids runtime color generation (which would require bundling `@material/material-color-utilities`).
---
@@ -54,65 +191,53 @@
| Category | Recommended | Alternative | Why Not |
|----------|-------------|-------------|---------|
| Framework | React 18 | Vue 3 | Vue is a reasonable choice but the wizard library ecosystem (react-hook-form, Formik) is React-first. No strong reason to diverge. |
| Framework | React 18 | Svelte / SvelteKit | Svelte has no widely-adopted multi-step form library. Would require hand-rolling wizard state. The compile-time model is elegant but not worth the ecosystem tradeoff here. |
| Build tool | Vite | Create React App | CRA is officially deprecated by the React team. Not a valid choice for new projects in 2025. |
| Build tool | Vite | Next.js | Next.js is a server-framework. Using it for a pure static SPA adds file-based routing conventions, SSR plumbing, and deployment assumptions that are all irrelevant here. `vite + react` is simpler and more appropriate. |
| Styling | Tailwind CSS | Material UI / shadcn/ui | shadcn/ui is worth considering as a component library for accessible form elements (inputs, selects, checkboxes). It is built on Radix UI primitives and works with Tailwind. If the team wants pre-built accessible components rather than raw HTML + Tailwind, shadcn/ui is the right addition — not a replacement for Tailwind, but a layer on top. |
| Forms | react-hook-form | Formik | Formik is older and uses controlled inputs (re-render on every keystroke). react-hook-form is the current standard and has better performance and Zod integration. |
| ZIP | JSZip | fflate | fflate is faster and smaller than JSZip. Both are valid. JSZip has more documentation and community examples for the browser download pattern, making it easier to implement correctly without prior experience. If bundle size becomes a concern, swap to fflate. |
| State | useReducer + Context | Zustand | Zustand is excellent but unnecessary at this scale. No async state, no complex selectors needed. Adding a dependency for something React itself handles cleanly is not justified. |
---
## Recommended shadcn/ui Addition
**Use shadcn/ui for form components.** shadcn/ui is not a dependency — it is a code generator. Running `npx shadcn-ui@latest add button input select checkbox` copies accessible, Tailwind-styled components into your project. These components are owned by the project (not a node_module) and fully customizable. For a wizard with many form inputs, this provides:
- Accessible labels, focus states, error message patterns out of the box
- Consistent visual design without a custom design system
- Radix UI primitives under the hood (keyboard navigation, ARIA) at no extra runtime cost
This is the current 2025 best practice for React + Tailwind projects.
| Component library | None (keep semantic HTML + Tailwind) | Material Tailwind v3 | Material Tailwind is React + Tailwind but: (a) requires rewriting all existing components, (b) v3 is still in pre-order/beta, (c) adds ~50KB+ bundle weight for components the wizard doesn't need. Not worth the rewrite cost for 6-8 component types. |
| Component library | None | MUI (Material UI) | MUI uses Emotion CSS-in-JS, fundamentally conflicts with Tailwind. Would require ripping out Tailwind entirely. Wrong direction. |
| Component library | None | shadcn/ui | Good library but opinionated toward Radix primitives. Adding it now means learning a new component API while also implementing MD3 tokens. For v1.2 scope (cards, inputs, buttons, toggles), hand-authored Tailwind components are faster and simpler. |
| Color generation | `@material/material-color-utilities` (dev-only) | `m3-tailwind-colors` npm package | Only 3 GitHub stars, single maintainer, uncertain maintenance. The underlying `@material/material-color-utilities` is the official Google package -- better to use it directly with a small script than depend on a wrapper. |
| Color generation | Build-time script | Runtime `@material/material-color-utilities` in bundle | Adds ~30KB to the client bundle for something that only needs to run once per accent color change. Pre-generate at build time instead. |
| Dark mode toggle | Custom 15-line hook | next-themes | next-themes is designed for Next.js SSR hydration edge cases. For a Vite SPA, it's unnecessary complexity. The core logic is `classList.toggle('dark')` + `localStorage`. |
| Dark mode approach | Class-based (`@custom-variant`) | Media query (prefers-color-scheme only) | Media query approach doesn't allow manual toggle. Users expect a toggle button. Class-based supports both: system preference as default, manual override via toggle. |
---
## Installation
```bash
# Scaffold
npm create vite@latest ready2blob -- --template react-ts
cd ready2blob
# Dev dependency only -- NOT bundled into the app
npm install -D @material/material-color-utilities
# Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
# Forms and validation
npm install react-hook-form zod @hookform/resolvers
# ZIP generation
npm install jszip
# shadcn/ui setup (optional but recommended)
npx shadcn-ui@latest init
# Then add components as needed:
npx shadcn-ui@latest add button input select checkbox label
# That's it. No other new dependencies.
```
### Files to Create
| File | Purpose |
|------|---------|
| `scripts/generate-theme.ts` | Node script: seed color -> MD3 CSS tokens |
| `src/theme-tokens.css` | Generated output: CSS custom properties for light + dark |
| `src/hooks/useTheme.ts` | Theme toggle hook (light/dark/system) |
### Files to Modify
| File | Change |
|------|--------|
| `src/index.css` | Add `@import "./theme-tokens.css"`, `@custom-variant dark`, `@theme` block |
| `package.json` | Add script: `"generate-theme": "tsx scripts/generate-theme.ts"` |
---
## What NOT to Use
## What NOT to Add
| Technology | Why Not |
|------------|---------|
| Next.js | Server framework. Adds SSR/SSG complexity with zero benefit for a pure client-side tool. |
| Create React App | Officially deprecated. Abandoned by React team. |
| Redux / Redux Toolkit | Overkill for wizard state. useReducer + Context is sufficient. |
| Formik | Superseded by react-hook-form. Controlled inputs cause unnecessary re-renders. |
| Angular | Enterprise framework, large bundle, steep learning curve, wrong tool for a simple wizard. |
| Backend of any kind | Explicitly out of scope. All generation is string manipulation in the browser. |
| LocalStorage / IndexedDB | Out of scope per PROJECT.md — no persistence. |
| Material Tailwind / MUI / any component library | Rewrite cost exceeds benefit. Keep semantic HTML + Tailwind utilities with MD3 tokens. |
| CSS-in-JS (Emotion, styled-components) | Conflicts with Tailwind. Wrong direction. |
| next-themes | Next.js-specific. Vite SPA needs 15 lines of code, not a library. |
| framer-motion | MD3 motion is subtle transitions (opacity, scale). CSS transitions + Tailwind's `@theme` animation tokens handle it. |
| PostCSS plugins | Tailwind v4 uses the `@tailwindcss/vite` plugin, not PostCSS. Don't add PostCSS config. |
| tailwind.config.js | Tailwind v4 is CSS-first. All config goes in `src/index.css` via `@theme`. No JS config file. |
| Runtime color generation in browser | Pre-generate tokens at build time. Don't ship the color algorithm to users. |
---
@@ -120,24 +245,26 @@ npx shadcn-ui@latest add button input select checkbox label
| Decision | Confidence | Basis |
|----------|------------|-------|
| React 18 + Vite as core | HIGH | Industry-standard since 2023, no credible challenger for this use case |
| TypeScript | HIGH | Unambiguously correct for generated-output correctness |
| react-hook-form + Zod | HIGH | De-facto standard pairing for React forms as of 2024-2025 |
| Tailwind CSS | HIGH | Dominant utility-CSS framework; strong fit for wizard UI |
| shadcn/ui | MEDIUM | Strong community adoption but version numbers evolve quickly; verify CLI syntax |
| JSZip for ZIP | MEDIUM | Stable and widely used, but fflate is a valid modern alternative — verify latest version on npm |
| Blob API for single-file download | HIGH | Native browser API, no version concern |
| Version numbers (all) | LOW | Training data cutoff August 2025; must verify on npmjs.com before scaffolding |
| Zero new runtime dependencies | HIGH | Existing Tailwind v4 handles everything; verified in official docs |
| `@custom-variant dark` for dark mode | HIGH | Verified in official Tailwind v4 dark mode documentation |
| `@theme` directive for MD3 tokens | HIGH | Verified in official Tailwind v4 theme documentation |
| `@material/material-color-utilities` 0.4.0 for token generation | HIGH | Official Google package, actively maintained, used by Material Theme Builder |
| MD3 shape scale values (4/8/12/16/28/9999 px) | HIGH | Confirmed in official Material Design 3 shape documentation |
| MD3 elevation box-shadow values | MEDIUM | Values sourced from community reference (Studio N Creations) cross-referenced with Material Web component source. Official docs don't publish exact CSS box-shadow -- they use `--md-elevation-level` in their web components. The shadow values are a reasonable approximation. |
| No component library needed | HIGH | Project has 159 tests against current DOM structure; rewriting components is unjustified for a styling overhaul |
| Pre-generated accent colors (not runtime) | MEDIUM | Architectural choice -- runtime generation is valid but adds bundle weight for a rarely-used feature |
---
## Sources
- PROJECT.md: project requirements and constraints (pure frontend, no backend, static hosting)
- React documentation (react.dev) — training data, verify current version
- Vite documentation (vitejs.dev) — training data, verify current version
- react-hook-form documentation (react-hook-form.com) — training data, verify current version
- Zod documentation (zod.dev) — training data, verify current version
- JSZip (stuk.github.io/jszip) — training data, verify current version
- shadcn/ui (ui.shadcn.com) — training data, verify CLI commands
- MDN Web Docs: Blob API, URL.createObjectURL — browser built-in, no version concern
- [Tailwind v4 Dark Mode Documentation](https://tailwindcss.com/docs/dark-mode) -- `@custom-variant` syntax, class-based toggle, localStorage pattern
- [Tailwind v4 Theme Documentation](https://tailwindcss.com/docs/theme) -- `@theme` directive, CSS variable generation, namespace conventions
- [Material Design 3 Design Tokens](https://m3.material.io/foundations/design-tokens) -- token naming, semantic color roles
- [Material Design 3 Shape Scale](https://m3.material.io/styles/shape/corner-radius-scale) -- corner radius values (4/8/12/16/28dp)
- [Material Design 3 Elevation](https://m3.material.io/styles/elevation/applying-elevation) -- elevation levels 0-5
- [@material/material-color-utilities on npm](https://www.npmjs.com/package/@material/material-color-utilities) -- v0.4.0, official Google color algorithm
- [Material Theme Builder](https://material-foundation.github.io/material-theme-builder/) -- CSS export format, `--md-sys-color-*` naming convention
- [MD3 Box-Shadow CSS Values](https://studioncreations.com/blog/material-design-3-box-shadow-css-values/) -- elevation shadow approximations (MEDIUM confidence)
- [m3-tailwind-colors GitHub](https://github.com/somteacodes/m3-tailwind-colors) -- evaluated and rejected (3 stars, single maintainer)
- [Tailwind v4 Multi-Theme Strategy](https://simonswiss.com/posts/tailwind-v4-multi-theme) -- community pattern for theme switching with CSS variables