feat: IMAP mail sync with thread-to-contact matching (PRD §6.1)
Real IMAP connection via imapflow library: - Connects to IMAP server (IMAPFlow, TLS on port 993) - Fetches recent messages (configurable limit, default 20) - Extracts: from, fromEmail, subject, date, snippet (200 chars) - Thread-to-contact matching (PRD §6.1): 1. Match sender email against persons table 2. If no person match, extract domain and match against company.website 3. Returns matchedCompany + matchedPerson for each email - Audit-logged (action: crm.mailsync:imap) - Zod validated (host, port, user, password, folder, limit) - 502 on IMAP connection failure with detail - 400 on validation failure Tested: invalid creds → 502 'IMAP connection failed', missing host → 400
This commit is contained in:
1 parent
7acc0c5451
commit
e45b68bb8b
1089 files changed
+260614
No files matched your search
@@ -0,0 +1,474 @@
|
||||
# Mission Control Design System
|
||||
|
||||
> Category: Developer Tools
|
||||
> Space/aerospace mission monitoring. Dark command center, amber telemetry, monospace precision. Functional clarity above all else.
|
||||
|
||||
## 1. Visual Theme & Atmosphere
|
||||
|
||||
A **deep space command center** — dark, information-dense, unambiguous. Every pixel earns its place. The aesthetic draws from NASA mission control rooms, SpaceX launch consoles, and ISRO's mission operations complex. Amber data on navy is the core contrast pair; everything else is subdued.
|
||||
|
||||
| Element | Hex | Role |
|
||||
|---------|-----|------|
|
||||
| Background | `#0B1120` | Deep space navy, primary canvas |
|
||||
| Surface | `#111827` | Elevated panels, cards |
|
||||
| Surface Hover | `#1A2535` | Interactive surface hover |
|
||||
| Border | `#1E3A5F` | Panel dividers, subtle structure |
|
||||
| Primary Data | `#FFB800` | Telemetry values, key metrics |
|
||||
| Accent | `#00D4FF` | Active/healthy indicators |
|
||||
| Alert | `#FF4757` | Critical warnings, errors |
|
||||
| Text Primary | `#E8F0FE` | High-contrast readable text |
|
||||
| Text Secondary | `#8BA3C7` | Labels, secondary information |
|
||||
| Text Tertiary | `#4A6080` | Timestamps, metadata |
|
||||
|
||||
*Every readout must be readable at 3 meters in low light by someone who hasn't slept in 18 hours.*
|
||||
|
||||
### Use Cases
|
||||
|
||||
Mission Control is purpose-built for:
|
||||
- **Operations dashboards** — real-time system health, infrastructure monitoring, on-call status boards
|
||||
- **Build and deploy status screens** — CI/CD pipelines, release coordination, incident response
|
||||
- **Real-time monitoring UIs** — telemetry aggregation, sensor networks, financial data feeds
|
||||
- **Any information-dense, low-light, high-stakes display**
|
||||
|
||||
### Prior Art
|
||||
|
||||
NASA Mission Control (Houston), ISRO ISTRAC, SpaceX Falcon/Dragon consoles, ESA ESOC — all share amber-on-navy telemetry, monospace data fields, and hierarchical alert systems. The shared constraints (low light, fatigue, split-second decisions) drive convergent design.
|
||||
|
||||
## 2. Color
|
||||
|
||||
### Surface Palette
|
||||
|
||||
| Token | Hex | Usage |
|
||||
|-------|-----|-------|
|
||||
| Background | `#0B1120` | Page canvas, primary depth |
|
||||
| Surface | `#111827` | Panels, cards, elevated areas |
|
||||
| Surface Hover | `#1A2535` | Interactive surface state |
|
||||
| Surface Active | `#1E3A5F` | Selected, active panel |
|
||||
| Border | `#1E3A5F` | Panel dividers, grid lines |
|
||||
| Border Subtle | `#162035` | Inner dividers, minor separation |
|
||||
|
||||
### Data Palette (telemetry values)
|
||||
|
||||
| Token | Hex | Usage |
|
||||
|-------|-----|-------|
|
||||
| Primary | `#FFB800` | Primary telemetry values, key metrics |
|
||||
| Secondary | `#00D4FF` | Healthy/active indicators, links |
|
||||
| Alert Critical | `#FF4757` | Errors, critical alerts, abort states |
|
||||
| Alert Warning | `#FF9F43` | Warnings, degraded performance |
|
||||
| Success | `#26DE81` | Nominal status, completed actions |
|
||||
|
||||
All data colors on `#111827` pass WCAG AA (minimum 4.5:1).
|
||||
|
||||
### Text Palette
|
||||
|
||||
| Token | Hex | Usage |
|
||||
|-------|-----|-------|
|
||||
| Primary | `#E8F0FE` | Readable at distance, primary content |
|
||||
| Secondary | `#8BA3C7` | Labels, descriptors |
|
||||
| Tertiary | `#4A6080` | Timestamps, metadata, grid labels |
|
||||
|
||||
### Dark Mode
|
||||
|
||||
Dark mode is the native mode. No light mode variant by design — mission control environments are always low-light (ISRO ISTRAC, NASA FDO, SpaceX launch consoles all run dark). daytime operations centers with high ambient light are outside scope for v1; a light mode adaptation would require rethinking the full semantic color layer.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--bg-default: #0B1120;
|
||||
--bg-surface: #111827;
|
||||
--bg-surface-hover: #1A2535;
|
||||
--bg-surface-active: #1E3A5F;
|
||||
--border-default: #1E3A5F;
|
||||
--border-subtle: #162035;
|
||||
--data-primary: #FFB800;
|
||||
--data-secondary: #00D4FF;
|
||||
--data-alert-critical: #FF4757;
|
||||
--data-alert-warning: #FF9F43;
|
||||
--data-success: #26DE81;
|
||||
--fg-primary: #E8F0FE;
|
||||
--fg-secondary: #8BA3C7;
|
||||
--fg-tertiary: #4A6080;
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Typography
|
||||
|
||||
### Font Stack
|
||||
|
||||
```css
|
||||
/* Monospace for all data readouts — consistency at speed */
|
||||
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
||||
|
||||
/* Sans-serif for labels, navigation, prose */
|
||||
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
```
|
||||
|
||||
### Type Scale
|
||||
|
||||
| Role | Size | Weight | Line Height | Font |
|
||||
|------|------|--------|-------------|------|
|
||||
| Display | 48px | 700 | 1.0 | JetBrains Mono |
|
||||
| H1 | 18px | 600 | 1.2 | Inter |
|
||||
| H2 | 13px | 600 | 1.2 | Inter, uppercase, tracked |
|
||||
| Body | 14px | 400 | 1.5 | Inter |
|
||||
| Caption | 12px | 400 | 1.4 | Inter |
|
||||
| Micro | 10px | 600 | 1.0 | Inter, uppercase |
|
||||
|
||||
**Font labels for catalog extraction:**
|
||||
|
||||
```
|
||||
Display: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace
|
||||
Body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif
|
||||
Mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace
|
||||
```
|
||||
|
||||
## 4. Spacing
|
||||
|
||||
4px baseline grid for dense telemetry layouts. 8px for outer padding, 16px+ for section gaps.
|
||||
|
||||
```css
|
||||
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
||||
--space-5: 20px; --space-6: 24px; --space-8: 32px; --space-12: 48px;
|
||||
--space-16: 64px; --space-20: 80px;
|
||||
```
|
||||
|
||||
## 5. Layout & Composition
|
||||
|
||||
### Grid System
|
||||
|
||||
12-column grid, 4px gutters. Dense information layout — no wasted whitespace, but clear visual grouping.
|
||||
|
||||
```css
|
||||
/* Standard panel: spans 3, 4, or 6 columns */
|
||||
.panel {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: 4px;
|
||||
padding: var(--space-4);
|
||||
}
|
||||
|
||||
/* Full-width telemetry strip */
|
||||
.telemetry-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: var(--space-2);
|
||||
}
|
||||
```
|
||||
|
||||
### Panel Structure
|
||||
|
||||
```css
|
||||
/* .panel base styles are defined in the Grid System section above. */
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--space-3);
|
||||
padding-bottom: var(--space-2);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--fg-secondary);
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Components
|
||||
|
||||
### Status Badge
|
||||
|
||||
```css
|
||||
/* Nominal — green, all clear */
|
||||
.badge-nominal {
|
||||
background: rgba(38, 222, 129, 0.15);
|
||||
color: #26DE81;
|
||||
border: 1px solid rgba(38, 222, 129, 0.3);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 2px 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Warning — amber, attention needed */
|
||||
.badge-warning {
|
||||
background: rgba(255, 159, 67, 0.15);
|
||||
color: #FF9F43;
|
||||
border: 1px solid rgba(255, 159, 67, 0.3);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 2px 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Critical — red, immediate action */
|
||||
.badge-critical {
|
||||
background: rgba(255, 71, 87, 0.15);
|
||||
color: #FF4757;
|
||||
border: 1px solid rgba(255, 71, 87, 0.3);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 2px 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
### Data Tile
|
||||
|
||||
```css
|
||||
/* Single metric display */
|
||||
.data-tile {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-default);
|
||||
border-radius: 4px;
|
||||
padding: var(--space-3);
|
||||
}
|
||||
|
||||
.data-tile-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--fg-secondary);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.data-tile-value {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--data-primary);
|
||||
line-height: 1.0;
|
||||
}
|
||||
|
||||
.data-tile-unit {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--fg-tertiary);
|
||||
margin-left: 4px;
|
||||
}
|
||||
```
|
||||
|
||||
### Countdown Timer
|
||||
|
||||
```css
|
||||
/* T-minus / T-plus display */
|
||||
.countdown {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 48px;
|
||||
font-weight: 700;
|
||||
color: var(--data-primary);
|
||||
line-height: 1.0;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.countdown-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--fg-tertiary);
|
||||
}
|
||||
|
||||
/* Positive delta (T+) — time after event */
|
||||
.countdown.positive { color: var(--data-success); }
|
||||
|
||||
/* At T-0 */
|
||||
.countdown.zero { color: var(--data-secondary); animation: pulse-glow 2s ease-in-out infinite; }
|
||||
|
||||
@keyframes pulse-glow {
|
||||
0%, 100% { text-shadow: 0 0 8px currentColor; }
|
||||
50% { text-shadow: 0 0 20px currentColor, 0 0 40px currentColor; }
|
||||
}
|
||||
```
|
||||
|
||||
### Signal Strength Indicator
|
||||
|
||||
```css
|
||||
/* Vertical bar signal meter */
|
||||
.signal-bars {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.signal-bar {
|
||||
width: 4px;
|
||||
background: var(--border-default);
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.signal-bar.active.weak { background: var(--data-alert-warning); }
|
||||
.signal-bar.active.moderate { background: var(--data-primary); }
|
||||
.signal-bar.active.strong { background: var(--data-secondary); }
|
||||
|
||||
.signal-bar:nth-child(1) { height: 5px; }
|
||||
.signal-bar:nth-child(2) { height: 8px; }
|
||||
.signal-bar:nth-child(3) { height: 12px; }
|
||||
.signal-bar:nth-child(4) { height: 16px; }
|
||||
```
|
||||
|
||||
### Alert Banner
|
||||
|
||||
```css
|
||||
/* Full-width critical alert */
|
||||
.alert-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
background: rgba(255, 71, 87, 0.1);
|
||||
border: 1px solid rgba(255, 71, 87, 0.4);
|
||||
border-left: 4px solid #FF4757;
|
||||
border-radius: 4px;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
}
|
||||
|
||||
.alert-banner-icon {
|
||||
color: #FF4757;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.alert-banner-text {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #FF4757;
|
||||
}
|
||||
|
||||
.alert-banner-time {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--fg-tertiary);
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Coordinate Display
|
||||
|
||||
```css
|
||||
/* Latitude / Longitude / Altitude readout */
|
||||
.coordinate {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 14px;
|
||||
color: var(--data-secondary);
|
||||
}
|
||||
|
||||
.coordinate-label {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--fg-tertiary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
### Progress Bar
|
||||
|
||||
```css
|
||||
/* Mission phase / upload / loading progress */
|
||||
.progress-bar {
|
||||
height: 4px;
|
||||
background: var(--border-default);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar-fill {
|
||||
height: 100%;
|
||||
background: var(--data-secondary);
|
||||
border-radius: 2px;
|
||||
transition: width 300ms ease-out;
|
||||
}
|
||||
|
||||
.progress-bar-fill.warning { background: var(--data-alert-warning); }
|
||||
.progress-bar-fill.critical { background: var(--data-alert-critical); }
|
||||
```
|
||||
|
||||
### Telemetry Chart Line
|
||||
|
||||
```css
|
||||
/* Sparkline chart for data over time */
|
||||
.telemetry-chart {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
.telemetry-chart-bar {
|
||||
flex: 1;
|
||||
background: var(--data-primary);
|
||||
border-radius: 1px 1px 0 0;
|
||||
min-width: 2px;
|
||||
}
|
||||
|
||||
.telemetry-chart-bar.alert { background: var(--data-alert-critical); }
|
||||
.telemetry-chart-bar.warning { background: var(--data-alert-warning); }
|
||||
```
|
||||
|
||||
## 7. Motion & Interaction
|
||||
|
||||
| Interaction | Duration | Easing | Effect |
|
||||
|-------------|----------|--------|--------|
|
||||
| Alert pulse | 2s | ease-in-out | Glow intensity oscillation (loop) |
|
||||
| Panel appear | 200ms | ease-out | Opacity 0→1 |
|
||||
| Value change | 150ms | ease-out | Background flash on new data |
|
||||
| Progress fill | 300ms | ease-out | Width transition |
|
||||
| Hover state | 100ms | ease-in | Border color brightens |
|
||||
|
||||
```css
|
||||
--transition-fast: 100ms ease-in;
|
||||
--transition-base: 150ms ease-out;
|
||||
--transition-slow: 300ms ease-out;
|
||||
```
|
||||
|
||||
### prefers-reduced-motion
|
||||
|
||||
Static environments are common in mission control. Replace all animations with instant state changes.
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. Voice & Brand
|
||||
|
||||
### Iconography
|
||||
|
||||
Minimal, functional iconography — Lucide icons (stroke weight 1.5px, 16px default). No decorative icons. Every icon must communicate operational state.
|
||||
|
||||
### Tone
|
||||
|
||||
- **Precise**: Data-first, no marketing language
|
||||
- **Sparse**: The UI speaks through values and color, not prose
|
||||
- **Hierarchical**: Visual urgency maps directly to operational urgency
|
||||
|
||||
### Visual Signals
|
||||
|
||||
Color is the primary signal carrier. Every color choice must communicate operational state — never decorative.
|
||||
|
||||
## 9. Anti-patterns
|
||||
|
||||
- Do not use decorative colors in data displays — every hue must convey operational meaning
|
||||
- Do not use rounded corners > 4px — mission control is functional, not friendly
|
||||
- Do not use proportional fonts for telemetry values — use monospace exclusively for data
|
||||
- Do not animate non-alert elements — motion is reserved for signals that matter
|
||||
- Do not use light mode — low-light environments are the only context
|
||||
- Do not use low-contrast text on dark backgrounds — tertiary `#4A6080` is only for non-critical metadata (timestamps, grid labels)
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
name: mission-control
|
||||
description: Space/aerospace mission monitoring: dark command center, amber telemetry on navy, monospace precision. Functional clarity above all. For ops dashboards, build/deploy status, and real-time monitoring.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: hand-authored
|
||||
---
|
||||
|
||||
<!-- HAND_AUTHORED_MANAGED_START -->
|
||||
# Mission Control Design System Skill (Universal)
|
||||
|
||||
## Mission
|
||||
You are an expert design-system guideline author for Mission Control.
|
||||
Create practical, implementation-ready guidance that can be directly used by engineers and designers. This system is hand-authored; treat its DESIGN.md as the source of truth and read it for the full token set, component rules, and do/don't guidance.
|
||||
|
||||
## Brand
|
||||
Mission Control — precise, subdued, mission-critical.
|
||||
|
||||
## Style Foundations
|
||||
- Visual style: themed, information-dense, low-light, high-stakes
|
||||
- Typography fonts: primary=monospace, display=monospace, mono=monospace
|
||||
- Color palette: amber telemetry, navy canvas, cyan healthy, alert red
|
||||
- Key tokens: background=#0B1120, surface=#111827, border=#1E3A5F, primary=#FFB800, accent=#00D4FF, alert=#FF4757, text=#E8F0FE, text-2=#8BA3C7, text-3=#4A6080
|
||||
- Spacing / layout: hierarchical telemetry grid; readable at 3m in low light
|
||||
|
||||
## Accessibility
|
||||
WCAG 2.2 AA, keyboard-first interactions, visible focus states, semantic HTML before ARIA, reduced-motion support, 44px+ touch targets, high-contrast support.
|
||||
|
||||
## Writing Tone
|
||||
precise, subdued, mission-critical
|
||||
|
||||
## Rules: Do
|
||||
- prefer semantic tokens over raw values
|
||||
- preserve visual hierarchy
|
||||
- keep interaction states explicit
|
||||
- read DESIGN.md for the authoritative palette, type, and component rules
|
||||
|
||||
## Rules: Don't
|
||||
- avoid low contrast text
|
||||
- avoid inconsistent spacing rhythm
|
||||
- avoid ambiguous labels
|
||||
- do not invent hex values outside this system's palette
|
||||
|
||||
## Expected Behavior
|
||||
- Follow the foundations first, then component consistency.
|
||||
- When uncertain, prioritize accessibility and clarity over novelty.
|
||||
- Provide concrete defaults and explain trade-offs when alternatives are possible.
|
||||
- Keep guidance opinionated, concise, and implementation-focused.
|
||||
|
||||
## Guideline Authoring Workflow
|
||||
1. Restate the design intent in one sentence before proposing rules.
|
||||
2. Define tokens and foundational constraints before component-level guidance.
|
||||
3. Specify component anatomy, states, variants, and interaction behavior.
|
||||
4. Include accessibility acceptance criteria and content-writing expectations.
|
||||
5. Add anti-patterns and migration notes for existing inconsistent UI.
|
||||
6. End with a QA checklist that can be executed in code review.
|
||||
|
||||
## Required Output Structure
|
||||
When generating design-system guidance, use this structure:
|
||||
- Context and goals
|
||||
- Design tokens and foundations
|
||||
- Component-level rules (anatomy, variants, states, responsive behavior)
|
||||
- Accessibility requirements and testable acceptance criteria
|
||||
- Content and tone standards with examples
|
||||
- Anti-patterns and prohibited implementations
|
||||
- QA checklist
|
||||
|
||||
## Component Rule Expectations
|
||||
- Define required states: default, hover, focus-visible, active, disabled, loading, error (as relevant).
|
||||
- Describe interaction behavior for keyboard, pointer, and touch.
|
||||
- State spacing, typography, and color-token usage explicitly.
|
||||
- Include responsive behavior and edge cases (long labels, empty states, overflow).
|
||||
|
||||
## Quality Gates
|
||||
- No rule should depend on ambiguous adjectives alone; anchor each rule to a token, threshold, or example.
|
||||
- Every accessibility statement must be testable in implementation.
|
||||
- Prefer system consistency over one-off local optimizations.
|
||||
- Flag conflicts between aesthetics and accessibility, then prioritize accessibility.
|
||||
|
||||
## Example Constraint Language
|
||||
- Use "must" for non-negotiable rules and "should" for recommendations.
|
||||
- Pair every do-rule with at least one concrete don't-example.
|
||||
- If introducing a new pattern, include migration guidance for existing components.
|
||||
|
||||
<!-- HAND_AUTHORED_MANAGED_END -->
|
||||
Reference in new issue
Block a user