Messenger/packages/web/eslint.config.mjs
Заид Омар Медхат | Zaid Omar Medhat 47fbf861ee Phase 6.5: notifications service + in-app toasts; in-app voice/video messages; SVG icons
Notifications (web push now, Android FCM ready, iOS prepared):
- device_tokens / notification_settings / conversation_mutes (migration 006)
- REST: register/list/unregister devices, get/update settings (quiet hours,
  timezone, enable), mute/unmute conversation, VAPID public key
- BullMQ queue: backend enqueues a job per new message; a dedicated stateless
  `notifications` worker service drains it
- Delivery gating: skip sender, muted chats, disabled users, quiet hours, and
  ONLINE users (they get the message live + an in-app toast) — offline → push
- Providers behind one interface: Web Push (VAPID/web-push) + FCM (firebase-admin,
  HTTP v1; Android + iOS via the same path). Dead tokens (404/410/unregistered)
  auto-retired; transient failures recorded
- Web: service worker (push display + tap-to-open the originating chat), push
  registration/unregistration, in-app toast stack, deep-link via ?conversation=

In-app voice & video messages: MediaRecorder capture in the composer (mic/video),
live preview + timer, upload via the existing presigned-media path.

No emojis anywhere: replaced all glyphs with inline SVG icons (shared/ui) so the
UI renders identically across web/desktop/mobile; notification text is plain.

Chores: dedupe ioredis (BullMQ) + pin uuid>=11.1.1 (audit clean) via pnpm overrides;
reusable Centrifugo client factory for the worker.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFRyKxkKEjfAgpXygzoNiD
2026-07-10 19:05:39 +05:00

53 lines
1.6 KiB
JavaScript

import { base } from '../../eslint.config.mjs';
import reactHooks from 'eslint-plugin-react-hooks';
import globals from 'globals';
// Strict Feature-Sliced Design: a layer may import only from itself and the
// layers below it. Upward imports are build errors. Enforced with path-based
// no-restricted-imports (reliable across relative imports), one override per
// layer forbidding every higher layer.
const FSD_LAYERS = ['app', 'pages', 'widgets', 'features', 'entities', 'shared'];
const fsdLayerOverrides = FSD_LAYERS.flatMap((layer, index) => {
const higherLayers = FSD_LAYERS.slice(0, index);
if (higherLayers.length === 0) {
return [];
}
return [
{
files: [`src/${layer}/**/*.{ts,tsx}`],
rules: {
'no-restricted-imports': [
'error',
{
patterns: higherLayers.map((higher) => ({
group: [`**/${higher}`, `**/${higher}/**`],
message: `FSD violation: layer '${layer}' may not import from the higher layer '${higher}'.`,
})),
},
],
},
},
];
});
export default [
// `public/` holds static assets (incl. the service worker) served as-is; it is
// not part of the typed TS project, so keep it out of the typed-lint graph.
{ ignores: ['dist/**', 'public/**'] },
...base,
{
files: ['src/**/*.{ts,tsx}'],
languageOptions: {
globals: { ...globals.browser },
},
plugins: {
'react-hooks': reactHooks,
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
},
},
...fsdLayerOverrides,
];