Changelog
[1.3.0] — 2026-03-24
Added
- Weekend configuration — dashboard settings page with 7 toggle buttons (Mon–Sun) to configure working days.
isWorkingDay()accepts customweekendDays[](default Sat/Sun). Crons skip configured weekend days. - LLM nudge messages — deadline nudge DMs use Claude Haiku for natural, personal tone. Falls back to static blocks if no API key.
- Notification cooldown (2h) — after any notification DM, suppress non-urgent nudges for 2 hours. Prevents scanner from spamming users who already got a morning summary.
- Urgent bypass — P1/P2 tasks or tasks due within 2 hours bypass the cooldown and fire immediately.
Changed
- Progress channel — removed daily task list posting entirely. Submission deadline now replies as a thread reply to the morning thread, tagging only missing users. No more individual DMs for deadline.
- Scanner batching — 15-min proactive scanner groups tasks per-user and queues ONE batch nudge per user instead of N individual jobs.
- Batch handler — now also picks up stale tasks (in_progress 2+ days) alongside deadline tasks.
Fixed
- Notification spam — users were receiving 3-4 separate DMs from the scanner (one per task). Now receive one consolidated LLM-generated message.
[1.2.0] — 2026-03-23
Added
- Employee dashboard redesign — filters (status, priority, search, sort), list/board view toggle, clickable tasks open TaskDetailPanel sheet
- Pipeline access for employees — employees can now view and move their own tasks in the pipeline kanban
- Pipeline filters — status, priority, assignee, client, search filters on pipeline page
- Temporary password system —
mustChangePasswordcolumn, forced password change on first login, change-password page - Clear bot DMs — admin can clear bot messages from any user’s DM via dashboard or
/clear-dmsslash command - LLM smart reminders — personal summary DM uses Claude Haiku to write 2-3 line natural nudge instead of dumping all tasks
- Notification dedup — Redis-backed
TaskNotificationDedupServiceprevents same task being reminded across multiple channels - Display IDs in slash commands —
/tasksshows#displayId,/donematches by displayId - Smart
/blockedand/unblocked— require task ID + reason, show task list when no args - Password visibility toggle — eye icon on all auth pages (login, signup, complete-signup, change-password)
- Slack commands reference — added to
docs/development/setup.mdx - Assistant streaming responses — AI App split-pane shows responses progressively (sentence-by-sentence) using
chat.update, instead of waiting for the full reply - Context-aware assistant prompts —
threadContextChangeddetects client channels viaslackChannelIdlookup and shows client-specific suggested prompts (e.g. “Show [Client] Tasks”)
Fixed
- Morning thread duplicate tasks — follow-up replies now use LLM to match existing tasks instead of creating duplicates
- EOD collection blanket status — was applying same status to ALL tasks when one emoji found; now uses LLM per-task matching
- Chat tool matching —
complete_task,update_task,reassign_task,move_task_stageuse scored matching + displayId instead of.includes() - Status dropdown refresh — task list message updates in-place when status changed via dropdown
- Daily progress includes overdue — “23 Mar Tasks” message now shows carry-forward/overdue tasks from previous days
- Deadline message merging — deadline post updates existing daily message instead of posting duplicate
- Hardcoded deadline time — morning thread uses org’s configured
submissionDeadlineTime, not “11 AM” - Dashboard relative time — Due Today shows “in 2h”, “30m ago” instead of just “Today”
- Dashboard clickable cards — Due Today, Needs Attention, Active Alerts tasks open TaskDetailPanel on click
- Needs Attention shows overdue — was showing “ALL CLEAR”, now includes overdue + blocked + stale tasks
- Due date timezone — morning thread tasks get correct EOD time in org timezone
- Draft wording — removed “needs confirmation” language, tasks are auto-confirmed
- Action item cancelled status — added ‘cancelled’ to action item status enum
- Change password validation —
currentPasswordoptional whenmustChangePasswordis true
[Unreleased]
V2 Pivot: Remaining Gaps — Intervention, Same-as-Yesterday, Designer Handoffs, Reassignment, Weekend Exclusion
Added
- Intervention bot command —
log_interventionLLM tool lets users say “I picked up X’s newsletter” and the bot resolves the attributed user by name, logs the intervention via InterventionsService, and posts to progress channel - Task reassignment —
reassign_taskLLM tool; finds task by title search and user by name, callsTasksService.reassignTask()which updates assignment, logs “reassigned” action, and DMs both old and new owners via Slack - “Same as yesterday” detection — Jaccard similarity check on morning thread submissions; >85% similarity to yesterday’s flags to ops channel with percentage.
calculateSimilarity()utility with 7 unit tests (tests/unit/same-as-yesterday.test.ts) - Designer dependency tracking — on content task completion (keywords: draft, content, writing, copy, blog, newsletter, article), looks up client’s
assignedDesignersand DMs each designer that design work can begin - Public holiday configuration —
isWorkingDay(date, preferences)utility atapps/api/src/common/utils/working-day.tschecks weekends + orgholidayspreference array ([{date: "YYYY-MM-DD", name: "..."}]).holidaysfield added toOrgPreferencesinterface - Weekend/holiday exclusion — 10 cron handlers wrapped with
isWorkingDay(): daily-checkin, personal-summary, morning-thread, submission-deadline, eod-nudge, eod-collection, blocker-escalation, classification-digest, thursday-checkin, daily-report. Always-run crons (aggregation, OOO, weekly/monthly reports, SOP jobs) unchanged ReportsModuleimported intoChatModule(providesInterventionsService)SlackModuleimported intoTasksModule(providesSlackWebApiServicefor designer DMs and reassignment notifications)
V2 Pivot: Phase 5B — SOP Tracking System
Added
- New
sopsAPI module with service, controller, and REST endpoints for managing recurring Standard Operating Procedures - DB schema —
sopsandsop_recordstables with frequency (daily/weekly/monthly/one_time), role/user/client assignment, category grouping, and full audit trail - Period generation — automatic record creation per frequency cycle (daily at 00:10) with duplicate prevention
- Overdue detection — daily check at 10:00 marks pending records past their period end as overdue, DMs users via Slack, escalates 2+ day overdue to admins
- Missed marking — 2-day grace period before overdue records become missed (daily at 00:15)
- Compliance calculation — per-SOP, per-user, and per-category compliance rates (completed / non-pending * 100)
- Slack bot integration —
show_sop_statusandcomplete_sopLLM tools for natural language SOP interaction - Admin UI — SOP management page at
/dashboard/sopswith SOPs tab (grouped by category, create/edit modal) and Compliance tab (overview stats, per-SOP table with compliance bars, per-user rates, per-category grid) - Report integration — weekly private reports include SOP compliance summary with overdue/missed counts; monthly reports include per-category compliance and best/worst performers
- Default SOP seeding —
POST /api/sops/seed-defaultscreates client SOPs per active client + internal ops + analytics SOPs - SDK methods:
getSOPs(),getSOP(),createSOP(),updateSOP(),deleteSOP(),getSOPRecords(),getSOPCompliance(),getMySOPStatus(),completeSOPRecord(),seedDefaultSOPs() - SDK types:
SOP,SOPRecord,UserSOPStatus,SOPComplianceReport - Zod schemas:
createSOPSchema,updateSOPSchema,completeSOPRecordSchema - API endpoints:
GET /api/sops,GET /api/sops/:id,POST /api/sops,PATCH /api/sops/:id,DELETE /api/sops/:id,GET /api/sops/records,GET /api/sops/compliance,GET /api/sops/my-status,POST /api/sops/records/:id/complete,POST /api/sops/seed-defaults,POST /api/sops/generate-periods - 3 new dynamic cron jobs:
sop-period-generation(00:10),sop-overdue-check(10:00),sop-missed-check(00:15) - Sidebar nav link: “SOPs” with
FileCheckicon (manager+ role) - Unit tests:
tests/unit/sop-tracking.test.ts(22 tests — period generation, due descriptions, overdue/missed detection, compliance calculation, user applicability)
V2 Pivot: Phase 5A — Checklist System
Added
- New
checklistsAPI module with service, controller, and REST endpoints - Pre-defined checklists per role (writer, designer, ops) with configurable items
- Completion tracking — start completion, toggle items, auto-detect full completion
- Slack bot integration —
show_checklist,complete_checklist_item,complete_all_checklistLLM tools for natural language checklist interaction - Admin UI — checklist management page at
/dashboard/checklistswith create/edit modal, drag-to-reorder items, completion log, stats overview - Default checklist templates — Content Writing, Content QC, Design QC, Client QC, Designer checklists seeded via
POST /api/checklists/seed-defaults - Report integration — daily private reports include checklist completion summary; weekly private reports include per-checklist completion rates and users who never completed
- New DB tables:
checklists,checklist_completionswith appropriate indexes - SDK methods:
getChecklists(),createChecklist(),updateChecklist(),deleteChecklist(),getCompletions(),getCompletionStats(),getPendingChecklists(),startCompletion(),toggleChecklistItem(),seedDefaultChecklists() - SDK types:
Checklist,ChecklistCompletion,PendingChecklist,ChecklistStats - Zod schemas:
createChecklistSchema,updateChecklistSchema,startCompletionSchema,toggleItemSchema - API endpoints:
GET /api/checklists,POST /api/checklists,PATCH /api/checklists/:id,DELETE /api/checklists/:id,POST /api/checklists/seed-defaults,GET /api/checklists/completions,GET /api/checklists/completions/stats,GET /api/checklists/completions/pending,POST /api/checklists/completions,PATCH /api/checklists/completions/:id/toggle - Sidebar nav link: “Checklists” with
ClipboardListicon (manager+ role) - Unit tests:
tests/unit/checklists.test.ts(toggle logic, completion stats, item matching, pending checklists)
V2 Pivot: Phase 4C — Action Item Tracking
Added
- Action Items admin dashboard page (
/dashboard/action-items) with ops-brain dark theme - Filter by status (all/open/closed/cancelled), priority (all/high/mid/low), and assignee
- Inline status updates (mark done, cancel) with optimistic UI
- Create new action items manually with assignee and priority selection
- Auto-creation of action items from weekly report recommendations (with duplicate detection)
- Carry-forward badge display (
CF: N) for items carried across reports - “From report” source indicator for auto-generated items
- “View all →” link on Reports page navigating to Action Items
GET /api/action-items/countendpoint for nav badgegetActionItemCount()SDK methodcreateActionItem()web API client method- Sidebar nav link with
ListChecksicon between Reports and Cards - Left join on users table for
assignedToNamein action items listing
V2 Pivot: Phase 4B — Positive Reinforcement System
Added
- New
ReinforcementService(apps/api/src/modules/reinforcement/) with automatic recognition for high performers - Daily shoutouts — users with 100% weighted task completion get recognized in #wins channel (or progress channel fallback)
- Performer of the Week — highest weighted completion user recognized after weekly report generation
- Employee of the Month — highest average completion user recognized after monthly report generation
- DM notifications to recognized users alongside public channel posts
- New
reinforcementsDB table for tracking recognition history - REST endpoints:
GET /api/reinforcement/history,POST /api/reinforcement/trigger/daily,POST /api/reinforcement/trigger/weekly - Org preferences:
reinforcementEnabled(default: true),winsChannelId(nullable, falls back to progress channel) - Admin settings UI section for reinforcement toggle and wins channel picker
- SDK methods:
getReinforcementHistory(),triggerDailyShoutout(),triggerWeeklyPerformer() - Hooks into existing daily/weekly/monthly report crons — no new cron jobs created
- Unit tests:
tests/unit/reinforcement.test.ts(selection logic, tiebreaking, edge cases)
V2 Pivot: Phase 3D — Client Health Tracking
Added
- New
ClientHealthService(apps/api/src/modules/clients/client-health.service.ts) computing per-client health metrics - Health score (0-100) composite: 50% task completion rate, 30% deploy day compliance, 20% carry-forward ratio
- Health levels:
healthy(≥75),at_risk(≥50),critical(<50) - Deploy compliance tracking — checks for completed deploy/send/newsletter/publish tasks before the configured deploy day
- Deploy streak — consecutive weeks with on-time deploys (up to 12 weeks lookback)
- Week-over-week change — completion rate delta vs previous week
- Per-member breakdown — per-writer/designer task completion for a client
- 4-week trend — weekly completion rate and deploy compliance history
- Active blocker count per client from linked tasks
- API endpoints:
GET /api/clients/health(all clients),GET /api/clients/:id/health(single client detail) - SDK methods:
getClientHealth(),getClientHealthDetail(clientId) - Web API client methods:
getClientHealth(),getClientHealthDetail(clientId) - Dashboard rewrite — clients page now shows real health scores, completion rates, deploy streaks, week-over-week trends, and expandable detail with member breakdown and 4-week trend
- Report integration — weekly private and monthly reports now include client health summaries; critical clients generate recommended actions
- SDK types:
ClientHealthSummary,ClientHealthDetail - Unit tests:
tests/unit/client-health.test.ts(25+ tests for health score, thresholds, carry-forward scoring, deploy streaks, member aggregation)
V2 Pivot: Phase 3B — Report Generation System
Added
- New
reportsAPI module with service, controller, and REST endpoints - Daily public/private reports posted at 9 PM — per-person task list, completion % (weighted), team total; private adds cards, stale tasks, OOO context, intervention logs, client summary
- Weekly public/private reports posted Friday at 6 PM — team stats, target day compliance, performer of week; private adds KPI comparison, card tally, carry-forward patterns, workload distribution, recommended actions
- Monthly reports generated on last working day at 6 PM — trend lines, card history, recurring blockers, scalability assessment, employee of month, recommended 1:1s, action items
- Intervention logging system —
/log-interventionSlack command for managers to record 1:1s, coaching, and corrective actions attributed to team members - Action items with carry-forward tracking — open action items automatically carry forward into the next report period
- Auto-generated recommended actions based on team data (cards, blockers, carry-forward patterns)
- New DB tables:
reports,interventions,action_items - New dynamic crons:
{orgId}:daily-report(9 PM),{orgId}:weekly-report(Friday 6 PM),{orgId}:monthly-report(last working day 6 PM) - SDK methods:
getReports(),logIntervention(),getActionItems(),getInterventions(),updateActionItem() - Zod schemas:
logInterventionSchema,updateActionItemSchema
Dashboard Overhaul: Ops-Brain Command Center
Added
- Ops-brain dashboard for managers/admins — dark theme, IBM Plex Mono + Instrument Serif fonts
- 5 purpose-built views: Today (live task feed), Clients (health dashboard), Team (per-person KPI), Reports (daily/weekly/monthly), Cards (card management)
- Today view: task feed grouped by person, completion percentages, card pills, OOO badges, cron status panel, active alerts
- Clients view: health cards with open rate/CTR metrics, deploy streaks, sparkline charts, team avatars
- Team view: two-column layout with person list and detail panel, KPI bars, task list, card history with advisory notes
- Reports view: three tabs (Weekly Private, Weekly Public, Daily Digest) with KPI comparison, sends tracking, invisible labor log, action items
- Cards view: card log with dismiss functionality, weekly summary, manual red card issuance, rules reference
- Shared ops components: StatusDot, Tag, SizeTag, CardPill, OpsAvatar, KpiBar, MiniSparkBar
- Employee role retains simplified dashboard with task stats and recent tasks
- API client methods: cards, blockers, OOO, reports, KPI, interventions (graceful fallback for unbuilt endpoints)
- Unit tests: 43 tests for ops utility functions (status colors, completion calculation, card pill formatting, health determination, size tags)
- CSS: ops-brain keyframes (blink, glow, in), custom properties, font imports
V2 Pivot: Phase 2A — Card System (Yellow/Red Cards)
Added
- New
cardsAPI module with service, controller, and REST endpoints - Yellow card triggers: missing submission (11 AM deadline), task overdue 2+ days, no EOD update
- Red card: 3 yellows/week auto-converts to red, manual
/red-card @user reasonSlack command - Exemptions: OOO users fully exempt; ramp-up period first 2 weeks exempt, weeks 3+ noted
- Card dismissal by Admin/Manager with reason and DM notification
- DM notifications on card issuance (yellow and red) via Slack
- Weekly card summary endpoint with per-user breakdown
- Duplicate prevention: same trigger+task combo won’t issue twice in the same week
- Card evaluation rules as pure functions in
packages/rules/src/cards.ts - New static cron: daily at noon scans overdue tasks (2+ days) for yellow cards
- Integration: submission deadline (11 AM) issues MISSING_SUBMISSION cards
- Integration: EOD collection (7 PM) issues NO_EOD_UPDATE cards for users without replies
- SDK methods:
getCards(),getCardsByUser(),getCardSummary(),issueCard(),issueRedCard(),dismissCard() - Zod schemas:
issueCardSchema,dismissCardSchema - API endpoints:
GET /api/cards,GET /api/cards/user/:userId,GET /api/cards/summary,POST /api/cards,POST /api/cards/:id/dismiss - Unit tests:
tests/unit/card-rules.test.ts(23 tests)
V2 Pivot: Phase 2C — Blocker System
Added
- New
blockersAPI module with service, controller, and REST endpoints /blocked [reason]command — reports a blocker on user’s active task, notifies ops via progress channel/unblocked [note]command — resolves active blocker with optional resolution note, posts resolution time- Auto-detection from carry-forward reasons — EOD collection scans carry-forward text for blocker keywords (
blocked,waiting on,depends on,stuck,can't proceed,need approval,pending review,waiting for) - Escalation ladder:
- 0h: Ops notified via progress channel on report
- 8h: Admin/founder DM escalation
- 24h: Critical alert in progress channel
- Resolution time tracking — calculates hours blocked, posts to progress channel on resolution
- New DB table:
blockers(id, taskId, userId, organizationId, reason, escalationLevel, source, resolved, resolvedAt, resolutionNote) - New task fields:
blocked(boolean),blockedAt(timestamp) - New dynamic cron:
{orgId}:blocker-escalation(every hour) - SDK methods:
reportBlocker(),resolveBlocker(),getActiveBlockers(),getBlockerStats(),getBlockersByUser(),detectBlockerFromCarryForward() - Zod schemas:
reportBlockerSchema,resolveBlockerSchema,detectBlockerSchema - API endpoints:
GET /api/blockers,GET /api/blockers/stats,GET /api/blockers/user/:userId,POST /api/blockers,POST /api/blockers/:id/resolve,POST /api/blockers/detect - Blocker detection unit tests:
tests/unit/blocker-detection.test.ts(16 tests)
V2 Pivot: Phase 2D — OOO (Out-of-Office) System
Added
- New
oooAPI module with service, controller, and REST endpoints - LLM-based parsing of OOO messages from Slack channel (
#out-of-office) - Channel monitoring: bot detects messages in the configured OOO channel, parses with LLM, stores in
ooo_records, reacts with ✅ /oooslash command fallback for structured input- Daily OOO status transition cron:
{orgId}:ooo-status-update(upcoming → active → completed) - New org preference:
oooChannelIdfor configuring the OOO Slack channel - SDK methods:
listOOORecords(),getActiveOOO(),checkUserOOO(),createOOO(),parseOOOMessage(),cancelOOO() - API endpoints:
GET /api/ooo,GET /api/ooo/active,GET /api/ooo/check/:userId,POST /api/ooo,POST /api/ooo/parse,DELETE /api/ooo/:id - Unit tests:
tests/unit/ooo-parser.test.ts
V2 Pivot: Phase 2B — Auto-Classification Engine
Added
- New
classificationAPI module with service, controller, and REST endpoints - Keyword-based task classification — auto-assigns type, size, weight, and client to tasks based on org-configurable keyword mappings
- Auto-classification on task creation — every confirmed task draft is immediately classified
- Morning thread submission classification — submissions are parsed and classified on recording
- 11:30 AM classification digest — daily summary posted to progress channel grouping tasks by confidence level
- Admin UI — task type map management page at
/dashboard/settings/task-typeswith CRUD, seed defaults, and bulk classify actions - Task type map CRUD — create, update, delete keyword-to-type mappings per org; seed default mappings for new orgs
- SDK methods:
classifyTask(),classifyAndUpdateTask(),bulkClassify(),getTaskTypeMap(),createTaskTypeMapEntry(),updateTaskTypeMapEntry(),deleteTaskTypeMapEntry(),seedTaskTypeMap() - New dynamic cron:
{orgId}:classification-digestat 11:30 AM - Shared Zod schemas:
classifyTaskSchema,createTaskTypeMapSchema,updateTaskTypeMapSchema - Unit tests:
tests/unit/classification.test.ts
V2 Pivot: Phase 1E — Schedule Settings UI
Added
- Admin dashboard: Added “Daily Task Loop” settings section in Channels & Deadlines tab
- Configurable morning thread time, submission deadline, EOD nudge time, and EOD collection time
- Toggle to enable/disable morning threads with progress channel validation
- Sequential time validation (morning → deadline → nudge → collection)
V2 Pivot: Phase 1D — EOD Collection System
Added
- New
eodAPI module with service, controller, and REST endpoints - 5 PM EOD nudge — bot posts a reminder as a reply to the morning thread prompting users to update task statuses with emoji reactions
- 7 PM EOD collection scan — bot scans morning thread replies and parses emoji statuses into
task_statusesrecords:- Done, carry forward, dropped, no update
- Carry-forward counter —
carryForwardCounton tasks is incremented each time a task is marked as carry forward - No-update detection — users who did not reply to the morning thread by 7 PM are flagged with
no_updatestatus entries - Daily summary — aggregated EOD summary posted to the progress channel after collection
- New org preferences:
eodNudgeTime(default17:00),eodCollectionTime(default19:00) - New dynamic crons:
{orgId}:eod-nudge,{orgId}:eod-collection - SDK methods:
getEodSummary(),getEodStatuses(),triggerEodCollection() - EOD parser unit tests:
tests/unit/eod-parser.test.ts - API endpoints:
GET /api/eod/summary/:date?,GET /api/eod/statuses/:date?,POST /api/eod/collect
V2 Pivot: Phase 1A — Database Schema (Foundation)
New Tables
clients— Client entities with deploy schedules, content cadence, assigned writers/designerscards— Yellow/red accountability cards with trigger tracking, weekly reset, dismissalmorning_threads— Daily morning thread records (channel, thread TS, deadline/EOD flags)thread_submissions— User replies to morning threads (raw text, parsed status)task_statuses— Daily per-task status snapshots (done, carry_forward, dropped, no_update)ooo_records— Out-of-office records (manual or parsed from Slack, date range, status)task_type_map— Org-configurable keyword → task type/size/weight mapping
Modified Tables
tasks— Added:taskType,size(S/M/L),weight,clientId(FK → clients),carryForwardCounttask_drafts— Added:taskType,size,weight,clientId(mirrors tasks for draft → task conversion)users— Added:rampUpStartDate,rampUpDurationWeeks(for onboarding ramp-up periods)
New Enums (@hitler/shared)
TaskSize(small/medium/large),TaskType(newsletter_draft, social_post, design_task, etc.)CardType(yellow/red),CardTrigger(missing_submission, task_overdue, no_eod_update, auto_convert, manual)ReportType(daily_public, daily_private, weekly_public, weekly_private, monthly)TaskStatusType(done, carry_forward, dropped, no_update),OOOStatus(active, upcoming, completed)TASK_SIZE_WEIGHTSconstant mapping sizes to numeric weights
V2 Pivot: Phase 1B — Client Management Module
Added
- New
clientsAPI module with full CRUD (create, list, get, update, soft delete) - Member assignment endpoint (
PUT /api/clients/:id/members) for assigning writers and designers - Deploy schedule endpoint (
GET /api/clients/schedule) for weekly content planning - Zod validation schemas:
createClientSchema,updateClientSchema,assignMembersSchema ClientStatusenum (active,paused,offboarded) in shared package- SDK methods:
createClient,listClients,getClient,updateClient,deleteClient,assignClientMembers,getDeploySchedule - Admin dashboard page at
/dashboard/clientswith table view, status filter, create/edit forms, and member assignment dialog - “Clients” entry in sidebar navigation (manager+ role)
- API reference documentation for all 7 client endpoints
V2 Pivot: Phase 1C — Morning Thread System
Added
- New
morning-threadsAPI module with service, controller, and REST endpoints - 9 AM cron posts daily thread to
#today-in-progresschannel - Thread reply tracking: Slack bot detects replies and stores as
thread_submissions - 11 AM deadline scan DMs users who haven’t submitted to the morning thread
- New org preferences:
enableMorningThread,morningThreadTime,submissionDeadlineTime,progressChannelId - SDK methods:
getTodayMorningThread(),recordThreadSubmission(),findMorningThreadByTs() - API endpoints:
GET /api/morning-threads/today,GET /api/morning-threads/by-date/:date,GET /api/morning-threads/:id/submissions,GET /api/morning-threads/:id/missing
[1.4.0] - Task Table UX, Deadline Nudges, Progress Channel & Bug Fixes
Summary
Dashboard task tables now show project names, inline status actions, and overdue highlighting. Short-deadline tasks get immediate DM nudges. Progress channel uses status-based indicators. Multiple bug fixes for flags, scheduler date serialization, and Slack status validation.Added
Inline Task Actions (Dashboard + Project Tables)
- Dropdown menu on each task row: Start, Complete, Cancel, View Details
- Project task table also has Remove from Project action
- Client-side pagination (10 per page) on project task table
Overdue Highlighting
- Task due dates in red with “OVERDUE” badge when past due and not completed/cancelled
Deadline Nudges for Short Deadlines
queueDeadlineNudge()injobs.service.tssupports BullMQdelayparameter- When a task with a due date < 24h is confirmed, three nudges are scheduled:
- Gentle — immediately
- Reminder — at 50% of remaining time
- Urgent — at 85% of remaining time (min 5 min before due)
- Previously, only the 15-minute cron caught these — a 10-minute deadline would be missed entirely
Status-Based Progress Channel Indicators
⬜Pending,🔵In-progress,✅Completed (strikethrough),🔴Overdue,⚫Cancelled (strikethrough)- Priority shown as suffix only for P1/P2:
(P1),(P2) - Replaces old priority-based colored circles which made it hard to distinguish status
Fixed
Project Name in Task Table (Backend Bug)
findByUserPaginated()intasks.service.tsnow does aleftJoinwithprojectstable- Previously returned
projectName: nullfor all tasks because the JOIN was missing
Flags Endpoint Validation Error
- Frontend was sending
status=activebut Zod schema only acceptsopen,suggested_resolved,resolved - Fixed
api.tsclient andteam/page.tsxto useopeninstead ofactive - Fixed Swagger annotations in
flags.controller.ts
Scheduler Date Serialization
- Proactive nudge scanner was crashing every 15 minutes:
TypeError: "string" argument must be string, got Date - All
Dateobjects insqltemplate literals now use.toISOString()(5 occurrences inscheduler.service.ts)
Nullable projectId in Task Updates
updateTaskSchemanow acceptsprojectId: nullfor removing a task from a project
Files Changed
| File | Changes |
|---|---|
apps/api/src/modules/tasks/tasks.service.ts | leftJoin for project name; deadline nudge scheduling |
apps/api/src/modules/tasks/tasks.controller.ts | Nullable projectId in update schema |
apps/api/src/modules/jobs/jobs.service.ts | queueDeadlineNudge() with delay support |
apps/api/src/modules/jobs/scheduler.service.ts | Date .toISOString() fixes (5 occurrences) |
apps/api/src/modules/slack/slack-blocks.ts | Status-based indicators + dueDate in interface |
apps/api/src/modules/jobs/workers/progress-channel.worker.ts | Pass dueDate in task data |
apps/api/src/modules/flags/flags.controller.ts | Fix Swagger enum for flag status |
apps/web/src/app/dashboard/tasks/page.tsx | Inline status dropdown + overdue highlighting |
apps/web/src/app/dashboard/projects/page.tsx | Action buttons + pagination |
apps/web/src/app/dashboard/team/page.tsx | Fix flag status from “active” to “open” |
apps/web/src/lib/api.ts | Nullable projectId; fix flag status type |
tests/unit/progress-channel.test.ts | Updated for status-based emojis |
[1.3.0] - Slack Onboarding, Bot Fixes & API Client Hardening
Summary
Welcome DM after Slack bot install, test connection button on onboarding, redirect fixes, auto-detected timezone, loading states, and multiple bug fixes across the SDK, adapters, and progress channel worker.Added
Welcome DM After Slack Install
- Bot sends a welcome DM to the installing user immediately after the OAuth flow completes
SlackModuleimported intoAuthModulesoSlackAuthControllercan injectSlackWebApiService- Welcome message: “Hey! Hitler is now connected to your workspace. You can start chatting with me right here…”
- Wrapped in try/catch so a failed DM never breaks the install flow
Test Connection Button (Onboarding)
- New
POST /api/organizations/:id/test-slackendpoint — sends a test DM to verify the bot works - Onboarding step 2 now shows a “Connected” state with:
- Green checkmark + “Slack Connected!” confirmation
- “We sent you a welcome message in Slack — check your DMs!”
- “Send Test Message” button to verify bot connection before proceeding
- “Continue” button to advance to step 3
testSlackConnection()method added to web API client
Auto-Detected Timezone
- Onboarding timezone selector now auto-detects the user’s timezone via
Intl.DateTimeFormat().resolvedOptions().timeZone - If the detected timezone is not in the common list, it’s dynamically added with “(detected)” label
- Hint text shows the detected timezone to the user
Loading States on Onboarding
- All onboarding buttons now show loading spinners and are disabled during async operations
- Prevents double-clicks and provides feedback during network requests
Fixed
Slack OAuth Redirect (302)
handleInstallCallback()inslack-auth.controller.tsnow uses explicitreply.status(302).redirect()for all redirect paths- Added logging before each redirect for debugging
API Client Content-Type Header
apps/web/src/lib/api.ts—fetch()helper now only setsContent-Type: application/jsonwhen a body is present- Previously, bodyless POST/PATCH/DELETE requests sent the header, causing Fastify to reject with “Body cannot be empty when content-type is set to ‘application/json’”
- Also added
body: JSON.stringify({})toconfirmTaskDraft()andrejectTaskDraft()as belt-and-suspenders
SDK Paginated Response Handling
packages/sdk/src/client.ts—getTasks()now unwraps paginated{items, total}responses from the API- Previously returned the raw object, causing
tasks.slice is not a functioncrashes in the Slack bot’s Home tab “My Tasks” button
Status Button Validation Error
packages/adapters/src/conversation.ts—handleStatus()was passingstatus: "open"to the API, which only accepts"pending","in_progress","completed","cancelled"- Now fetches
"pending"and"in_progress"separately and sums the counts
Progress Channel Duplicate Messages
- Added unique
jobId(progress-${eventType}-${taskId}) to BullMQ progress channel jobs to prevent duplicate processing - Wrapped project channel post in try/catch so a failure there doesn’t cause a job retry that re-posts to the progress channel
Files Changed
| File | Action |
|---|---|
apps/api/src/modules/auth/auth.module.ts | Import SlackModule |
apps/api/src/modules/auth/slack-auth.controller.ts | Welcome DM + 302 redirect fix |
apps/api/src/modules/organizations/organizations.controller.ts | Add test-slack endpoint |
apps/api/src/modules/jobs/jobs.service.ts | Add jobId to progress channel jobs |
apps/api/src/modules/jobs/workers/progress-channel.worker.ts | Try/catch on project channel post |
apps/web/src/lib/api.ts | Content-Type fix + testSlackConnection method |
apps/web/src/app/onboarding/page.tsx | Connected state, test button, timezone, loading |
packages/sdk/src/client.ts | Unwrap paginated getTasks response |
packages/adapters/src/conversation.ts | Fix status “open” → “pending” + “in_progress” |
[1.2.0] - Dark Mode Support
Summary
Added full dark mode support across the entire admin dashboard. Light/Dark/System toggle with consistent theming using CSS custom properties and semantic design tokens. All ~275 hardcoded gray Tailwind classes replaced with theme-aware tokens.Added
next-themes— theme provider withclassstrategy, system preference detection, and persistent storage.darkCSS variables inglobals.css— full dark palette for background, foreground, card, popover, primary, secondary, muted, accent, destructive, border, input, ringThemeTogglecomponent — Sun/Moon dropdown with Light/Dark/System options usinguseTheme()from next-themessuppressHydrationWarningon<html>tag to prevent flash of unstyled content
Changed
providers.tsx— wrapped app with<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>dashboard-layout.tsx— theme toggle added to header, all gray classes converted to semantic tokens- ~275 hardcoded gray classes replaced across 25+ files:
text-gray-900/700→text-foregroundtext-gray-600/500/400→text-muted-foregroundbg-white→bg-backgroundorbg-cardbg-gray-50/100→bg-mutedborder-gray-200/300→border-borderdivide-gray-*→divide-borderhover:bg-gray-50→hover:bg-mutedhover:bg-gray-100→hover:bg-accent
- Dark mode variants added for colored elements (status badges, alerts, flags):
- Green:
dark:bg-green-900/30 dark:text-green-400 - Red:
dark:bg-red-900/30 dark:text-red-400 - Yellow:
dark:bg-yellow-900/30 dark:text-yellow-400 - Blue:
dark:bg-blue-900/30 dark:text-blue-400 - Purple/Indigo/Orange: same pattern
- Green:
badge.tsx— success/warning/info variants now include dark mode colors- Auth pages — error/success banners have
dark:variants for red/green backgrounds - Integration pages — converted to semantic tokens with dark mode alert variants
Technical Notes
- Sidebar stays dark in both modes (intentional — already uses hitler-dark background)
- Landing page (
/) intentionally unchanged — already dark-themed in both modes - Chart components use hardcoded hex colors for Recharts compatibility (not CSS variables)
ring-8 ring-whitein activity-feed timeline may needring-backgroundadjustment if visual issues arise- Zero gray Tailwind classes remain in
apps/web/src/**/*.tsx
Files Changed
- 1 new file:
theme-toggle.tsx - 25+ modified files: all dashboard pages, auth pages, integration pages, shared components, UI primitives
[1.1.0] - Admin Dashboard: shadcn/ui Migration
Summary
Migrated the entire admin dashboard from hand-written Tailwind CSS classes to shadcn/ui component library with lucide-react icons. Added testing infrastructure with Vitest + React Testing Library. All 16 pages migrated with zero business logic changes.Added
- shadcn/ui component library — 21 components: Button, Card, Badge, Input, Textarea, Select, Checkbox, Switch, Label, Tabs, Dialog, DropdownMenu, Table, Separator, Skeleton, Avatar, Tooltip, ScrollArea, Sheet, Slider, Sonner
- lucide-react icons — replaced ~80 inline SVG icon function components across all pages
- CSS variable theming —
:rootvariables for primary, secondary, sidebar, muted, accent, destructive, border, ring - Testing infrastructure — Vitest + jsdom + React Testing Library + custom render with AuthProvider mock
- 15 component tests — Button (8 tests) and Badge (7 tests)
apps/web/src/lib/utils.ts—cn()utility (clsx + tailwind-merge)apps/web/components.json— shadcn/ui configurationapps/web/vitest.config.mts— web-specific test configuration
Changed
- All 16 pages migrated to shadcn/ui components:
- 9 dashboard pages (main, tasks, projects, team, chat, analytics, settings, notifications, profile)
- 3 auth pages (login, signup, complete-signup)
- 3 integration pages (integrations, slack, slack/callback)
- 1 landing page
- dashboard-layout.tsx — Sheet for mobile sidebar, DropdownMenu for profile, Avatar, lucide-react icons
- notifications-dropdown.tsx — DropdownMenu with Bell trigger
- empty-state.tsx — Button component replacing CSS class buttons
- settings page — Tabs replaces manual tab state, Switch replaces checkboxes, Dialog replaces confirm(), Sonner toast replaces inline save messages
- tailwind.config.js — added tailwindcss-animate plugin, CSS variable color mappings, shadcn conventions
Removed
- 40+ custom CSS classes from
globals.css@layer componentsblock (btn-, card-, badge-, table-, modal-, avatar-, etc.) - ~80 inline SVG icon function components replaced by lucide-react imports
Technical Notes
- Radix Select uses
__none__sentinel for empty values (projects page channel selector) - Landing page FeatureCard kept custom glass-morphism styling (Card’s white bg would break dark theme)
- Brand icons (Teams, WhatsApp) kept as custom SVGs — no lucide-react equivalents
- Root vitest config excludes
apps/web/**— web tests run viapnpm --filter @hitler/web test
[Unreleased] - Team Visibility, Projects & Proactive Nudges
Added
Phase 0: Slack Web API Service
SlackWebApiService— wraps@slack/web-apiwith per-org bot token retrieval from Cloudflare KVSlackModule— NestJS module exporting the serviceslack-blocks.ts— reusable Slack block builders for channel posts (daily task post, deadline tag, EOD summary, nudge DM, overdue escalation)
Phase 1: Database Schema — Projects + Task Duration
projectstable with Slack channel linking and escalation configurationprojectIdandestimatedDurationMinutescolumns added totasksandtaskDraftsOverdueEscalationModeenum andprojectSchemaZod validation
Phase 2: Projects API Module
- Full CRUD for projects (create, list, get, update, archive)
- Task service extended with project-aware queries (
findByProject,findTodaysTasks,findUsersWithoutTasksToday) - Organization endpoint for listing Slack channels (admin dropdown)
Phase 3: Job System — Workers
PROGRESS_CHANNEL_UPDATE— live task create/complete updates in progress channelPROGRESS_CHANNEL_DEADLINE— deadline enforcement with public taggingPROGRESS_CHANNEL_EOD_SUMMARY— end-of-day summary compilationPROACTIVE_NUDGE— DM nudges about approaching deadlinesOVERDUE_ESCALATION— configurable escalation flow (DM → channel → admin)
Phase 4: Scheduler — New Cron Jobs
- Daily task deadline check (every 5 minutes, timezone-aware)
- End-of-day summary (every 5 minutes, timezone-aware)
- Proactive nudge scanner (every 15 minutes)
- Enhanced overdue scanner with project escalation support
Phase 5: LLM Tool Integration
create_task_drafttool extended withproject_nameandestimated_duration_minutes- New
get_projectstool for listing org projects - Duration inference in system prompt (quick call=15min, meeting=60min, etc.)
Phase 6: Admin Dashboard
- “Channels & Deadlines” settings tab (progress channel, deadline, EOD summary, nudges)
- Projects management page (CRUD, escalation config, task listing)
- Task table updated with project and duration columns
Phase 7: SDK + Adapter Updates
Projectinterface and project methods in SDK clientTaskandTaskDrafttypes extended withprojectIdandestimatedDurationMinutes- Block builders updated to show project and duration information
New Organization Preferences
dailyTaskDeadlineEnabled,dailyTaskDeadlineprogressChannelId,progressChannelName,enableProgressChanneleodSummaryTimeenableProactiveNudges,nudgeIntensity
Files Changed
- 15 new files across API modules, DB schema, web app, and tests
- 20 modified files spanning all layers of the stack
[1.0.0] - Admin Dashboard Baseline
Summary
Initial release of the Hitler admin dashboard. Hand-written Tailwind CSS with 40+ custom component classes, inline SVG icons, manual dropdowns/modals, no component library, and zero frontend tests.Current State
- 16 pages: 9 dashboard routes, 3 auth routes, 3 integration routes, 1 landing page
- 9 component files: dashboard-layout, notifications-dropdown, error-boundary, protected-route, add-to-slack-button, animations, empty-state, activity-feed, charts
- 40+ custom CSS classes in globals.css (
@layer components) - 0 frontend tests
- Stack: Next.js 15, React 19, Tailwind CSS 3, Framer Motion, Recharts