BluprintDocumentation
Open Bluprint
Get Started
Use Cases & Guides
Tutorials
Projects
Tasks
Views
The Associate (AI)
AI Helpers
Communication
Documents & Knowledge
Time Tracking
Companies & Workspaces
Roles & Permissions
Billing
Account & Profile
Security & Compliance
IntegrationsSoon
FAQ
Release LogSoon
ResourcesSoon
DocumentationRelease Log

Release Log

Everything new in Bluprint — features, improvements, and fixes.

Changelog

All notable changes to Bluprint are documented here.

This file is the source-of-truth for release notes surfaced in the app navbar.

v0.4.141 - 2026-04-30

Fix: Feedback submission — non-blocking notifications + real error messages + env wiring

  • Backend (core/api/v1/feedback_views.py): Made send_feedback_notification() non-blocking with try/except. Feedback is already persisted in MongoDB before notification is attempted; email failure no longer fails the user submission. Logs failure via logfire.exception().
  • Frontend (src/components/Navbar.tsx): Feedback submit now parses the backend JSON response and surfaces the real error message (e.g., csrf_internal_proxy_rejected, message_required) instead of a generic "Failed to submit feedback" alert.
  • Infrastructure:
    • backend/.env.dev-server: Added INTERNAL_PROXY_SECRET with fallback default.
    • docker-compose.dev-server.yml + docker-compose.dev.yml: Added INTERNAL_PROXY_SECRET to frontend service environment so proxy route can authenticate with backend.

Validation

  • Python syntax check: passed
  • TypeScript type-check (tsc --noEmit): passed

Security / compliance / performance review

  • SOC 2: Internal proxy secret provides additional authentication layer. Notification failures are logged, not lost.
  • GDPR: No change to data handling.
  • Performance: Notification is still synchronous but wrapped in try/except; no timeout change.

v0.4.140 - 2026-04-30

Fix: Feedback submission now works through internal proxy

  • Frontend (src/app/api/dashboard/feedback/route.ts):
    • Added INTERNAL_PROXY_SECRET env var support and X-Internal-Proxy / X-Internal-Proxy-Secret headers so the proxy route identifies itself as an internal proxy to the backend.
    • Fixed Django endpoint path: /api/v1/feedback → /api/v1/feedback/ (trailing slash required).
    • Changed headers from let to const since headers are now built once with proxy identifiers.

Validation

  • TypeScript type-check (tsc --noEmit): passed

Security / compliance / performance review

  • SOC 2: Internal proxy secret provides additional authentication layer between frontend and backend. Existing auth token still required.
  • GDPR: No change to data handling.
  • Performance: No change.

v0.4.139 - 2026-04-30

Fix: Changelog API now reads bundled file for production runtime

  • Frontend (src/app/api/changelog/route.ts): Simplified readChangelogFile() to read directly from public/changelog.md instead of walking the filesystem looking for docs/CHANGELOG.md. This ensures the changelog is always available in Docker/production builds where the repo root is not present.
  • Frontend (public/changelog.md): Added bundled copy of docs/CHANGELOG.md that ships with the production image.
  • Frontend (src/components/Navbar.tsx): Patch notes modal footer now displays the real source path (public/changelog.md) dynamically from the API response instead of a hardcoded string.

Validation

  • TypeScript type-check (tsc --noEmit): passed
  • File copied successfully to frontend/public/changelog.md

Security / compliance / performance review

  • SOC 2: No change to access control. Changelog is public release notes; no sensitive data.
  • GDPR: No personal data in changelog.
  • Performance: File read is synchronous local filesystem access; negligible overhead.

v0.4.138 - 2026-04-30

Feature: Usage dashboard now shows USD spend instead of raw units

  • Backend (core/api/v1/usage_views.py):
    • _sum_cards(): Now calculates volume_cost_usd and impact_cost_usd from unit counts using per-category rates (~$0.0048/volume unit, ~$0.0053/impact unit).
    • CompanyUsageOverviewAPIView: Added cost_usd to the totals object.
    • CompanyUsageProjectsAPIView / CompanyUsageUsersAPIView: Added cost_usd to each project/user result. Results now sorted by cost_usd descending (highest spend first).
  • Frontend (page.tsx):
    • Overview cards: "Volume Units" → "Volume Spend", "Impact Units" → "Impact Spend". Values now formatted as USD currency.
    • Projects/Users rows: {units} units → {formatUsd(cost_usd)}. Added formatUsd() helper using Intl.NumberFormat.

Validation

  • Python syntax check: passed
  • Frontend type-check (tsc --noEmit): passed

Security / compliance / performance review

  • SOC 2: No change to access control or auditability. Cost calculations are deterministic derived values.
  • GDPR: No new personal data exposure.
  • RBAC / security: Same permission checks as before (_is_company_usage_reader).
  • Performance: Cost calculation is O(N) over already-aggregated rows. No additional DB queries.

v0.4.137 - 2026-04-30

Feature: Replace "Session Management" with "Active Timers" in company dashboard

  • Backend (time_tracking/api/views.py): Added CompanyActiveSessionsAPIView to list all active time-tracking sessions across the company, sorted by longest-running first. Added AdminForceStopSessionAPIView to allow owner/admin to force-stop another user's timer with a required reason (audit-logged).
  • Backend (time_tracking/api/urls.py): Registered new endpoints at sessions/active-company/ and sessions/<uuid>/force-stop/.
  • Frontend (page.tsx): Replaced the auth session management tab (device/IP/revoke login sessions) with an "Active Timers" tab showing users with running timers, the task they're working on, elapsed duration, and a stop button. Stop action requires selecting a reason via a confirmation modal. Timer list auto-refreshes every 60 seconds.

Validation

  • Python syntax check: passed
  • Frontend type-check (tsc --noEmit): passed

Security / compliance / performance review

  • SOC 2: Force-stop action is audit-logged via both log_time_tracking_action and AuditRepo.create() with actor, target user, reason, and duration. Full traceability.
  • GDPR: No new personal data exposure. Timer data (user name, task title) already accessible to admins via existing time-tracking analytics.
  • RBAC / security: CompanyActiveSessionsAPIView restricted to owner/admin/manager. AdminForceStopSessionAPIView restricted to owner/admin only. Company-scoped — cannot see/stop timers from other companies.
  • Performance: WorkSession.objects.filter(is_active=True) uses the existing (is_active, user) index. Active sessions are typically a small set (< 50). No full table scans.

v0.4.136 - 2026-04-30

Fix: Company dashboard leaderboard now shows real data for "Tasks Closed" and "Activity"

  • Backend (core/api/v1/views.py): Task patch endpoints now set completed_by (user ID) on the task document when status moves to done. This enables accurate attribution for the leaderboard going forward.
  • Backend (companies/api/views.py):
    • Tasks Closed: Rewrote aggregation pipeline to handle tasks with and without completed_by. For historical tasks missing the field, falls back to assignee_user_ids[0] or assignee_id. Also fixed completed_at type comparison (handles both ISO string and BSON Date).
    • Activity Score: Changed from audit_events collection (empty in production) to querying embedded activity arrays within db.tasks (populated on every task mutation). Uses $unwind on the activity array, filters by activity.timestamp, scores by activity.type (task_completed=10, status_changed=3, comment_added=2, etc.), and groups by activity.user_id.
    • Fixed Python 2-style except clauses (except X, Y: → except (X, Y):) which would silently swallow errors.

Validation

  • Python syntax check: passed

Security / compliance / performance review

  • SOC 2: No access control changes. Reading from embedded task activity arrays preserves auditability — these are written on every mutation and contain the same event data.
  • GDPR: No new personal data exposure. Leaderboard shows names/emails already accessible to company members via existing endpoints.
  • RBAC / security: Endpoint retains existing IsCompanyMemberOrAdmin permission and explicit company membership check.
  • Performance: Activity pipeline now queries db.tasks with an initial $match on updated_at to limit the scan to recently-modified tasks. $unwind across only recent tasks is efficient. The $limit: 5 keeps result sets small.

v0.4.135 - 2026-04-30

Fix: Company dashboard "Workspaces at a Glance" — real data instead of fallback values

  • Backend (company_settings_views.py): Fixed project_id mismatch in task aggregation pipeline. The query was using MongoDB _id (ObjectId) to match against tasks.project_id (UUID), causing all task_summary results to be zero. Now correctly uses the project's UUID project_id field.
  • Frontend (page.tsx):
    • Header "Tasks" count now sums task_summary.total across all projects (was previously capped at 20 due to &limit=20 on a separate tasks API call).
    • Workspace-level Progress now shows task-based completion percentage (was showing project-completion ratio which was always 0%).
    • Workspace-level Due now shows the furthest-away project due date in human-readable form (was showing active project count).
    • Workspace-level Status now derives from task progress + overdue state: On Track / At Risk / Delayed / Completed (was showing only Active/Inactive based on project status field).
    • Expanded project rows now display real progress, due dates, and status (were all zeros due to the backend aggregation bug).

Validation

  • Python syntax check: passed
  • Frontend TypeScript type-check (tsc --noEmit): passed

Security / compliance / performance review

  • SOC 2: No change to access control or auditability. Same auth checks and logfire instrumentation preserved.
  • GDPR: No new personal data exposure. Task summaries remain aggregate counts only.
  • RBAC / security: Role-based workspace filtering unchanged. Members queried only for authorized workspaces.
  • Performance: No new queries added. Backend aggregation pipeline was already in place — now it actually matches documents correctly.

v0.4.134 - 2026-04-29

Ops: Dev-server survives EC2 reboot (nginx + Compose auto-start)

Root-caused and fixed a dev-server outage on the EC2 monolith (bluprint.alesko.online / 3.105.83.223). Ports 22/80/443 were accepting TCP but no process responded, because the host-level nginx front door was disabled; inactive and the 8 Compose containers had RestartPolicy: no — a reboot left the whole stack down with no supervisor to bring it back.

What shipped

  • docker-compose.dev-server.yml — added restart: unless-stopped to all 8 services (redis, mongo, minio, backend, daphne, celery, celery-beat, frontend) so Docker auto-revives containers after crashes and after the Docker daemon restarts on boot.
  • infra/aws/nginx/bluprint-dev.conf — new. Committed the live nginx reverse-proxy config (Next.js /api/* carve-outs, Django /api/, /admin/(login|management|performance) → Next, /admin/ → Django, /ws/ → Daphne, TLS + HTTP→HTTPS redirect). Previously this only existed on the EC2 host and was a real rebuild / compliance gap.
  • infra/aws/systemd/bluprint-dev.service — new. Boot-time systemd unit that runs docker compose up -d against docker-compose.dev-server.yml. Belt-and-braces on top of per-container restart policies so the stack still comes up even if the compose file is ever edited incorrectly.
  • infra/aws/ec2-setup.sh — now runs systemctl enable --now nginx (was enable only, which was why nginx had drifted to disabled), and installs the new bluprint-dev.service unit after cloning the repo.

Live host remediation (already applied on 3.105.83.223)

  • sudo systemctl enable --now nginx — nginx active + will auto-start
  • docker compose -f docker-compose.dev-server.yml up -d — 8 containers back up

Validation

  • External: https://bluprint.alesko.online/ → 200; http://... → 301 HTTPS redirect; /api/users/me/ → 401 (expected unauth).
  • Internal: backend Django ready on :8000, Daphne listening on :8001, Celery worker ready. + beat running scheduled tasks, redis/mongo/minio (healthy).
  • Host: 7.1G free RAM, 17/100G disk, no OOM in dmesg.

Security / compliance / performance review

  • SOC 2: Availability/reliability control gap on dev-server is closed (service supervision now codified in git). Incident is logged here as required operational evidence. No production impact.
  • GDPR: No personal-data handling changes. No data written to unexpected paths during the outage.
  • RBAC / security: No authorization boundary changes. Committed nginx config makes future rebuilds reproducible rather than relying on tribal knowledge on the host.
  • Performance: Low impact. restart: unless-stopped adds negligible overhead; nginx being always-on is standard. Pre-existing DRF min_value warning noted in backend startup logs — unrelated, low-priority tech debt.

Follow-ups (not in this change)

  • CloudWatch alarm on StatusCheckFailed_Instance + a Route 53 health check or uptime ping on https://bluprint.alesko.online/ so the next outage pages us instead of being noticed by hand.
  • Sweep scripts/dev-server-git-sync.sh / scripts/sync-dev.sh to systemctl is-enabled nginx and re-enable if drifted, as a deploy-time guardrail.

v0.4.133 - 2026-04-29

Fix: /index associate showcase typography consistency + dark-mode readability

  • Updated frontend/src/components/landing/AssociateShowcaseSection.module.css so the “Introducing Associate” heading uses the same lighter display weight as the landing hero style, reducing visual heaviness.
  • Updated the associate demo panel text defaults in dark mode to keep response/empty-state copy dark on the panel’s light background (.demoPanel, .demoEmptyTitleDark, .demoEmptyHintDark).

Validation

  • npm run lint -- src/components/landing/AssociateShowcaseSection.tsx src/app/index/page.tsx ❌ (environment issue: eslint-config-next/core-web-vitals import cannot be resolved from frontend/eslint.config.mjs)

v0.4.132 - 2026-04-29

Fix: Landing typography aligned to exact website-landing split and hero subtext reset

  • Updated global font loading in frontend/src/app/layout.tsx to use Inter only.
  • Updated typography tokens in frontend/src/app/globals.css to mirror the website-landing split exactly: Inter body fallback chain (Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif), default serif display stack, and default mono stack.
  • Reset hero subtext in frontend/src/components/landing/HeroSection.tsx back to Project Management reimagined.

Validation

  • Not re-run in this pass (existing environment ESLint config resolution issue remains).

v0.4.131 - 2026-04-28

UX: Admin Test Data tab now shows active tenant state + explicit purge confirmation

Improves the Test Data Seeder admin console so operators can safely avoid duplicate seeding and get a clear confirmation when a tenant is fully purged and ready to seed again.

What shipped

  • frontend/src/app/admin/management/components/TestDataTab.tsx
    • Active scenario status badge on each scenario card when a matching seed is currently active (status === completed and not in purge-in-flight state).
    • Launch button now visually switches to "Seed again (...)" when an active tenant exists for that scenario.
    • Clicking launch while active now prompts a confirmation dialog (Seed another tenant anyway?) to reduce accidental duplicate seed runs.
    • Added in-tab notices:
      • info: seed queued / purge queued
      • success: tenant purged and ready to reseed
    • Purge flow now tracks pending purge records and confirms completion when status transitions to purged.
    • Polling now treats purge-in-flight (purge_status: queued|running) the same as seed in-flight states.

Validation

  • npm run lint -- src/app/admin/management/components/TestDataTab.tsx ✅
  • npx tsc --noEmit ✅

Security / compliance / performance review

  • SOC 2: No auth/permission model changes; only operator-facing status/notice UX.
  • GDPR: No data model changes; no changes to retention/purge semantics.
  • RBAC / security: Uses existing admin-only test-data endpoints; no broadened access.
  • Performance: No additional API endpoints. Existing polling reused; only small client-side derivations added.

v0.4.130 - 2026-04-28

Feat: Enterprise seed follow-up — task comments, message reactions/pins/threads, full project-feed coverage

This follow-up closes the remaining content gaps for enterprise seeding after the initial engagement expansion.

What shipped

  • Task comments added as first-class seed surface:

    • New TaskCommentSpec + TaskCommentReplySpec dataclasses in backend/core/services/test_data_seeder.py.
    • New ScenarioSpec.task_comments list.
    • Seeder now resolves task_key -> task_id via the existing task_ref_map and inserts top-level + reply comments via CommentsRepo.create(...).
    • Enterprise scenario seeds comments on key tasks across Atlas, Brand Redesign, Security Hotfixes, Team Analytics, and Q2 Launch.
  • Comms Hub message richness:

    • MessageSpec now supports:
      • reply_to_message_index (thread replies)
      • pin (conversation pinned messages)
      • reactions ([(email_local, emoji)])
    • Seeder applies these via MessageService.create_message(reply_to=...), pin_message_in_conversation(...), and add_reaction(...).
    • Enterprise conversations now contain deterministic pinned messages, emoji reactions, and thread reply relationships for UI coverage.
  • Project feed coverage completed:

    • Added feed posts for previously missing project slugs:
      • board-prep-q2
      • fy26-okrs
      • billing-webhooks-v2
      • mobile-push
    • This ensures every project now has at least one project-scoped or associated feed post fixture.
  • Small-team parity tweak:

    • Added explicit subtasks to previously sparse small_team tasks (demolition, electrical certification, insurance renewal) while preserving domain-specific construction language.

Validation

  • ruff format + ruff check clean on:
    • backend/core/services/test_data_seeder.py
    • backend/core/services/scenarios_enterprise.py

Security / compliance / performance review

  • SOC 2: No new external integrations or privilege changes. New seeded comments/messages/reactions remain synthetic and auditable in existing stores.
  • GDPR: All seeded identities remain synthetic tenant fixtures; no change to retention/purge behavior.
  • RBAC / security: Task comments route through existing project-scoped comment storage; message reactions/pinning/threading use existing Comms service methods.
  • Performance: Adds one-time seed-time writes only (comments/reactions/pins). No runtime query-path changes or new hot-path logic.

v0.4.129 - 2026-04-28

Feat: Enterprise seed — rich Comms Hub, Feed threads, 1000+ subtasks, 40+ notifications

Fills out the enterprise ("Northwind Systems") fixture so every comms + engagement surface has meaningful content for the marketing-video tenant and full-spectrum QA regression.

What shipped

  • Seeder engagement bug fixes (backend/core/services/test_data_seeder.py):

    • FeedService.create_post(...) calls were missing the required author_avatar_url kwarg — silently failing under try/except, meaning no announcements or feed posts were actually being persisted. Now passes author_avatar_url=None.
    • MessageService.send_message(...) does not exist — the real method is create_message(...) with full sender metadata. Updated to call create_message(sender_id, sender_email, sender_display_name, sender_avatar_url, text) so conversation messages actually land in Mongo.
    • These two fixes mean the previously-reported Phase C counts (6 announcements, 25 feed posts, 64 messages) were aspirational — they now actually seed.
  • New FeedCommentSpec dataclass with 1-level threaded replies. Extended FeedPostSpec with comments: List[FeedCommentSpec] and upvoter_email_locals: List[str]. Seeder now:

    1. Captures the post ID returned by create_post.
    2. Seeds comments via FeedService.create_comment(...), then one-level replies via the same method with parent_comment_id=<top-level id>.
    3. Seeds upvotes via FeedService.upvote_post(post_id, user_id).
    4. Surfaces feed_comments and feed_upvotes counts in the seed response.
  • Auto-subtask generator (_auto_subtasks in scenarios_enterprise.py) — label-aware, status-aware, deterministic. When a _t(...) call omits subtasks and the task is non-trivial (estimate ≥ 6h, priority high/urgent, or status in progress/review/done/blocked), it emits 3–5 subtasks with titles drawn from a per-flavour scaffold (design, docs, architecture, ci, security, perf, qa, marketing, research, bug, api, frontend, generic fallback). Subtask completion/status distribution mirrors the parent task (e.g. done → all completed, in_progress → first half done + middle in progress + rest todo, blocked → mix with blocker still on parent).

    • Result: 1,098 subtasks across 235 of 259 tasks (was 14 subtasks across 3 tasks).
  • Enterprise content expansion in backend/core/services/scenarios_enterprise.py:

    • Feed: 35 posts (was 25) — 10 new engagement-rich posts with 33 threaded comments + replies and 59 upvotes across leaders, engineers, PMs, designers, ops and finance.
    • Comms Hub: 20 conversations (was 8) — now includes dedicated on-call channel, data-migration pod group, cross-project security war-room, content-team pod, onboarding crit group, analytics beta feedback channel, vendor-renewals group, all-hands prep channel, plus 4 new private DMs (Riya↔Alex, Ava↔Theo, Sam↔Alex, Alex↔Devon).
    • Messages: 122 (was 64) — every mega-project has at least 3 active channels/groups + a DM thread.
    • Announcements: 6 (unchanged — already above the 5 minimum requested).
    • Notifications: 43 (was 12) — now covers task.{assigned,reassigned,comment,completed,overdue,due_soon,status_changed,mention}, dependency.{blocker_stuck,cleared,blocked}, project.{health_dropped,health_improved,at_risk}, milestone.{upcoming,missed}, sprint.{started,ended}, chat.{mention,new_message}, feed.{reply,upvote}, document.{shared,comment,updated}, workspace.{invite,role_changed}, calendar.{invite,reminder}, security.{alert,access_review}, billing.{invoice_ready,payment_succeeded}, automation.{triggered,failed}, ai.{daily_brief,scope_creep_warning}, form.new_submission, system.maintenance, announcement.posted, comment.mention — 35 distinct notification types.

Seed response delta

The enterprise seed now reports (approximate):

projects:            18
tasks:               259
subtasks:            1098  (+1084)
announcements:       6
feed_posts:          35    (+10)
feed_comments:       33    (NEW — includes replies)
feed_upvotes:        59    (NEW)
conversations:       20    (+12)
messages:            122   (+58)
notifications:       43    (+31)

Files touched

  • backend/core/services/test_data_seeder.py — FeedCommentSpec; FeedPostSpec.comments + upvoter_email_locals; engagement orchestration fixes + comment/upvote seeding; engagement counts keys.
  • backend/core/services/scenarios_enterprise.py — Optional import; _auto_subtasks helper; _t auto-wires subtasks when caller omits them; 10 new feed posts (with comments + upvotes); 12 new conversations; 31 new notifications; FeedCommentSpec import.

Validation

  • ruff check + ruff format — clean on both touched files.
  • Isolated import + count smoke test — 18 projects / 259 tasks / 1098 subtasks / 35 feed posts / 20 conversations / 43 notifications confirmed.
  • Runtime integration smoke still blocked by the pre-existing root-README / hatchling OSError blocking uv run. Unchanged from v0.4.128.

Security / compliance / performance review

  • SOC 2: Auto-subtasks are derived in-process from scenario input only — no PII, no external data. Fake notifications in the security.* and billing.* categories exercise audit-worthy paths but use only synthetic recipients (all @northwind-systems.com). No new audit records changed.
  • GDPR: All seeded commentary / messages / notifications are synthetic. Full-tenant purge (purge_test_company) unchanged — new content lives in the same collections already purged.
  • RBAC / security: Comments, upvotes, and chat messages inherit existing authorization paths from FeedService.create_comment, upvote_post, and MessageService.create_message. No new bypass paths. Feed visibility (workspace / project) and conversation project_id scoping unchanged.
  • Performance: Subtask explosion (1098 vs 14) lives entirely inside existing tasks_repo.insert_many bulk insert — still one Mongo round-trip per project. Comment + upvote seeding adds ~92 extra Mongo ops to the enterprise seed (one-off on create). Conversation count tripled → 58 more messages, inserted one-per-call as before (no change to runtime messaging hot path). No new indexes needed.

v0.4.128 - 2026-04-28

Feat: Enterprise seed — company-wide Docs Hub (company dashboard documents)

Adds the company-dashboard docs surface to the enterprise scenario so the /company/<id>/documents pipeline is exercised by every enterprise seed.

Why this is separate from project docs

Company-wide docs live in the same co_{uuid}.documents Mongo collection as project docs but are differentiated by a synthetic project_id scope of the form company-<slug>. The UI surfaces them at /company/[companyId]/documents ("Company Library") and they hold HR documents, company policies, company assets — anything that belongs to the org rather than a specific project.

What shipped

  • New CompanyDocFolderSpec dataclass in backend/core/services/test_data_seeder.py — company-scoped folders (no project_slug, POSIX path + name only).

  • Seeder orchestration in _seed_engagement_surfaces:

    1. Calls the canonical _ensure_company_docs_seeded(company_id, user_id) helper first so the default skeleton (/templates, /policies, /standards, /legal) matches what a real company creation would produce.
    2. Resolves the company-docs scope via _company_docs_scope_id(company_id).
    3. Creates each scenario-specified folder as a metadata-only row via BlobDocumentsRepo.create with project_id=scope_id, source="docs_hub", metadata={"scope": "company"} — the exact convention used by the interactive CompanyDocumentCreateFolderView.
    4. Best-effort — failure in one folder does not abort the seed.
  • Enterprise content — 37 additional folders layered on top of the 4 default skeleton folders. Tree now looks like:

    • /templates, /policies, /standards, /legal (default skeleton)
    • /hr/{handbook,benefits,payroll,performance,recruiting,offboarding}
    • /onboarding/{new-hire-checklist,it-setup,first-30-days,security-training}
    • /assets/{logos,brand,decks,product-screenshots,photography}
    • /finance/{expense-policy,reimbursements,travel}
    • /engineering/{development-practices,code-review,incident-response,oncall}
    • /security/{policies,soc2,acceptable-use}
    • /all-hands/{recordings,decks}
    • /strategy/{okrs,board-packs}
  • Purge: covered automatically by the existing whole-DB drop on co_{uuid} and the Django Company cascade — no purge-path changes needed.

Known visibility note (by design)

Current company-scope read model allows any authenticated company member to read the tree and content; mutations are admin-only (check_company_admin). HR folders seeded at company scope inherit this — teams can read the handbook and onboarding packs, which matches the requested "teams to have access to" intent. If future requirements add per-folder admin-only reads at company scope (mirroring the project-level /hr/ admin-only virtual folder), the filter belongs in CompanyDocumentsTreeView / CompanyDocumentContentView — the seeder content will adopt the new model automatically.

Updated enterprise scenario totals

ElementCount
Company doc folders (incl. 4 default skeleton)41
Project doc folders15

All other enterprise totals from v0.4.127 unchanged.

v0.4.127 - 2026-04-28

Feat: Enterprise test-data scenario — Phases D + E + F (completion)

Completes the Northwind Systems enterprise scenario started in v0.4.126. Adds knowledge + tooling surfaces (project templates applied, Knowledge Centre seeds, task templates, automations, forms) and polish (deterministic demo notifications). Meetings deliberately skipped (coming-soon feature).

New *Spec dataclasses in test_data_seeder.py

  • ProjectTemplateApplicationSpec — apply a canonical software|marketing|design|product_launch template to a seeded project after creation (seeds default board columns, docs, automations).
  • KnowledgeCentreSeedSpec — trigger seed_system_templates_for_project() per project, populating Docs Hub with raw_content-filled system templates.
  • TaskTemplateSpec — reusable task blueprints scoped to a project (title suggestion, default labels/priority, checklists, description template).
  • AutomationSpec — trigger → action rules wired into the existing AutomationsRepo + AutomationEngine.
  • FormSpec + FormFieldSpec + FormSubmissionSpec — published forms with pre-filled submission history.
  • NotificationSpec — deterministic demo notifications via NotificationsRepo.create_canonical for screenshot / video fixtures.

Each surface uses a best-effort try/except wrapper in _seed_engagement_surfaces so a missing dependency or authoring error can't abort the whole seed.

Enterprise content added

SurfaceCountNotes
Project templates applied10software × 4, marketing × 3, design × 2, product_launch × 1
Knowledge Centre seeds5Both mega-projects + SSO, SOC 2, Q2 Launch
Task templates6Bug Report, Feature Brief, Campaign Brief, Security Postmortem, Sprint Planning, Control Evidence
Automations6Dependency unblock notify, label auto-tag, war-room scope-change alert, P0 auto-assign, stuck escalation, control-reference labelling
Forms (published)2Bug Report (q1-bugfix) + Feature Request (team-analytics)
Form submissions10Mix of identified customer advisors + anonymous
Demo notifications12Spans assignments, mentions, dependency alerts, overdue, health drop, automation triggered, form submission, announcement

Phase D calendar events

Already shipped in v0.4.126 — 12 events covering milestones, deadlines, all-hands, OKR review, SSO GA, Q2 launch go-live, partner launch, SOC 2 auditor kickoff. Meetings skipped per product roadmap.

Polish notes

  • Deliberate circular dependency attempts in Brand Redesign (from v0.4.126) already exercise the associate cycle-detection + clear flow.
  • WorkSession + TimeLogSummary PG tables use CASCADE on user/project FKs, so the existing purge_test_company flow cleans them up automatically when the company is purged — no purge-path changes needed.

Final enterprise scenario totals

ElementCount
Users (all 9 roles)35
Workspaces5
Projects18
Tasks259
Milestones (major + minor)48
Sprints6
Dependencies26 (incl. 2 circular + 3 cross-project)
Announcements6
Feed posts25
Conversations (channels + groups + DMs)8
Messages64
Calendar events12
Doc folders15
Project templates applied10
KC seed-runs5
Task templates6
Automations6
Forms / submissions2 / 10
Notifications12

v0.4.126 - 2026-04-28

Feat: Enterprise test-data scenario — Northwind Systems (Phases B + C)

Ships the full enterprise scenario content that was scaffolded by the Phase A engine work in v0.4.125. The new scenario is a complete, realistic test tenant that doubles as the marketing-video training fixture AND the full-spectrum QA fixture for RBAC, project health, and engagement surfaces.

Scenario shape

ElementCount
Users (all 9 canonical roles)35
Workspaces5
Projects18
Tasks259
Milestones (major + minor)48
Sprints6
Task dependencies26
Announcements6
Feed posts25
Conversations (channels + groups + DMs)8
Messages64
Calendar events12
Docs Hub folders15

Company: Northwind Systems — a 35-person B2B SaaS dev platform in AU.

Workspaces: Leadership & Strategy · Engineering · Product & Design · Go-to-Market · Operations.

Mega-projects:

  • Atlas v3 — Platform Rebuild (Engineering, healthy, 60 tasks across 4 sprints): monorepo migration, OpenAPI v3, JWT/SSO rework, new ORM, TS+Python SDKs, canary rollout plan. ~40% multi-assignee.
  • Brand & Product Site Redesign (GTM, critical, 55 tasks across 2 sprints): research, brand direction, sitemap, visual design, Next.js + Sanity CMS build, content migration, SEO, launch. Deliberate chaos — 2 circular dependency attempts, multiple hard-blockers, 50% actual > 2× estimated, 5 change_request labels, 3 scope-change tasks for backlog-growth signals.

Standard projects (16): FY26 OKRs, Board Prep Q2, SSO/SAML, Mobile Push, Billing Webhooks v2, Q1 Bugfix Triage, Security Hotfixes, Team Analytics, Onboarding v2, Settings UX, Q2 Launch Campaign, Partner Program, Content Engine H1, SOC 2 Readiness, Vendor Review 2026, All-Hands Q2.

Health distribution (designed for scorer coverage)

  • 4 healthy (score ≥75): Atlas v3, FY26 OKRs, Mobile Push, Content Engine
  • 6 trending (65–75): Board Prep, SSO/SAML, Team Analytics, Q2 Launch, Partner Program, All-Hands
  • 5 at-risk (40–65): Billing Webhooks v2, Q1 Bugfix, Onboarding v2, SOC 2, Vendor Review
  • 3 critical (<40): Brand Redesign, Security Hotfixes, Settings UX

Each project's task mix is designed with specific signals: healthy projects have ≥70% done + recent completions + low overdue; critical projects have ≥30% overdue + 20% blocked/stuck + zero completions in last 7 days + 2× estimate overruns.

Cross-project dependencies (for associate-clear flow)

  • Hard external: Atlas v3 migration guide blocks Q2 Launch landing page copy
  • Soft external: Brand Redesign design system blocks Q2 Launch landing page
  • Soft external: Atlas SSO abstraction blocks SOC 2 access review
  • Circular attempts (internal, within Brand Redesign): sitemap ↔ redirect-map and homepage-design ↔ brand-guidelines — deliberately wired to exercise the associate's cycle-detection + conflict resolution flow

Billing + time tracking

  • plan="enterprise" stamped on Company_Profile.billing.plan and metadata.plan
  • Realistic actual_time_spent populated on ~175 tasks; PG WorkSession rows + daily TimeLogSummary aggregates auto-seeded
  • Task time cache invalidation applied so dashboards + analytics read fresh data

Engagement content (Phase C)

Chat threads, feed posts, and announcements are authored to read like a real company's activity — project-scoped channels for both mega-projects, working-group side chats, DMs between leads, and workspace-wide pinned announcements. Most messages reference actual seeded tasks and block/unblock narrative, so video demos and AI-assistant context tests hit realistic data.

Compatibility

  • small_team scenario is unchanged.
  • New scenario loaded lazily via try/except in test_data_seeder.py — an authoring error in the enterprise content can't break small_team or import of the module.
  • Enterprise scenario lives in a separate file (backend/core/services/scenarios_enterprise.py) to keep test_data_seeder.py focused on the engine.

v0.4.125 - 2026-04-28

Feat: Enterprise-seed engine foundations (Phase A)

Groundwork for the upcoming enterprise test-data scenario (35 users, 5 workspaces, ~18 projects including two mega-projects with 50+ tasks each). No new scenario is registered yet — this PR ships only the engine, schema, and UI changes needed to author the content in a follow-up.

New canonical repos

  • core.repos.task_dependencies_repo.TaskDependenciesRepo — first-class wrapper around co_{uuid}.task_dependencies. Mirrors the rich document shape previously inlined in projects/api/views.py::TaskDependencyListCreateAPIView.post (scope, enforcement, cross-project snapshots, subscriber fan-out, blocking-task snapshot). Lets the seeder and future tooling avoid raw-Mongo writes.
  • core.repos.milestones_repo.MilestonesRepo — first-class wrapper around co_{uuid}.milestones. Previously the only create path was inlined inside timelines/api/views.py::ProjectMilestonesAPIView.post.

Milestone tier (major vs minor) — end to end

Milestones now carry a tier: "major" | "minor" field so the Gantt/Timeline surfaces can emphasise flagship milestones.

  • Backend schemas: CreateMilestoneSchema, UpdateMilestoneSchema, and ProjectMilestoneSchema in backend/timelines/api/schemas.py gained a tier field (defaults to "minor", back-compat for existing docs).
  • Inline create/update views persist tier to Mongo and return it in responses. List/detail/Gantt emit points read it with "minor" fallback.
  • ProjectTimelineMilestone (frontend lib/fetchers.ts) and GanttMilestone (Gantt page) gained tier?: 'major' | 'minor'.
  • New CSS variants .milestoneMarkerMajor / .milestoneMarkerMinor in frontend/src/app/project/[projectId]/gantt/gantt.module.css. Major milestones render with a larger diamond, bolder label, 3px timeline connector, and a small pennant flag above the marker.

TasksRepo.insert_many

Batch-insert path for seeding large task payloads (mega-projects with 50+ tasks). Keeps the exact same doc shape as TasksRepo.create, does a single Mongo round-trip, and invalidates daily-brief + associate-context caches once per distinct project instead of once per task.

Test-data seeder extensions

backend/core/services/test_data_seeder.py now supports:

  • Multi-assignee and multi-reporter per task (TaskSpec.assignee_email_locals, reporter_email_locals). Back-compat preserved via the existing single-value fields.
  • start_date + actual_time_spent (via TaskSpec.start_in_days, actual_hours).
  • Task-level sprint assignment (TaskSpec.sprint_key, resolved after SprintSpec insert).
  • Deterministic completed_at override via TaskSpec.completed_in_days — critical for seeding velocity-sensitive health signals.
  • MilestoneSpec with tier.
  • SprintSpec (per project).
  • DepSpec (scenario-local by task_key).
  • AnnouncementSpec, FeedPostSpec (via FeedService).
  • ConversationSpec + MessageSpec (via Comms Hub ConversationService / MessageService).
  • CalendarEventSpec (via CalendarRepo).
  • DocFolderSpec (metadata-only Docs Hub folders).
  • Optional ScenarioSpec.plan — writes billing.plan and metadata.plan on Company_Profile.

The seeder also seeds real time-tracking data:

  • Writes PG time_tracking.WorkSession rows (one per task with actual_hours), dated 1–14 days in the past.
  • Upserts time_tracking.TimeLogSummary daily rollups per (user, project, date).
  • Invalidates the Redis time_tracking:task:{task_id} cache so the UI reads fresh rollups.

Each engagement surface is best-effort — a failure in one does not abort the whole seed.

Bug fix: analytics_service.py Python-2 except syntax

backend/ai/services/analytics_service.py:614 used the pre-Python 3 comma form except ValueError, TypeError:, which fails to parse under Python 3.0+. Python 3.14 (our runtime) rejects it with a SyntaxError at import, silently breaking AnalyticsService._analyze_project_insights_sync — the backbone of the AI Associate's analyze_project_health tool and the primary canonical health scorer. Replaced with the correct parenthesised form except (ValueError, TypeError):.

Compatibility

  • small_team scenario is unchanged. All new *Spec fields default to empty/None, so existing scenario content continues to produce identical seeded data (verified via dataclass audit — no breaking fields added without defaults).
  • Existing milestones without a tier field fall back to "minor" on read paths.

v0.4.125 - 2026-04-29

Fix: Landing page typography now resolves to actual loaded fonts

  • Replaced unresolved landing font setup (CohereText, Unica77 Cohere Web, CohereMono names with no font source) with concrete next/font/google loading in frontend/src/app/layout.tsx.
  • Mapped design tokens to real runtime variables in frontend/src/app/globals.css so --font-display, --font-body, and --font-mono always resolve.
  • Tuned hero/nav/CTA typography for closer parity with the reference marketing screenshot: tighter display tracking, adjusted weight/line-height, updated CTA copy, and added a secondary "See How It Works" action target.
  • Added frontend typography token guidance in docs/frontend/conventions.md to prevent future token-to-font drift.

Validation

  • Attempted npm run lint -- src/app/layout.tsx src/components/landing/HeroSection.tsx src/components/landing/PhilosophySection.tsx src/components/landing/LandingNavbar.tsx; blocked by existing ESLint config import issue (eslint-config-next/core-web-vitals resolution) in this environment.

v0.4.124 - 2026-04-28

Fix: Associate runtime prompt alignment with current tool surface + recent features

The runtime system prompt (backend/core/constants/associate_runtime_prompt.py) had drifted from the actual tool surface over the v0.4.118-123 batch. Three classes of drift were removed and the new bundle / cache behaviors were wired into the agent's instructions.

Stale claims removed

  • "Scheduling meetings and calendar events" was still listed under core capabilities, but CalendarService was retired in v0.4.122 and no scheduling tool exists. The agent could hallucinate a scheduling call and fail. Replaced with accurate capability bullets (task management, project health, team/presence, generation, MAX Gantt, web research, memory, staging).
  • Staged task sentinel task_id=0 was the pre-v0.4.122 mock behavior. Task IDs are now strings; staged tasks carry task_id="" until the user commits. Prompt now states this correctly so the agent does not try to call assign_task / update_task_status on a sentinel ID.
  • Task Review Agent "coming soon to UI" — actually shipped (Task Modal "Associate Analysis" panel, v0.4.x). Prompt now tells users where to find it.

Missing tools added to inventory

The LLM only invokes tools it knows about from the prompt. Six registered tools were undocumented:

  • fetch_task_context — full task detail by id or title.
  • suggest_task_for_timer — focus-session / timer-fit recommendations.
  • get_user_presence, get_project_presence, find_active_team_members — presence/activity tools.
  • get_project_doc_summary moved from Staging & Memory (wrong category) to the new Analytics & Insights block as a read-only surface.

A cross-check test was added that enumerates every @tool_with_policy / @max_only_tool decorator in the repo and asserts the prompt mentions each by name.

Bundle + cache behaviors promoted

  • The Agent Recommendation Matrix now leads with project_audit_bundle as the recommended path for broad-review intents ("audit this project", "what's the state of things?", "how healthy is my project?").
  • The "Maximize Each Tool Call" guidance now lists the bundle as the consolidated-read sibling to bulk_create_tasks, with an explicit instruction to prefer it over chaining analyze_project_health + project_insights + summarize_project_risks + recommend_next_actions.
  • A new guidance item explains the per-turn analytics cache so the agent feels free to compose a bundle call with targeted follow-ups (e.g. project_audit_bundle → then a specific search_tasks) without worrying about redundant reads.
  • Tool-failure guidance updated to reflect the generous budget (dozens of calls per turn, failure budget 10) — old language implied a tight budget, which could make the agent conservative when thoroughness is more valuable.

Harness focus-area heuristic

  • _extract_focus_areas in backend/ai/services/associate_harness.py now recognizes "audit", "review", "state of", "how is", "how healthy", "overview", "summary of" as analysis focus hints. Previously these broad-review intents fell through to general, meaning the ContextLoader wouldn't prioritize the timeline/activity evidence the bundle needs. Tests pin this mapping.

Dead code deleted

  • backend/ai/prompts.py (35-LOC legacy JSON-response prompt with zero imports anywhere in the repo) deleted.

Regression tests

Two new test classes in backend/tests/test_ai_associate_security.py:

  • Section9RuntimePromptTests (5 tests):
    1. Every @tool_with_policy / @max_only_tool in the codebase is referenced in the prompt.
    2. Retired "Scheduling meetings and calendar events" claim stays out.
    3. Pre-v0.4.122 task_id=0 staging sentinel is not resurrected.
    4. project_audit_bundle is present in the matrix as "(you)".
    5. Per-turn cache guidance is present so the agent knows analytics are cheap.
  • Section9HarnessFocusAreaTests (2 tests): broad-review phrasings route to analysis focus; unrelated phrases still default to general.

Validation

  • ruff check + ruff format clean on touched files.
  • pytest backend/tests/test_ai_associate_security.py → 48/48 passing (41 pre-existing + 7 new prompt/harness tests).
  • Tool-surface cross-check: 50 registered tools, all now advertised in the prompt.

v0.4.123 - 2026-04-28

Performance: per-turn analytics cache + project_audit_bundle meta-tool

Addresses two remaining sources of MAX tool pressure identified in the v0.4.121/122 follow-ups:

  1. Redundant Mongo scans — analyze_project_health, project_insights, and summarize_project_risks all read the same tasks collection. A deep-audit chat turn could hit the same data 3-4× in sequence.
  2. Tool budget burn — each of those tools counted as a separate call against the role cap, so a natural "give me a full project review" question ate 3-4 of the user's budget before the agent even started writing its answer.

Per-turn analytics cache

  • New BlueprintDependencies.turn_cache: Dict[str, Any] field — fresh per chat request (default_factory=dict, so no cross-request leakage via mutable default).
  • New helper _turn_cache_get_or_compute(ctx, key, factory) in backend/ai/associate.py: first caller with a given key runs the async factory, subsequent callers in the same agent run return the cached value. Cache key embeds tool name + company_id + project_id + window params so staleness is impossible.
  • Wired into three hot paths:
    • analyze_project_health (cache key: analyze_project_health:<company>:<project>:<period>:<predictions>)
    • project_insights (cache key: project_insights:<company>:<project>:<current>:<previous>)
    • _load_project_context_snapshot_for_tools — the ContextLoader snapshot used by summarize_project_risks, recommend_next_actions, context_delta_since_last_visit, simulate_capacity_plan, and the new bundle. Keyed by company + project + sorted(focus_areas) so different focus sets don't collide.

project_audit_bundle meta-tool

  • New read-only tool project_audit_bundle that returns health, insights, risks, and optional next_actions in one tool call instead of 3-4.
  • Counts as a single call against the role cap → deep-audit requests drop from ~4 tool slots to 1.
  • Each sub-section is wrapped in its own try/except: a partial failure in one section (e.g. insights errors) does NOT blank the other three. result["errors"] reports which sections failed.
  • Accepts the same tuning knobs as its sub-tools: analysis_period_days, previous_period_days, include_predictions, include_next_actions, next_actions_limit.
  • Loads the ContextLoader snapshot once and reuses it for both the risks and next-actions sections (with the per-turn cache as a belt-and-braces fallback).
  • Registered as ToolCategory.READ in PolicyResolver.TOOL_CATEGORIES and added to READ_ONLY_ASSOCIATE_TOOLS, so viewer roles can call it.
  • System prompt (core/constants/associate_runtime_prompt.py) now flags the bundle as the preferred path for broad project-review questions.
  • Billing pricebook (seed_billing_pricebook.py): listed at $0.035 fixed — higher than an individual analytical tool (0.020) to reflect the larger single-call work, but well below the sum of its parts (≈0.060) so users are rewarded for choosing the consolidated path.
  • risk_tool_sources in usage_views.py now includes the bundle so risks-surfaced-early KPIs capture it.

Cache-composition behavior

If the agent calls project_audit_bundle and then later calls analyze_project_health (or vice versa) in the same turn, the second call hits the cache instantly — the bundle and its sub-tools share the same keyspace. This means the agent can freely compose bundle + targeted follow-ups without burning tool budget on recomputation.

Live smoke-test sanity check (against stub DB)

  • Two consecutive project_audit_bundle calls → analytics.analyze_project_health called 1× (not 2×), analyze_project_insights called 1× (not 2×). Cache working as intended.
  • Bundle output: success=True, health_score=42.0, insights_status=ok, risk_level=medium, 2 next actions. All four sections populated.

Regression tests

  • New class Section9TurnCacheAndBundleTests (6 tests):
    1. BlueprintDependencies.turn_cache exists with default_factory=dict producing fresh dicts per instance (no mutable-default leak).
    2. _turn_cache_get_or_compute memoizes same key; different keys recompute.
    3. Fresh per-request: two separate BlueprintDependencies have independent caches.
    4. project_audit_bundle registered in READ_ONLY_ASSOCIATE_TOOLS and ToolCategory.READ; viewer role can call it.
    5. Tool callable on the ai.associate module.
    6. Static-source assertion: bundle references analyze_project_health, analyze_project_insights, and _turn_cache_get_or_compute.

Impact check (requested)

Confirmed no stragglers depend on retired v0.4.122 mocks:

  • No TaskService / CalendarService / task_service. / calendar_service. references remain outside historical comments and new tests.
  • AnalyticsService.analyze_project_health / analyze_project_insights — only call sites are in ai.associate (agent tools) and tests.
  • ProjectAIService.analyze_project_health at backend/ai/services/project_ai.py:239 is a different class used by project_creation_ai.py (project-setup flow, not the live agent) — unaffected by the v0.4.122 retirement.

Validation

  • ruff check + ruff format clean on all touched backend files.
  • pytest backend/tests/test_ai_associate_security.py → 41/41 passing (35 pre-existing + 6 new cache+bundle tests).
  • Live stub-DB smoke test confirms cache hits and correct bundle composition.

Follow-ups (smaller)

  • After 1-2 weeks of production use, pull tool_call_total distribution per conversation and confirm project_audit_bundle adoption is reducing the p95.
  • Consider adding a Mongo projection/$group pipeline variant for _analyze_health_sync if any tenant has >5k tasks per project (current loop is O(n) client-side).

v0.4.122 - 2026-04-28

Feature: Retire Associate mock services — real task writes and real project-health analytics

Three Associate "services" were previously SimpleNamespace mocks returning placeholder data. All three have been retired or replaced with canonical production paths.

TaskService → deleted; create_task tool now uses TasksRepo directly

  • backend/ai/services/task_service.py (289 LOC of mock _*_sync helpers returning task.id = 1) deleted.
  • TaskService field removed from BlueprintDependencies and from create_dependencies.
  • The agent's create_task tool (backend/ai/associate.py:1709) now builds a core.repos.tasks_repo.TaskCreate payload and writes through TasksRepo(company_id).create(...) inside a sync_to_async wrapper so the async agent loop is not blocked. Assignee resolution handles multi-email mapping and uses string user IDs (Mongo-native).
  • TaskCreationResult.task_id changed from int → str since real task IDs are ObjectId strings. All three TaskCreationResult construction sites updated (success / staging / error branches).

CalendarService → deleted

  • backend/ai/services/calendar_service.py deleted. Had zero call sites in the agent code — pure dead injection.
  • CalendarService field removed from BlueprintDependencies and from create_dependencies.
  • If calendar work is needed in a future tool, wire it through core.repos.calendar_repo.CalendarRepo directly.

AnalyticsService._analyze_health_sync → real Mongo aggregation

  • The hardcoded mock (health_score=75.5, total_tasks=25, canned risk strings) replaced with a tenant-scoped Mongo aggregation backed by company_db(company_id).tasks.
  • AnalyticsService.analyze_project_health signature updated: now requires keyword-only company_id and project_id (string UUIDs) to prevent positional misuse across tenants.
  • Real counting rules:
    • completed: status in {done, completed, closed}.
    • blocked: stuck == True or status == blocked.
    • overdue: due_date in the past AND not completed.
    • in_progress: status in {in_progress, review}.
  • Composite health score formula: healthy_share − risk_penalty, bounded 0-100.
    • healthy_share = (completed + 0.5 × in_progress) / total × 100 — credits work-in-progress at half weight so active projects are not penalized for being mid-flight.
    • risk_penalty = min(40, (overdue + 1.5 × blocked) / total × 100) — bounded so a small project cannot score negative on a single slip.
    • total_tasks == 0 returns a neutral 50 (no data signal yet) instead of a misleading 0.
  • Team utilization proxy derived from open-workload-per-active-assignee, capped at 100%.
  • Estimated completion uses rolling velocity over the requested window, capped at 365 days so near-zero-velocity projects do not produce 10-year ETAs.
  • Risks / recommendations are now generated from the observed numbers (overdue counts, blocked counts, completion percentage, utilization) rather than fixed strings. Projects with no issues get a "maintain cadence" recommendation instead of a fabricated list.
  • The tool call site in associate.py now passes company_id=str(ctx.deps.company_id) + project_id=str(ctx.deps.project.id).

Sanity benchmarks (live run against in-memory stub DB)

Scenariocompletion_ratehealth_score
Small distressed (4 tasks, 1 done, 1 overdue WIP, 1 blocked, 1 WIP)25%10
Healthy large (100 tasks, 60 done, 30 WIP, 1 overdue, 1 blocked)60%73
Empty project (0 tasks)0%50 (neutral)

Regression tests

  • New class Section9MockServiceRetirementTests (6 tests):
    1. Asserts task_service.py and calendar_service.py are gone.
    2. Asserts BlueprintDependencies no longer has task_service / calendar_service fields.
    3. Asserts ai.services package no longer exports TaskService / CalendarService.
    4. Asserts analyze_project_health has keyword-only company_id + project_id parameters.
    5. Static-source assertion that _analyze_health_sync hits company_db + tasks.find and no longer returns health_score=75.5.
    6. Static-source assertion that create_task tool uses TasksRepo + TaskCreate and no longer references ctx.deps.task_service.

Follow-ups

  • Consider caching _analyze_health_sync results for the duration of a single chat turn — a deep-audit request may call it multiple times.
  • Tool consolidation: analyze_project_health + project_insights + summarize_project_risks overlap in their task reads; a future pass can group them.

Validation

  • ruff check + ruff format clean on all touched backend files.
  • pytest backend/tests/test_ai_associate_security.py → 35/35 passing (29 pre-existing + 6 new mock-retirement tests).
  • Live smoke test against stub DB produced sane numbers across three scenarios (see table above).

v0.4.121 - 2026-04-28

Feature: Associate tool-call budgets + failure resilience

Addresses the observation that Alesko Associate MAX occasionally fails on deep-analysis requests. Root cause: MAX and Standard shared the same role-based tool cap even though MAX is designed for multi-tool audit-style queries. Combined with a tight 5-failure budget, a single transient Mongo blip during a deep audit could trip the budget before the agent finished planning.

  • Role tool caps raised across the board (backend/ai/services/policy_engine.py):
    • owner 15 → 80
    • admin 12 → 64
    • manager 10 → 50
    • member 8 → 40
    • viewer 3 → 16
    • guest 5 → 20
    • billing unchanged at 0 (no AI access)
  • MAX model multiplier: new PolicyResolver.get_effective_max_tools(role, model_id) applies a 1.75× multiplier on top of the role cap when model_id == "max". Effective MAX ceilings: owner 140, admin 112, manager 88, member 70, guest 35. No-AI roles (billing) stay at 0 — the multiplier cannot promote a role into AI access.
  • Failure budget raised from 5 → 10 (BlueprintDependencies.tool_failure_budget) so transient Mongo / provider flaps during a long chain no longer kill the run. tool_retry_limit = 2 unchanged — per-tool retries stay bounded.
  • Default max_tools_per_request on BlueprintDependencies and create_dependencies raised from 20 → 40 to match the member role cap (the most common authenticated path).
  • Views wiring: associate_chat_view now calls PolicyResolver.get_effective_max_tools(company_role, model_id) instead of the old model-agnostic get_max_tools_per_request, so MAX requests automatically see the higher ceiling. The per-request warning log now includes model_id for debugging.
  • Policy endpoint: PolicyResolver.get_policy_summary now returns max_tools_per_request_standard, max_tools_per_request_max, and max_model_tool_multiplier so the UI can display the effective budget per model.

What this does NOT change

  • Access control: MAX still requires ModelType.MAX ∈ allowed_models (enforced by PolicyResolver.can_use_model). This change only affects the budget the user gets once they are entitled to MAX.
  • Personal + workspace chat views intentionally pass max_tools_per_request=0 (tools disabled in those contexts). Unchanged.
  • Tool-level model gates (@max_only_tool) unchanged. A Standard user still cannot invoke MAX-only tools.

Follow-ups (next pass)

  • Consolidate overlapping read tools (e.g. fetch_task_context + get_task_comments) behind grouped meta-tools so a deep-audit request needs fewer calls in absolute terms.
  • Cache project_insights / analyze_project_health results so the same aggregation is not re-run mid-conversation.

Validation

  • ruff check + ruff format clean on touched backend files.
  • pytest backend/tests/test_ai_associate_security.py → 29/29 passing (24 pre-existing + 5 new tool-budget regression tests).

v0.4.120 - 2026-04-28

Security: AI-P0-3 — retire the unguarded Mongo-first Associate agent

  • Deleted backend/ai/associate_mongo.py, backend/ai/associate_bridge.py, and backend/ai/runner.py. These three files formed a parallel Associate pipeline with no PolicyResolver gate on tools and trusted caller-supplied tenant_id / user_id / project_id arguments (associate_mongo.MongoDeps._deps). If any HTTP route or task had reached this agent with attacker-supplied tenant, writes would have landed in another tenant.
  • Verified zero external callers before removal (rg for imports, bridge symbols, and start_chat_stream — only the three files referenced each other). ASSOCIATE_BOT_USER_ID is independently redefined in backend/comms/tasks.py:18 and backend/core/api/v1/messaging_views.py:40, so deleting the bridge's copy is safe.
  • Updated backend/core/services/ai_scope_guard.py docstring and backend/core/services/ops_testing_service.py:1595 comment to reflect the retirement.
  • Replaced the existence-probe test Section9AssociateMemorySurfaceTests.test_associate_memory_module_discoverable with test_associate_mongo_agent_retired, which asserts all three files are gone so the surface cannot silently return.

Observability: extend CancelledError handling to personal + workspace chat views

  • Follow-up to v0.4.119: personal_associate_chat_view and workspace_associate_chat_view SSE generators now catch asyncio.CancelledError, log a client-disconnect line with the conversation id, and re-raise for clean ASGI teardown. Parity with the main project associate_chat_view stream.
  • Personal and workspace streams still emit no usage events today (neither path wires _queue_usage_event); the disconnect log is purely observability.

Billing / Analytics: Gap 5 — capture provider token usage on SSE

  • associate_chat_view now reads pydantic-ai event.result.usage() inside the AgentRunResultEvent branch and stores the full RunUsage snapshot (requests, request_tokens, response_tokens, total_tokens, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, tool_calls) in a generator-local run_usage dict.
  • _emit_request_usage now threads run_usage into the event's metadata.token_usage payload AND switches the top-level units from the placeholder 1 to total_tokens when present, so billing/analytics aggregate on the real cost dimension.
  • Fail-safe: token capture is wrapped in try/except with a DEBUG log so a missing/renamed pydantic-ai usage API cannot break the stream; legacy units=1 behavior remains the floor.

Validation

  • ruff check + ruff format clean on touched backend files.
  • pytest backend/tests/test_ai_associate_security.py → 24/24 passing (test renamed + the three files confirmed retired).
  • Backend module smoke import (ai.api.views) clean.

v0.4.119 - 2026-04-28

Security: AI-P0-4 staging commit/revert role recheck (defense-in-depth)

  • Closed the AI Section 9 audit finding AI-P0-4. StagingManager.commit_staging_session and StagingManager.revert_staging_session previously only checked session.user_id == user_id and status == ACTIVE, meaning a user whose role was downgraded to viewer after staging-session creation could still commit or revert pending changes.
  • Added StagingManager._assert_project_write_access which re-runs core.auth.utils.check_project_role_strict(required="project:write") against the tenant/user/project at commit AND revert time, raising PermissionError("staging_write_access_required") when the caller no longer holds write.
  • Translated PermissionError to HTTP 403 at the view boundary in StagingCommitView.post / .delete so the client gets a canonical forbidden response instead of a 500. Failed-commit usage event (USAGE_EVENT_STAGING_COMMIT_FAILED) is still emitted for observability with metadata.error = "role_recheck_denied".
  • Covered by Section9StagingRoleRecheckTests (3 new tests) in backend/tests/test_ai_associate_security.py.

UX: Gap 1 — Associate SSE stream cancellation + Stop button

  • Fixed the long-standing bug where useAssociateChat.ts allocated an AbortController per request but never called .abort(). Navigating away, closing the sidebar, or pressing the send button during a stream would leak the SSE connection, fire React setState into an unmounted component, and leave the partial response invisible forever.
  • Added cancelStream to useAssociateChat and wired two new cleanup effects: one aborts on pathname change (Next.js usePathname), the other aborts on hook unmount.
  • ChatInput.tsx now renders a red Stop button while the stream is live, replacing the spinner send button. Clicking Stop triggers cancelStream which aborts the fetch, and the existing AbortError branch resets all streaming state cleanly.
  • Backend associate_chat_view now catches asyncio.CancelledError in the SSE generator, logs a client-disconnect line, and emits a failed USAGE_EVENT_ASSOCIATE_REQUEST_FAILED with error_code = "client_disconnect" so billing/observability see the abort instead of silently dropping the stream.

Cleanup: Strip dead associate_usage pipeline from company leaderboard

  • Removed the associate_pipeline Mongo aggregation and its companion associate_usage response key from LeaderboardView in backend/companies/api/views.py. The Associate AI ranking tab was removed from LeaderboardWidget.tsx back in v0.4.12, but the backend kept doing the aggregation work on every leaderboard fetch — reading from the ai_interactions Mongo collection that has zero writers anywhere in the repo.
  • Endpoint response is now strictly {tasks_closed, activity_score, period_days, generated_at}. Per-user AI usage lives under the dashboard AI Usage & Cost card, which is wired to real usage-metering endpoints.

Corrections / retractions

  • Retracted: prior v0.4.118 notes flagged several except (A, B, C): → except A, B, C: patterns (backend/companies/api/views.py:871, 944, 997, etc.) as Python-2 SyntaxErrors. This was wrong. The project runs on Python 3.14 (backend/Dockerfile* pins python:3.14-slim, requires-python = ">=3.14") and PEP 758 — accepted for 3.14 — allows parentheses-less except tuple lists. Ruff's formatter is correctly preferring the new syntax for this target. No ruff bug; no Python 2 regression. ruff format applied to all touched backend files in this change.

Validation

  • ruff check + ruff format clean on touched backend files.
  • pytest backend/tests/test_ai_associate_security.py → 24/24 passing (18 pre-existing + 3 AI-P0-2 guard + 3 AI-P0-4 recheck).
  • tsc --noEmit clean on frontend.
  • eslint baseline unchanged (44 pre-existing issues, zero introduced by this change).

v0.4.118 - 2026-04-28

Security: AI-P0-2 staging/memory/project-doc tenant boundary fix

  • Closed the AI Section 9 audit finding AI-P0-2: four legacy DRF views under /api/v1/ai/companies/<company_pk>/projects/<project_pk>/ only validated that the target project lived in company_pk, not that the caller belonged to company_pk. A user in Company A with a valid project UUID in Company B could list/commit/revert staged changes, read the project doc summary, or CRUD AI memory in the foreign tenant.
  • Wired the canonical core.services.ai_scope_guard.require_ai_project_access helper into every method of StagingSessionView, StagingCommitView, ProjectDocView, and AIMemoryView via a new _guard_ai_project_access wrapper in backend/ai/api/views.py. The guard runs before project lookup, short-circuits with a 401/403 JSON response on failure, and enforces strict JWT-only company scope plus project-level access via the Section 6 require_project_access chain.
  • Permission floor per method: list-staging = project:read, commit/revert staging = project:write, project-doc read = project:read, AI-memory CRUD = project:read (the per-memory scope/admin check at AIMemoryView._is_admin still runs for write differentiation).
  • Added regression test class Section9StagingMemoryScopeGuardTests (3 tests) to backend/tests/test_ai_associate_security.py asserting that every affected view method lexically calls the guard before _resolve_project_for_company, locking the wiring against accidental regression.
  • Validation: ruff check clean on touched files; pytest tests/test_ai_associate_security.py 21/21 passing.

Dev server bugfix: admin seed purge followed by login failures

  • Investigated post-purge login/admin failures via dev-server container logs and confirmed the immediate outage was PostgreSQL connection-slot exhaustion (FATAL: remaining connection slots are reserved for roles with the SUPERUSER attribute), which caused /api/users/me, admin login, and related authenticated routes to return 500s.
  • Mitigated the live outage by terminating stale idle PostgreSQL sessions on the dev host and restarting app containers.
  • Hardened dev-server backend defaults by changing DB_CONN_MAX_AGE fallback from 60 to 0 in backend/core/settings/dev_server.py so long-lived dev processes do not keep too many persistent DB connections open by default.

Dev-server ops fix: Denis admin account login recovery

  • Investigated denis@alesko.ai admin-login failures after the purge incident and confirmed the account existed but had no usable password hash (has_usable_password=False), while jared@alesko.ai remained healthy.
  • Repaired dev account state by setting a usable password hash and restoring admin flags (is_staff=True, is_superuser=True) for denis@alesko.ai so admin login parity is restored.
  • Verified both denis@alesko.ai and jared@alesko.ai now succeed via POST /api/admin/login (HTTP 200).

Safety hardening: purge command protects admin console users by default

  • Updated backend/core/management/commands/purge_test_company.py so users listed in ADMIN_CONSOLE_ALLOWED_EMAILS (fallback: jared@alesko.ai, denis@alesko.ai) are excluded from deletion during company purge by default.
  • Added explicit override flag --include-protected-admins for exceptional cases where protected admin users must also be deleted.
  • Added guardrail for direct --user-email purges: command now errors if targeting a protected admin unless --include-protected-admins is provided.

v0.4.117 - 2026-04-28

Bugfix: Associate sidebar persisting on landing page

  • Fixed a bug where the Associate sidebar remained visible and open when navigating from an authenticated page to the landing page (/index), distorting the page layout via body.associate-open padding.
  • Added /index to the public route exclusion in AssociateSidebarWrapper so the sidebar is never rendered on the landing page.
  • Added /index to the auto-close effect so localStorage state and body classes are cleaned up when navigating to the landing page.

Refactor: Consolidated public route definitions

  • Extracted public route definitions into a single shared module frontend/src/lib/publicRoutes.ts (PUBLIC_PATHS_EXACT, PUBLIC_PATH_PREFIXES, isPublicPath()).
  • Updated middleware.ts, AppProviders.tsx, and AssociateSidebarWrapper.tsx to import from the shared module instead of maintaining separate inline lists.
  • Prevents future route mismatches across auth, activity tracking, and sidebar visibility.
  • Hardened the shared route utility by separating middleware-safe public routing (isPublicPath) from client UX routing (isClientPublicPath) so /admin/* is not accidentally treated as globally public for auth checks.

v0.4.116 - 2026-04-28

Login page visual finalization

  • Updated login action hierarchy based on UX review:
    • sign-in mode now presents SSO login + Login with password as the two primary actions,
    • create-account mode now presents passwordless SSO login only.
  • Moved optional Tenant ID field into Advanced options and surfaced password input in the main sign-in form area for a cleaner default flow.
  • Added three new vertical architecture background images for login hero rotation:
    • frontend/public/images/login/vertical-city-sunrise-1.jpg
    • frontend/public/images/login/vertical-architecture-waterfront-2.jpg
    • frontend/public/images/login/vertical-business-district-3.jpg
  • Widened the login hero image panel and enabled client-side randomized background selection on load while preserving hydration-safe defaults.
  • Tweaked logo horizontal alignment to better match card visual balance.

Personal dashboard projects list-only mode

  • Removed the card/grid projects presentation and now render Personal Dashboard projects in list-table format only for a cleaner, denser workflow view.
  • Removed view-mode toggle + project pager behavior from the projects dock and now show all available projects in the single list view.
  • Preserved existing list-table capabilities (column drag-reorder and column resize) and kept New Project + Workspace switching behavior unchanged.

Personal dashboard top section visual refinement

  • Refined the dark hero panel surface treatment with layered gradients, stronger panel boundaries, and tighter spacing to reduce perceived empty space while preserving existing interactions.
  • Rebalanced Daily Brief and My Tasks top layouts by tightening paddings/gaps, improving activity/brief column proportions, and making the right-side time stats rail feel more intentional.
  • Improved top-section readability hierarchy (header/title/subtitle typography and announcement emphasis) without changing tab logic, task filtering, or data behavior.
  • Improved empty-activity handling so the All caught up state now shows meaningful context (overdue/today counts + next-up summary + quick actions) instead of a sparse blank panel.
  • Updated Daily Brief expansion affordance with a larger chip-style Expand details / Hide details control and adjacent arrow icon to make expand/collapse behavior more obvious.
  • Reworked Daily Brief right panel into a readiness-first preflight: 2-minute alignment status, prioritized action cards, and compact timeline metrics (Next up, Due today, Events next 7 days) before optional expanded details.
  • Made readiness risk indicators actionable: clicking the N risk(s) signal in 2-minute alignment now auto-expands details to reveal specific Risks and blockers content.
  • Added section-level skeleton loading states for personal dashboard top surfaces (My Tasks list, time stats rail, Daily Brief two-column preflight, activity feed, and announcements) so users see progress while workspace/project/brief data is loading.
  • Fixed top-panel loading flicker so skeletons are only shown for initial empty states; refresh/loading transitions now preserve existing content instead of flashing full-width skeleton placeholders after data has already rendered.
  • Refined My Tasks presentation in Personal Dashboard with an impact-first header, inline bucket counts (Overdue/Today/This week/All), and a Start now recommendation card while keeping existing task-fetch/filter behavior unchanged.
  • Improved task list visual hierarchy using urgency-weighted row accents and clearer project tagging so high-priority work is easier to scan before opening the board.
  • Reworked the Hours worked rail into a compact Time pulse panel with a single hero metric (today), weekly/session context, 7-day mini trend bars from existing daily breakdown data, and a clearer top-project summary.
  • De-emphasized time export action from primary button style to a secondary link-style control to keep focus on day-start guidance.
  • Reworked Personal Dashboard Announcements tab into a more impactful spotlight experience with an at-a-glance summary strip (Total, Projects, Celebrate) and stronger visual hierarchy for headline announcements.
  • Added announcement tone treatment (Celebrate, Priority, Announcement) inferred from existing message text to make wins feel celebratory while still surfacing urgent communication clearly.

Admin panel light mode toggle

  • Added a theme toggle button (☀️/🌙) next to the Logout button on both /admin/management and /admin/performance pages.
  • Light mode uses a light grey palette (#f3f4f6 background, #e5e7eb cards) instead of pure white, preserving cyan/emerald/amber/rose status accent colors for readability.
  • Theme preference is persisted in localStorage under bp.adminTheme and synced across both admin pages.
  • Implemented via CSS override strategy in frontend/src/app/admin/management/admin-theme.css to avoid touching 381 hardcoded slate color references across 14 component files.

Validation

  • Frontend lint run on touched admin files:
    • npm run lint -- src/app/admin/management/page.tsx src/app/admin/performance/page.tsx
    • Result: pass (no new errors/warnings introduced; pre-existing setState-in-effect and no-explicit-any errors in performance page remain unchanged).

Security / Compliance / Performance review

  • SOC 2: No changes to auth flows, audit logs, or access controls. Theme is a pure client-side UI preference.
  • GDPR: No personal data collection changes. localStorage key bp.adminTheme stores only a theme enum ("dark" | "light"), not PII.
  • RBAC / Security: No authorization boundary changes. Theme toggle is available to any authenticated admin user already on the page.
  • Performance: CSS override approach adds ~100 CSS rules loaded only on admin routes. No additional JS bundles or runtime overhead beyond a single useState toggle.

v0.4.115 - 2026-04-28

Login UX refresh + SSO entry handoff

  • Rebuilt the primary auth page (frontend/src/app/login/page.tsx) with a cleaner split-layout card experience, explicit Sign in / Create account mode toggle, and improved loading/error/success messaging for magic-link and session-edge states.
  • Replaced social-login style secondary CTA with a first-class Continue with SSO action that routes through a new frontend handoff endpoint (GET /api/auth/sso/start) instead of any provider-branded button.
  • Added frontend/src/app/api/auth/sso/start/route.ts to centralize SSO-start redirect behavior, sanitize next routing targets, and safely fall back to /login?error=sso_not_configured or /login?error=sso_invalid_url when env config is missing/invalid.
  • Added SSO_LOGIN_URL / NEXT_PUBLIC_SSO_LOGIN_URL support in frontend/src/lib/env.ts so SSO integration can be configured per environment without hardcoding provider URLs in UI code.
  • Added compatibility env aliases in frontend/src/lib/env.ts for Google-based SSO setups (GOOGLE_ALIAS_ID, GOOGLE_CLIENT_ID, GOOGLE_SSO_REDIRECT_URI, and *_NEXT_PUBLIC_* variants) so existing env-driven Google alias ID integrations continue to work without route code changes.
  • Enhanced GET /api/auth/sso/start (frontend/src/app/api/auth/sso/start/route.ts) with Google authorize URL fallback generation when only alias/client-id + redirect URI envs are provided (no prebuilt full SSO_LOGIN_URL required).
  • Improved login error handling for common auth redirect codes (invalid_or_expired_token, missing_exchange, missing_tokens, SSO config errors) so users get immediate, actionable feedback when sign-in fails.

Auth cookie/session consistency hardening

  • Updated refresh route cookie handling (frontend/src/app/api/auth/refresh/route.ts) to decode JWT exp and set auth_token cookie maxAge from token TTL (instead of fixed 12h), aligning refresh behavior with login/magic-link cookie issuance policy.
  • Added cross-subdomain cookie domain parity to refresh route (Azure Container Apps parent-domain behavior) so refreshed sessions remain stable across frontend/backend subdomain topology.

Validation

  • Frontend lint run on touched auth files:
    • npm run lint -- src/app/login/page.tsx src/app/api/auth/refresh/route.ts src/app/api/auth/sso/start/route.ts src/lib/env.ts
    • Result: pass (no errors/warnings on these targets after fixes).
  • Frontend build health check rerun after auth updates and TaskModal type compatibility fix:
    • npm run build
    • Result: pass.

Build unblock follow-up included with this auth pass

  • Fixed a repository type-check blocker in frontend/src/components/TaskModal/TaskModal.tsx that prevented next build from completing:
    • updated AIInsights.insights typing to support both legacy string arrays and structured insight objects,
    • added safe insight parsing helpers for executive-summary and full-insights rendering,
    • added missing optional is_valid typing on AIInsights used by subtask verification UI.

Security / Compliance / Performance review

  • SOC 2: Improved auth operability by reducing ambiguous login failures and centralizing SSO redirect logic with explicit safe fallbacks; no token exposure changes (cookies remain HttpOnly).
  • GDPR: No expansion of personal-data collection; login UX changes remain data-minimal. Existing remembered-email localStorage behavior is unchanged.
  • RBAC / Security: SSO handoff route enforces path sanitization for next and does not grant auth itself; authorization boundaries remain backend-enforced.
  • Performance: Login page interaction flow is more linear with fewer hidden affordances for primary actions; no added backend round-trips in standard magic-link/password paths.

v0.4.115 - 2026-04-28

Bug fixes

  • Real AssociateSidebar mounting on landing page (AssociateSidebarWrapper.tsx): The /index landing page was not included in the public-route exclusion list, so the real AssociateSidebar (with its useEffect hooks for prewarm, history loading, etc.) was mounting alongside the demo showcase section and writing to MongoDB on every visit. Added /index to isPublicRoute so the sidebar returns null on the landing page. Also removed an unused ChatInput import from AssociateShowcaseSection.tsx.

Enhancements

  • Associate Showcase — ICP-targeted demo with profession selector (AssociateShowcaseSection.tsx, AssociateShowcaseSection.module.css): Revamped the "Introducing Associate" section on the landing page:
    • Added profession selector pills: PM/Ops, Engineers, Leadership, Finance/Security
    • 28 role-tailored demo scripts (4 shared questions with profession-specific responses + 3 unique questions per profession)
    • Slow theatrical animation sequence: user message → planning panel with steps appearing one-by-one → thinking content streaming line-by-line → response streaming line-by-line → impact receipt reveal
    • Animations are cancellable (clicking a new question cancels the current one)
    • Buttons disabled during animation to prevent overlap
    • Subtitle updated: "Same question. Different role. Tailored answers."
    • Layout redesigned: demo panel capped at 480px (realistic sidebar width), centered with questions panel vertically aligned alongside. Reduced gap between profession pills and demo area.

v0.4.114 - 2026-04-27

Bug fixes discovered during test-tenant bring-up

  • Nginx routing (/etc/nginx/conf.d/bluprint.conf): the Next.js proxy allow-list regex required a trailing / (^/api/(login|logout|...)/), which caused exact paths like POST /api/login to fall through to the Django backend (which has no such route) and return a 404. Fixed by changing the trailing / to (/|$) so both /api/login and /api/login/… match. Reloaded nginx on dev.
  • Seeder project_id mismatch (test_data_seeder.py): tasks were storing the project's Mongo ObjectId hex string as project_id instead of the canonical UUID. The project snapshot endpoint (which drives the 33.3% completion pill) uses $in: [UUID, ObjectId-hex, ObjectId] so it silently matched, but TasksRepo.list() (which powers the Kanban board) uses exact UUID equality and returned zero tasks — rendering the board empty. Fixed by preferring project_doc["project_id"] over project_doc["id"] when building the task payload.
  • Kanban silently dropping blocked tasks (frontend/src/app/project/ [projectId]/board/page.tsx): the hard-coded 4-column grouping silently discarded any task with status="blocked" (or any future backend status value). Added an explicit blocked → todo mapping in toFrontendStatus, plus a defence-in-depth fallback that routes any unknown status into TODO with a console.warn so regressions surface.
  • Admin test-data proxy import paths (frontend/src/app/api/admin/test-data/ seeds/[seedId]/route.ts, frontend/src/app/api/admin/test-data/seeds/ [seedId]/purge/route.ts): relative import depth to admin/testing/_lib.ts was off by one segment in nested dynamic routes, causing Next.js Module not found build/runtime failures when opening or purging a seed record. Fixed import paths so purge/details routes compile and execute.

Test Data Seeder — Phase 1 (small_team scenario) shipped

  • New admin feature: Test Data tab under /admin/management for spinning up realistic, demo-ready test tenants on demand (product videos, QA, RBAC verification, end-to-end flow testing).
  • New scenario catalog (backend/core/services/test_data_seeder.py):
    • small_team — Harborview Build Co, a 5-person residential + commercial builder. 5 users spanning owner/admin/manager/member/contractor roles, 3 workspaces (Residential / Commercial / Ops & Compliance), 3 projects, 16 realistic construction-themed tasks, 21 embedded subtasks.
    • Contractor intentionally excluded from the Ops workspace to exercise workspace-scoped RBAC visibility.
  • New management command seed_test_company:
    • uv run python manage.py seed_test_company (defaults to small_team)
    • --list-scenarios, --scenario, --company-name, --password, --purge <uuid>, --json, --force-production (emergency escape)
    • Refuses to run when ENVIRONMENT=production unless --force-production is explicitly supplied.
  • New admin API surface (non-prod only):
    • GET /api/v1/internal/ops/test-data/scenarios/
    • GET /api/v1/internal/ops/test-data/seeds/ (credentials redacted)
    • POST /api/v1/internal/ops/test-data/seeds/ (launches Celery seed task)
    • GET /api/v1/internal/ops/test-data/seeds/<seed_id>/ (full detail incl. credentials)
    • POST /api/v1/internal/ops/test-data/seeds/<seed_id>/purge/ (launches Celery purge task)
    • View-level env gate via _test_data_env_gate() returns 403 when ENVIRONMENT=production; access gate reuses _has_ops_access semantics (superuser OR owner/admin of caller's own company).
  • New Celery tasks (core.execute_test_data_seed_task, core.execute_test_data_purge_task) with status persisted to new central Mongo collection ops_test_seeds (mirrors ops_test_runs shape).
  • Enhanced purge_company() now drops the per-tenant co_{uuid} Mongo database in addition to delegating to the existing purge_test_company management command for PG + central Mongo cleanup.
  • Admin UI (frontend/src/app/admin/management/components/TestDataTab.tsx):
    • Scenario cards with counts + optional custom company name.
    • Live-polling seed history (2s cadence while any seed is queued/running).
    • Credentials modal with show/hide passwords, copy-email / copy-password buttons, and prominent dev-only banner.
    • Purge button with confirmation; status pill transitions to purged.
  • Every seeded company is tagged:
    • Company.company_name prefixed with [TEST] plus a unique 4-char hex suffix so multiple concurrent seeds coexist safely.
    • Company_Profile.metadata.is_test_tenant = True + seed_scenario + seed_tag + seeded_at for queryable exclusion from billing/usage.
  • Next.js proxy routes under frontend/src/app/api/admin/test-data/* reuse the existing alesko_perf_access-cookie gate from testing/_lib.ts.

Dev validation:

  • ruff check + ruff format --check — pass on all touched backend files.
  • Django manage.py check on dev server — no issues.
  • End-to-end CLI seed: 5 users, 3 workspaces, 3 projects, 16 tasks, 21 subtasks all created in ~4s; Mongo document counts verified (workspace_memberships: 14 = 5+5+4, confirming Tom the contractor is excluded from Ops workspace).
  • End-to-end API seed via Celery: queued → running → completed in ~6s.
  • Login as seeded owner (sarah.mitchell.<tag>@harborview-build.com with shared password) returns valid access + refresh tokens with correct company_role=owner and tenant_id=<company_id>.
  • Purge via API: 2-phase task (command delegation + per-tenant DB drop); final seed record status transitions to purged with company_id + mongo_db recorded in purge_info.

Security / Compliance / Performance review

  • SOC 2: Every seeded and purged tenant is attributable to the triggering operator (triggered_by = user email) and persisted to the ops_test_seeds audit trail. Test tenants are marked with is_test_tenant=True so they can be systematically excluded from SOC 2-relevant operational reports and billing rollups. Generated passwords are surfaced once via the detail endpoint and redacted in the list endpoint; not persisted server-side beyond Django's salted hash on the user row.
  • GDPR: Seeded users use a non-deliverable harborview-build.com domain (the DNS zone is not controlled by BluPrint, so no real mail can be sent even if triggered). Test tenants are fully purged across PG, central Mongo, and per-tenant Mongo DB by the purge_company() helper. Per-tenant Mongo DB drop closes the prior gap in purge_test_company (which left co_{uuid} DBs orphaned).
  • RBAC / Security: View-layer env gate _test_data_env_gate returns 403 in ENVIRONMENT=production regardless of role. Access gate uses the same _has_ops_access-style check as other admin surfaces (superuser OR owner/admin of caller's own company). Next.js proxy requires the existing alesko_perf_access=1 unlock cookie + authenticated session cookie. The scenario intentionally creates a contractor excluded from an internal-ops workspace so consuming RBAC tests have a real boundary to verify.
  • Performance: small_team seed completes in ~4s locally / ~6s async (incl. Celery dispatch overhead). Task insertion uses insert_one per task (embedded sub_tasks[]) — acceptable at this scale; larger enterprise scenarios in Phase 2 will switch to insert_many. ops_test_seeds collection is newly introduced; no indexes required at current volume but a (triggered_by, created_at) index should be added when history exceeds a few hundred records.
  • Not fully verified (low risk): None outstanding. Initial build used Mongo user IDs for projects.members[].user_id / project_lead / task assignee_id / reporter_user_id, which triggered Failed to ensure Postgres shadow project warnings and left the Django projects.Project shadow M2M empty (silently breaking the django_project.members.filter(...) fallback RBAC check in project_settings_views.py:280). Fixed by switching those fields to Postgres CustomUser.id while keeping workspace/company membership on Mongo users._id — matches the canonical ID convention used by the real project-membership API. Post-fix verification: PG shadow membership populated correctly (5/5/3 users per project), Mongo members[].user_id resolves cleanly to real CustomUser rows, all task assignees and reporters resolve to real users, contractor correctly excluded from the Ops project in both stores.

v0.4.113 - 2026-04-27

Security / AI & Associate - Section 9 Phase B0 foundations

  • Added strict JWT-only company resolver foundation for AI-P0-1:
    • backend/core/auth/utils.py::get_authenticated_company_id_strict refuses the X-Company-Id header fallback. Section 9 mutation endpoints will consume this helper in B1.
  • Added canonical AI audit service backend/core/services/ai_audit_service.py:
    • dotted taxonomy (ai.tool_invoked, ai.tool_rejected, ai.policy_denied, ai.staging_committed, ai.staging_reverted, ai.memory_created/updated/deleted, ai.task_created_by_ai, ai.conversation_deleted, ai.conversation_bulk_deleted),
    • one-release legacy dual-write with event_migration payload (mirrors Section 7 document audit service),
    • best-effort emit pattern (audit failures never break primary AI action).
  • Added canonical AI scope guard backend/core/services/ai_scope_guard.py:
    • is_same_company / is_project_in_scope predicates with fail-closed semantics — empty allowed_project_ids with all_projects=False denies (fix for AI-P1-19).
    • require_company_scope(request, path_company_id) HTTP guard backed by strict JWT-only resolver (foundation for AI-P0-1, AI-P0-2).
    • require_ai_project_access(...) wraps Section 6 require_project_access behind the strict company-scope check.
    • assert_task_in_project(db, task_id, project_id) for tool-layer scope gate (AI-P0-5, AI-P1-26, CC-1).
    • assert_user_in_company(user_id, company_id) for presence/memory tools (AI-P0-6, AI-P1-28).
  • Wired new helpers into backend/core/services/__init__.py exports for consistent import ergonomics.
  • Orchestrator + pytest suite expansion:
    • ai_associate suite flipped from planned → active in backend/core/services/ops_testing_service.py.
    • Runtime posture checks now cover audit-service surface + dual-write marker, scope-guard surface + fail-closed predicate behavior, and strict company resolver availability.
    • backend/tests/test_ai_associate_security.py grew from 3 → 18 tests.

Dev validation:

  • ruff check core/auth/utils.py core/services/ai_audit_service.py core/services/ai_scope_guard.py core/services/__init__.py core/services/ops_testing_service.py tests/test_ai_associate_security.py: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_ai_associate_security.py -q: 18 passed.
  • Combined regression: pytest tests/test_ai_associate_security.py tests/test_documents_file_storage.py tests/test_projects_tasks_security.py -q → 55 passed.

No endpoint/tool call sites modified in B0 — Phase B1 starts wiring in blast-radius order (AI-P0-1/AI-P0-2 first, then AI-P0-7, then tool-layer scope gates, then staging role check, then associate_mongo_agent retire-or-harden decision).

v0.4.112 - 2026-04-27

Security / AI & Associate - Section 9 Phase A audit complete

  • Completed Phase A audit pass across all Section 9 surfaces: policy engine, chat + streaming endpoints, conversation endpoints, task analysis + snapshot review + recommended-task write paths, context loader + cache, task context service, associate runtime + bridge + orchestrator + runner, associate memory, staging manager, presence tools, provider registry + client + config.
  • Populated docs/architecture/ai-associate-audit-matrix.md with a full findings table containing file:line evidence:
    • 7 P0 release-blocking findings (AI-P0-1 .. AI-P0-7).
    • 28 P1 findings (AI-P1-1 .. AI-P1-28).
    • 20+ P2 hygiene items + 5 cross-cutting systemic findings (CC-1 .. CC-5).
  • Updated SECURITY_AUDIT_SECTIONS.md Section 9 block with P0 headlines, cross-cutting observations, locked pass criteria, and Phase B deliverable plan.
  • Notable P0 themes captured for Phase B execution:
    • Cross-tenant spoof via X-Company-Id header fallback on AI mutation endpoints (AI-P0-1).
    • Cross-company access via unchecked _resolve_project_for_company in staging/memory/ProjectDoc views (AI-P0-2).
    • Secondary Mongo-first agent associate_mongo_agent with no policy gate and caller-trusted tenant_id (AI-P0-3).
    • staging_manager.commit_staging_session commits without project-write role check (AI-P0-4).
    • associate.duplicate_task reads by ObjectId without project_id filter (AI-P0-5).
    • Presence tools trust model-supplied scope arguments (AI-P0-6).
    • AI write endpoints (create_recommended_task, suggest_time_estimate ai_estimate update) bypass PolicyResolver (AI-P0-7).

v0.4.111 - 2026-04-27

Security / AI & Associate - Section 9 Phase A scaffolding

  • Flipped Section 9 (AI / Associate) to In Progress in SECURITY_AUDIT_SECTIONS.md with full scope, threat model, two-worker split, and Phase A/B/C deliverables locked.
  • Added canonical Phase A audit artifact docs/architecture/ai-associate-audit-matrix.md:
    • endpoint inventory (chat / staging / memory / policy / project-doc / snapshot-review / task-analysis),
    • core module inventory (policy engine, context loader/cache, associate runtime, memory, tools, staging manager, provider registry, agents),
    • working threat model (T1–T10),
    • product decisions to lock before Phase B,
    • pass criteria template,
    • first seed finding AI-SEED-1 (module-import side effect on provider env).
  • Wired new ai_associate suite into Admin Testing Orchestrator:
    • backend/core/services/ops_testing_service.py adds ai_associate suite definition (release-blocking, stage=planned) with runtime-posture scaffolding checks + pytest target binding.
  • Added Section 9 pytest scaffold:
    • backend/tests/test_ai_associate_security.py (3 tests) verifying policy/context/memory surface discoverability with a provider-decoupled memory check to keep the scaffold green while AI-SEED-1 is outstanding.

Dev validation:

  • ruff check core/services/ops_testing_service.py tests/test_ai_associate_security.py: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_ai_associate_security.py -q: 3 passed.

v0.4.110 - 2026-04-27

Security / Documents & File Storage - Section 7 B3 legacy retirement + boundary checks

  • Retired legacy GridFS document surface and dependencies:

    • removed backend/core/api/v1/documents_views.py,
    • removed backend/core/repos/documents_repo.py.
  • Rewired docs search to the blob-backed canonical repository:

    • backend/core/api/v1/docs_search_views.py now uses BlobDocumentsRepo.search(...).
    • Added blob-repo search implementation in backend/core/repos/blob_documents_repo.py.
  • Retired orphaned knowledge-centre API module files that were not mounted:

    • removed backend/knowledge_centre/api/urls.py,
    • removed backend/knowledge_centre/api/views.py,
    • removed backend/knowledge_centre/api/schemas.py.
  • Updated template bootstrap path to blob-backed docs metadata:

    • backend/core/repos/project_templates_repo.py now seeds default template folders via BlobDocumentsRepo + DocumentCreate.
  • Expanded Section 7 runtime/test guardrails:

    • backend/core/services/ops_testing_service.py now checks:
      • docs search blob-repo wiring,
      • legacy documents module removal,
      • orphaned knowledge-centre API removal.
    • backend/tests/test_documents_file_storage.py now includes:
      • legacy-retirement assertions,
      • docs-search repository wiring assertions,
      • additional cross-tenant boundary assertions for document download and task-attachment delete path guards.
  • Section 6 test suite cleanup for retired legacy docs module references:

    • backend/tests/test_projects_tasks_security.py removed documents_views-specific assertions/tests.
  • Documentation updates:

    • SECURITY_AUDIT_SECTIONS.md Section 7 updated with B3 progress.
    • docs/architecture/documents-file-storage-audit-matrix.md updated with B3 status and validation.
    • docs/architecture/feature-flows.md docs-hub/search flow references updated to blob-backed routes/modules.

Dev validation:

  • ruff check core/api/v1/docs_search_views.py core/repos/blob_documents_repo.py core/repos/project_templates_repo.py core/services/ops_testing_service.py tests/test_documents_file_storage.py tests/test_projects_tasks_security.py: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_documents_file_storage.py tests/test_projects_tasks_security.py -q: 37 passed.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_documents_file_storage.py -q: 18 passed.

v0.4.109 - 2026-04-27

Security / Documents & File Storage - Section 7 B1/B2 progress

  • Expanded canonical Section 7 event taxonomy in backend/core/api/v1/blob_documents_views.py:

    • rename flows now emit document.renamed (legacy document_renamed dual-write retained),
    • move flows now emit document.moved (legacy document_moved dual-write retained),
    • restore-version flows now emit document.version_restored (legacy document_restored dual-write retained).
  • Hardened archived-task download validation in backend/core/api/v1/blob_documents_views.py:

    • _download_archived_task(...) now validates task IDs with ObjectId.is_valid(...) before DB access,
    • malformed IDs return 400 with invalid_archived_task_id instead of falling through to generic failure handling.
  • Reduced profile-picture signed URL exposure window in backend/core/services/blob_storage.py:

    • profile-picture URL generation now uses PROFILE_PICTURE_URL_TTL_MINUTES (default 15 minutes),
    • TTL is clamped between 1 and 1440 minutes.
  • Hardened blob backend configuration posture in backend/core/services/blob_storage.py:

    • backend selection now fails closed when neither S3 nor Azure backend config is provided,
    • removed permissive implicit fallback behavior for missing backend config.
  • Expanded Section 7 orchestrator/test coverage:

    • backend/core/services/ops_testing_service.py runtime checks now assert:
      • archived-task ObjectId guard wiring,
      • canonical rename/move/restore dotted taxonomy wiring,
      • profile-picture TTL helper wiring,
      • fail-closed backend selection behavior.
    • backend/tests/test_documents_file_storage.py expanded from 8 to 14 tests.
  • Documentation updates:

    • SECURITY_AUDIT_SECTIONS.md Section 7 updated with B1/B2 progress bullets.
    • docs/architecture/documents-file-storage-audit-matrix.md updated with B1/B2 implementation status and validation notes.
    • docs/api/README.md updated with Section 7 B1/B2 hardening notes.

Dev validation:

  • ruff check core/api/v1/blob_documents_views.py core/services/blob_storage.py core/services/ops_testing_service.py tests/test_documents_file_storage.py: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_documents_file_storage.py -q: 14 passed.

v0.4.108 - 2026-04-27

Security / Documents & File Storage - Section 7 Phase B0 foundations

  • Added canonical Section 7 upload validator service backend/core/services/document_upload_validator.py:

    • server-side size/extension/MIME validation with signature (magic-byte) checks,
    • active web payload classes (text/html, script, SVG signatures) rejected,
    • canonical MIME selection used by downstream blob writes.
  • Added canonical Section 7 audit emitter service backend/core/services/document_audit_service.py:

    • log_document_event(...) for dotted document taxonomy with one-release dual-write compatibility,
    • log_upload_rejected(...) for rejected upload evidentiary events.
  • Added shared origin-guard service backend/core/services/request_origin_guard.py and hardened proxy trust posture:

    • proxy-header path now fails closed when INTERNAL_PROXY_SECRET is missing outside DEBUG,
    • DEBUG-only bypass retained for local development loops.
  • Expanded Section 7 project documents hardening in backend/core/api/v1/blob_documents_views.py:

    • project document upload now enforces canonical validator before blob write,
    • project mutation routes now apply mutation-origin guard (upload, delete, folder create, file create, content put, restore version, metadata patch, rename, move),
    • canonical dotted document audit events added for upload/update/delete with legacy compatibility keys.
  • Expanded adjacent file-ingress hardening:

    • backend/core/api/v1/task_attachments_views.py upload now enforces canonical validator and upload/delete now enforce mutation-origin guard.
    • backend/core/api/v1/feedback_views.py feedback attachment ingestion now enforces canonical validator and feedback submit now enforces mutation-origin guard.
  • Frontend proxy trust-boundary update:

    • frontend/src/app/api/proxy/[...path]/route.ts now forwards X-Internal-Proxy-Secret when INTERNAL_PROXY_SECRET (or NEXT_INTERNAL_PROXY_SECRET) is configured.
  • Added Section 7 orchestrator/test coverage:

    • new ops suite documents_file_storage in backend/core/services/ops_testing_service.py (runtime posture checks + pytest target),
    • new regression suite backend/tests/test_documents_file_storage.py.
  • Documentation updates:

    • docs/architecture/documents-file-storage-audit-matrix.md now includes Phase B0 implementation status.
    • SECURITY_AUDIT_SECTIONS.md Section 7 updated with shipped B0 foundations and delivered artifacts.
    • docs/api/README.md updated with Section 7 hardening notes and suite wiring.

Dev validation:

  • ruff check core/services/document_upload_validator.py core/services/document_audit_service.py core/services/request_origin_guard.py core/services/__init__.py core/services/ops_testing_service.py core/api/v1/blob_documents_views.py core/api/v1/task_attachments_views.py core/api/v1/feedback_views.py tests/test_documents_file_storage.py: pass.
  • ruff format applied to touched files; ruff check re-run: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_documents_file_storage.py -q: 8 passed.

v0.4.107 - 2026-04-27

Security / Documents & File Storage - Section 7 Phase A complete (audit-only)

  • Added the Section 7 Phase A audit artifact: docs/architecture/documents-file-storage-audit-matrix.md.
  • Documented full Section 7 surface inventory across:
    • blob-backed project documents routes,
    • company documents hub routes,
    • adjacent file ingress surfaces (task attachments, feedback attachments, profile pictures),
    • embed/share-adjacent routes (/api/v1/docs/embed/*),
    • storage adapters (core/blob/blob_service.py, core/services/blob_storage.py),
    • tenant isolation and repo layers (company_db, BlobDocumentsRepo),
    • legacy/orphaned document systems (GridFS docs views/repo and knowledge-centre API module).
  • Locked and recorded Phase A findings: 4 P0, 8 P1, 4 P2 with pass criteria IDs (DF-P0-*, DF-P1-*, DF-P2-*).
  • Highlighted four sign-off blockers for Phase B0 kickoff:
    • inconsistent mutation-origin guard coverage across document mutation routes (DF-P0-1),
    • fail-open proxy-secret posture risk when INTERNAL_PROXY_SECRET is unset (DF-P0-2),
    • MIME trust on client-declared content_type without server-side sniffing/allowlist (DF-P0-3),
    • no dedicated Section 7 regression suite (DF-P0-4).
  • Updated SECURITY_AUDIT_SECTIONS.md Section 7 from Not Started to In Progress, linked the new audit artifact, captured Phase A finding counts, and codified queued B0 foundations (document_upload_validator, document_audit_service, uniform origin-guard posture, documents_file_storage orchestrator suite, test_documents_file_storage.py).
  • Recorded Section 7 product decisions for B-phase planning:
    • retire both legacy GridFS docs surface and orphaned knowledge_centre API module in B3,
    • use magic-byte sniffing + allowlist as canonical MIME policy,
    • treat blob-service consolidation as in-scope P1 work,
    • land profile-picture presigned URL TTL reduction in B2,
    • keep public-share links as an explicit product decision item before any implementation.

Validation: audit/documentation-only update; no runtime code changed and no code-level checks were required for this phase.

v0.4.106 - 2026-04-27

Security / User Profile & GDPR - Section 5 Phase B1 coverage expansion

  • Expanded canonical GDPR export in backend/core/services/gdpr_service.py for multi-company users:

    • export now assembles companies[] payloads per company membership,
    • includes per-company workspace memberships, audit events, document metadata authored/edited by user, comms counts, AI-memory/associate-memory counts, and time-tracking records,
    • computes aggregate domain_status across all companies.
  • Expanded canonical erasure cascade in backend/core/services/gdpr_service.py:

    • Django model cleanup: WorkSession + TimeLogSummary,
    • tenant Mongo cleanup: documents (user-created/edited rows), comms_feed_posts, comms_feed_comments, associate_memory,
    • existing B0 paths retained (token/session cleanup, profile blob delete, comms-message anonymization, notifications, AI memory, central Mongo membership/user cleanup).
  • Strengthened Section 5 Testing Orchestrator runtime checks in backend/core/services/ops_testing_service.py:

    • added checks for multi-company export iteration wiring,
    • added checks for time-tracking cascade wiring,
    • added checks for docs/comms/associate-memory cascade wiring.
  • Expanded Section 5 regression suite in backend/tests/test_user_profile_gdpr.py:

    • added multi-company erasure-request audit-emission coverage,
    • added multi-company export shape/aggregation coverage,
    • added erasure execution cascade coverage for time-tracking + blob deletion + core mongo cleanup markers.
  • Docs updates:

    • docs/architecture/user-profile-gdpr-audit-matrix.md updated with B1 implementation status.
    • SECURITY_AUDIT_SECTIONS.md Section 5 updated with B1 delivered artifacts.
    • docs/api/README.md Section 5 API contract updated for expanded export and cascade behavior.

Dev validation:

  • ruff check core/services/gdpr_service.py core/services/ops_testing_service.py tests/test_user_profile_gdpr.py: pass.
  • ruff format --check core/services/gdpr_service.py core/services/ops_testing_service.py tests/test_user_profile_gdpr.py: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_user_profile_gdpr.py -q: 11 passed.

v0.4.105 - 2026-04-27

Security / Projects & Tasks - Section 6 Phase B0 foundations

  • Added canonical Section 6 project-access wrapper in backend/core/auth/rbac.py:

    • new helper require_project_access(request, *, company_id, project_id, permission, user_id=None)
    • implemented as a stable entry point over existing require_project_role(...) semantics so project/task surfaces can converge on one authorization call signature.
  • Added canonical Section 6 audit emitter service backend/core/services/project_audit_service.py:

    • log_project_task_event(...) for general project/task mutation events,
    • log_task_attachment_uploaded(...),
    • log_task_attachment_deleted(...).
    • Dual-write migration support included: canonical dotted events can be emitted alongside legacy snake_case events with an event_migration payload marker.
  • Expanded Section 6 task-lifecycle audit migration in backend/core/api/v1/views.py:

    • task create/update lifecycle audit writes now route through log_project_task_event(...),
    • canonical dotted events are emitted with legacy dual-write compatibility for:
      • task_created,
      • task_completed,
      • task_status_changed,
      • task_assigned,
      • task_priority_changed.
  • Migrated task attachment route guards to canonical project-access checks in backend/core/api/v1/task_attachments_views.py:

    • TaskAttachmentsUploadView, TaskAttachmentsListView, and TaskAttachmentDeleteView now call require_project_access(...) instead of direct check_project_role(...) calls.
  • Migrated task action manager checks to canonical project-access checks in backend/core/api/v1/task_actions_views.py:

    • TaskReopenView, TaskArchiveView, and TaskUnarchiveView manager authorization now uses require_project_access(..., permission="task:manage").
  • Updated backend/core/api/v1/views.py::_require_project_access_json(...) to delegate default read/edit authorization through require_project_access(...) while retaining compatibility behavior for explicit require_admin=True checks.

  • Expanded Section 6 canonical access migration in backend/core/api/v1/views.py:

    • ProjectsView.post now uses require_project_access(..., permission="project:create") for project-create authorization.
    • ProjectAuditFeedView full-audit-stream admin gate now uses require_project_access(..., permission="task:manage").
  • Expanded Section 6 canonical access migration in adjacent project surfaces:

    • backend/core/api/v1/task_templates_views.py now uses require_project_access(...) across list/create/detail/update/delete/instantiate flows.
    • backend/core/api/v1/automations_views.py now uses require_project_access(...) across list/create/detail/update/delete flows.
    • backend/core/api/v1/updates_views.py post and comment write paths now use require_project_access(...) with explicit post project-context lookup.
    • backend/core/api/v1/messaging_views.py conversation-create authorization now uses require_project_access(...).
  • Expanded legacy route audit migration:

    • backend/projects/api/archive_views.py task archive/unarchive audit writes now route through log_project_task_event(...) with dual-write compatibility (task_archived, task_unarchived).
    • backend/projects/api/reopen_views.py task reopen audit writes now route through log_project_task_event(...) with dual-write compatibility (task_reopened).
  • Wired Section 6 attachment audit events in backend/core/api/v1/task_attachments_views.py:

    • upload emits task.attachment_uploaded (dual-written with legacy task_attachment_uploaded),
    • delete emits task.attachment_deleted (dual-written with legacy task_attachment_deleted),
    • payloads include task/project/attachment context.
  • Added Section 6 orchestrator support in backend/core/services/ops_testing_service.py:

    • new suite key projects_tasks in suite catalog,
    • runtime posture checks (_check_projects_tasks) for helper availability, dual-write marker presence, and attachment route wiring,
    • pytest binding (_check_projects_tasks_pytest) to tests/test_projects_tasks_security.py.
  • Added Section 6 regression suite backend/tests/test_projects_tasks_security.py:

    • verifies require_project_access delegation contract,
    • verifies project audit service dual-write behavior,
    • verifies task attachment views are wired to canonical access helper,
    • verifies task action views are wired to canonical access helper.
    • verifies core task lifecycle audit migration markers are present in core/api/v1/views.py.
    • verifies ProjectsView + ProjectAuditFeedView canonical access usage and legacy /projects/api audit migration wiring.
    • verifies task templates, automations, and updates view canonical access migration wiring.
    • adds behavior assertions for deny-paths on task templates/automations/updates and verifies updates-comment authorization resolves project context from the target post.
    • adds wiring + deny-path behavior assertions for documents and messaging conversation-create canonical access checks.

Security / Projects & Tasks - Section 6 Phase A complete (audit-only)

  • Added the Section 6 Phase A audit artifact: docs/architecture/projects-tasks-audit-matrix.md.
  • Documented the full Section 6 surface inventory across:
    • modern /api/v1 project/task/board/sprint/comment/attachment routes,
    • legacy backend/projects/api routes that remain mounted,
    • websocket/SSE project-linked realtime surfaces,
    • tenant-scoped repos (projects_repo, tasks_repo, comments_repo, blob_documents_repo, audit_repo),
    • AI write paths (backend/ai/associate.py, backend/ai/api/snapshot_review_views.py).
  • Locked and recorded Phase A findings: 3 P0, 7 P1, 3 P2 with pass criteria IDs (PT-P0-*, PT-P1-*, PT-P2-*).
  • Captured Section 6 product decisions for Phase B0 kickoff:
    • audit both route families and plan legacy projects/api retirement in B-phase,
    • consolidate project authorization helpers in B0 before P0/P1 fixes,
    • normalize project/task audit events to dotted taxonomy with one-release dual-write compatibility,
    • keep AI project/task write paths in Section 6 scope.
  • Updated SECURITY_AUDIT_SECTIONS.md Section 6 from Not Started to In Progress, linked the new audit artifact, added finding counts/headline risks, and codified expected B0 foundations (require_project_access consolidation, project_audit_service, projects_tasks orchestrator suite, test_projects_tasks_security.py).

Validation: audit/documentation-only update; no runtime code changed and no code-level checks were required for this phase.

Dev validation (Section 6 B0):

  • ./.venv/bin/python -m ruff check core/auth/rbac.py core/services/project_audit_service.py core/api/v1/task_attachments_views.py core/services/ops_testing_service.py tests/test_projects_tasks_security.py (pass)
  • ./.venv/bin/python -m ruff format core/api/v1/task_attachments_views.py core/services/ops_testing_service.py (applied), then re-ran ruff check (pass)
  • DJANGO_SETTINGS_MODULE=core.settings.dev ./.venv/bin/python -m pytest tests/test_projects_tasks_security.py -q -> 4 passed

Security / User Profile & GDPR - Section 5 Phase B0 foundations

  • Added canonical GDPR service backend/core/services/gdpr_service.py:

    • export_user_data(user) now returns a stable schema (schema_version: v1) with explicit domain coverage markers and emits user.data_exported audit events.
    • request_erasure(user, enqueue_callable) now enforces transactional durability: queue failure rolls back gdpr_erasure_requested_at and returns non-success to callers.
    • execute_gdpr_erasure(user_id) centralizes erasure/anonymization orchestration and is now the Celery execution path.
  • Added canonical passcode service backend/core/services/passcode_service.py:

    • lockout policy: 5 failed attempts in a 15-minute window with 30-minute cooldown,
    • audit events: user.passcode_set, user.passcode_verify_succeeded, user.passcode_verify_failed, user.passcode_locked, user.passcode_verify_blocked.
  • Replaced Section 5 GDPR API handlers with DRF-authenticated views in backend/core/api/v1/gdpr_views.py:

    • all endpoints now use IsAuthenticated,
    • removed csrf_exempt posture for these state-changing routes,
    • removed dependency on header-trust identity extraction path for these endpoints.
  • Updated erasure task wiring in backend/core/tasks.py:

    • gdpr_erasure_task delegates to gdpr_service.execute_gdpr_erasure,
    • queue scheduling uses canonical enqueue_gdpr_erasure_request helper.
  • Added Section 5 orchestrator/test coverage:

    • new ops suite user_profile_gdpr in backend/core/services/ops_testing_service.py (runtime posture checks + pytest target),
    • new regression suite backend/tests/test_user_profile_gdpr.py.
  • Documentation updates:

    • docs/architecture/user-profile-gdpr-audit-matrix.md now includes Phase B0 implementation status against P0/P1 items.
    • SECURITY_AUDIT_SECTIONS.md Section 5 updated with shipped B0 foundations and delivered artifacts.
    • docs/api/README.md updated with Section 5 endpoint contracts and passcode lockout behavior.

Dev validation:

  • ruff check on touched backend files: pass.
  • ruff format --check on touched backend files: pass.
  • DJANGO_SETTINGS_MODULE=core.settings.dev .venv/bin/python -m pytest tests/test_user_profile_gdpr.py -q: 8 passed.

v0.4.104 - 2026-04-27

Security / User Profile & GDPR - Section 5 Phase A complete (audit-only)

  • Added the Section 5 Phase A audit artifact: docs/architecture/user-profile-gdpr-audit-matrix.md.
  • Documented full Section 5 surface inventory (user profile, preferences, sessions, profile picture, GDPR export/erasure, consent, passcode, erasure worker path, and comms GDPR endpoint).
  • Locked and recorded Phase A findings: 3 P0, 7 P1, 3 P2 with pass criteria IDs (UG-P0-*, UG-P1-*, UG-P2-*).
  • Highlighted three sign-off blockers for Phase B0 kickoff:
    • header-trust auth bypass risk in GDPR handlers via get_authenticated_user_id (UG-P0-1),
    • erasure request acknowledgement even when async scheduling fails (UG-P0-2),
    • incomplete Art. 17 cascade across platform stores (UG-P0-3).
  • Updated SECURITY_AUDIT_SECTIONS.md Section 5 from Not Started to In Progress, linked the new audit artifact, added Phase A finding counts, and captured locked B0 product decisions (erasure orchestration contract, export schema direction, passcode lockout baseline, audit retention policy).

Validation: audit/documentation-only update; no runtime code changed and no code-level checks were required for this phase.

v0.4.103 - 2026-04-27

Security / Company & Workspace — Section 4 Phase C complete + Section 5 prep

Section 4 completion

  • Section 4 flipped to Completed. SECURITY_AUDIT_SECTIONS.md updated with full sign-off summary. All three in-scope P0 items (CW-P0-2, CW-P0-3, CW-P0-4) shipped; CW-P0-1 explicitly deferred per the revised email-OTP 2FA product decision (v0.4.99). All 14 P1 items shipped.

  • backend/tests/test_company_workspace.py — 34 SimpleTestCase-based tests covering every Phase B surface. Mock-only, runs in the dev-server orchestrator environment without create-test-database privileges. Coverage:

    • B0 service surface callable (company_security_service + audit_service 15 helpers).
    • B0 defaults / clamp logic for 2FA + session timeout.
    • B1 CW-P0-2 issue_scoped_access_token aligns JWT exp with cookie max_age within 2s clock-slew and both track get_session_timeout_seconds.
    • B1 CW-P0-3 password policy returns canonical {error, rule_errors, messages, policy} payload for short/empty/missing-classes/compliant inputs.
    • B1 CW-P0-3 source-level assertions: all six password endpoints route through the canonical enforcer + emit user.password_changed.
    • B1 CW-P0-4 CompanySecuritySettingsView.update override + _ALLOWED_UPDATE_FIELDS allow-list present; dead CompanySecurityUpdateSchema removed; v1 GET reads PG canonical via _is_2fa_required_safe.
    • B1 CW-P0-4 update_security_settings emits company.security_settings_updated with before/after diff via mocked AuditRepo — verifies payload shape end-to-end without touching Mongo.
    • B2 audit-event wiring presence assertions across all seven audit sites (company detail, logo, profile, member role/remove, workspace update/archive, location CRUD, workspace assignment).
    • B3 workspace read gate checks MembershipRepo + is_active; admin-helper forwarders reference core.auth.utils; three DRF permission classes contain is_active; dead schemas absent; company_db validator accepts canonical UUIDs and rejects injection payloads.
    • B1 seven token-issuing sites confirmed to use issue_scoped_access_token by source-level inspection.
  • Admin Testing Orchestrator company_workspace suite wired (backend/core/services/ops_testing_service.py). 18 runtime posture checks cover the full Section 4 surface (see pytest target for the regression layer). 18/18 runtime + 34/34 pytest cases pass on dev.

  • Fixed: company_db() ordering bug — CW-P1-13 validator was running after get_mongo(), meaning invalid callers hit a slow Mongo connection timeout before seeing the ValueError. Reordered so the UUID-hex check runs before any Mongo interaction. Fail-fast behaviour preserved; test coverage added.

UI follow-up (CW-P0-1 mitigation)

  • frontend/src/components/CompanySettingsModal/CompanySettingsModal.tsx — the company-level "Require Two-Factor Authentication" toggle is now disabled and shows an inline "Coming soon" pill next to the label. Accompanying description clarifies the future email-OTP flow ("When available, each user will opt in to email-based 2FA in their account settings. This company-level policy will then require all members to have 2FA enabled."). Toggle is aria-disabled="true" with a tooltip explaining the deferral. Prevents customers from perceiving the toggle as active policy while the 2FA workstream is built. Closes the only SOC 2 risk introduced by the CW-P0-1 deferral.

Section 5 preparation

  • SECURITY_AUDIT_SECTIONS.md Section 5 entry expanded with full scope inventory (UserProfileAPIView, UserSessionsAPIView, UserPreferencesAPIView, UserProfilePictureAPIView, UserDataExportView, RequestErasureView, AcceptTermsView, SetPasscodeView, VerifyPasscodeView, CustomUser consent/passcode fields, tenant-Mongo cascade surface), known concerns carried from Section 4 handoff (erasure cascade completeness, export payload completeness, IP-address lawful basis, audit PII retention, passcode threat model), Phase A deliverables template, and expected Phase B0 foundations (gdpr_service, passcode_service, user.gdpr_erasure_* audit events).

Dev validation: ruff check + ruff format --check clean on all touched files. Pytest target executes 34 cases in ~5s on dev. Orchestrator runtime checks execute in <200ms. No Mongo / Redis / external-service dependency in either the runtime checks or the pytest target.

v0.4.102 - 2026-04-27

Security / Company & Workspace — Section 4 Phase B2 + B3 (all P1 items)

B2 — Audit trail (CW-P1-2, P1-3, P1-4, P1-5, P1-6, P1-7, P1-14)

Seven previously-silent mutations now emit structured AuditRepo events via the core.services.audit_service helpers introduced in Phase B0. Every helper swallows exceptions via logfire.exception, so audit-pipeline outages cannot break a primary business operation.

  • CW-P1-2 CompanyDetailView (backend/companies/api/views.py:47) — perform_update + perform_destroy overrides emit company.updated (with a targeted before/after diff over company_name, description, industry, website) and company.deleted.
  • CW-P1-3 CompanyLogoUploadView (backend/companies/api/views.py:72) — emits company.logo_updated with {previous_url, new_url} after the successful save.
  • CW-P1-4 CompanySettingsAPIView.patch (backend/core/api/v1/company_settings_views.py:568) — emits company.profile_updated with a targeted before/after diff limited to the keys actually changing, plus changed_fields list. Uses the generic log_company_mutation helper.
  • CW-P1-5 CompanyMemberDetailView (backend/core/api/v1/company_management_views.py:988,1071) — patch emits company.member_role_changed only when the role genuinely differs (no spam on no-op PATCHes); delete emits company.member_removed with the member email.
  • CW-P1-6 CompanyWorkspaceDetailView (backend/core/api/v1/company_management_views.py:1355,1401) — patch emits workspace.updated with before/after over name, description, icon, color; delete (archive) emits workspace.archived.
  • CW-P1-7 / CW-P2-b LocationViewSet (backend/companies/api/views.py:256,265,276) — perform_create/update/destroy emit company.location_created/updated/deleted; update carries a before/after diff over name + address + country. Existing logfire.info calls retained for local-dev signal.
  • CW-P1-14 CompanyMemberWorkspaceAssignmentView.post (backend/core/api/v1/company_management_views.py:1416) — now computes added_workspace_ids and removed_workspace_ids as set differences over the old vs new assignment, then emits one workspace.member_added or workspace.member_removed per workspace per operation. Membership deltas are visible in the audit trail for SOC 2.

B3 — Defence-in-depth hardening (CW-P1-9, P1-10, P1-11, P1-12, P1-13)

  • CW-P1-9 Workspace read gate — CompanyWorkspaceDetailView.get (backend/core/api/v1/company_management_views.py:1338) previously allowed any same-tenant user to read arbitrary workspace metadata even without being a member of that workspace. Now requires one of: active superuser, company admin/owner (check_company_admin), or explicit workspace membership in MembershipRepo.list_user_workspaces (or an all_access row). Aligns with the project-level gate pattern.
  • CW-P1-10 DRY admin helpers — the two remaining duplicate admin checks in backend/core/api/v1/company_settings_views.py (tuple-returning check_company_admin at :306 and inline _is_company_admin on CompanySessionsAPIView) are now thin forwarders to the canonical core.auth.utils.check_company_admin. The tuple wrapper preserves its (has_permission, reason) contract for local callers while delegating the actual authorization decision. Closes the last divergent admin-check sites in the section-4 surface; Section 3 B3 already consolidated company_management_views.py:401.
  • CW-P1-11 Superuser + is_active guard — all three DRF permission classes in backend/companies/api/permissions.py (IsCompanyMemberOrAdmin, IsCompanyAdminManagerOrOwner, IsCompanyAdminOrOwner) now require is_superuser AND is_active for the bypass. Deactivated or compromised superuser accounts fall through to the normal membership/role checks.
  • CW-P1-12 Dead-code removal — TransferWorkspaceSchema (backend/core/api/v1/company_management_views.py:118) had zero call-sites anywhere in the backend. Removed with an inline comment preserving the historical context. Module docstring line "transfer" also dropped.
  • CW-P1-13 company_db() format validator — backend/core/storage.py:71 now rejects any company_id that doesn't normalise to 32 lowercase hex characters (^[0-9a-f]{32}$). Injection-style payloads ("; drop database"), non-UUID strings, and uppercase-hex variants all raise ValueError before Mongo is touched. Current in-tree callers all derive from PostgreSQL UUID columns so this validator is defence-in-depth only; it eliminates the theoretical "future accidental caller creates co_foo; drop Mongo DB" risk Phase A flagged.

Section 4 sign-off status

All three remaining P0 items (CW-P0-2, CW-P0-3, CW-P0-4) shipped; CW-P0-1 explicitly deferred per the revised 2FA product decision (v0.4.99). All 14 P1 items shipped (CW-P1-1 was closed implicitly by CW-P0-4 in v0.4.100; CW-P1-8 was closed by the password-policy slice in v0.4.99). P2 items: P2-a + P2-d remain open (CI tenant-isolation rule and hardcoded "Starting Point" workspace name — neither is security-critical and both are tracked as future hardening). P2-b + P2-c closed alongside their P1 counterparts. P2-e partially mitigated by the new company_db validator; URL-pattern tightening deferred (large-scope URL-pattern change across many callers).

Dev validation: ruff check + ruff format --check clean on all eight touched files. Import-sanity smoke via django.setup() confirms every touched endpoint class loads. Behavioural smoke:

  • _COMPANY_ID_PATTERN accepts canonical 32-hex UUIDs and rejects injection payloads, short/long strings, and uppercase variants.
  • check_company_admin and _is_company_admin both contain the canonical-forwarder code path.
  • All three DRF permission classes contain the is_active guard.
  • TransferWorkspaceSchema confirmed absent from module namespace.
  • get_session_timeout_seconds(None) + issue_scoped_access_token round-trip from the prior slice still passes.

End-to-end DB-backed validation of the audit-event writes deferred to Phase C on the dev server (local dev DB has no seeded companies; local Mongo not running).

v0.4.101 - 2026-04-27

Security / Company & Workspace — Section 4 Phase B1 (CW-P0-2)

  • CW-P0-2 Session timeout now enforced end-to-end. CompanySecuritySettings.session_timeout_minutes was previously a cosmetic field — declared, serialized, UI-writable, but never read by any auth path. Django's SESSION_COOKIE_AGE and SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"] unconditionally overrode it. It is now the single source of truth for per-company session length.
  • New helper core.services.company_security_service.issue_scoped_access_token(refresh, company_id) -> (access_token_str, max_age_seconds) takes a RefreshToken, mutates its access_token.exp claim to now + get_session_timeout_seconds(company_id), and returns the JWT string plus the matching cookie max_age. Clamp floor is 300s (5 min) to prevent accidental lockout from mis-configured values.
  • Seven backend call-sites wired:
    • backend/users/api/views.py:162 — CustomAuthToken (password login).
    • backend/users/api/views.py:406 — signup auto-login path.
    • backend/users/api/views.py:680 — RefreshTokenView (token refresh now cannot silently extend session beyond policy).
    • backend/core/api/v1/auth_views.py:461 — magic-link exchange set-cookie redirect.
    • backend/core/api/v1/auth_views.py:810 — SelectTenantView (uses the newly-selected tenant's policy, not the pre-select company).
    • backend/core/api/v1/invitation_views.py:574 — invitation-accept auto-login.
    • backend/core/api/v1/setup_account_views.py:313 — setup-account complete auto-login.
    • backend/users/api/magic_link_views.py:452 — magic-link verify (tokens handed off through exchange cache; access-token exp scoped at generation).
  • Frontend cookie alignment (frontend/src/app/api/auth/set-cookie/route.ts): the Next.js POST + GET handlers that set auth_token now decode the JWT's exp claim and compute maxAge = exp - now (clamped 300s–24h). The browser cookie lifetime therefore tracks whatever the backend issued regardless of which endpoint minted the token. Replaces the previous hardcoded maxAge: 43200 / expiresIn: 43200 values. Helper getAccessTokenMaxAge(accessToken, fallbackSeconds) falls back gracefully if the token is malformed.
  • Net effect: a company setting session_timeout_minutes=30 now sees 30-minute JWTs and 30-minute cookies across every login path. A company setting it to 480 gets 8-hour sessions. The prior 1h in prod / 24h in dev Django-level override is superseded per-company.
  • Dev validation: ruff check + ruff format --check clean on all seven touched Python files + core/services/* + __init__.py. Import-sanity smoke via django.setup() confirms all seven endpoint classes load. Unit-level smoke of issue_scoped_access_token with an anonymous RefreshToken confirms the returned max_age equals the JWT exp - now to within a 2-second clock-slew tolerance and equals get_session_timeout_seconds(None) (3600s default). End-to-end browser-cookie validation deferred to Phase C orchestrator suite.

v0.4.100 - 2026-04-27

Security / Company & Workspace — Section 4 Phase B1 (CW-P0-4 + CW-P1-1 + CW-P2-c)

  • CW-P0-4 Dual-store collapse. CompanySecuritySettingsView.update (backend/companies/api/views.py:190) now routes every PATCH (and PUT) through core.services.company_security_service.update_security_settings(...) instead of DRF's default serializer.save(). The service writes PG first (canonical), mirrors every changed field into Mongo Company_Profile.settings as a best-effort read-cache, and emits a company.security_settings_updated audit event with a before/after diff. An _ALLOWED_UPDATE_FIELDS allow-list inside the view guards against any future serializer surface-area creep. PUT/PATCH continue to return the refreshed serialized row so existing clients are unaffected.
  • CW-P0-4 GET alignment. v1 CompanySettingsAPIView.get (backend/core/api/v1/company_settings_views.py:534) now reads require_2fa via new _is_2fa_required_safe(company_id) helper, which delegates to core.services.company_security_service.is_2fa_required(...). Previously the GET returned whatever was sitting in Mongo Company_Profile.settings.require_2fa — which could drift arbitrarily from the PG canonical. The helper fails closed (returns False) on any read error so the API never raises on a read-path regression.
  • CW-P1-1 Audit trail for security-settings PATCH. Now implicit in CW-P0-4: every security-settings write emits company.security_settings_updated with {changed_fields: [...], diff: {field: {before, after}}} via AuditRepo. SOC 2 gap on the most security-relevant setting is closed.
  • CW-P2-c Dead-code removal. Legacy CompanySecurityUpdateSchema (declared at company_settings_views.py:255, zero call-sites anywhere in the backend) removed. Inline comment documents the removal and points to the canonical write path for future readers.
  • Backfill command. New python manage.py backfill_security_settings_mirror [--dry-run] [--company <uuid>] iterates existing CompanySecuritySettings rows, reads each tenant's current Company_Profile.settings, and writes the canonical PG values only where the Mongo mirror drifts. Idempotent; safe to run repeatedly; emits one log line per company that needed a write. --dry-run reports would-be changes without writing.
  • Dev validation: ruff check + ruff format --check clean on all three touched files. Import-sanity smoke via django.setup() confirms: view override present (update + _ALLOWED_UPDATE_FIELDS), dead CompanySecurityUpdateSchema gone, _is_2fa_required_safe returns False for unknown companies without raising. End-to-end DB-level validation of update_security_settings round-trip deferred to Phase C on the dev server (local dev DB has no companies seeded).

v0.4.99 - 2026-04-27

Product Decision — 2FA scope revised

  • CW-P0-1 deferred out of Section 4. The originally locked Phase A decision called for soft-enforce 2FA (login response flag + audit event) now and full TOTP enrolment later. That decision has been revised: the 2FA system itself has not been built yet, so there is no per-user enrolment state for the soft-enforce flag to check against, which makes the intermediate step meaningless. Future 2FA design is email-OTP: a per-user opt-in toggle in account settings; when enabled, login emails a 6-digit code that the user enters to complete sign-in. enforce_2fa at the company level will then mean "every user in this company must have their per-user toggle on". Implementation lives in its own 2FA workstream, separate from Section 4.
  • is_2fa_required(company_id) stays in core.services.company_security_service ready to be consumed by the future workstream.
  • UI follow-up: company-level enforce_2fa toggle in CompanySecuritySettings admin UI must be hidden or marked "coming soon" until the 2FA workstream lands, so customers don't mistake it for active policy.
  • docs/architecture/company-workspace-audit-matrix.md and SECURITY_AUDIT_SECTIONS.md Section 4 pass criteria both updated to reflect the deferral. Section 4 sign-off now requires three of four P0 items (CW-P0-2, CW-P0-3, CW-P0-4) + the full P1 sweep.

Security / Company & Workspace — Section 4 Phase B1 (CW-P0-3 + CW-P1-8)

  • CW-P0-3 Password policy enforced across every post-provisioning password flow. All six endpoints now call core.services.company_security_service.enforce_password_policy_for_user(user, password) before set_password(...), replacing the prior Django-only validate_password check that silently ignored CompanySecuritySettings (min length + character-class rules). Policy violations return the canonical Section 3 payload {error: "password_policy_violation", rule_errors: [...], messages: [...], policy: {...}} so the frontend can highlight each failed rule.
    • backend/users/api/views.py:604 — ResetPasswordView (/api/users/reset-password/).
    • backend/users/api/views.py:1247 — ChangePasswordView (/api/users/me/change-password/).
    • backend/users/api/views.py:1454 — SetInitialPasswordView (authenticated magic-link users adding a password).
    • backend/users/api/views.py:1508 — SetInitialPasswordViaTokenView (legacy admin-provisioning set-initial-by-token flow).
    • backend/core/api/v1/user_settings_views.py:669 — UserForcePasswordChangeAPIView (/api/v1/user/force-password-change).
    • backend/core/api/v1/user_settings_views.py:731 — v1 SetInitialPasswordView (/api/v1/user/set-initial-password).
  • CW-P1-8 Credential-event audit trail. Every password write now emits a user.password_changed event to AuditRepo via core.services.audit_service.log_password_changed(...), carrying {method, ip_address} where method is one of reset | change | set_initial | set_initial_via_token | force_change. Failures to write audit events are captured via logfire.exception and never break the business-logic response (best-effort mirror pattern consistent with Section 3 B3).
  • Unused validate_password and DjangoValidationError imports removed from both modules now that all sites route through the canonical policy enforcer.
  • Dev validation: ruff check + ruff format --check clean on both touched files. manage.py-free import-sanity smoke confirms all six endpoint classes load post-edit. Direct call to enforce_password_policy_for_user with ('short', 'NoNumbersAtAll', 'Compliant123Password', '') returns the expected rule-error sets (['min_length', 'require_uppercase', 'require_number'], ['require_number'], [], ['missing']) and produces the canonical response payload shape.

v0.4.98 - 2026-04-26

Security / Company & Workspace — Section 4 Phase B0 (foundations)

  • New module backend/core/services/company_security_service.py introducing the canonical loader + writer for CompanySecuritySettings:
    • is_2fa_required(company_id) — reads enforce_2fa from PG (source of truth); defaults to False when the row is missing. Prerequisite for CW-P0-1.
    • get_session_timeout_seconds(company_id) — reads session_timeout_minutes, converts to seconds, clamps at 300s minimum; defaults to 3600s. Prerequisite for CW-P0-2.
    • enforce_password_policy_for_user(user, password) — derives company_id from the user's active company membership and delegates to the existing onboarding_security.enforce_password_policy helper. Canonical entry point for all password-change flows. Prerequisite for CW-P0-3.
    • update_security_settings(company_id, actor_id, **fields) — atomic PG write, before/after diff, company.security_settings_updated audit event, best-effort mirror into Mongo Company_Profile.settings. Prerequisite for CW-P0-4.
  • New module backend/core/services/audit_service.py with log_company_mutation(...) generic helper + fifteen convenience wrappers for the P1 audit gaps identified in Phase A (company.updated, company.deleted, company.logo_updated, company.member_role_changed, company.member_removed, workspace.updated, workspace.archived, workspace.member_added, workspace.member_removed, company.location_created/updated/deleted, user.password_changed, company.two_factor_warning). All helpers swallow AuditRepo failures via logfire.exception so audit-pipeline outages never break the business-logic response.
  • core/services/__init__.py exports the public symbols for direct import.
  • No view wiring in B0 — Phase B1 consumes these services.

v0.4.97 - 2026-04-26

Fixed

  • Fixed dashboard tenant-proxy forwarding for login/personal-dashboard bootstrap by targeting the canonical backend route GET /api/v1/auth/my/tenants/ (trailing slash) from frontend/src/app/api/dashboard/my-tenants/route.ts.
  • This removes avoidable redirect behavior on the Next.js server-side fetch path and keeps auth context stable when loading tenant/company data immediately after sign-in.
  • Hardened frontend session guard behavior in frontend/src/lib/auth.ts so transient backend/network failures (5xx/transport errors) during checkAuth() no longer force an immediate logout redirect to /login.
  • checkAuth() now only returns unauthenticated on explicit auth failures (401/403 after refresh retry), preventing false logout loops right after magic-link sign-in when backend services are briefly warming/restarting.
  • Updated magic-link cookie handoff page (frontend/src/app/api/auth/set-cookie/route.ts) to initialize last_activity before redirect, preventing the inactivity guard from interpreting a fresh sign-in as an expired idle session.

v0.4.95 - 2026-04-24

Security / Testing — Section 3 Phase C + Completion

  • New pytest target backend/tests/test_onboarding_invitations.py — 18 SimpleTestCase-based tests covering every Phase B surface: B0 token hashing (determinism, HMAC keying, round-trip), B0/B1 password policy (short, missing classes, compliant, empty, payload shape), B1 legacy accept endpoints (/api/v1/auth/invitations/accept/ + /api/invitations/accept/{token}/) returning 410, B2 rate-limit middleware registration + pattern-keyed bucket guarantee, B2 SelectTenantView source-level regression guard, B2 anonymous invitation-accept email binding ordering (email check before atomic claim), B3 check_company_admin / check_company_owner forwarders, B3 invite audit event wiring. All tests use mocks + SimpleTestCase so they run in the dev-orchestrator environment without create-test-database privileges.
  • Admin Testing Orchestrator onboarding_invitations suite wired — 11 runtime checks covering helper imports, HMAC keyed hash, password-policy enforcer, rate-limit middleware installed, onboarding buckets registered, legacy v1/auth endpoint 410, legacy PG endpoint 410, SetupAccountCompleteView atomic claim, SelectTenantView legacy-fallback removal, invite lifecycle audit events, and check_company_admin forwarder. The suite also executes the pytest target via _check_onboarding_invitations_pytest. 11/11 runtime + 18/18 pytest cases pass on dev.
  • Section 3 Completed — SECURITY_AUDIT_SECTIONS.md flipped to Completed. All 4 P0 items shipped. 13 of 15 P1 items shipped; ON-P1-6 / ON-P1-7 (email-outbox migration for CompanyMemberInviteView + CompanyProvisionUserView) explicitly deferred as a follow-up because it requires EmailDeliveryOutbox template wiring beyond Section 3 scope; the delivery path itself remains functional.

v0.4.94 - 2026-04-24

Security / Onboarding — Section 3 Phase B3 (DRY + audit)

  • ON-P1-8 check_company_admin consolidation — the duplicate implementations of check_company_admin and check_company_owner that lived in backend/core/api/v1/company_management_views.py:401 (predating the Section 2 B0 consolidation) are now thin forwarders to core.auth.utils. Removes ~95 lines of divergent logic and closes a subtle drift in legacy-role handling. Callers across the module continue to use the local names; behaviour now matches the rest of the codebase, including superuser bypass logging.
  • ON-P1-13 Invite lifecycle audit events — CompanySendInvitationView.post and InvitationDetailView.delete now write company.invitation_sent and company.invitation_revoked events to AuditRepo. Paired with the existing company.invitation_accepted write in InvitationAcceptView, this provides the complete SOC 2 audit trail for invite create → revoke / accept transitions. Failures to write audit events are captured via logfire.exception without breaking the business-logic response.

Deferred to B4 / follow-up

  • ON-P1-6 / ON-P1-7 Email outbox migration — migrating CompanyMemberInviteView (deprecated _safe_send_mail) and CompanyProvisionUserView (raw send_mail) onto EmailDeliveryOutbox requires template wiring for CompanyInvitationEmail / AccountCreatedEmail beyond the immediate Section 3 scope. Tracked as a separate follow-up and noted in docs/architecture/onboarding-invitations-audit-matrix.md.

v0.4.93 - 2026-04-24

Security / Onboarding — Section 3 Phase B2 (P1 token + auth fixes)

  • ON-P1-1 / ON-P1-9 Rate limits — RateLimitMiddleware is now actually installed in settings.MIDDLEWARE (previously defined but unwired) and new buckets were added: /api/v1/invitations (30/hr/IP), /api/v1/setup-account (30/hr/IP), /api/v1/auth/signup (5/hr/IP). Middleware now keys cache buckets by matched pattern instead of full request path, fixing a pre-existing bug where each unique token produced its own bucket and effectively disabled throttling for brute-force token enumeration. Verified on dev: invitation requests start 429ing at req 31, signup at req 6.
  • ON-P1-2 Atomic setup-token claim — SetupAccountCompleteView.post now performs an affected-row=1 update on set_password_token_claim_at__isnull=True before completing setup. Two concurrent requests for the same token see exactly one 200 and one 409 (Setup link is already being processed). Verified with a parallel curl race on dev.
  • ON-P1-3 SelectTenant legacy FK fallback removed — /api/v1/auth/select-tenant/ no longer accepts the legacy user.company_id FK match when CompanyMembership.status != ACTIVE. Mirrors the Section 2 ON-P0-1 fix in access_scope.resolve_access_scope. Offboarded users with stale legacy columns now get a 403 instead of a tenant-scoped JWT. Verified on dev (403 with User is not an active member of this company).
  • ON-P1-4 Anonymous invitation-accept email binding — POST /api/v1/invitations/{token}/accept/ now requires the caller to echo the invited email in the request body even on the anonymous signup path. Email validation runs before the atomic claim so a mismatch does not strand the invitation in the processing state (previously a subtle stuck-invitation bug). Frontend accept-invitation/[token] page now posts body.email = invitation.email. Verified on dev: missing email → 403, wrong email → 403, invitation still pending, matching email completes 200.
  • ON-P1-11 Invitation hash-preferred lookups — InvitationDetailView (GET / DELETE) and InvitationAcceptView (POST), plus SetupAccountDetailView / SetupAccountCompleteView, now query token_hash (HMAC-SHA256) first and fall back to plaintext token during the Phase B rollout window. All new invitations created via AuthRepo.create_invitation dual-write token_hash; plaintext column is kept for the in-flight invitations until a future backfill removes it in B4. Dev smoke confirms both hash-first hits and plaintext fallback hits resolve correctly.

v0.4.92 - 2026-04-24

Security / Onboarding — Section 3 Phase B1 (P0 fixes)

  • ON-P0-1 Setup-account password policy (backend/core/api/v1/setup_account_views.py:140): replaced the hardcoded len(password) >= 8 check with core.services.onboarding_security.enforce_password_policy(company_id, password). Responses now return 400 with a structured {error: "password_policy_violation", rule_errors: [...], messages: [...], policy: {...}} payload so the frontend can highlight each failed rule. Default policy (no per-company override) is min 12 + upper + lower + number. Token lookup still runs first so password-policy responses never leak whether a token is valid.
  • ON-P0-2 Provisioning temp password removed (backend/core/api/v1/company_management_views.py:1952): CompanyProvisionUserView no longer mints a temporary password nor returns it in the API response. The sole credential-handoff path is now the setup-account token emailed directly to the user; send_credentials is effectively always true. Response fields temporary_password, setup_url, warning are removed. Per SOC 2 / GDPR credential-handling controls, plaintext passwords never live in HTTP responses, browser state, or logs.
  • ON-P1-10 Setup-token lifetime reduced from 168h (7 days) to 48h in the provisioning flow. Expired links can be regenerated by an admin via resend-invite.
  • ON-P0-3 Legacy AcceptInvitationView (backend/core/api/v1/auth_views.py:187) retired. Endpoint now returns 410 Gone with a migration payload pointing clients at the canonical POST /api/v1/invitations/{token}/accept/. This removes the X-User-Id-trusting path that had no invited-email match and could be used to accept any pending invitation as an arbitrary user_id.
  • ON-P0-4 Legacy PG InvitationAcceptView (backend/companies/api/views.py:295) retired. Endpoint at /api/invitations/accept/{token}/ now returns 410 Gone with the same migration payload. Removes the parallel PG CompanyInvitation acceptance surface that had no rate limit, no atomic claim, no hashed token storage.
  • Dev validation: manage.py check clean; curl smoke confirms both legacy endpoints return 410, nonexistent setup-token returns 404 (no leakage via policy response), weak passwords return 400 with rule_errors, policy-compliant password completes with 200.

v0.4.91 - 2026-04-24

Security / Onboarding — Section 3 Phase B0 (foundations)

  • New module backend/core/services/onboarding_security.py introducing the canonical primitives that the rest of the Section 3 hardening will build on:
    • hash_token(plaintext) -> str and verify_token(plaintext, stored) — HMAC-SHA256 keyed by settings.SECRET_KEY, so a DB-only compromise cannot be used to hijack pending invitations / setup tokens (addresses ON-P1-11, ON-P1-12, ON-P1-15).
    • generate_token(n_bytes) — returns (plaintext, hash) so callers persist only the hash and transmit plaintext only in outgoing email.
    • enforce_password_policy(company_id, password) — loads CompanySecuritySettings (default min length 12, require upper/lower/number) and returns a structured PasswordPolicyResult with per-rule error keys + human messages (prerequisite for ON-P0-1).
    • consume_single_use_setup_token(plaintext) — atomic affected-row=1 claim that mirrors the invitation's find_one_and_update flow and eliminates the setup-complete race (ON-P1-2). Dual-reads hash + plaintext during the rollout window.
  • CustomUser model — added set_password_token_hash (unique, indexed) and set_password_token_claim_at fields; generate_set_password_token now writes both hash and plaintext. Plaintext column retained during the dual-read rollout; scheduled for removal in Phase B4 after backfill.
  • AuthRepo.create_invitation — dual-writes token_hash alongside the existing plaintext token in the Mongo invitations collection. Plaintext is still returned to the caller for embedding in the outgoing email; lookups will migrate to hash-preferred in B2.
  • Migration users.0010_set_password_token_hash — additive schema change, reversible, does not touch the existing plaintext column.
  • No behaviour changes yet: call sites still use plaintext lookups; B1 onwards will switch over.
  • Dev validation: ruff clean; migration applied cleanly; shell smoke run confirms hash determinism, HMAC keying, policy enforcement (missing / min_length / require_uppercase / require_number / happy-path), and empty-token rejection path in consume_single_use_setup_token.

v0.4.90 - 2026-04-24

Security / Audit

  • Section 3 Phase A complete — Onboarding & Invitations audit. See docs/architecture/onboarding-invitations-audit-matrix.md for the full finding list with file_path:line references and pass criteria.
  • Scope covered: primary Mongo invitation pipeline (/api/v1/invitations/*, /api/v1/setup-account/*, /api/v1/companies/{id}/members|provision|invitations|join-requests/*), legacy PG + /api/v1/auth/invitations/* paths, signup, tenant selection, frontend onboarding pages and proxies.
  • Phase A findings: 4 P0, 15 P1, 8 P2. No cross-tenant data leaks reachable. Risks concentrated in SOC 2/GDPR controls (provisioning temp password returned in API response, password-policy bypass on setup-account, unhashed tokens at rest, missing rate limits on primary token endpoints, legacy X-User-Id-trusting accept endpoint still routable, duplicate PG invitation-accept surface still routable at /api/invitations/accept/{token}/).
  • Product decisions locked: legacy accept endpoints → return 410; provisioning setup-token expiry → 48h; all onboarding tokens → hashed at rest (HMAC-SHA256); provisioning → always email setup link, no plaintext password in responses.
  • SECURITY_AUDIT_SECTIONS.md Section 3 flipped to In Progress with onboarding_invitations as the orchestrator suite key and explicit pass criteria listed.
  • No code changes this commit — audit-only.

v0.4.89 - 2026-04-24

Fixed

  • POST /api/v1/ai/analyze-task/ no longer escalates request-validation failures into HTTP 500 responses when Pydantic error context includes non-JSON-serializable exception objects (for example ValueError inside ctx).
  • Validation error details are now normalized to JSON-safe structures before JsonResponse, so invalid inputs (such as blank due_date) correctly return HTTP 400 with VALIDATION_ERROR details.
  • Create Task Assist executive snapshot no longer displays provider model identifiers to end users.
  • Removed legacy Suggested Title and Suggested Description cards from Create Task Assist detailed view to avoid duplicate recommendation surfaces with rename variants and description re-alignment.
  • Subtask Report panel in Task Modal now follows the executive-snapshot + expandable-details pattern used across updated task-intelligence agents, including staged loading context and prioritized execution summary.
  • Subtask Report details are reordered for higher actionability (recommended subtasks and dependency actions first, then blockers/strengths/recommendations) while preserving one-click apply flows and Docs Hub report save/open actions.
  • Fixed magic-link request sync failures caused by non-string Mongo user fields (name/email) during Django-user sync normalization; sync now safely coerces values before .strip() operations.
  • Removed duplicated Step 2 user-sync block in MagicLinkRequestView to keep the request flow single-pass and reduce duplicate error paths/log noise.
  • Upgraded Subtask Verify in Task Modal to the executive-snapshot + expandable-details UX pattern with staged loading context, clearer readiness framing, and high-signal top insight/split/dependency summary.
  • Added richer verification context plumbing (parent_task_status, parent_task_progress, parent_task_start_date, parent_task_due_date, existing_subtasks[]) from Task Modal -> Next proxy -> /api/v1/ai/verify-subtask/ -> verifier agent prompt context for stronger sequencing/dependency recommendations.
  • Added verification apply actions: one-click Apply Title + Description and one-click Create Split Subtasks from split recommendations, with immediate task save persistence behavior aligned to existing subtask actions.
  • Fixed task-activity proxy path for POST /api/dashboard/tasks/{taskId}/activity to target backend trailing-slash route (/api/v1/tasks/{taskId}/activity/), preventing APPEND_SLASH redirect failures that surfaced as 500/502 during subtask report save/activity writes.
  • Repositioned subtask rewording as a secondary control in Task Modal (Quick Polish) to reflect its narrower scope (wording-only rewrite) while keeping Subtask Verify as the primary quality/dependency/split workflow.

Security / Testing

  • Section 2 Phase C — Authorization & RBAC regression suite landed.
  • New pytest target backend/tests/test_rbac_authorization.py — 15 SimpleTestCase-based tests covering: consolidated RBAC helper imports, role alias normalization, unauthenticated fail-closed paths for all three require_* helpers, P0-1 removed-member fallback regression, P1-1 Presence Redis namespace, P1-2 FeedbackRepo scoping, P1-9 check_project_role project binding for member/admin, and P0-2 AI endpoints returning 401 anonymously. All tests run without a create-test-database capable Postgres role (compatible with the dev-server orchestrator environment).
  • Admin Testing Orchestrator auth_rbac suite upgraded from 2 callable-exists checks to 10 runtime checks (helpers, DRF permission classes, normalize aliases, check_project_role project binding, guard callables, ProjectsRepo.is_member/list_for_user, Presence/Feedback scoping) plus the pytest target via _check_auth_rbac + _check_auth_rbac_pytest. 10/10 runtime checks pass on dev; 15/15 pytest cases pass.
  • Section 2 Completed — SECURITY_AUDIT_SECTIONS.md updated. All 3 P0, 25 P1 items resolved across Phase B; P1-23 (manager project scope) explicitly deferred per product decision. P2 hardening items landed in B4.

v0.4.88 - 2026-04-24

Security / Internal

  • Section 2 Phase B4 — P2 hardening: consolidation + Mongo index guard.
  • P2-a The five duplicated _require_company_membership helpers across core/api/v1/views.py, meetings_views.py, calendar_views.py, task_actions_views.py, and workspace_analytics_views.py are now thin forwarders to the canonical core.auth.rbac.require_company_membership. Call-sites stay identical; future behavior changes (logging, caching, stricter fallback) now land in exactly one place. companies/api/views.py::_require_company_membership is architecturally distinct (DRF object-level permission resolver) and intentionally left unchanged.
  • P2-q AuthRepo.__init__ now ensures a unique index on users.email in the central Mongo database, so future email-based lookups (used by the auth path and by resolve_access_scope) cannot accidentally pick up a collision. Idempotent; swallows failures so index creation never blocks startup.

v0.4.87 - 2026-04-24

Security

  • Section 2 Phase B3 (batch 2) — presence + feedback repo tenant scoping.
  • P1-1 PresenceRepo Redis keys are now namespaced by company_id (presence:{company_id}:user:{user_id} etc.). Knowing another tenant's project/workspace/user/session UUID no longer allows reading presence or session data cross-tenant. get_company_online_count now reads the per-company presence:{company_id}:online set in O(1) instead of scanning every key in Redis DB 3. Legacy unscoped reads are preserved as a fallback during rollout. PresenceService and all HTTP + consumer call-sites now pass company_id; chat/api/presence_views.py, chat/consumers/presence_consumer.py, and core/api/v1/company_settings_views.py (force-logout) updated.
  • P1-2 FeedbackRepo(company_id=...) now injects company_id into every list/get filter and stamps it on every create. The submit endpoint (feedback_views.py:266) uses the scoped form so no endpoint can surface another tenant's feedback through crafted query filters. The cross-tenant admin view (AleskoFeedbackListView) intentionally uses the unscoped variant and is separately gated by is_superuser/is_staff.

v0.4.86 - 2026-04-24

Security

  • Section 2 Phase B3 (batch 1) — WebSocket hardening and infrastructure P1s.
  • P1-5 ChatConsumer — per-message TOCTOU bypass closed. handle_send_message, handle_message_read, handle_reaction_broadcast, handle_typing_start, handle_typing_stop now reject any conversation_id the socket has not previously joined via chat.join_conversation (where membership is verified). This brings the WebSocket path to parity with the HTTP MessageViewSet.create 403 gate; a valid JWT can no longer persist messages, reactions, or read-receipts for conversations the user is not a participant in.
  • P1-6 ChatConsumer.connect — verify workspace membership via MembershipRepo.has_workspace_access, closing the gap where any authenticated socket could claim an arbitrary workspace_id at connect and pollute that workspace's presence/event groups. Matches PresenceConsumer parity.
  • P1-7 MeetingConsumer._check_access — before the board:view short-circuit fires, verify that the meeting's project_id matches the one the client supplied in the query string. Previously a user with board:view on project A could attach ?project_id=A to a meeting scoped to project B within the same tenant.
  • P1-8 channels_middleware.py — WebSocket auth hardening:
    • Only AccessToken is accepted; refresh_token cookie fallback removed (resource access via refresh tokens is not denylist-checked and was inconsistent with the HTTP auth class).
    • Redis jwt_denylist:access:{jti} entries are now honored on connect, matching HTTP.
    • Narrow exception handling replaces the previous catch-all. All auth failures (invalid token, denylisted, missing user_id, user not found, DB error) are logged at WARNING with a reason code for SOC 2 auditability.
  • P1-3 ProjectsRepo.list_for_user(user_id) — new Mongo-indexed query that returns every non-deleted project the user is a member or lead of, with no result cap. resolve_access_scope now uses it in place of the capped list(limit=500) call, fixing the silent access loss for members on tenants with >200 projects.

v0.4.85 - 2026-04-24

Security

  • Section 2 Phase B2 (batch 2) — authorization-layer P1 finishers.
  • P1-14 projects/api/views.py — three direct request.user.company_role not in allowed_roles checks (project create/update/delete) now go through normalize_company_role, closing case-sensitivity and watcher/contractor alias divergence.
  • P1-24 project_creation_ai.py::ProjectCreateWithAIView.post reads tenant from JWT claim only (not the X-Tenant-Id header) and gates on require_company_role('owner','admin','manager'). ProjectCreationProgressView.get now requires an authenticated user + active company membership.
  • P1-25 comms/tasks.py — removed broken int(project_id) cast on a UUID field that rendered the project-name lookup dead while also bypassing company scoping.

v0.4.84 - 2026-04-24

Security

  • Section 2 Phase B2 (batch 1) — authorization-layer P1 findings.
  • P1-9 check_project_role now honors its project_id parameter. For project-scoped permission keys (project:*, task:*, document:*, board:*), non-admin roles must be explicit project members before the check passes; company owners/admins/managers still have company-wide authority. Closes the long-standing gap where any member could write to any project in their company.
  • P1-4 backend/projects/api/snapshot_views.py — project lookup is now scoped by the authenticated user's company in the query itself, collapsing the 404-vs-403 enumeration oracle that distinguished "project exists in another tenant" from "does not exist".
  • P1-21 / P1-22 AI endpoints (ai/api/views.py, ai/api/snapshot_review_views.py) now gate on scope.has_any_access() immediately after resolve_access_scope, and on scope.is_read_only() for mutation-equivalent paths. billing-only users no longer leak AI policy summaries; viewer/contractor/guest/watcher roles cannot trigger project health-report generation even when listed as project members.
  • P1-16 task_checklist_views.py — preflight/postflight/toggle/delete handlers now gate on require_project_role('task:update'|'task:delete'). The DELETE handler no longer skips user_id entirely.
  • P1-17 forms_views.py — all list/detail/submission endpoints now require authentication and verify project membership before exposing fields or accepting submissions.
  • P1-18 updates_views.py — read endpoints (posts, post detail, comments, reactions) require authentication, and verify project membership when a post is project-scoped. Reactions POST additionally gates on task:update for the post's project.
  • P1-19 core/api/v1/snapshot_views.py::ProjectSnapshotView.get now gates on require_project_role('board:view').
  • P1-10 email_test_views._is_authorized restricted to Django is_staff/is_superuser, @alesko.ai email, or shared-secret header. Previously any authenticated user could trigger test-email blasts.
  • P1-11 _require_mutation_origin_guard (blob_documents_views.py) now validates X-Internal-Proxy: 1 against INTERNAL_PROXY_SECRET; an unverified header is rejected with 403 rather than bypassing CSRF.
  • P1-12 ops_views._has_ops_access tightened to superuser OR owner/admin of the caller's own company. The manager grant is removed and client-supplied company_id query parameters are no longer used for authorization (only for scoping the data view).
  • P1-13 AleskoFeedbackListView restricted to Django is_staff/is_superuser; the @alesko.ai email, dashboard-password, and arbitrary company_id query parameter paths have been removed.

v0.4.83 - 2026-04-24

Security

  • Section 2 Phase B1 — all three P0 findings resolved.
  • P0-1 backend/core/auth/access_scope.py now rejects the legacy CustomUser.company_id/company_role fallback when no ACTIVE CompanyMembership exists. Users whose membership had been moved to removed/suspended no longer silently retain access via stale legacy columns; access revocation via CompanyMembership.status is now the single source of truth. Superuser bypass is preserved and logged at INFO for SOC 2 audit.
  • P0-2 backend/core/api/v1/ai_views.py — all four AI endpoints (/ai/verify-subtask/, /ai/review-task/, /ai/subtask-report/, /ai/reword-subtask/) now require a valid access token; company_id is taken from JWT claims only (no longer accepted from the request body), and review-task additionally requires the caller to be an eligible project member via require_project_role("task:update"). Unauthenticated requests now return HTTP 401 instead of silently driving AI flows against arbitrary tenants.
  • P0-3 backend/core/api/v1/company_settings_views.py::CompanyMembersAPIView.get now requires active company membership before returning the member roster. The previous implementation allowed any authenticated user to enumerate names, emails, and roles of any company by iterating company_id in the URL.

v0.4.82 - 2026-04-24

Security / Internal

  • Section 2 (Authorization & RBAC) Phase B0 — foundations. Added consolidated RBAC helpers in backend/core/auth/rbac.py:
    • require_company_membership(request, company_id) — drop-in replacement for the six duplicated _require_company_membership helpers (PG CompanyMembership-aware, superuser bypass logged).
    • require_company_role(request, company_id, *roles) — company-role gate with alias normalization.
    • require_project_role(request, company_id=, project_id=, required=) — closes the long-standing check_project_role gap where project_id was accepted but never used; non-admin roles must now be explicit project members for project-scoped permissions (project:*, task:*, document:*, board:*).
    • DRF permission classes: IsCompanyMember, HasCompanyRole.of('owner', 'admin', ...), IsCompanyAdmin, IsCompanyAdminOrManager.
    • company_role_required(*roles) decorator for function-based views.
  • Expanded normalize_company_role alias table (core/services/company_membership_service.py): watcher and read_only → viewer, billing_only → billing, worker → member. Single source of truth for role normalization.
  • Added ProjectsRepo.is_member(project_id, user_id) — fail-closed project-membership lookup covering members, member_ids, and project_lead_id fields.
  • No behavior changes for existing call-sites; migration to the new helpers is staged in follow-up B1/B2/B3 patches.

v0.4.81 - 2026-04-24

Security

  • Completed Phase A of Section 2 (Authorization & RBAC) of the production security audit. Read-only discovery across all 40 core/api/v1/* view modules, 25 Mongo/Postgres repos, Channels consumers, resolve_access_scope/check_project_role/check_company_admin helpers, and JWT/cookie/WebSocket auth paths. No code changes.
  • Produced docs/architecture/rbac-audit-matrix.md with endpoint × role matrix, helper inventory, WebSocket parity analysis, cross-tenant isolation review, and a ranked findings register.
  • Headline results: 3 P0 items (removed-member fallback in access_scope, unauthenticated ai_views.py endpoints, open CompanyMembersAPIView GET), 25 P1 items (Chat WS TOCTOU, presence Redis key namespace, feedback repo tenant scope, check_project_role ignoring project_id, ~15 endpoints missing role/scope checks), ~20 P2 hardening items. No cross-tenant data leak reachable via current HTTP routes (physical per-tenant Mongo DB isolation holds).
  • Updated SECURITY_AUDIT_SECTIONS.md with Section 2 Phase A completion, Phase B/C pass criteria, and authorization_rbac orchestrator-suite key.

v0.4.80 - 2026-04-24

Fixed

  • Hardened POST /api/v1/ai/review-task/ against transient model output-schema validation failures (for example Exceeded maximum retries (1) for output validation).
  • The review endpoint now returns HTTP 200 with a structured fallback review (fallback: true, conservative health/risk guidance, and diagnostic detail) instead of bubbling a backend 500, preventing Task Modal review from hard-failing during LLM validation incidents.
  • Added explicit warning + usage metering error code (review_output_validation_fallback) so these degraded responses remain observable without breaking user flow.
  • Added pre-validation coercion in TaskReview schema to parse JSON-encoded string payloads for nested object/list fields, so provider outputs that stringify progress_insights / timeline_analysis no longer fail strict output validation.
  • Fixed stale AI review leakage in Task Modal: switching/closing tasks now invalidates in-flight review requests and clears review state so Task A insights can no longer render on Task B.

Changed

  • Refined Task Modal Associate review presentation to better suit Bedrock-speed responses: the panel now opens with an executive snapshot (health posture, top focus, primary risk, critical next step, generation metadata) and moves the full detailed analysis behind an explicit expand/collapse control, reducing wall-of-text overload while preserving full diagnostic depth on demand.
  • Upgraded Task Modal review loading UX from a generic spinner to a staged skeleton experience with rotating "thinking" status messages (context read, risk mapping, executive build, action prioritization), so fast Bedrock responses still feel intentional and progress-visible while analysis is running.
  • Loading-stage messaging now references live task context (task title/status) during review generation so the wait state feels grounded in the specific work item being analyzed.
  • Polished expanded review layout typography/spacing for consistency with the executive card style and moved Suggested Subtasks to the top of expanded details so recommended execution breakdown is immediately visible.
  • Applied the same executive snapshot + expandable detailed-analysis pattern to Create Task Assist (/api/dashboard/ai/analyze-task/), including matching staged skeleton loading, cleaner detail typography, and faster high-signal readout for creation-time guidance.
  • Expanded Create Task Assist with pre-create execution helpers: title rename variants, structured description re-alignment preview/apply, auto dependency suggestions from project task context (with confidence + reasoning), and duplicate/overlap warnings before task creation.

v0.4.79 - 2026-04-24

Changed

  • EC2 dev-server sync helpers gain a --rebuild-clean mode that rebuilds images and wipes the named dep volumes (bluprint_frontend-node-modules, bluprint_frontend-next, bluprint_backend-node-modules) before docker compose up -d. Use this when requirements.* or package.json changes, because the compose file mounts those named volumes over /app/node_modules and /app/.next and a normal --rebuild leaves the pre-upgrade volume contents in place — producing runtime failures like Cannot find module '@tailwindcss/postcss' even after a clean image build.
  • scripts/sync-dev.sh now warns (non-fatal) when backend/requirements.*, backend/Dockerfile*, frontend/package*.json, or frontend/Dockerfile.dev has been modified since its last successful sync, nudging the operator toward --rebuild-clean.
  • Both scripts' --help, the deployment doc (docs/operations/deployment.md), and the mode cheat-sheet updated to describe the new mode.

v0.4.78 - 2026-04-24

Changed

  • Hardened the EC2 dev-server deploy helpers in scripts/ now that the canonical dev target is the AWS EC2 monolith (docker-compose.dev-server.yml).
    • scripts/sync-dev.sh and scripts/dev-server-git-sync.sh now:
      • Run under set -euo pipefail and fail fast if the SSH key is missing.
      • Accept EC2_HOST, SSH_KEY, and REMOTE_DIR env overrides instead of a hardcoded configuration.
      • Support three modes: --restart (default, mirror of prior behaviour), --up (docker compose up -d for compose-file edits), and --rebuild (rebuild backend+frontend images and up -d — needed whenever Dockerfiles, requirements.*, or the Python/Node base versions change).
      • Restart the full service set (backend daphne celery celery-beat frontend); celery-beat was previously missing from the restart list so scheduled tasks would keep running stale code.
      • Protect host-only state via rsync excludes (.pytest_cache, .ruff_cache, .mypy_cache, coverage/, *.log, logs/, tsconfig.tsbuildinfo, backend/.env.dev.backup*, backend/staticfiles/, .DS_Store). Quoted glob patterns so shells cannot pre-expand them.
    • scripts/dev-server-git-sync.sh additionally refuses to run if the server-side working tree is dirty (instead of silently losing changes on git checkout/pull).

Removed

  • scripts/staging_diag.py. Azure-era wrapper around az containerapp exec against bp-backend-staging in the korali-aue-stg-rg resource group; superseded by running the audit_rbac management command directly inside the EC2 container (docker compose exec backend python manage.py audit_rbac ...).
  • Stale "Azure AKS Deployment" block in docs/operations/deployment.md; replaced with the current EC2 dev-server instructions and a note that infra/azure/ remains as historical reference only.

v0.4.77 - 2026-04-24

Changed

  • Migrated Task Intelligence Pydantic agents off direct xAI/Grok wiring to shared Associate STANDARD provider resolution, aligning analyze/review/subtask/time-estimate flows with Bedrock-first runtime routing (ASSOCIATE_STD_PROVIDER, ASSOCIATE_STD_MODEL_ID) and defaulting to Nemotron Super (nvidia.nemotron-super-3-120b) where configured.
  • Updated task-intelligence API handlers to stop hard-gating on XAI_API_KEY; health/status metadata now resolves from Associate STANDARD provider configuration instead of legacy Grok constants.
  • Updated API/architecture/deployment docs to reflect Bedrock-backed Task Intelligence routing and runtime model source of truth.
  • Migrated backend/ai/associate_mongo.py from direct Grok provider initialization to shared Associate STANDARD provider resolution.
  • Reworked Associate document-analysis tools (get_document_insights, compare_documents, ask_document) to use provider-routed STANDARD model execution instead of direct AsyncOpenAI xAI client calls and API-key checks.
  • Updated snapshot-review health/metadata model reporting to resolve provider-configured model IDs instead of legacy hardcoded Grok model labels.
  • Hardened frontend server-side auth/proxy backend URL fallbacks (env.SERVER_API_URL, /api/proxy/*, /api/auth/refresh) to prefer internal container targets (Daphne) instead of localhost, preventing login/magic-link 401 loops and password-login 404s caused by backend host mismatch.
  • Added temporary diagnostic logging for failed magic-link exchange in frontend/src/app/api/auth/set-cookie/route.ts to surface upstream status/target URL during auth incidents.

Changed

  • Bumped backend Python runtime from 3.12 / local 3.13.2 to Python 3.14.3 (latest stable).
    • backend/Dockerfile and backend/Dockerfile.dev: base image python:3.12-slim → python:3.14-slim.
    • backend/pyproject.toml: requires-python >=3.12 → >=3.14, [tool.ruff].target-version = "py314", [tool.mypy].python_version = "3.14".
    • Recompiled backend/requirements.txt with --python-version 3.14.
    • Rebuilt local backend/.venv on 3.14.3 and resynced; confirmed python manage.py check passes and the Auth & Sessions pytest suite passes (aside from the one case that requires a live Redis).
    • Ruff re-checked clean against the new py314 target.

v0.4.76 - 2026-04-24

Changed

  • Backend dependency upgrade sweep:
    • Django 5.2.11 → 6.0.4 (major). Renamed all models.CheckConstraint(check=...) usages to models.CheckConstraint(condition=...) in app models (billing_and_payments/models.py, companies/models.py) and in existing migrations (companies/migrations/0006_company_membership.py). The check= keyword was deprecated in Django 5.1 and removed in 6.0.
    • djangorestframework 3.16.1 → 3.17.1.
    • pydantic 2.12.5 → 2.13.3 (and pydantic-core 2.41.5 → 2.46.3).
    • celery 5.6.2 → 5.6.3, django-celery-beat 2.8.1 → 2.9.0.
    • Refreshed floor pins in backend/requirements.in to current majors (redis>=7.1, pymongo>=4.16, logfire[django]>=4.22, uvicorn[standard]>=0.40, gunicorn>=25, ruff>=0.15, pytest>=9.0, pytest-cov>=7.0, black>=26.1, mypy>=1.19, Pillow>=12.0, django-redis>=6.0, psycopg2-binary>=2.9.11) and recompiled backend/requirements.txt.
    • Verified python manage.py check passes on Django 6 and the Auth & Sessions test suite (backend/tests/test_auth_session_security.py) passes aside from one case that requires a live Redis instance.
  • Frontend dependency upgrade sweep:
    • tailwindcss 3.4.x → 4.2.4 (major). Migrated via the official @tailwindcss/upgrade codemod: tailwind.config.ts removed (custom brand/purple palette and gradient-radial background-image moved to a CSS-first @theme block in src/app/globals.css), @tailwind base/components/utilities replaced with @import 'tailwindcss';, postcss config switched to @tailwindcss/postcss plugin, and autoprefixer removed (bundled by Tailwind 4). Deprecated v3 utility aliases in 16 files were rewritten by the codemod (e.g., bg-gradient-to-br → bg-linear-to-br). A v3-compatibility shim preserves default border color semantics.
    • typescript 5.x → 6.0.3 (major). Removed the deprecated baseUrl from tsconfig.json (TypeScript 6 warns and will stop honouring it in 7.0); path aliases via paths alone continue to work.
    • eslint-config-next 15.5.14 → 16.2.4 (major). Migrated eslint.config.mjs from the legacy FlatCompat.extends("next/core-web-vitals") bridge to the new native flat configs: eslint-config-next/core-web-vitals + eslint-config-next/typescript.
    • @types/node ^20 → ^22 (aligns with Node 22 LTS).
    • date-fns 3.6.0 → 4.1.0 (major; no call-site changes needed for current usage).
    • lucide-react 0.545.0 → 1.9.0 (1.0 is a stability marker; icon API compatible).
    • react-markdown 9.x → 10.1.0 (no call-site changes needed for current usage).
    • Verified tsc --noEmit is clean and next build succeeds on the full project.
  • Held back: ESLint is pinned at 9 rather than 10 because eslint-config-next@16 transitively depends on an eslint-plugin-react version that does not yet support ESLint 10's rule-listener API (breaks on Components.componentRule). Revisit when either eslint-plugin-react or eslint-config-next publish an ESLint 10-compatible release.

v0.4.75 - 2026-04-24

Fixed

  • Admin Home Overview business-metrics endpoint no longer crashes on import/runtime due to missing Decimal import and a shadowed timezone symbol (datetime.timezone vs. django.utils.timezone) in backend/core/api/v1/ops_views.py. Django's timezone import is now aliased (django_timezone) and Decimal is explicitly imported.
  • Admin CRM panel no longer fails to compile. CRMContainer.tsx was referencing an undefined module-scope addPerson in AddPersonModal's prop typing and using PersonSource without importing it. Replaced with an explicit AddPersonInput type alias and added PersonSource to the @/lib/crm/types import.
  • Associate chat hook (useAssociateChat.ts) no longer fails TypeScript compilation: planRevealTimer, tokenFlushFrame, and streamFinalized are now declared before the try block so the matching catch cleanup path can reach them.
  • Onboarding setup modal (OnboardingSetupModal.tsx) StepCompletion type now includes the project key to match its actual usage in stepCompletion state and the step-completion guards.

Changed

  • Lifted CRM state into a provider (@/lib/crm/context). CRMContainer now wraps inner tabs with <CRMProvider> and each tab consumes the shared store via useCRM(), so adds/edits/deletes in People, Companies, and NPS immediately reflect across Dashboard, Analytics, and NPS views instead of each tab maintaining an isolated snapshot.
  • Migrated NPS responses off direct localStorage reads/writes onto the storage.ts helper layer (getNPSResponses/saveNPSResponse/deleteNPSResponse) for consistency with People/Companies/Follow-ups. Storage key (crm_nps_responses_v1) is preserved, so existing server-side data is read as-is.
  • Relaxed NPSResponse.companyId to optional to match the current admin UX, which keys NPS records by free-text company name until company entities are linked.
  • Replaced approximate 30-day revenue bucketing in AdminBusinessOverviewAPIView with calendar-aware month buckets ([month_start, next_month_start)), eliminating month-drift and duplicated/skipped labels near month boundaries.

Security

  • Hardened auth/tenant trust boundaries by removing proxy forwarding of user-supplied company_id/tenant_id query params into internal tenancy headers (X-Company-Id / X-Tenant-Id) and by making backend authenticated company resolution JWT-claim first before header fallback.
  • Reduced token exposure in browser login flow by removing token echo payload (tokens.access/tokens.refresh) from frontend /api/login response body while keeping HttpOnly cookie issuance.
  • Improved logout/session revocation by denylisting presented access tokens (jwt_denylist:access:{jti}) on logout and preserving refresh-token blacklisting.
  • Strengthened password policy enforcement by applying Django password validators in reset/change/force-password/set-initial flows.
  • Expanded post-password-change protection by revoking outstanding refresh tokens and active Django sessions after password reset/change and initial password set.
  • Tightened middleware auth signal to rely on auth_token cookie only (removed sessionid fallback) for route gating decisions.

Changed

  • Updated API docs (docs/api/README.md) to reflect new proxy tenancy-header behavior and current trusted-forwarding contract.
  • Added Section 1 Auth & Sessions test coverage in the admin Testing Orchestrator via a new active release-blocking suite (auth_sessions) that continuously verifies JWT-vs-header company precedence, access-token denylist writes, password-validator coverage hooks, proxy tenancy-header hardening, login token-echo removal, and middleware auth-cookie signal policy.
  • Extended auth_sessions suite to execute backend pytest target(s) (currently backend/tests/test_auth_session_security.py) so admin-run suite status is a single source-of-truth gate for Section 1 readiness.
  • Added backend regression tests for Auth & Session security hardening (backend/tests/test_auth_session_security.py) and a root tracker document for audit section continuity (SECURITY_AUDIT_SECTIONS.md).
  • Updated architecture feature-flow mapping to include Auth & Sessions security checks in the admin Testing Orchestrator scope.

v0.4.74 - 2026-04-22

Changed

  • Dev-server credential isolation for upcoming Bedrock migration: switched Docker/backend MinIO credential wiring from global AWS vars to storage-scoped env keys (S3_STORAGE_ACCESS_KEY_ID, S3_STORAGE_SECRET_ACCESS_KEY) so EC2 instance-role credentials can be used by runtime AWS SDK clients without MinIO overrides.
  • Updated dev-server storage settings/services to read new storage-scoped keys with backward-compatible fallback to legacy AWS env names.
  • Updated operations docs and runbooks with EC2 Bedrock-auth guidance and storage-vs-runtime credential separation notes.
  • Switched Associate provider routing to env-driven provider/model config for both tiers and enabled Bedrock-backed defaults on dev server (ASSOCIATE_STD_PROVIDER=bedrock, ASSOCIATE_MAX_PROVIDER=bedrock) with Sydney model IDs (nvidia.nemotron-super-3-120b, moonshotai.kimi-k2.5).
  • Updated Associate agent bootstrap to resolve default runtime model via provider registry instead of hardcoded XAI Grok initialization.
  • Updated architecture/deployment docs to reflect Bedrock-ready STD/MAX routing and provider configuration variables.
  • Updated Associate per-request model override handling so both standard and max lanes resolve fresh provider models per request (fixes intermittent standard-lane credential/provider drift in long-lived dev processes).
  • Updated dev-server frontend proxy target to Daphne (SERVER_API_URL=http://daphne:8001) to stabilize async SSE streaming/event-loop behavior for Associate chat.
  • Refined Associate sidebar auto-scroll behavior to stop forcing bottom-lock during gradual manual upward scrolling.
  • Fixed occasional duplicate final assistant rendering in Associate streaming by hardening client-side stream finalization and token flush timing around done events.
  • Updated Associate UX flow to delay plan card reveal with a short planning phase (Planning execution...) so responses feel less abrupt and more polished before content streams in.
  • Added lightweight premium planning presentation in Associate (ThinkingStream) with staged plan-step reveal, tool chips, and shimmer skeleton placeholders during active planning.
  • Added client-side response pacing in Associate streaming so token reveal feels more natural (especially on fast Bedrock completions) instead of dumping full replies instantly.

Fixed

  • Fixed Comms WebSocket Channels group-name failures after Daphne/ASGI routing updates by switching user/conversation/feed/workspace-presence groups to deterministic short hashed identifiers under the Channels 100-character limit.
  • Aligned websocket publishers and notification push paths (comms views/tasks, core notifications, docs/calendar/meetings/task attachments, mention parser) to use shared hashed group-name helpers so realtime fanout consistently reaches connected clients.
  • Reduced project-board time-tracking request bursts that were triggering 429 responses by de-duplicating client timer sync loops (useTimer sync cooldown + in-flight coalescing, removal of cross-component timer event ping-pong) and tightening board active-timer polling guards (single in-flight fetch, minimum interval, and temporary cooldown after 429).
  • Split backend time-tracking throttling by endpoint intent so frequent read polling (sessions/active, active-timers) no longer competes with mutation budgets (sessions/start, sessions/stop, audit writes), improving timer stability during board/project load.

Fixed

  • Fixed Project tab snapshot status aggregation so tasks saved as in_progress are counted as in-progress work instead of falling back to todo in project snapshot metrics.
  • Fixed stale Project tab behavior after Board mutations by wiring board task changes (move/save/force-complete/delete/archive) to emit snapshot refresh signals consumed by the Project overview page for immediate re-fetch.
  • Hardened project snapshot response cache behavior with no-store headers to reduce stale snapshot payload reuse across navigation hops.
  • Fixed navbar View Changelog modal loading failures by moving changelog JSON delivery to a non-/api app route (/changelog-data) so middleware/auth proxy behavior no longer blocks changelog rendering.
  • Fixed dev-server Nginx admin routing so /admin/login, /admin/management, and /admin/performance resolve to the Alesko Next.js admin console instead of Django admin, restoring Jared/Denis credential flow (Alesko2026$) for the internal admin panel.
  • Fixed admin-console post-login redirect loop by exempting /admin/login, /admin/management, and /admin/performance from generic app middleware auth/onboarding redirects that previously sent valid admin sessions back to /login.
  • Fixed an additional admin console bounce-to-login issue by treating /admin/* as public for global activity-tracker wiring, preventing the shared session checker from auto-logging out admin routes during initial mount.

Changed

  • Updated feature-flow documentation to reflect board-driven project snapshot refresh signaling in the Task Management flow.

v0.4.73 - 2026-04-20

Added

  • Added canonical PostgreSQL company membership foundation via new CompanyMembership model (backend/companies/models.py) with explicit role/status lifecycle, uniqueness constraints, and query indexes to support true multi-company users.
  • Added migration backend/companies/migrations/0006_company_membership.py to create companies_companymembership and backfill membership rows from legacy users_customuser.company_id + company_role mappings.
  • Added backend/core/services/company_membership_service.py with normalized role helpers and active-membership lookup checks for phased route-derived authz migration.
  • Added multi-tenant implementation blueprint doc docs/architecture/multi-tenant-roadmap.md covering backend, websockets, Redis, frontend context UX, and notifications behavior.

Changed

  • Updated docs/api/README.md tenant/company context section to document PostgreSQL membership as the new canonical multi-tenant foundation and compatibility posture during migration.
  • Updated docs/architecture/feature-flows.md to include the multi-tenant context and membership roadmap flow ownership across frontend, API, and backend auth/services.
  • Implemented Phase 2 auth pivot in backend auth paths:
    • backend/core/auth/utils.py now prioritizes PostgreSQL CompanyMembership checks for project/company authorization before legacy user-company fallback.
    • backend/core/auth/access_scope.py now derives scope company role from active membership first.
    • backend/core/auth/token_generator.py now prefers active membership role for token claims when available.
    • backend/core/api/v1/auth_views.py (my/tenants, select-tenant) now validates and resolves active company memberships, enabling multi-company tenant listing/selection with compatibility fallback.
  • Implemented initial Phase 3 route/request-derived context hardening:
    • notifications endpoints in backend/core/api/v1/views.py now prefer explicit request company context (X-Company-Id or company_id) before JWT fallback.
    • workspace analytics/activity endpoints in backend/core/api/v1/workspace_analytics_views.py now enforce explicit/request company context and membership validation.
  • Added Phase 2 regression tests for membership-first auth behavior in backend/tests/test_multi_tenant_phase2.py.
  • Expanded Phase 3 route-derived tenancy hardening to task actions, calendar, and meetings API families:
    • backend/core/api/v1/task_actions_views.py
    • backend/core/api/v1/calendar_views.py
    • backend/core/api/v1/meetings_views.py These now prefer explicit request company context and enforce membership-aware company access checks.
  • Implemented initial Phase 4 websocket isolation hardening by introducing company-scoped group naming and membership validation across realtime surfaces:
    • backend/comms/consumers/chat_consumer.py
    • backend/meetings/consumers/meeting_consumer.py
    • backend/chat/consumers/presence_consumer.py
    • backend/chat/services/presence_service.py
    • plus aligned websocket publishers in comms/core notification push paths.
  • Added explicit company-context unit coverage in backend/tests/test_multi_tenant_phase2.py.
  • Updated realtime regression and frontend socket handling for the new tenancy isolation contract:
    • updated chat consumer feed-group test expectation in backend/tests/test_chat_consumer_feed_security.py to company-scoped feed channel naming.
    • updated frontend websocket hooks (frontend/src/hooks/usePresence.ts, frontend/src/hooks/useCommsWebSocket.ts) to treat close code 4004 (membership denied) as non-retry auth failure.
  • Fixed Company Dashboard People access gating for multi-tenant users in frontend/src/app/company/[companyId]/dashboard/page.tsx:
    • admin/manager role checks now prefer the active company role from fetchTenants() for the current route company instead of legacy single-company user.company_role fallback.
    • restores Invite/Provision actions for users who are admin/owner in the selected company but not in the legacy primary company field.

v0.4.72 - 2026-04-19

Fixed

  • Fixed task reopen 500 errors when moving a task out of done after completion by normalizing completed_at parsing in the /api/v1/tasks/{task_id}/reopen/ handler.
  • Reopen time-limit checks now safely handle legacy/naive completed_at values (including ISO strings without timezone offsets) by coercing them to UTC before date math.
  • Improved company dashboard People management invite UX in frontend/src/app/company/[companyId]/dashboard/components/PeopleManagementModal.tsx so the Invite action now surfaces validation feedback, supports Enter-to-submit from the email field, and prevents ambiguous no-op clicks when email is empty.
  • Refined People list metadata styling by replacing the default No title pill with cleaner inline job-title text to remove visual clutter in the member list.
  • Added a People modal Provision User flow in company dashboard so owner/admin users can create full member profiles (email, first name, last name, role, job title) and trigger setup-email onboarding via /api/v1/companies/{company_id}/provision/.

v0.4.71 - 2026-04-17

Fixed

  • Restored /index as the canonical public landing page route with full landing content rendering directly at frontend/src/app/index/page.tsx.
  • Updated root route behavior so / now always redirects to /index, preventing split landing behavior across two routes.
  • Updated middleware routing to remove the legacy /index -> / normalization, so bluprint.alesko.online/index is the stable homepage.
  • Hardened landing dark/light mode toggle behavior by persisting the selected mode in browser localStorage and restoring it on load.
  • Updated landing logo links (navbar and footer) to target /index, eliminating unnecessary route hops back to the canonical landing URL.

v0.4.70 - 2026-04-16

Fixed

  • Updated landing Usage wallet pricing copy to fixed values with no About wording:
    • Associate chat: $0.01 (unchanged),
    • Project document: $0.05,
    • Health report / Gantt analysis: $0.03.
  • Replaced login-page top-left Bluprint text label with the light-mode (2) brand logo asset.

v0.4.69 - 2026-04-16

Fixed

  • Restored the full marketing landing page on / after the routing change that moved the page to /index.
  • Added compatibility routing so /index now redirects back to / instead of hosting a separate landing implementation.
  • Updated landing header/footer logo links to use / so navigation no longer depends on /index.

v0.4.68 - 2026-04-16

Changed

  • Updated landing-page routing so / now redirects to /index, and moved the interactive landing page entrypoint to /index.
  • Updated landing header/footer logo links to target /index to match the new canonical landing route.

v0.4.67 - 2026-04-16

Changed

  • Refined landing-page Pricing structure and copy:
    • merged standalone How it works guidance into the Usage wallet card,
    • removed the separate pricing How it works block and related in-section link,
    • moved pricing terms/fine-print into a dedicated row between the top pricing cards and workload-benefit cards,
    • widened the pricing section container for improved horizontal balance on desktop.
  • Updated landing-page pricing language to match fixed pricing:
    • changed table header from Typical cost (wallet) to Typical cost,
    • changed Associate chat typical price from About 1 cent to $0.01,
    • updated onboarding line to Get $10 in credits instantly on company account creation.
  • Simplified landing hero CTAs by removing See how it works.
  • Updated landing footer branding and navigation:
    • switched footer logo to use the same dark/light (2) mode-specific assets as the navbar,
    • removed Philosophy from footer Product links.

v0.4.66 - 2026-04-15

Added

  • Added EC2 dev server infrastructure for rapid iteration:
    • Single t3.large instance on Amazon Linux 2023 with Docker, PostgreSQL 16, Nginx, and Certbot.
    • docker-compose.dev-server.yml running frontend, backend, Daphne, Celery, Redis, MongoDB, and MinIO.
    • Hot-reload dev mode via volume mounts (next dev, Django runserver).
    • Nginx reverse proxy with WebSocket support and Let's Encrypt SSL for bluprint.alesko.online.
    • scripts/sync-dev.sh for one-command rsync from local machine to EC2.
    • scripts/dev-server-git-sync.sh for git-pull based updates on the server.
    • backend/core/settings/dev_server.py and backend/.env.dev-server for dev-server-specific configuration.

Fixed

  • Fixed Next.js dev-mode CSP error on the dev server by adding 'unsafe-eval' to script-src in next.config.ts, resolving broken signup page buttons and HMR.
  • Fixed Docker Compose plugin version mismatch on Amazon Linux 2023 by installing Compose v2.35.0.

Security

  • Dev server uses console email backend so no real emails are sent; all emails are logged to container stdout.
  • Secrets isolated in .env.dev-server on the EC2 host, not committed to git.

v0.4.65 - 2026-04-15

Fixed

  • Fixed Onyx Kimi reasoning model tool-call failures caused by missing reasoning_content in assistant messages with tool_calls in conversation history. Added reasoning_content preservation across turns by:
    • extending ChatMessageSimple and AssistantMessage models with a reasoning_content field,
    • populating it from ToolCall.reasoning_tokens when building chat history from the database,
    • threading it through _build_structured_assistant_message and the LLM loop so subsequent turns include the required reasoning block for Moonshot/Kimi thinking models.

Changed

  • Replaced landing-page pricing tiers with a usage-based pricing layout in Pricing:
    • new two-panel structure (Beta offer + Usage wallet) with shared-wallet explanation,
    • added concrete usage cost examples aligned to seeded wallet pricebook values,
    • added a workload-based Only pay when you work strip for spend variability clarity,
    • added an in-section How it works explainer anchor and beta-credit policy notes.
  • Refined landing Pricing onboarding and copy:
    • replaced closed-beta Express Interest header CTA with sign-up-now messaging,
    • renamed Beta offer to Welcome offer,
    • updated top-up language to Top up as required with explicit $20 minimum top-up terms note,
    • removed decorative icons from Usage wallet header and workload strip, and center-aligned workload strip text.
  • Finalized landing Pricing visual polish:
    • centered the workload-summary sentence,
    • renamed top and bottom CTAs to Get started,
    • removed light-mode CTA button shadows,
    • normalized dark-mode pricing text treatment to white for readability consistency.
  • Removed the landing-page Our Build Philosophy section from the homepage flow to keep focus on feature and pricing narrative.
  • Updated landing navbar dark/light logo assets to temporary (2) variants for A/B visual preview.
  • Refined landing Philosophy pillar row dividers to use thin vertical separators between columns only (removed extra top/edge divider lines).

v0.4.64 - 2026-04-14

Fixed

  • Fixed Personal Dashboard Announcements tab timeline handling so announcement duration windows are enforced in heartbeat data:
    • announcements now drop from the feed after pinned_until expires (24h / 48h / 7d),
    • legacy announcement records without pinned_until remain visible for backward compatibility.
  • Fixed Personal Dashboard Daily Brief language so announcements are treated as informational updates by default and are no longer framed as needs attention blockers without explicit urgency signals.
  • Fixed Associate task assignment self-identity handling so requests like assign it to me resolve to the authenticated chat user instead of prompting for member identity.
  • Fixed Associate staging commit support for complete_subtask and add_comment_to_task so accepted staged changes now apply correctly.
  • Fixed Associate complete_subtask task resolution for ObjectId-backed task IDs in project chat flows.
  • Fixed Associate tool trace reliability so tool calls that return { "success": false } are reported as failed in tool_usage.
  • Fixed Associate complete_subtask runtime path to use async Mongo access correctly (resolves object dict can't be used in 'await' expression errors).
  • Fixed usage-metering resilience by adding inline persist/charge fallback when Celery enqueue fails, so wallet billing still records tool usage without an active worker.
  • Fixed usage dashboard visibility gap by adding raw usage_events aggregation fallback in usage APIs when usage_rollups_daily is missing/stale.
  • Fixed Associate add_comment_to_task task resolution so non-ObjectId task references (task-title inputs) no longer fail early with Invalid task ID before fallback matching.
  • Fixed Project Usage tab filtering to avoid passing stale workspace scope from local storage, so project-level AI usage metrics render reliably for the active project.
  • Fixed Company Dashboard AI Usage & Cost panel to consume live usage endpoints (company/projects/users) instead of placeholder text.
  • Fixed Navbar Changelog modal API to avoid hard failure when docs/CHANGELOG.md is unavailable in runtime environments by returning a safe fallback payload.
  • Changed Company Settings Billing tab UI to a simplified operational layout:
    • removed the non-actionable free-plan summary card,
    • added focused controls for Balance, Top Up, and Manage Auto Top Up,
    • added a Usage (Last 30 Days) total derived from wallet charge ledger entries.

Added

  • Added heartbeat announcement window regression tests for active/expired/legacy/naive-datetime cases.
  • Added Daily Brief language guardrail regression tests for announcement phrasing normalization.

Changed

  • Added explicit Logout actions on admin console surfaces (/admin/management and /admin/performance) that terminate the current session via /api/logout and redirect to /admin/login.

v0.4.63 - 2026-04-14

Fixed

  • Fixed project-member Associate access scope resolution for non-admin users by correcting the Postgres project shadow model used in access-scope evaluation (projects.models.Project instead of legacy blueprint.models.Project).

Changed

  • Normalized company role aliases used by access scope (watcher -> viewer, contractor -> guest, billing_only -> billing) and expanded explicit no-Associate roles to include billing.
  • Aligned RBAC enforcement for project permissions:
    • contractor/guest/viewer now enforce read-only access in check_project_role.
    • billing/billing_only now enforce no project-role access.
  • Aligned Associate model-tier policy:
    • member: standard + max
    • viewer/watcher: standard only
    • guest/contractor: standard only
    • billing/billing_only: no model access
  • Expanded membership permission mapping to include explicit entries for manager, viewer, guest, and billing roles.

Added

  • Added RBAC regression tests covering:
    • project member scope resolution path for Associate,
    • contractor read-only enforcement,
    • billing no-access enforcement,
    • Associate model-tier matrix expectations for member/viewer/guest/billing.

v0.4.62 - 2026-04-10

Changed

  • Updated Project > Overview top layout for PM-first scan:
    • action queue cards now appear first with no section header,
    • Project Snapshot now surfaces four key stats: Overdue, Completed this week, Active members, Meetings,
    • replaced the large storage block with a compact top-right storage capacity bar showing % left.
  • Updated Supporting Evidence KPI strip layout to a single-row 1x5 card grid on desktop widths.
  • Moved the storage capacity bar into the sub-tab header row (Overview / Activity / Audit / Usage / People) aligned to the far right.
  • Removed the duplicate health badge from the top-right of Project Snapshot and simplified snapshot styling to reduce nested card clutter.
  • Reworked Project Snapshot stat tiles to a compact, left-aligned footprint so the section no longer feels visually over-stretched.
  • Consolidated Project Snapshot and Supporting Evidence into a single KPI strip using the supporting-evidence card style.
  • Expanded the unified KPI strip from 1x5 to 1x7 by adding Overdue and Active Members, removing duplicated metric presentation across sections.
  • Removed the merged section heading and helper sentence above KPI cards to reduce visual clutter and reclaim vertical space.
  • Center-aligned KPI card content in the unified snapshot/evidence strip for improved visual balance across wide cards.
  • Upgraded Overview chart layer with a timeframe switcher (7d, 30d, 90d, Sprint) and quick context chips (Trend, Risk, Confidence).
  • Replaced basic chart visuals with decision-oriented views:
    • Task Status -> Delivery Flow progress bars,
    • Priority Distribution -> Priority Risk Matrix with at-risk overlay,
    • Team Velocity -> Velocity vs Capacity combo chart with capacity trend line.
  • Added sprint-specific timeframe control behavior: when Sprint is selected, a sprint dropdown appears inline so PMs can choose which sprint context to view.
  • Corrected velocity visualization to be strictly data-driven: replaced inferred capacity line with a rolling average of actual completed work so timeframe switches no longer produce misleading capacity values.
  • Hardened Overview chart layer for auditability by removing inferred Trend/Confidence chips and narrative inference text; charts now present raw metrics only.
  • Replaced estimated Priority Risk Matrix overlays with raw Priority Load counts and simplified velocity rendering to completed tasks per period only.
  • Added a data-backed capacity line for all chart ranges (7d, 30d, 90d, Sprint) by bucketing task estimate values by due_date across the selected timeline window.
  • Sprint mode capacity now uses sprint-scoped tasks only (matching selected sprint), while non-sprint ranges use project-scoped tasks for the selected window.
  • Added an All time chart range for project-lifetime visibility, using month-based buckets from the earliest tracked project task date to present.
  • Expanded capacity extraction to use both estimate and estimated_effort task fields and added explicit in-chart messaging when capacity is unavailable due to missing estimates/due dates.
  • Updated timeframe control wrapping so All time remains visible even on narrower desktop widths.
  • Re-defined velocity chart capacity as team capacity (project member count) across all timeframes and removed estimate/effort-based capacity calculations.

v0.4.61 - 2026-04-09

Changed

  • Added server-side pagination/search to company people operations:
    • GET /api/v1/companies/{company_id}/members/ now supports search, role, status, page, page_size and returns pagination metadata.
    • GET /api/v1/companies/{company_id}/pods/ now supports search, status, page, page_size and returns pagination metadata.
  • Upgraded Company Dashboard People Management popout to consume server-side paging/filtering for both members and pods, including in-UI page navigation controls.
  • Added pod analytics cards in people management (capacity coverage, cross-pod load, unassigned members, avg active pod size).
  • Added per-pod quick actions (Archive/Activate, Duplicate) alongside edit/delete controls.

v0.4.60 - 2026-04-09

Changed

  • Added role-gated workspace settings actions in the Company Dashboard workspace-management popout:
    • Manage Settings now follows the same disabled/tooltip UX pattern when the user lacks required owner/admin permissions.
  • Added a dedicated premium People Management popout on Company Dashboard quick links:
    • moved Manage People quick action away from Company Settings tab routing and into a focused people-ops popout,
    • added people directory search/filter, role/status visibility, admin invite flow, and member management editor.
  • Added company teams/pods operations in the new people popout:
    • teams/pods listing cards with lead/member visibility,
    • create/edit/delete pod workflows,
    • direct lead/member assignment controls.
  • Extended member-update flow to support admin-managed profile fields (first_name, last_name, job_title) alongside role updates.

Added

  • Added new company pod endpoints:
    • GET|POST /api/v1/companies/{company_id}/pods/
    • PATCH|DELETE /api/v1/companies/{company_id}/pods/{pod_id}/

v0.4.59 - 2026-04-09

Changed

  • Added role-based UX guardrails for Company Dashboard project management actions:
    • Manage buttons in workspace-expanded project rows are now disabled for users below manager role,
    • disabled state includes a clear tooltip explaining required role (owner/admin/manager).
  • Extended the dedicated workspace-management popout with per-workspace project listing and direct Manage Project actions that open ProjectSettingsModal.

Fixed

  • Raised ProjectSettingsModal overlay z-index so project settings reliably opens above dashboard workspace-management popouts and nested settings layers.

v0.4.58 - 2026-04-09

Fixed

  • Fixed nested workspace create/manage modals rendering behind the new Company Dashboard workspace-management popout by raising workspace modal overlay z-index.

Changed

  • Added a real Manage action in expanded project rows on Company Dashboard workspaces table.
  • Wired project management action to open ProjectSettingsModal directly from Company Dashboard, aligned with existing project settings UX patterns.

v0.4.57 - 2026-04-09

Changed

  • Company Dashboard quick-link Manage Workspaces now opens a dedicated workspace management popout instead of routing users into the Company Settings modal tab flow.
  • Added a premium-style Workspace Management popout with:
    • high-level workspace metrics,
    • workspace search/filter,
    • create-workspace action,
    • direct per-workspace settings management actions.
  • Removed the workspaces tab/surface from CompanySettingsModal so workspace operations are handled by the dedicated dashboard popout.
  • Removed the funded/debt badge from the Company Dashboard billing wallet card header to reduce non-actionable visual noise.
  • Updated company settings route section parsing to drop legacy section=workspaces support.

v0.4.56 - 2026-04-09

Fixed

  • Fixed usePresence cache upsert typing to avoid PresenceState | "" union leakage that broke production type-checking during next build.

Changed

  • Improved Personal Dashboard Announcements UX:
    • upgraded announcements card header with clearer priority framing,
    • restyled announcement rows with stronger hierarchy (announcement badge, headline, body preview, project tag, open hint),
    • upgraded the expand interaction to a larger, high-affordance control with adjacent arrow and expanded/collapsed directional state.

v0.4.55 - 2026-04-09

Added

  • Added a production launch gate checklist at docs/operations/production-readiness-checklist.md with item-by-item PASS/PARTIAL/FAIL criteria across:
    • build and quality gates,
    • secrets/configuration hygiene,
    • auth/RBAC/admin controls,
    • deployment/release automation,
    • observability/runbooks,
    • SOC 2/GDPR readiness controls.

Changed

  • Linked runbooks to the new mandatory production release gate checklist (docs/operations/runbooks.md).

Found

  • Recorded current launch blockers in the new checklist, including:
    • frontend production build failure,
    • committed secrets in tracked environment/deployment files,
    • hardcoded admin fallback credentials,
    • disabled Celery TLS certificate verification,
    • missing CI workflow gate.

v0.4.54 - 2026-04-09

Fixed

  • Removed now-unused People-tab CSS selectors in ProjectPeoplePage.module.css after the previous header control cleanup.
  • Fixed Docs Hub PowerPoint/Office preview gating so presentation files can render in-app by default when blob URLs are available (NEXT_PUBLIC_ENABLE_OFFICE_PREVIEW now defaults to enabled unless explicitly set to false).

Changed

  • Updated feature-flow documentation to reflect Office/PPT preview behavior in Docs Hub.

v0.4.53 - 2026-04-09

Fixed

  • Removed non-functional project/connection header controls from the project People tab UI (ProjectPeoplePage) to reduce dead actions/noise.
  • Fixed project People presence rendering so online members are shown correctly by normalizing mixed websocket payload shapes (snake_case + camelCase) and ID formats in usePresence.
  • Fixed presence websocket broadcast forwarding so live events retain a client-consumable type, enabling real-time online/offline updates in the People tab.

Changed

  • Updated presence/realtime architecture mapping to explicitly include project People-tab presence flow ownership across frontend hook + backend presence service.

v0.4.52 - 2026-04-08

Added

  • Added Home tab to /admin/management as the default landing view.
  • Added Business-at-a-Glance UI section for admin management with initial preview metrics:
    • total users,
    • total companies,
    • users online,
    • companies online,
    • MRR,
    • ARR,
    • total revenue.
  • Added supporting executive snapshot UI blocks:
    • MRR trend preview,
    • health indicators,
    • growth signals.

Changed

  • Updated admin management shell copy to reflect the new home overview plus 6 operational pillars.
  • Updated architecture feature-flow mapping for Admin Performance and Ops to include the Home overview surface.

v0.4.51 - 2026-04-08

Added

  • Added backend management command bootstrap_alesko_admins to create/repair a fully usable Alesko admin tenant across PostgreSQL + MongoDB:
    • upserts jared@alesko.ai (owner) and denis@alesko.ai (admin) with usable passwords,
    • enforces Django company linkage and role state,
    • hydrates company profile defaults in tenant Mongo Company_Profile,
    • creates a default workspace if missing,
    • syncs canonical Mongo memberships (company_memberships, workspace_memberships) plus legacy membership compatibility,
    • ensures billing wallet exists, with optional idempotent welcome-credit repair (--ensure-welcome-credit).
  • Added operations runbook for admin account bootstrap and verification:
    • docs/operations/admin-account-bootstrap.md

v0.4.50 - 2026-04-08

Changed

  • Reverted temporary PIN-based /admin/login experiment.
  • Restored admin login UI to email/password mode for jared@alesko.ai and denis@alesko.ai.
  • Restored /api/admin/login to email/password bootstrap gate flow with optional backend fallback password (ADMIN_CONSOLE_BACKEND_PASSWORD).
  • Removed PIN/service-login env keys from frontend env files.

v0.4.49 - 2026-04-08

Changed

  • Replaced admin email/password login UI with PIN-only admin access on /admin/login.
  • Updated /api/admin/login to validate ADMIN_CONSOLE_PIN (default 123456) and then perform backend service-user login using:
    • ADMIN_CONSOLE_SERVICE_EMAIL (default jared@alesko.ai)
    • ADMIN_CONSOLE_SERVICE_PASSWORD (fallback to ADMIN_CONSOLE_BACKEND_PASSWORD).
  • Added new admin PIN/service-login env examples and staging/local defaults in frontend env files.

v0.4.48 - 2026-04-08

Changed

  • Added frontend admin-login backend-password fallback env configuration entries:
    • set ADMIN_CONSOLE_BACKEND_PASSWORD in frontend/.env.local,
    • added frontend/.env.staging with ADMIN_CONSOLE_BACKEND_PASSWORD,
    • documented key in frontend/.env.example.

v0.4.47 - 2026-04-08

Fixed

  • Hardened /api/admin/login bootstrap flow for staging/production credential drift:
    • if bootstrap email/password gate passes but backend /api/users/login/ rejects the entered password, route now optionally retries backend login with ADMIN_CONSOLE_BACKEND_PASSWORD (when configured),
    • preserves existing default behavior when fallback env is not set,
    • improves lockout resilience where bootstrap password and user account password differ.

v0.4.46 - 2026-04-08

Changed

  • Enhanced navbar beta feedback intake for bug reports with optional debug fields:
    • severity,
    • repro_steps,
    • expected_result,
    • actual_result.
  • Extended POST /api/v1/feedback handling to store and include these fields in feedback notifications.
  • Extended feedback->support ingestion to carry issue context fields into support tickets:
    • source_severity, source_repro_steps, source_expected_result, source_actual_result.
  • Upgraded Support Desk ticket cards with a dedicated Customer Contact block:
    • clear submitter/company/contact display,
    • Copy Email action,
    • Email Customer action.
  • Added Issue Context panel on beta-feedback tickets with severity/repro/expected/actual plus attachment links.
  • Updated API docs for /api/v1/feedback optional payload fields.

v0.4.45 - 2026-04-08

Changed

  • Expanded Support Desk ticket identity context for beta-feedback-ingested tickets:
    • added submitter metadata (submitter_name, submitter_email, source_user_id),
    • added company context (company_name),
    • persisted feedback diagnostics (source_user_agent, source_attachments) for triage.
  • Updated Support Desk ticket cards to show:
    • submitter name,
    • company name,
    • contact email (submitter email fallback to customer email).

v0.4.44 - 2026-04-08

Changed

  • Wired Support Desk intake to the navbar beta feedback source:
    • support ticket listing now idempotently syncs missing feedback_submissions records into ops_support_tickets,
    • synced tickets are tagged with source=beta_feedback and include feedback linkage metadata (source_feedback_id, feedback type, page URL),
    • queue/priority defaults are inferred from feedback type (bug -> technical/high, feature -> product/medium, feedback -> general/medium).
  • Updated Support Desk UI to surface ticket source context:
    • source badge per ticket row,
    • quick link indicator for beta-feedback-origin tickets,
    • intake copy now reflects automatic beta feedback ingestion.
  • Updated architecture flow documentation for the feedback-to-support ingestion path.

v0.4.43 - 2026-04-08

Changed

  • Upgraded Testing Orchestrator tab to Testing V1 hardening:
    • release readiness decision panel (READY/HOLD/INSUFFICIENT_DATA) focused on release-blocking suites,
    • suite reliability trend cards (recent pass-rate),
    • run-history filters (suite + status),
    • active-run/watch visibility and telemetry freshness indicator,
    • richer run detail with artifact metadata visibility.
  • Updated planning checklist to mark Phase 3 Testing Orchestrator V1 hardening complete.

v0.4.42 - 2026-04-08

Changed

  • Upgraded Ops Command tab to Ops Dashboard V1 with must-have and good-to-have operations primitives:
    • golden signal cards (latency, traffic, errors, saturation),
    • SLO/error-budget with burn-rate risk context,
    • incident response panel (status, severity, owner, start context, runbook/deployment/status links),
    • user-impact alert list (symptom-first operational posture),
    • dependency map (datastores + broker health snapshot),
    • critical journey checks (sign-in, dashboard load, task pipeline),
    • incident timeline panel from runtime history samples,
    • runtime target selector (when supported) and telemetry freshness guard.
  • Updated planning checklist to mark Phase 2 Ops Dashboard V1 hardening complete.

v0.4.41 - 2026-04-08

Changed

  • Added management-console role profile route:
    • GET /api/admin/management/access
    • returns highest effective company role + tab-action permission flags.
  • Added role-based action visibility/guards in management tabs:
    • Testing Orchestrator run actions are gated by testing permission.
    • Support Desk mutate actions (create/update ticket, create job) are gated by support permission.
    • Product Feedback mutate actions are gated by product permission.
    • Customer/Billing credit action is gated to owner/admin permissions.
    • Comms send/retry actions are gated by comms permission.
  • Added immutable admin-action audit logging service:
    • core/services/admin_action_audit_service.py
    • writes operational action events to ops_admin_action_logs.
  • Wired audit fanout for Phase 6-sensitive actions:
    • billing credit apply (billing.credit_apply) in admin_billing_test_credit,
    • email test sends (comms.test_send_batch, comms.test_send_single) in email testing views,
    • email retries (comms.retry_single, comms.retry_batch) in email admin views.

v0.4.40 - 2026-04-08

Changed

  • Implemented Phase 6 Customer/Billing Ops + Comms Center for /admin/management.
  • Added Customer & Billing Ops live control surface:
    • company scope selection,
    • wallet summary, recent ledger, and top-up orders visibility,
    • credit application action wired to POST /api/v1/admin/test-billing/credit/.
  • Added admin billing proxy routes:
    • /api/admin/billing/overview
    • /api/admin/billing/apply-credit
  • Added Comms Center live control surface:
    • email test catalog loading and selected/bulk test sends,
    • delivery/failure metric cards (from available email admin stats),
    • failed email queue selection with retry-batch action.
  • Added admin comms proxy routes:
    • /api/admin/comms/overview
    • /api/admin/comms/send-tests
    • /api/admin/comms/retry-batch
  • Marked Phase 6 checklist items complete in docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.md.

v0.4.39 - 2026-04-08

Changed

  • Implemented Phase 5 Product Feedback + Roadmap for /admin/management:
    • added internal product feedback APIs:
      • GET|POST /api/v1/internal/ops/feedback/requests/
      • GET|PATCH /api/v1/internal/ops/feedback/requests/{request_id}/
    • introduced product feedback service model ops_product_feedback_service:
      • request intake persistence (ops_product_feedback_requests),
      • stage pipeline (triage, validated, planned, in_delivery, shipped, closed_not_planned),
      • voting + impact/effort scoring and derived priority index,
      • decision log entries for governance traceability.
  • Added frontend admin product feedback proxy routes:
    • /api/admin/feedback/requests
    • /api/admin/feedback/requests/{requestId}
  • Replaced ProductFeedbackTab scaffold with live workflow:
    • request intake form,
    • pipeline metrics,
    • stage/scoring/vote updates,
    • decision note capture and recent decision visibility.
  • Marked Phase 5 checklist items complete in docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.md.

v0.4.38 - 2026-04-08

Changed

  • Implemented Phase 4 Support Desk + Jobs for /admin/management:
    • added internal support operations APIs:
      • GET|POST /api/v1/internal/ops/support/tickets/
      • GET|PATCH /api/v1/internal/ops/support/tickets/{ticket_id}/
      • GET|POST /api/v1/internal/ops/support/tickets/{ticket_id}/jobs/
      • GET /api/v1/internal/ops/support/jobs/
    • introduced support service model ops_support_service with:
      • ticket persistence (ops_support_tickets) including queue, priority, status, assignee, internal notes, and audit events,
      • SLA due-time policy and breach indicator computation,
      • ticket-to-job conversion and job persistence (ops_support_jobs).
  • Added frontend admin support proxy routes:
    • /api/admin/support/tickets
    • /api/admin/support/tickets/{ticketId}
    • /api/admin/support/tickets/{ticketId}/jobs
    • /api/admin/support/jobs
  • Replaced SupportDeskTab scaffold with live queue operations:
    • create ticket intake form,
    • ticket queue metrics and list,
    • per-ticket status/priority/assignee/internal-note updates,
    • ticket-to-job creation,
    • recent jobs panel.
  • Marked Phase 4 checklist items complete in docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.md.

v0.4.37 - 2026-04-08

Changed

  • Implemented Phase 3 Testing Orchestrator for /admin/management:
    • added internal ops testing backend contract:
      • GET /api/v1/internal/ops/testing/suites/
      • GET /api/v1/internal/ops/testing/runs/
      • POST /api/v1/internal/ops/testing/runs/
      • GET /api/v1/internal/ops/testing/runs/{run_id}/
    • introduced ops_testing_service run engine and storage model:
      • suite catalog and release-blocking metadata,
      • persisted run history (ops_test_runs) and summary artifacts (ops_test_artifacts),
      • release-gate readiness summary per run.
    • added async execution path through core.execute_ops_test_run_task.
  • Added frontend admin testing proxy routes:
    • /api/admin/testing/suites
    • /api/admin/testing/runs
    • /api/admin/testing/runs/{runId}
  • Upgraded TestingOrchestratorTab from scaffold to live control surface:
    • loads suite catalog,
    • launches suite runs,
    • displays run history and run detail steps,
    • polls non-terminal runs for status updates.
  • Marked Phase 3 checklist items complete in docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.md.

v0.4.36 - 2026-04-08

Changed

  • Implemented Phase 2 Ops Command integration on /admin/management:
    • added SLO/error-budget section (reliability SLO, failure-rate objective, budget consumed, summary latency objective),
    • added incident status context with runbook/deployment doc links,
    • added embedded full /admin/performance control-plane surface directly inside Ops Command (toggle open/close), while retaining standalone route access.
  • Marked Phase 2 checklist items complete in docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.md.

v0.4.35 - 2026-04-08

Changed

  • Implemented Phase 1 management console information architecture on /admin/management:
    • replaced the prior 3-tab shell with 6 pillar tabs:
      • Ops Command
      • Testing Orchestrator
      • Support Desk
      • Product Feedback
      • Customer & Billing Ops
      • Comms Center
  • Added shared management console UI primitives for consistent pillar surfaces and metric cards.
  • Added first-pass pillar components and tab content scaffolding:
    • OpsCommandTab (runtime summary + link to full /admin/performance)
    • TestingOrchestratorTab (suite catalog scaffold + existing live email testing suite)
    • SupportDeskTab (ticket/SLA/job workspace scaffold)
    • ProductFeedbackTab (request pipeline scaffold)
    • CustomerBillingOpsTab (customer/billing operations scaffold)
    • CommsCenterTab (outbound comms workspace scaffold)
  • Updated management console planning document to mark Phase 1 IA shell delivery complete.
  • Updated architecture feature-flow mapping to reflect the 6-pillar admin management workspace.

v0.4.34 - 2026-04-08

Changed

  • Added a dedicated internal admin bootstrap login surface at /admin/login, linked from the /login footer legal area, to provide a clear entrypoint into /admin/management.
  • Added frontend admin bootstrap auth route POST /api/admin/login:
    • restricts login to jared@alesko.ai and denis@alesko.ai by default (env-overridable),
    • validates a bootstrap admin password (default Alesko2026$, env-overridable),
    • on success, issues auth_token/refresh_token cookies and unlocks admin management cookie (alesko_perf_access=1).
  • Updated middleware public-route allowlist to include /admin/login.
  • Added planning doc docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.md to track the full 6-pillar management-console rebuild roadmap and phase execution.
  • Updated feature-flow architecture map to include the new admin login surface and admin bootstrap API flow.

v0.4.33 - 2026-04-08

Fixed

  • Resolved Personal Dashboard My Tasks sub-tab flicker/revert bug where clicking Overdue, This week, or All could briefly switch then snap back to the previous sub-tab.
  • Dashboard navigation URL-sync now updates myTasksSubTab state directly from query params instead of re-invoking URL mutation handlers during sync.

v0.4.32 - 2026-04-08

Fixed

  • Project Comms feed now resolves workspace_id from the active project (GET /api/v1/projects/{project_id}) before loading feed data or creating posts, reducing stale local-storage workspace mismatches.
  • Creating announcements in Project Comms now consistently writes to the project's workspace scope, improving visibility in Personal Dashboard Announcements heartbeat.
  • Daily Brief activity refresh now reloads from a stable baseline window (last login fallback to 24h) instead of delta-only refresh from prior check timestamp, so Here's what's happened updates without requiring full page reload/login.

v0.4.31 - 2026-04-08

Fixed

  • Daily Brief activity feed (Here's what's happened) now resolves workspace scope through workspace projects (project_id matching) instead of relying on task-level workspace_id fields.
  • Daily Brief activity feed now recognizes activity timestamps from both created_at and timestamp, restoring updates for task/comment events that were previously skipped.
  • Project Comms feed workspace scoping now prefers selected workspace id (bp.selectedTenantId) before company id fallback, improving announcement visibility alignment with Personal Dashboard heartbeat.
  • Added backfill script backend/scripts/backfill_comms_workspace_ids.py to repair existing comms feed post workspace_id values from project workspace ownership.

v0.4.30 - 2026-04-08

Fixed

  • Personal Dashboard list-format project table now supports manual column width resizing by dragging header resize handles.
  • Project list column widths now persist in local storage (bp.projectsColumnWidths) per browser session context.

v0.4.29 - 2026-04-08

Fixed

  • Personal Dashboard project cards and project list no longer show project quick-action menus.
  • Personal Dashboard project name rows/cards no longer render the gray Project eyebrow label.
  • List-view table layout was rebalanced after action-column removal to keep columns aligned across header, rows, skeleton, and empty states.

v0.4.28 - 2026-04-08

Fixed

  • Company Documents mutation proxy origin checks now accept trusted same-site browser requests (via sec-fetch-site) when Origin/Referer are absent.
  • Resolved intermittent forbidden_origin failures when updating Company Documents template lifecycle (for example switching a document back to draft).
  • Applied the same guard hardening to Company Documents use-in-project proxy mutations for consistency.

v0.4.27 - 2026-04-08

Fixed

  • Personal account settings reliability (second pass):
    • Next.js proxy now forwards multipart form uploads using FormData passthrough, preventing profile picture uploads from dropping file payloads in transit.
    • User profile picture API now accepts both file and profile_picture multipart keys for compatibility across clients.
    • Added persisted user-level date_format and week_starts_on fields so personal date/week preferences save and rehydrate consistently.
    • Personal Settings language selector now updates date format defaults only when language is explicitly changed, avoiding background override drift of user-selected date format.

v0.4.26 - 2026-04-08

Fixed

  • Invite/setup routing continuity:
    • setup-account completion now signs users in immediately (auth + refresh cookies) and returns dashboard redirect context instead of forcing a login round-trip.
    • setup-account frontend now routes to /personal-dashboard?open_settings=1&settings_tab=security and persists accepted company/workspace context in local storage.
    • invite acceptance workspace selection now prefers backend-confirmed workspace_id before fallback preferred_workspace_id to reduce blank-page workspace mismatches.
  • Invitation workspace fallback hardening:
    • when preferred workspace lookup fails during invitation accept, backend now falls back to the preferred workspace id as assignment target when no other workspace context exists.
  • Onboarding workspace/settings consistency:
    • onboarding default view options now align to workspace settings-compatible values (board, gantt, snapshot) and submit canonical values.
    • workspace creation now persists extended workspace settings (default_view, enable_time_tracking, visibility, inherit_company_settings) so workspace settings screens can read onboarding-provided values.
  • Company settings profile hydration:
    • company profile retrieval now prioritizes Company_Profile records scoped to current company_id, improving consistency for website/profile fields from creation flow.

v0.4.25 - 2026-04-08

Fixed

  • Member project visibility hardening (second pass):
    • /api/v1/projects and /api/v1/projects/dashboard-summary/ now normalize project/member identity keys and enforce explicit assignment checks against project payload member fields (member_ids, members, project_lead, created_by) for non-privileged roles.
    • reduces cases where members could see projects they were not explicitly assigned to due to identifier-shape drift.
  • Personal identity display consistency:
    • /api/user/me now returns normalized name + display_name payload values.
    • Personal Dashboard user bootstrap now persists the normalized name back into bp.currentUser, reducing stale username display after profile-name updates.

v0.4.24 - 2026-04-08

Fixed

  • Kanban board priority handling and ordering consistency:
    • board task ordering now sorts by pinned first, then priority rank (High, Medium, Low, Stuck) for a stable high-priority-first lane view.
    • reopen-task normalization now reuses the shared priority normalizer (including Stuck) to reduce priority label drift from backend payloads.
  • Kanban default density fallback:
    • board now falls back to user appearance preference (/api/v1/user/preferences view_density) when no per-project compact override exists in local storage.
  • Workflow status rename flow alignment:
    • Project Settings Workflow -> Task Statuses save now attempts to sync board column labels (todo, in_progress, review, done) via board config API, so renamed statuses reflect in board/task status selectors.

v0.4.22 - 2026-04-08

Fixed

  • Member project visibility hardening on dashboard summary:
    • membership filtering now matches both PostgreSQL project UUID and MongoDB mongodb_document_id, preventing member users from seeing unassigned projects due to ID-shape mismatch.
  • Added member escalation path for blocked project creation:
    • new endpoint POST /api/v1/projects/create-request/ sends notifications to owner/admin/manager approvers.
    • Create Project wizard now surfaces a Request Project Create Access action when creation is denied by permissions.
  • Health report RBAC tightened:
    • POST /api/v1/ai/projects/{project_id}/health-report/ now blocks member role access with explicit 403.
    • Project overview UI now hides Generate Health Report for member-role users.
  • Project documents permissions aligned with member ownership rule:
    • members can only delete documents/folders they created in project Docs Hub.
    • delete attempts against other users’ documents now return 403 members_can_only_delete_their_own_documents.

v0.4.23 - 2026-04-08

Fixed

  • Project settings/team data consistency improvements:
    • project settings budget hydration now preserves explicit 0 values and normalizes numeric-string budget values from metadata.
    • project members API now includes profile_picture_path in addition to profile_picture_url for stronger avatar fallback compatibility.
  • Project Settings modal now applies stronger avatar fallback (profile_picture_url -> profile_picture_path) for team/member rendering and normalizes budget parsing to numeric.
  • Project Overview People tab role mapping now prioritizes project role and falls back to elevated company role (manager/admin/owner) before defaulting to member, reducing role-label mismatches.

v0.4.21 - 2026-04-08

Fixed

  • Personal settings/profile reliability:
    • Profile picture upload now sends the expected multipart key (file) and targets the canonical profile-picture endpoint path, resolving No file provided failures.
    • Profile picture updates/removals now refresh bp.currentUser avatar metadata in local storage.
    • Password change/reset now signs the user out immediately and redirects to login (/login?password_updated=1).
    • Personal profile save now refreshes local storage display-name fields to reduce stale name rendering in UI surfaces.
  • Locale/date format consistency:
    • User profile API now defaults language/date format consistently (en-AU + DD/MM/YYYY, en-US + MM/DD/YYYY) when unset.
  • Invitation acceptance context hardening:
    • Invitation accept response now returns resolved company_id (not raw tenant fallback where mismatched), and auth token company_id claim aligns with resolved company context.
    • Accept-invitation frontend now falls back to loading a company workspace when workspace_id is absent, reducing blank-state routing after acceptance.
  • Calendar create-event empty-state message now correctly guides users toward creating a project first instead of reporting missing workspace.
  • Project creation payload now always includes the creator in member_ids and filters non-workspace pseudo IDs from submission, avoiding create failures from external placeholder IDs.
  • Onboarding business step now uses the same company-size option set as Company Settings to keep setup/options consistent.

v0.4.20 - 2026-04-08

Fixed

  • Resolved frontend production build type error in Personal Dashboard settings deep-link handling:
    • tightened settings_tab query-param validation with a proper string-to-union type guard before calling setPersonalSettingsInitialSection
    • removed unsafe cast path that failed under next build type-checking

v0.4.19 - 2026-04-07

Fixed

  • Second-pass UI/UX polish across onboarding, company settings, and project creation:
    • Onboarding security step now uses stable component styling (instead of ad-hoc inline styles) for passcode/password inputs, show/hide controls, inline mismatch warnings, and ToS card layout.
    • Added dedicated onboarding form-grid and mobile stepper wrapping styles to improve spacing and responsiveness in setup modal flows.
    • Company Settings People tab now includes client-side search (name/email/role) with visible result/pending counts for faster member management.
    • Project creation footer now shows clearer long-running feedback and timeout expectations (up to 60 seconds), with helper copy under action buttons.

v0.4.18 - 2026-04-07

Fixed

  • Complete Setup modal UX streamlining:
    • Removed duplicate onboarding step controls (single stepper navigation only).
    • Security step now allows completion without passcode; passcode validation shows soft inline messaging when partially entered/mismatched.
    • Added company description capture in onboarding and pass-through to company create payload.
    • Added welcome credit copy ($10) in onboarding business step.
  • Company settings people section cleanup:
    • De-duplicated member rows and pending invitation rows by id/email in UI rendering.
    • Suppressed pending invitations for emails already in active member list.
  • Company/Personal settings modal polish:
    • Increased modal vertical headroom and content bottom padding to reduce clipping in profile/security areas.
    • Refined billing card visuals for clearer hierarchy and readability.
  • Create Project flow cleanup:
    • Removed General template option.
    • Footer action bar is no longer sticky; improved bottom spacing while scrolling.
    • Added explicit project creation timeout/error feedback (60s timeout + inline error banner).
    • External users added in project creation are now auto-selected as team members.
  • Task modal/task checklist UX refinements:
    • Header progress bar now spans available width.
    • Subtasks section now appears before dependencies section.
    • Checklist item/add-form layout now wraps cleanly to prevent clipping.
  • Comms Hub UI cleanup:
    • Search result avatars now use stronger fallback resolution for member profile pictures.
    • Removed plus action from Private Chats section header.
    • Removed bookmark icon/action from feed post footer.
    • Improved pinned-post state clarity (accent border + pinned badge) and normalized pin toggle id matching.

v0.4.17 - 2026-04-07

Fixed

  • Stabilized dashboard auth/session proxying to prevent context loss after company/billing navigation:
    • Next.js proxy routes now forward the full incoming cookie header (not only auth_token) while still attaching bearer auth when available.
    • Updated routes:
      • frontend/src/app/api/proxy/[...path]/route.ts
      • frontend/src/app/api/dashboard/projects/route.ts
      • frontend/src/app/api/dashboard/my-tenants/route.ts
  • Hardened backend company-context parsing:
    • company_id now rejects invalid values (undefined, null, malformed UUIDs) before request processing.
    • Prevents malformed company context from cascading into backend 500s.
  • Project dashboard summary now fails gracefully:
    • On unexpected aggregation errors, endpoint returns an empty/degraded payload with metadata instead of a hard 500.
  • Health report generation reliability improvements:
    • Generated health report filenames are now timestamped + versioned (high-resolution timestamp + short UUID suffix) to avoid duplicate key collisions when multiple reports are generated the same day.
    • Snapshot review agent now retries with STANDARD model if MAX/Kimi returns the known tool_choice + thinking incompatibility error.
  • Billing usage charge pipeline now normalizes company_id as canonical UUID before wallet debit attempts, preventing silent no-charge paths from malformed company identifiers.
  • Task assignment RBAC now enforces member self-assignment:
    • members can only assign tasks to themselves on create/update task APIs.
    • cross-user assignments by members now return 403 with members_can_only_assign_tasks_to_themselves.
  • Associate policy matrix now allows MAX model access for viewer/guest roles (billing remains denied), aligning backend model gating with current access expectations.
  • Invitation acceptance flow now issues auth cookies (auth_token + refresh_token) on success, so invited users can proceed directly into the app without an extra login step.
  • Invite acceptance UI now routes to Personal Dashboard (not Login) and carries accepted company/workspace context into local storage selection keys.
  • Personal Dashboard now supports query-driven opening of Personal Settings (?open_settings=1&settings_tab=...), enabling invite flows to land users directly into security/profile completion.

v0.4.20 - 2026-04-08

Changed

  • Company Dashboard Company Documents explorer actions now use the same icon style/sizing language as project documents for better UI consistency.
  • Updated company document tree hover action buttons to match project-doc icon treatment (transparent icon buttons with matching hover states).
  • Company Dashboard Company Documents sidebar search and toolbar controls now mirror project documents explorer spacing/size patterns for tighter visual parity.
  • Company Dashboard Company Documents file tree rail now uses project-doc width sizing (260px) for consistent explorer density and less empty horizontal space.

v0.4.19 - 2026-04-08

Changed

  • Company Dashboard Company Documents tree now supports inline folder creation and inline rename directly in the explorer.
  • Company Dashboard Company Documents tree rows now expose expanded hover actions:
    • folder: create file, create folder, rename
    • file: rename, delete
  • Company Dashboard Company Documents supports drag-and-drop move in-tree (including move to root drop zone).

v0.4.18 - 2026-04-08

Added

  • Company Documents backend mutation parity endpoints for owner/admin management:
    • POST /api/v1/company/documents/folder/
    • PUT /api/v1/company/documents/rename/
    • PUT /api/v1/company/documents/move/
  • Next.js dashboard proxy routes for company document folder/rename/move operations under:
    • /api/dashboard/company/documents/folder
    • /api/dashboard/company/documents/rename
    • /api/dashboard/company/documents/move
  • Frontend fetcher helpers to consume the new company document management routes.

v0.4.17 - 2026-04-08

Changed

  • Company Dashboard Company Documents explorer now creates files inline in the tree (no browser prompt flow).
  • Company Dashboard Company Documents tree rows now expose hover actions for quick file creation inside folders and quick file deletion.
  • New action in Company Documents now targets the active folder context and opens inline filename entry with keyboard submit/cancel (Enter/Escape).

v0.4.16 - 2026-04-07

Changed

  • Company Dashboard Billing Wallet card layout now shows Current balance inline on the right side (no separate balance box).
  • Manage Billing in the dashboard billing card now spans the full card width instead of being constrained to the left column.
  • Refined Billing Wallet balance presentation so the right-side Current balance block is vertically centered and uses a larger amount font for stronger hierarchy.

v0.4.12 - 2026-04-07

Fixed

  • Project-level owner/admin/lead users now receive task update/comment notifications even when they were not manually subscribed to the task.
  • Task creation now auto-subscribes project owner/admin stakeholders (in addition to creator/assignee) so notification coverage is consistent from first task onward.
  • Added regression tests for implicit notification recipients and project admin stakeholder resolution.
  • Project creation now validates workspace_id, project_lead_user_id, and member_ids against company/workspace access boundaries before persisting.
  • Create Project wizard now requires explicit workspace selection and fetches assignable members from workspace-scoped membership APIs.

v0.4.16 - 2026-04-07

Fixed

  • Personal Dashboard heartbeat requests now send explicit company_id with workspace_id, preventing cross-company context drift that could hide announcements.
  • Navbar notification polling, list fetch, and read/read-all actions now include active company_id context to ensure owners/admins read from the correct company notification store after workspace/company switching.
  • Comms heartbeat Next.js API route now forwards bearer auth plus tenant context headers (X-Company-Id, X-Tenant-Id) when provided.

v0.4.11 - 2026-04-07

Added

  • Backend wallet-based billing foundation in billing_and_payments:
    • shared CompanyWallet balances (promo, purchased, debt) with debt-floor policy support
    • immutable WalletLedgerEntry records with idempotency keys and balance-after snapshots
    • PromoCreditGrant tracking with expiry support
    • versioned PricingCatalogEntry and scoped BillingLimit models
  • Transactional wallet service with typed request schemas for:
    • promo grants
    • charges (promo-first burn, purchased fallback, then debt within floor)
    • top-ups (debt repayment first, remainder to purchased balance)
  • Automatic onboarding credit provisioning on company creation:
    • $10 welcome credits
    • 90-day expiry
    • idempotent grant keying per company
  • Django admin coverage for wallet, ledger, promo grants, pricing catalog, and limits (ledger is read-only in admin)
  • Company-scoped billing APIs for wallet operations:
    • wallet summary
    • manual top-up
    • Stripe checkout top-up session creation
    • top-up order history
    • ledger history
    • pricing catalog listing
    • billing limits list/create/update/delete
  • Stripe top-up backend plumbing:
    • WalletTopUpOrder model for provider payment lifecycle state
    • provider webhook handling on /api/billing/webhooks/stripe/ (and legacy /api/v1/webhooks/stripe/)
    • idempotent wallet credit settlement from successful Stripe events
  • Usage-to-billing charge hooks wired into async usage persistence flow:
    • persisted usage events now map to configured billing action keys
    • successful events trigger idempotent wallet charges
    • no-op for unmapped/unpriced or failed usage events

Changed

  • Billing architecture/docs now reflect wallet-credit foundation and onboarding dependency
  • Added optional Stripe env settings in backend config for secret/publishable/webhook keys and checkout defaults
  • Company billing UI now uses wallet-credit APIs:
    • Company Settings Billing section now shows wallet balances, spend leaders, top-up checkout trigger, top-up order history, billing limit management, and recent ledger activity
    • Company Dashboard billing panel now reflects wallet totals/promo/purchased/debt state instead of legacy seat/subscription placeholders
  • Admin testing dashboard now includes a Billing Test panel:
    • credit company wallets by company-name or user-email identifier
    • supply test amount/reason
    • view returned wallet + recent ledger logs inline for verification
  • Added admin testing API endpoint:
    • POST /api/v1/admin/test-billing/credit/

v0.4.12 - 2026-04-07

Changed

  • Personal Dashboard Daily Brief now removes the visible AI Value This Week section to prepare relocation into company-level surfaces.
  • Company Dashboard leaderboard card now excludes the Associate AI ranking tab and keeps task/activity leaderboard views.
  • Company Dashboard now includes a dedicated bottom AI Usage & Cost card with Company, Projects, and Users tabs in empty-state mode (no mocked values, backend wiring deferred).

Added

  • Added reusable AiValueThisWeekCard component scaffold for later company-dashboard integration.
  • Added dashboard planning document for:
    • My Tasks tab improvements
    • announcements-tab debugging and rollout steps
    • company usage/cost integration phases

v0.4.13 - 2026-04-07

Changed

  • Reordered Company Dashboard card layout for clearer billing flow:
    • Row 2 now shows Billing Wallet on the left and AI Usage & Cost on the right.
    • Row 3 now shows Company Information on the left and Storage on the right.

v0.4.14 - 2026-04-07

Changed

  • Company Dashboard Billing Wallet card now uses a two-column credits layout with:
    • left-side explanatory empty-state content and Manage Billing action
    • right-side prominent Current Balance display area (large figure slot)
  • Balance figure is intentionally kept in empty-state mode (--) until live usage/billing display is enabled.

v0.4.15 - 2026-04-07

Fixed

  • Company Dashboard Billing Wallet card now preserves the original left-side billing details/behavior, while keeping only the new right-side preview addition:
    • Current Balance
    • $--.-- placeholder

v0.4.8 - 2026-04-06

Added

  • Task creation assist now sends project-aware context (project_id + computed project_context) and surfaces confidence + model/latency request metadata in the suggestions panel
  • Subtask report flow now persists generated reports into Docs Hub (/ai-generated/subtask-reports/...) with quick actions to open the saved report and jump to the task activity log
  • Subtask dependency suggestion apply now prefers stable subtask IDs (with deterministic title-order fallback) to reduce incorrect matches when titles are duplicated
  • Associate task analysis panel now renders Progress Insights (status alignment, realism signal, and concern list)

v0.4.9 - 2026-04-06

Fixed

  • Frontend production build type mismatch between board/task modal activity unions by adding ai_subtask_report_saved to board task activity typing

v0.4.10 - 2026-04-06

Fixed

  • Task modal Associate panel header sizing now aligns with the main task header hierarchy
  • Task modal Review and Generate Report controls can reopen the Associate panel during in-flight analysis/report generation without triggering duplicate requests
  • Task modal top progress strip now shows only an inline percentage next to a shorter bar (removed Progress label)

v0.4.7 - 2026-04-06

Fixed

  • Task modal and task creation assist copy now consistently use Associate wording in user-facing analysis/suggestion/estimate messaging

v0.4.6 - 2026-04-06

Fixed

  • Project Overview health-report toast now deep-links into Docs Hub with ?path= so the generated report opens directly
  • Docs Hub viewer now uses MIME-aware preview typing and extracted-text fallback for unsupported/ambiguous document types, improving in-app visibility for generated reports
  • Task right-side analysis panel now uses Associate Analysis naming and tightened header/content spacing for better visual alignment with the main task header

v0.4.5 - 2026-04-06

Fixed

  • Docs Hub split-mode version diffs now use adaptive row density (line-number widths, font size, and spacing scale with available panel width)

v0.4.4 - 2026-04-06

Fixed

  • Docs Hub version diff in Split layout now renders as a stacked/narrow panel layout instead of forcing a horizontal two-column diff arrangement

v0.4.3 - 2026-04-06

Fixed

  • Company dashboard activity feed no longer crashes when system-generated audit events use non-UUID actor ids (for example associate_ai)

v0.4.2 - 2026-04-06

Fixed

  • Docs Hub workspace pills now support click-on / click-off toggle behavior and AI Context is renamed to Associate Context
  • Docs Hub save/update no longer performs a full tree reload, preserving expanded folders and current editing context while updating save/version state

v0.4.1 - 2026-04-06

Fixed

  • Navbar calendar now enables Project Calendar inside project routes while keeping it disabled on personal pages
  • Changelog API file lookup is now resilient across runtime working directories
  • Personal Dashboard list view no longer shows the horizontal pager arrow used by card view
  • Project Overview removed the top AI Value This Week strip from Snapshot/Overview
  • Comms Hub now handles direct-message conversation list visibility more reliably (including invite notifications and direct-type variants)
  • Associate chat no longer auto-snaps users back to bottom when they scroll up during streaming
  • Project board top control bar now wraps/flexes better on narrower widths and when Associate is expanded
  • Task modal now shows progress at the top header strip, supports real subtask collapse/expand, uses click-to-complete subtask interaction, and moves create-subtask action into the subtask section body

v0.4.0 - 2026-04-06

Added

  • Canonical feature-flow map (docs/architecture/feature-flows.md)
  • Documentation changelog endpoint for navbar consumption

Changed

  • Documentation refresh across API, architecture, and planning docs
  • API/auth docs aligned to proxy + cookie JWT behavior
  • Added docs PR checklist and planning maintenance notes
  • Docs Hub document workspace now prioritizes the viewer with tabbed secondary panels (AI Context, Version History, Controls, Audit) and Focus/Split layout modes
  • Docs Hub storage governance added: 1GB company hard cap, 100MB per-project soft cap, hard-cap enforcement on upload/edit/restore/template-copy writes, and storage telemetry surfaced in Usage APIs
  • Project Overview now shows a circular storage meter in Snapshot/Overview and backend document indexes were expanded for storage aggregation performance
  • Company Dashboard Workspaces at a Glance now exposes workspace analytics through a dedicated right-side Details action, removes the bottom Recent Tasks/Team Activity Feed row, keeps workspace names on a single line, and aligns expanded project rows to the same column grid as workspace rows
  • Company Dashboard now includes a bottom Storage card with a single 1GB company pie chart segmented by workspace usage, plus a color legend identifying workspace ownership and the highest storage consumer
  • Company Dashboard table spacing was refined so workspace names can use full column width and expanded project rows follow the same aligned column grid; storage legend cards were simplified to clean text rows
  • Company Dashboard project accordion rows now render directly on the main table grid for strict column alignment, and storage legend spacing/pie vertical centering were refined for cleaner layout balance
  • Company Dashboard alignment polish: project accordion Details now hard-aligns to the last table column, and the storage legend is shifted further right with more uniform horizontal balance
  • Company Dashboard project dropdown alignment bug fixed by removing conflicting legacy flex row styling on project table rows; storage legend labels were shifted further right for better card-space use
  • Company Dashboard storage card was refined with a larger circular chart and right-aligned legend positioning to better use horizontal space
  • Company Dashboard access is now restricted to company owner/admin roles (non-admin company members are redirected)
  • Added Company Documents authoring surface at /company/[companyId]/documents with company-scoped create/edit/delete + lifecycle controls, and project company docs scope now requests published-only company docs

v0.3.0 - 2026-02-01

Added

  • Task dependency management with multiple dependency types
  • Task checklists in task workflows
  • Project templates during project creation
  • Automation triggers and actions
  • Forms hub capabilities
  • Docs search and docs comments
  • Expanded audit log capabilities
  • Associate AI session context and tool enhancements

Fixed

  • Security and performance issues across WebSocket/CORS/permissions

v0.2.0 - 2024-12-01

Added

  • Subtask dependency linking
  • In-app beta feedback capture

Changed

  • Improved comment mentions and team targeting
  • Enhanced comms hub mention notification behavior
  • Improved docs hub archived task display

v0.1.0 - 2024-11-01

Added

  • Initial pilot release
  • Core task management and project boards
  • Initial AI Associate experience
  • Comms hub rollout
  • Docs hub rollout