website refactor

This commit is contained in:
2026-01-13 02:42:58 +01:00
parent 38b25bafe1
commit b82736b24b
6 changed files with 661 additions and 251 deletions

View File

@@ -2,6 +2,8 @@
This document defines **Blockers** as UX-only prevention mechanisms in the website.
**IMPORTANT**: Blockers are **optional UX helpers**. They are NOT enforced by ESLint rules and do not belong in the strict architecture contract.
Shared contract: [`docs/architecture/shared/BLOCKERS_AND_GUARDS.md`](docs/architecture/shared/BLOCKERS_AND_GUARDS.md:1)
## 1) Definition
@@ -10,42 +12,64 @@ A Blocker is a website mechanism that prevents an action from being executed.
Blockers exist solely to improve UX and reduce unnecessary requests.
Blockers are not security.
**Blockers are not security.** They are best-effort helpers that can be bypassed.
## 2) Responsibilities
## 2) Purpose
Blockers MAY:
Use Blockers to:
- Prevent multiple form submissions
- Debounce rapid button clicks
- Temporarily disable actions during loading
- Show/hide UI elements based on state
- prevent multiple submissions
- disable actions temporarily
- debounce or throttle interactions
- hide or disable UI elements
- prevent navigation under certain conditions
**Do NOT use Blockers for:**
- Authorization checks
- Security enforcement
- Permanent access control
Blockers MUST:
## 3) Placement
- be reversible
- be local to the website
- be treated as best-effort helpers
Since Blockers are UX-only, they belong in:
- `apps/website/components/**` (component-specific blockers)
- `apps/website/hooks/**` (shared blocker hooks)
- `apps/website/utils/**` (blocker utilities)
## 3) Restrictions
**NOT in `lib/`** - `lib/` is for business logic and architecture contracts.
Blockers MUST NOT:
## 4) Example
- enforce security
- claim authorization
- block access permanently
- replace API Guards
- make assumptions about backend state
```typescript
// ✅ OK: Component-level blocker
export function useSubmitBlocker() {
const [isSubmitting, setIsSubmitting] = useState(false);
return {
isSubmitting,
block: () => setIsSubmitting(true),
release: () => setIsSubmitting(false),
};
}
## 4) Common Blockers
// Usage
const blocker = useSubmitBlocker();
- SubmitBlocker
- ThrottleBlocker
- NavigationBlocker
- FeatureBlocker
async function handleSubmit() {
if (blocker.isSubmitting) return;
blocker.block();
await submitForm();
blocker.release();
}
```
## 5) Canonical placement
## 5) Key Principle
- `apps/website/lib/blockers/**`
**Blockers are optional.** The backend must never rely on them.
If a blocker prevents a submission, the backend should still:
- Validate the request
- Return appropriate errors
- Handle duplicate submissions gracefully
This is why Blockers don't need ESLint enforcement - they're just UX sugar.