2.0 KiB
Blockers (Website UX)
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
1) Definition
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. They are best-effort helpers that can be bypassed.
2) Purpose
Use Blockers to:
- Prevent multiple form submissions
- Debounce rapid button clicks
- Temporarily disable actions during loading
- Show/hide UI elements based on state
Do NOT use Blockers for:
- Authorization checks
- Security enforcement
- Permanent access control
3) Placement
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)
NOT in lib/ - lib/ is for business logic and architecture contracts.
4) Example
// ✅ OK: Component-level blocker
export function useSubmitBlocker() {
const [isSubmitting, setIsSubmitting] = useState(false);
return {
isSubmitting,
block: () => setIsSubmitting(true),
release: () => setIsSubmitting(false),
};
}
// Usage
const blocker = useSubmitBlocker();
async function handleSubmit() {
if (blocker.isSubmitting) return;
blocker.block();
await submitForm();
blocker.release();
}
5) Key Principle
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.