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): Madesend_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 vialogfire.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: AddedINTERNAL_PROXY_SECRETwith fallback default.docker-compose.dev-server.yml+docker-compose.dev.yml: AddedINTERNAL_PROXY_SECRETto 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_SECRETenv var support andX-Internal-Proxy/X-Internal-Proxy-Secretheaders 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
headersfromlettoconstsince headers are now built once with proxy identifiers.
- Added
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): SimplifiedreadChangelogFile()to read directly frompublic/changelog.mdinstead of walking the filesystem looking fordocs/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 ofdocs/CHANGELOG.mdthat 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 calculatesvolume_cost_usdandimpact_cost_usdfrom unit counts using per-category rates (~$0.0048/volume unit, ~$0.0053/impact unit).CompanyUsageOverviewAPIView: Addedcost_usdto thetotalsobject.CompanyUsageProjectsAPIView/CompanyUsageUsersAPIView: Addedcost_usdto each project/user result. Results now sorted bycost_usddescending (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)}. AddedformatUsd()helper usingIntl.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): AddedCompanyActiveSessionsAPIViewto list all active time-tracking sessions across the company, sorted by longest-running first. AddedAdminForceStopSessionAPIViewto 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 atsessions/active-company/andsessions/<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_actionandAuditRepo.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:
CompanyActiveSessionsAPIViewrestricted to owner/admin/manager.AdminForceStopSessionAPIViewrestricted 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 setcompleted_by(user ID) on the task document when status moves todone. 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 toassignee_user_ids[0]orassignee_id. Also fixedcompleted_attype comparison (handles both ISO string and BSON Date). - Activity Score: Changed from
audit_eventscollection (empty in production) to querying embeddedactivityarrays withindb.tasks(populated on every task mutation). Uses$unwindon the activity array, filters byactivity.timestamp, scores byactivity.type(task_completed=10, status_changed=3, comment_added=2, etc.), and groups byactivity.user_id. - Fixed Python 2-style
exceptclauses (except X, Y:→except (X, Y):) which would silently swallow errors.
- Tasks Closed: Rewrote aggregation pipeline to handle tasks with and without
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
IsCompanyMemberOrAdminpermission and explicit company membership check. - Performance: Activity pipeline now queries
db.taskswith an initial$matchonupdated_atto limit the scan to recently-modified tasks.$unwindacross only recent tasks is efficient. The$limit: 5keeps 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): Fixedproject_idmismatch in task aggregation pipeline. The query was using MongoDB_id(ObjectId) to match againsttasks.project_id(UUID), causing alltask_summaryresults to be zero. Now correctly uses the project's UUIDproject_idfield. - Frontend (
page.tsx):- Header "Tasks" count now sums
task_summary.totalacross all projects (was previously capped at 20 due to&limit=20on 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).
- Header "Tasks" count now sums
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— addedrestart: unless-stoppedto 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 runsdocker compose up -dagainstdocker-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 runssystemctl enable --now nginx(wasenableonly, which was why nginx had drifted todisabled), and installs the newbluprint-dev.serviceunit after cloning the repo.
Live host remediation (already applied on 3.105.83.223)
sudo systemctl enable --now nginx— nginx active + will auto-startdocker 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-stoppedadds negligible overhead; nginx being always-on is standard. Pre-existing DRFmin_valuewarning 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 onhttps://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.shtosystemctl is-enabled nginxand 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.cssso 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-vitalsimport cannot be resolved fromfrontend/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.tsxto useInteronly. - Updated typography tokens in
frontend/src/app/globals.cssto 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.tsxback toProject 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 === completedand 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.
- Active scenario status badge on each scenario card when a matching seed is currently active (
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+TaskCommentReplySpecdataclasses inbackend/core/services/test_data_seeder.py. - New
ScenarioSpec.task_commentslist. - Seeder now resolves
task_key -> task_idvia the existingtask_ref_mapand inserts top-level + reply comments viaCommentsRepo.create(...). - Enterprise scenario seeds comments on key tasks across Atlas, Brand Redesign, Security Hotfixes, Team Analytics, and Q2 Launch.
- New
-
Comms Hub message richness:
MessageSpecnow 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(...), andadd_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-q2fy26-okrsbilling-webhooks-v2mobile-push
- This ensures every project now has at least one project-scoped or associated feed post fixture.
- Added feed posts for previously missing project slugs:
-
Small-team parity tweak:
- Added explicit subtasks to previously sparse
small_teamtasks (demolition, electrical certification, insurance renewal) while preserving domain-specific construction language.
- Added explicit subtasks to previously sparse
Validation
ruff format+ruff checkclean on:backend/core/services/test_data_seeder.pybackend/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 requiredauthor_avatar_urlkwarg — silently failing under try/except, meaning no announcements or feed posts were actually being persisted. Now passesauthor_avatar_url=None.MessageService.send_message(...)does not exist — the real method iscreate_message(...)with full sender metadata. Updated to callcreate_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
FeedCommentSpecdataclass with 1-level threaded replies. ExtendedFeedPostSpecwithcomments: List[FeedCommentSpec]andupvoter_email_locals: List[str]. Seeder now:- Captures the post ID returned by
create_post. - Seeds comments via
FeedService.create_comment(...), then one-level replies via the same method withparent_comment_id=<top-level id>. - Seeds upvotes via
FeedService.upvote_post(post_id, user_id). - Surfaces
feed_commentsandfeed_upvotescounts in the seed response.
- Captures the post ID returned by
-
Auto-subtask generator (
_auto_subtasksinscenarios_enterprise.py) — label-aware, status-aware, deterministic. When a_t(...)call omitssubtasksand 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; engagementcountskeys.backend/core/services/scenarios_enterprise.py—Optionalimport;_auto_subtaskshelper;_tauto-wires subtasks when caller omits them; 10 new feed posts (with comments + upvotes); 12 new conversations; 31 new notifications;FeedCommentSpecimport.
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.*andbilling.*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, andMessageService.create_message. No new bypass paths. Feed visibility (workspace/project) and conversationproject_idscoping unchanged. - Performance: Subtask explosion (1098 vs 14) lives entirely inside existing
tasks_repo.insert_manybulk 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
CompanyDocFolderSpecdataclass inbackend/core/services/test_data_seeder.py— company-scoped folders (noproject_slug, POSIX path + name only). -
Seeder orchestration in
_seed_engagement_surfaces:- 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. - Resolves the company-docs scope via
_company_docs_scope_id(company_id). - Creates each scenario-specified folder as a metadata-only row via
BlobDocumentsRepo.createwithproject_id=scope_id,source="docs_hub",metadata={"scope": "company"}— the exact convention used by the interactiveCompanyDocumentCreateFolderView. - Best-effort — failure in one folder does not abort the seed.
- Calls the canonical
-
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
| Element | Count |
|---|---|
| Company doc folders (incl. 4 default skeleton) | 41 |
| Project doc folders | 15 |
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 canonicalsoftware|marketing|design|product_launchtemplate to a seeded project after creation (seeds default board columns, docs, automations).KnowledgeCentreSeedSpec— triggerseed_system_templates_for_project()per project, populating Docs Hub withraw_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 existingAutomationsRepo+AutomationEngine.FormSpec+FormFieldSpec+FormSubmissionSpec— published forms with pre-filled submission history.NotificationSpec— deterministic demo notifications viaNotificationsRepo.create_canonicalfor 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
| Surface | Count | Notes |
|---|---|---|
| Project templates applied | 10 | software × 4, marketing × 3, design × 2, product_launch × 1 |
| Knowledge Centre seeds | 5 | Both mega-projects + SSO, SOC 2, Q2 Launch |
| Task templates | 6 | Bug Report, Feature Brief, Campaign Brief, Security Postmortem, Sprint Planning, Control Evidence |
| Automations | 6 | Dependency unblock notify, label auto-tag, war-room scope-change alert, P0 auto-assign, stuck escalation, control-reference labelling |
| Forms (published) | 2 | Bug Report (q1-bugfix) + Feature Request (team-analytics) |
| Form submissions | 10 | Mix of identified customer advisors + anonymous |
| Demo notifications | 12 | Spans 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+TimeLogSummaryPG tables useCASCADEon user/project FKs, so the existingpurge_test_companyflow cleans them up automatically when the company is purged — no purge-path changes needed.
Final enterprise scenario totals
| Element | Count |
|---|---|
| Users (all 9 roles) | 35 |
| Workspaces | 5 |
| Projects | 18 |
| Tasks | 259 |
| Milestones (major + minor) | 48 |
| Sprints | 6 |
| Dependencies | 26 (incl. 2 circular + 3 cross-project) |
| Announcements | 6 |
| Feed posts | 25 |
| Conversations (channels + groups + DMs) | 8 |
| Messages | 64 |
| Calendar events | 12 |
| Doc folders | 15 |
| Project templates applied | 10 |
| KC seed-runs | 5 |
| Task templates | 6 |
| Automations | 6 |
| Forms / submissions | 2 / 10 |
| Notifications | 12 |
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
| Element | Count |
|---|---|
| Users (all 9 canonical roles) | 35 |
| Workspaces | 5 |
| Projects | 18 |
| Tasks | 259 |
| Milestones (major + minor) | 48 |
| Sprints | 6 |
| Task dependencies | 26 |
| Announcements | 6 |
| Feed posts | 25 |
| Conversations (channels + groups + DMs) | 8 |
| Messages | 64 |
| Calendar events | 12 |
| Docs Hub folders | 15 |
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_requestlabels, 3scope-changetasks 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 onCompany_Profile.billing.planandmetadata.plan- Realistic
actual_time_spentpopulated on ~175 tasks; PGWorkSessionrows + dailyTimeLogSummaryaggregates 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_teamscenario 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 keeptest_data_seeder.pyfocused 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 aroundco_{uuid}.task_dependencies. Mirrors the rich document shape previously inlined inprojects/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 aroundco_{uuid}.milestones. Previously the only create path was inlined insidetimelines/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, andProjectMilestoneSchemainbackend/timelines/api/schemas.pygained atierfield (defaults to"minor", back-compat for existing docs). - Inline create/update views persist
tierto Mongo and return it in responses. List/detail/Gantt emit points read it with"minor"fallback. ProjectTimelineMilestone(frontendlib/fetchers.ts) andGanttMilestone(Gantt page) gainedtier?: 'major' | 'minor'.- New CSS variants
.milestoneMarkerMajor/.milestoneMarkerMinorinfrontend/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(viaTaskSpec.start_in_days,actual_hours).- Task-level sprint assignment (
TaskSpec.sprint_key, resolved afterSprintSpecinsert). - Deterministic
completed_atoverride viaTaskSpec.completed_in_days— critical for seeding velocity-sensitive health signals. MilestoneSpecwith tier.SprintSpec(per project).DepSpec(scenario-local bytask_key).AnnouncementSpec,FeedPostSpec(viaFeedService).ConversationSpec+MessageSpec(via Comms HubConversationService/MessageService).CalendarEventSpec(viaCalendarRepo).DocFolderSpec(metadata-only Docs Hub folders).- Optional
ScenarioSpec.plan— writesbilling.planandmetadata.planonCompany_Profile.
The seeder also seeds real time-tracking data:
- Writes PG
time_tracking.WorkSessionrows (one per task withactual_hours), dated 1–14 days in the past. - Upserts
time_tracking.TimeLogSummarydaily 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_teamscenario is unchanged. All new*Specfields 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
tierfield 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,CohereMononames with no font source) with concretenext/font/googleloading infrontend/src/app/layout.tsx. - Mapped design tokens to real runtime variables in
frontend/src/app/globals.cssso--font-display,--font-body, and--font-monoalways 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.mdto 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-vitalsresolution) 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
CalendarServicewas 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=0was the pre-v0.4.122 mock behavior. Task IDs are now strings; staged tasks carrytask_id=""until the user commits. Prompt now states this correctly so the agent does not try to callassign_task/update_task_statuson 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_summarymoved 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_bundleas 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 chaininganalyze_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 specificsearch_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_areasinbackend/ai/services/associate_harness.pynow recognizes "audit", "review", "state of", "how is", "how healthy", "overview", "summary of" as analysis focus hints. Previously these broad-review intents fell through togeneral, meaning theContextLoaderwouldn'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):- Every
@tool_with_policy/@max_only_toolin the codebase is referenced in the prompt. - Retired "Scheduling meetings and calendar events" claim stays out.
- Pre-v0.4.122
task_id=0staging sentinel is not resurrected. project_audit_bundleis present in the matrix as "(you)".- Per-turn cache guidance is present so the agent knows analytics are cheap.
- Every
Section9HarnessFocusAreaTests(2 tests): broad-review phrasings route toanalysisfocus; unrelated phrases still default togeneral.
Validation
ruff check+ruff formatclean 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:
- Redundant Mongo scans —
analyze_project_health,project_insights, andsummarize_project_risksall read the same tasks collection. A deep-audit chat turn could hit the same data 3-4× in sequence. - 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)inbackend/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— theContextLoadersnapshot used bysummarize_project_risks,recommend_next_actions,context_delta_since_last_visit,simulate_capacity_plan, and the new bundle. Keyed bycompany + project + sorted(focus_areas)so different focus sets don't collide.
project_audit_bundle meta-tool
- New read-only tool
project_audit_bundlethat returnshealth,insights,risks, and optionalnext_actionsin 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.
insightserrors) 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
ContextLoadersnapshot 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.READinPolicyResolver.TOOL_CATEGORIESand added toREAD_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.035fixed — 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_sourcesinusage_views.pynow 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_bundlecalls →analytics.analyze_project_healthcalled 1× (not 2×),analyze_project_insightscalled 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):BlueprintDependencies.turn_cacheexists withdefault_factory=dictproducing fresh dicts per instance (no mutable-default leak)._turn_cache_get_or_computememoizes same key; different keys recompute.- Fresh per-request: two separate
BlueprintDependencieshave independent caches. project_audit_bundleregistered inREAD_ONLY_ASSOCIATE_TOOLSandToolCategory.READ; viewer role can call it.- Tool callable on the
ai.associatemodule. - 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 inai.associate(agent tools) and tests.ProjectAIService.analyze_project_healthatbackend/ai/services/project_ai.py:239is a different class used byproject_creation_ai.py(project-setup flow, not the live agent) — unaffected by the v0.4.122 retirement.
Validation
ruff check+ruff formatclean 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_totaldistribution per conversation and confirmproject_audit_bundleadoption is reducing the p95. - Consider adding a Mongo projection/
$grouppipeline variant for_analyze_health_syncif 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_*_synchelpers returningtask.id = 1) deleted.TaskServicefield removed fromBlueprintDependenciesand fromcreate_dependencies.- The agent's
create_tasktool (backend/ai/associate.py:1709) now builds acore.repos.tasks_repo.TaskCreatepayload and writes throughTasksRepo(company_id).create(...)inside async_to_asyncwrapper so the async agent loop is not blocked. Assignee resolution handles multi-email mapping and uses string user IDs (Mongo-native). TaskCreationResult.task_idchanged fromint→strsince real task IDs are ObjectId strings. All threeTaskCreationResultconstruction sites updated (success / staging / error branches).
CalendarService → deleted
backend/ai/services/calendar_service.pydeleted. Had zero call sites in the agent code — pure dead injection.CalendarServicefield removed fromBlueprintDependenciesand fromcreate_dependencies.- If calendar work is needed in a future tool, wire it through
core.repos.calendar_repo.CalendarRepodirectly.
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 bycompany_db(company_id).tasks. AnalyticsService.analyze_project_healthsignature updated: now requires keyword-onlycompany_idandproject_id(string UUIDs) to prevent positional misuse across tenants.- Real counting rules:
completed: status in{done, completed, closed}.blocked:stuck == Trueor status ==blocked.overdue:due_datein 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 == 0returns 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.pynow passescompany_id=str(ctx.deps.company_id)+project_id=str(ctx.deps.project.id).
Sanity benchmarks (live run against in-memory stub DB)
| Scenario | completion_rate | health_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):- Asserts
task_service.pyandcalendar_service.pyare gone. - Asserts
BlueprintDependenciesno longer hastask_service/calendar_servicefields. - Asserts
ai.servicespackage no longer exportsTaskService/CalendarService. - Asserts
analyze_project_healthhas keyword-onlycompany_id+project_idparameters. - Static-source assertion that
_analyze_health_synchitscompany_db+tasks.findand no longer returnshealth_score=75.5. - Static-source assertion that
create_tasktool usesTasksRepo+TaskCreateand no longer referencesctx.deps.task_service.
- Asserts
Follow-ups
- Consider caching
_analyze_health_syncresults 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_risksoverlap in their task reads; a future pass can group them.
Validation
ruff check+ruff formatclean 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):owner15 → 80admin12 → 64manager10 → 50member8 → 40viewer3 → 16guest5 → 20billingunchanged 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 whenmodel_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 = 2unchanged — per-tool retries stay bounded. - Default
max_tools_per_requestonBlueprintDependenciesandcreate_dependenciesraised from 20 → 40 to match the member role cap (the most common authenticated path). - Views wiring:
associate_chat_viewnow callsPolicyResolver.get_effective_max_tools(company_role, model_id)instead of the old model-agnosticget_max_tools_per_request, so MAX requests automatically see the higher ceiling. The per-request warning log now includesmodel_idfor debugging. - Policy endpoint:
PolicyResolver.get_policy_summarynow returnsmax_tools_per_request_standard,max_tools_per_request_max, andmax_model_tool_multiplierso the UI can display the effective budget per model.
What this does NOT change
- Access control: MAX still requires
ModelType.MAX ∈ allowed_models(enforced byPolicyResolver.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_healthresults so the same aggregation is not re-run mid-conversation.
Validation
ruff check+ruff formatclean 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, andbackend/ai/runner.py. These three files formed a parallel Associate pipeline with noPolicyResolvergate on tools and trusted caller-suppliedtenant_id/user_id/project_idarguments (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 (
rgfor imports, bridge symbols, andstart_chat_stream— only the three files referenced each other).ASSOCIATE_BOT_USER_IDis independently redefined inbackend/comms/tasks.py:18andbackend/core/api/v1/messaging_views.py:40, so deleting the bridge's copy is safe. - Updated
backend/core/services/ai_scope_guard.pydocstring andbackend/core/services/ops_testing_service.py:1595comment to reflect the retirement. - Replaced the existence-probe test
Section9AssociateMemorySurfaceTests.test_associate_memory_module_discoverablewithtest_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_viewandworkspace_associate_chat_viewSSE generators now catchasyncio.CancelledError, log a client-disconnect line with the conversation id, and re-raise for clean ASGI teardown. Parity with the main projectassociate_chat_viewstream. - 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_viewnow reads pydantic-aievent.result.usage()inside theAgentRunResultEventbranch and stores the fullRunUsagesnapshot (requests,request_tokens,response_tokens,total_tokens,input_tokens,output_tokens,cache_read_tokens,cache_write_tokens,tool_calls) in a generator-localrun_usagedict._emit_request_usagenow threadsrun_usageinto the event'smetadata.token_usagepayload AND switches the top-levelunitsfrom the placeholder1tototal_tokenswhen present, so billing/analytics aggregate on the real cost dimension.- Fail-safe: token capture is wrapped in
try/exceptwith a DEBUG log so a missing/renamed pydantic-ai usage API cannot break the stream; legacyunits=1behavior remains the floor.
Validation
ruff check+ruff formatclean 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_sessionandStagingManager.revert_staging_sessionpreviously only checkedsession.user_id == user_idandstatus == 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_accesswhich re-runscore.auth.utils.check_project_role_strict(required="project:write")against the tenant/user/project at commit AND revert time, raisingPermissionError("staging_write_access_required")when the caller no longer holds write. - Translated
PermissionErrorto HTTP403at the view boundary inStagingCommitView.post/.deleteso 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 withmetadata.error = "role_recheck_denied". - Covered by
Section9StagingRoleRecheckTests(3 new tests) inbackend/tests/test_ai_associate_security.py.
UX: Gap 1 — Associate SSE stream cancellation + Stop button
- Fixed the long-standing bug where
useAssociateChat.tsallocated anAbortControllerper 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
cancelStreamtouseAssociateChatand wired two new cleanup effects: one aborts onpathnamechange (Next.jsusePathname), the other aborts on hook unmount. ChatInput.tsxnow renders a red Stop button while the stream is live, replacing the spinner send button. Clicking Stop triggerscancelStreamwhich aborts the fetch, and the existingAbortErrorbranch resets all streaming state cleanly.- Backend
associate_chat_viewnow catchesasyncio.CancelledErrorin the SSE generator, logs a client-disconnect line, and emits a failedUSAGE_EVENT_ASSOCIATE_REQUEST_FAILEDwitherror_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_pipelineMongo aggregation and its companionassociate_usageresponse key fromLeaderboardViewinbackend/companies/api/views.py. The Associate AI ranking tab was removed fromLeaderboardWidget.tsxback in v0.4.12, but the backend kept doing the aggregation work on every leaderboard fetch — reading from theai_interactionsMongo 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 dashboardAI Usage & Costcard, 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*pinspython:3.14-slim,requires-python = ">=3.14") and PEP 758 — accepted for 3.14 — allows parentheses-lessexcepttuple lists. Ruff's formatter is correctly preferring the new syntax for this target. No ruff bug; no Python 2 regression.ruff formatapplied to all touched backend files in this change.
Validation
ruff check+ruff formatclean 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 --noEmitclean on frontend.eslintbaseline 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 incompany_pk, not that the caller belonged tocompany_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_accesshelper into every method ofStagingSessionView,StagingCommitView,ProjectDocView, andAIMemoryViewvia a new_guard_ai_project_accesswrapper inbackend/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 6require_project_accesschain. - 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 atAIMemoryView._is_adminstill runs for write differentiation). - Added regression test class
Section9StagingMemoryScopeGuardTests(3 tests) tobackend/tests/test_ai_associate_security.pyasserting that every affected view method lexically calls the guard before_resolve_project_for_company, locking the wiring against accidental regression. - Validation:
ruff checkclean on touched files;pytest tests/test_ai_associate_security.py21/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_AGEfallback from60to0inbackend/core/settings/dev_server.pyso 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.aiadmin-login failures after the purge incident and confirmed the account existed but had no usable password hash (has_usable_password=False), whilejared@alesko.airemained healthy. - Repaired dev account state by setting a usable password hash and restoring admin flags (
is_staff=True,is_superuser=True) fordenis@alesko.aiso admin login parity is restored. - Verified both
denis@alesko.aiandjared@alesko.ainow succeed viaPOST /api/admin/login(HTTP 200).
Safety hardening: purge command protects admin console users by default
- Updated
backend/core/management/commands/purge_test_company.pyso users listed inADMIN_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-adminsfor exceptional cases where protected admin users must also be deleted. - Added guardrail for direct
--user-emailpurges: command now errors if targeting a protected admin unless--include-protected-adminsis 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 viabody.associate-openpadding. - Added
/indexto the public route exclusion inAssociateSidebarWrapperso the sidebar is never rendered on the landing page. - Added
/indexto 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, andAssociateSidebarWrapper.tsxto 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 passwordas the two primary actions, - create-account mode now presents passwordless
SSO loginonly.
- sign-in mode now presents
- Moved optional
Tenant IDfield intoAdvanced optionsand 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.jpgfrontend/public/images/login/vertical-architecture-waterfront-2.jpgfrontend/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 upstate 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 detailscontrol and adjacent arrow icon to make expand/collapse behavior more obvious. - Reworked Daily Brief right panel into a readiness-first preflight:
2-minute alignmentstatus, 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 in2-minute alignmentnow auto-expands details to reveal specificRisks and blockerscontent. - 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 Taskspresentation in Personal Dashboard with an impact-first header, inline bucket counts (Overdue/Today/This week/All), and aStart nowrecommendation 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 workedrail into a compactTime pulsepanel 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
Announcementstab 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/managementand/admin/performancepages. - Light mode uses a light grey palette (
#f3f4f6background,#e5e7ebcards) instead of pure white, preserving cyan/emerald/amber/rose status accent colors for readability. - Theme preference is persisted in
localStorageunderbp.adminThemeand synced across both admin pages. - Implemented via CSS override strategy in
frontend/src/app/admin/management/admin-theme.cssto 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-effectandno-explicit-anyerrors 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.
localStoragekeybp.adminThemestores 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
useStatetoggle.
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, explicitSign in/Create accountmode 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 SSOaction 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.tsto centralize SSO-start redirect behavior, sanitizenextrouting targets, and safely fall back to/login?error=sso_not_configuredor/login?error=sso_invalid_urlwhen env config is missing/invalid. - Added
SSO_LOGIN_URL/NEXT_PUBLIC_SSO_LOGIN_URLsupport infrontend/src/lib/env.tsso SSO integration can be configured per environment without hardcoding provider URLs in UI code. - Added compatibility env aliases in
frontend/src/lib/env.tsfor 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 fullSSO_LOGIN_URLrequired). - 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 JWTexpand setauth_tokencookiemaxAgefrom 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.tsxthat preventednext buildfrom completing:- updated
AIInsights.insightstyping 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_validtyping onAIInsightsused by subtask verification UI.
- updated
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
nextand 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/indexlanding page was not included in the public-route exclusion list, so the realAssociateSidebar(with itsuseEffecthooks for prewarm, history loading, etc.) was mounting alongside the demo showcase section and writing to MongoDB on every visit. Added/indextoisPublicRouteso the sidebar returnsnullon the landing page. Also removed an unusedChatInputimport fromAssociateShowcaseSection.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 likePOST /api/loginto fall through to the Django backend (which has no such route) and return a 404. Fixed by changing the trailing/to(/|$)so both/api/loginand/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 asproject_idinstead 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, butTasksRepo.list()(which powers the Kanban board) uses exact UUID equality and returned zero tasks — rendering the board empty. Fixed by preferringproject_doc["project_id"]overproject_doc["id"]when building the task payload. - Kanban silently dropping
blockedtasks (frontend/src/app/project/ [projectId]/board/page.tsx): the hard-coded 4-column grouping silently discarded any task withstatus="blocked"(or any future backend status value). Added an explicitblocked → todomapping intoFrontendStatus, plus a defence-in-depth fallback that routes any unknown status into TODO with aconsole.warnso 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 toadmin/testing/_lib.tswas off by one segment in nested dynamic routes, causing Next.jsModule not foundbuild/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/managementfor 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=productionunless--force-productionis 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 whenENVIRONMENT=production; access gate reuses_has_ops_accesssemantics (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 collectionops_test_seeds(mirrorsops_test_runsshape). - Enhanced
purge_company()now drops the per-tenantco_{uuid}Mongo database in addition to delegating to the existingpurge_test_companymanagement 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_nameprefixed 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_atfor queryable exclusion from billing/usage.
- Next.js proxy routes under
frontend/src/app/api/admin/test-data/*reuse the existingalesko_perf_access-cookie gate fromtesting/_lib.ts.
Dev validation:
ruff check+ruff format --check— pass on all touched backend files.- Django
manage.py checkon 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.comwith shared password) returns valid access + refresh tokens with correctcompany_role=ownerandtenant_id=<company_id>. - Purge via API: 2-phase task (command delegation + per-tenant DB drop); final
seed record status transitions to
purgedwithcompany_id+mongo_dbrecorded inpurge_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 theops_test_seedsaudit trail. Test tenants are marked withis_test_tenant=Trueso 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.comdomain (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 thepurge_company()helper. Per-tenant Mongo DB drop closes the prior gap inpurge_test_company(which leftco_{uuid}DBs orphaned). - RBAC / Security: View-layer env gate
_test_data_env_gatereturns 403 inENVIRONMENT=productionregardless 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 existingalesko_perf_access=1unlock 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_oneper task (embeddedsub_tasks[]) — acceptable at this scale; larger enterprise scenarios in Phase 2 will switch toinsert_many.ops_test_seedscollection 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/ taskassignee_id/reporter_user_id, which triggeredFailed to ensure Postgres shadow projectwarnings and left the Djangoprojects.Projectshadow M2M empty (silently breaking thedjango_project.members.filter(...)fallback RBAC check inproject_settings_views.py:280). Fixed by switching those fields to PostgresCustomUser.idwhile keeping workspace/company membership on Mongousers._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), Mongomembers[].user_idresolves cleanly to realCustomUserrows, 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_strictrefuses theX-Company-Idheader 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_migrationpayload (mirrors Section 7 document audit service), - best-effort emit pattern (audit failures never break primary AI action).
- dotted taxonomy (
- Added canonical AI scope guard
backend/core/services/ai_scope_guard.py:is_same_company/is_project_in_scopepredicates with fail-closed semantics — emptyallowed_project_idswithall_projects=Falsedenies (fix forAI-P1-19).require_company_scope(request, path_company_id)HTTP guard backed by strict JWT-only resolver (foundation forAI-P0-1,AI-P0-2).require_ai_project_access(...)wraps Section 6require_project_accessbehind 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__.pyexports for consistent import ergonomics. - Orchestrator + pytest suite expansion:
ai_associatesuite flipped fromplanned→activeinbackend/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.pygrew from3→18tests.
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.mdwith 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).
- 7 P0 release-blocking findings (
- Updated
SECURITY_AUDIT_SECTIONS.mdSection 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-Idheader fallback on AI mutation endpoints (AI-P0-1). - Cross-company access via unchecked
_resolve_project_for_companyin staging/memory/ProjectDoc views (AI-P0-2). - Secondary Mongo-first agent
associate_mongo_agentwith no policy gate and caller-trustedtenant_id(AI-P0-3). staging_manager.commit_staging_sessioncommits without project-write role check (AI-P0-4).associate.duplicate_taskreads by ObjectId withoutproject_idfilter (AI-P0-5).- Presence tools trust model-supplied scope arguments (
AI-P0-6). - AI write endpoints (
create_recommended_task,suggest_time_estimateai_estimateupdate) bypassPolicyResolver(AI-P0-7).
- Cross-tenant spoof via
v0.4.111 - 2026-04-27
Security / AI & Associate - Section 9 Phase A scaffolding
- Flipped Section 9 (AI / Associate) to
In ProgressinSECURITY_AUDIT_SECTIONS.mdwith 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_associatesuite into Admin Testing Orchestrator:backend/core/services/ops_testing_service.pyaddsai_associatesuite 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 whileAI-SEED-1is 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.
- removed
-
Rewired docs search to the blob-backed canonical repository:
backend/core/api/v1/docs_search_views.pynow usesBlobDocumentsRepo.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.
- removed
-
Updated template bootstrap path to blob-backed docs metadata:
backend/core/repos/project_templates_repo.pynow seeds default template folders viaBlobDocumentsRepo+DocumentCreate.
-
Expanded Section 7 runtime/test guardrails:
backend/core/services/ops_testing_service.pynow checks:- docs search blob-repo wiring,
- legacy documents module removal,
- orphaned knowledge-centre API removal.
backend/tests/test_documents_file_storage.pynow 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.pyremoveddocuments_views-specific assertions/tests.
-
Documentation updates:
SECURITY_AUDIT_SECTIONS.mdSection 7 updated with B3 progress.docs/architecture/documents-file-storage-audit-matrix.mdupdated with B3 status and validation.docs/architecture/feature-flows.mddocs-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(legacydocument_renameddual-write retained), - move flows now emit
document.moved(legacydocument_moveddual-write retained), - restore-version flows now emit
document.version_restored(legacydocument_restoreddual-write retained).
- rename flows now emit
-
Hardened archived-task download validation in
backend/core/api/v1/blob_documents_views.py:_download_archived_task(...)now validates task IDs withObjectId.is_valid(...)before DB access,- malformed IDs return
400withinvalid_archived_task_idinstead 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(default15minutes), - TTL is clamped between
1and1440minutes.
- profile-picture URL generation now uses
-
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.pyruntime 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.pyexpanded from8to14tests.
-
Documentation updates:
SECURITY_AUDIT_SECTIONS.mdSection 7 updated with B1/B2 progress bullets.docs/architecture/documents-file-storage-audit-matrix.mdupdated with B1/B2 implementation status and validation notes.docs/api/README.mdupdated 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.pyand hardened proxy trust posture:- proxy-header path now fails closed when
INTERNAL_PROXY_SECRETis missing outside DEBUG, - DEBUG-only bypass retained for local development loops.
- proxy-header path now fails closed when
-
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.pyupload now enforces canonical validator and upload/delete now enforce mutation-origin guard.backend/core/api/v1/feedback_views.pyfeedback 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.tsnow forwardsX-Internal-Proxy-SecretwhenINTERNAL_PROXY_SECRET(orNEXT_INTERNAL_PROXY_SECRET) is configured.
-
Added Section 7 orchestrator/test coverage:
- new ops suite
documents_file_storageinbackend/core/services/ops_testing_service.py(runtime posture checks + pytest target), - new regression suite
backend/tests/test_documents_file_storage.py.
- new ops suite
-
Documentation updates:
docs/architecture/documents-file-storage-audit-matrix.mdnow includes Phase B0 implementation status.SECURITY_AUDIT_SECTIONS.mdSection 7 updated with shipped B0 foundations and delivered artifacts.docs/api/README.mdupdated 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 formatapplied to touched files;ruff checkre-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_SECRETis unset (DF-P0-2), - MIME trust on client-declared
content_typewithout server-side sniffing/allowlist (DF-P0-3), - no dedicated Section 7 regression suite (
DF-P0-4).
- inconsistent mutation-origin guard coverage across document mutation routes (
- Updated
SECURITY_AUDIT_SECTIONS.mdSection 7 fromNot StartedtoIn 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_storageorchestrator suite,test_documents_file_storage.py). - Recorded Section 7 product decisions for B-phase planning:
- retire both legacy GridFS docs surface and orphaned
knowledge_centreAPI 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.
- retire both legacy GridFS docs surface and orphaned
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.pyfor 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_statusacross all companies.
- export now assembles
-
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).
- Django model 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.mdupdated with B1 implementation status.SECURITY_AUDIT_SECTIONS.mdSection 5 updated with B1 delivered artifacts.docs/api/README.mdSection 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.
- new helper
-
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_migrationpayload 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.
- task create/update lifecycle audit writes now route through
-
Migrated task attachment route guards to canonical project-access checks in
backend/core/api/v1/task_attachments_views.py:TaskAttachmentsUploadView,TaskAttachmentsListView, andTaskAttachmentDeleteViewnow callrequire_project_access(...)instead of directcheck_project_role(...)calls.
-
Migrated task action manager checks to canonical project-access checks in
backend/core/api/v1/task_actions_views.py:TaskReopenView,TaskArchiveView, andTaskUnarchiveViewmanager authorization now usesrequire_project_access(..., permission="task:manage").
-
Updated
backend/core/api/v1/views.py::_require_project_access_json(...)to delegate default read/edit authorization throughrequire_project_access(...)while retaining compatibility behavior for explicitrequire_admin=Truechecks. -
Expanded Section 6 canonical access migration in
backend/core/api/v1/views.py:ProjectsView.postnow usesrequire_project_access(..., permission="project:create")for project-create authorization.ProjectAuditFeedViewfull-audit-stream admin gate now usesrequire_project_access(..., permission="task:manage").
-
Expanded Section 6 canonical access migration in adjacent project surfaces:
backend/core/api/v1/task_templates_views.pynow usesrequire_project_access(...)across list/create/detail/update/delete/instantiate flows.backend/core/api/v1/automations_views.pynow usesrequire_project_access(...)across list/create/detail/update/delete flows.backend/core/api/v1/updates_views.pypost and comment write paths now userequire_project_access(...)with explicit post project-context lookup.backend/core/api/v1/messaging_views.pyconversation-create authorization now usesrequire_project_access(...).
-
Expanded legacy route audit migration:
backend/projects/api/archive_views.pytask archive/unarchive audit writes now route throughlog_project_task_event(...)with dual-write compatibility (task_archived,task_unarchived).backend/projects/api/reopen_views.pytask reopen audit writes now route throughlog_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 legacytask_attachment_uploaded), - delete emits
task.attachment_deleted(dual-written with legacytask_attachment_deleted), - payloads include task/project/attachment context.
- upload emits
-
Added Section 6 orchestrator support in
backend/core/services/ops_testing_service.py:- new suite key
projects_tasksin 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) totests/test_projects_tasks_security.py.
- new suite key
-
Added Section 6 regression suite
backend/tests/test_projects_tasks_security.py:- verifies
require_project_accessdelegation 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+ProjectAuditFeedViewcanonical access usage and legacy/projects/apiaudit 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.
- verifies
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/v1project/task/board/sprint/comment/attachment routes, - legacy
backend/projects/apiroutes 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).
- modern
- 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/apiretirement 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.
- audit both route families and plan legacy
- Updated
SECURITY_AUDIT_SECTIONS.mdSection 6 fromNot StartedtoIn Progress, linked the new audit artifact, added finding counts/headline risks, and codified expected B0 foundations (require_project_accessconsolidation,project_audit_service,projects_tasksorchestrator 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-ranruff 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 emitsuser.data_exportedaudit events.request_erasure(user, enqueue_callable)now enforces transactional durability: queue failure rolls backgdpr_erasure_requested_atand 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:
5failed attempts in a15-minute window with30-minute cooldown, - audit events:
user.passcode_set,user.passcode_verify_succeeded,user.passcode_verify_failed,user.passcode_locked,user.passcode_verify_blocked.
- lockout policy:
-
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_exemptposture for these state-changing routes, - removed dependency on header-trust identity extraction path for these endpoints.
- all endpoints now use
-
Updated erasure task wiring in
backend/core/tasks.py:gdpr_erasure_taskdelegates togdpr_service.execute_gdpr_erasure,- queue scheduling uses canonical
enqueue_gdpr_erasure_requesthelper.
-
Added Section 5 orchestrator/test coverage:
- new ops suite
user_profile_gdprinbackend/core/services/ops_testing_service.py(runtime posture checks + pytest target), - new regression suite
backend/tests/test_user_profile_gdpr.py.
- new ops suite
-
Documentation updates:
docs/architecture/user-profile-gdpr-audit-matrix.mdnow includes Phase B0 implementation status against P0/P1 items.SECURITY_AUDIT_SECTIONS.mdSection 5 updated with shipped B0 foundations and delivered artifacts.docs/api/README.mdupdated with Section 5 endpoint contracts and passcode lockout behavior.
Dev validation:
ruff checkon touched backend files: pass.ruff format --checkon 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).
- header-trust auth bypass risk in GDPR handlers via
- Updated
SECURITY_AUDIT_SECTIONS.mdSection 5 fromNot StartedtoIn 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.mdupdated 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_tokenaligns JWTexpwith cookiemax_agewithin 2s clock-slew and both trackget_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.updateoverride +_ALLOWED_UPDATE_FIELDSallow-list present; deadCompanySecurityUpdateSchemaremoved; v1 GET reads PG canonical via_is_2fa_required_safe. - B1 CW-P0-4
update_security_settingsemitscompany.security_settings_updatedwith before/after diff via mockedAuditRepo— 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 referencecore.auth.utils; three DRF permission classes containis_active; dead schemas absent;company_dbvalidator accepts canonical UUIDs and rejects injection payloads. - B1 seven token-issuing sites confirmed to use
issue_scoped_access_tokenby source-level inspection.
-
Admin Testing Orchestrator
company_workspacesuite 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 afterget_mongo(), meaning invalid callers hit a slow Mongo connection timeout before seeing theValueError. 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 isaria-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.mdSection 5 entry expanded with full scope inventory (UserProfileAPIView,UserSessionsAPIView,UserPreferencesAPIView,UserProfilePictureAPIView,UserDataExportView,RequestErasureView,AcceptTermsView,SetPasscodeView,VerifyPasscodeView,CustomUserconsent/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_destroyoverrides emitcompany.updated(with a targeted before/after diff overcompany_name, description, industry, website) andcompany.deleted. - CW-P1-3
CompanyLogoUploadView(backend/companies/api/views.py:72) — emitscompany.logo_updatedwith{previous_url, new_url}after the successful save. - CW-P1-4
CompanySettingsAPIView.patch(backend/core/api/v1/company_settings_views.py:568) — emitscompany.profile_updatedwith a targeted before/after diff limited to the keys actually changing, pluschanged_fieldslist. Uses the genericlog_company_mutationhelper. - CW-P1-5
CompanyMemberDetailView(backend/core/api/v1/company_management_views.py:988,1071) —patchemitscompany.member_role_changedonly when the role genuinely differs (no spam on no-op PATCHes);deleteemitscompany.member_removedwith the member email. - CW-P1-6
CompanyWorkspaceDetailView(backend/core/api/v1/company_management_views.py:1355,1401) —patchemitsworkspace.updatedwith before/after overname, description, icon, color;delete(archive) emitsworkspace.archived. - CW-P1-7 / CW-P2-b
LocationViewSet(backend/companies/api/views.py:256,265,276) —perform_create/update/destroyemitcompany.location_created/updated/deleted; update carries a before/after diff over name + address + country. Existinglogfire.infocalls retained for local-dev signal. - CW-P1-14
CompanyMemberWorkspaceAssignmentView.post(backend/core/api/v1/company_management_views.py:1416) — now computesadded_workspace_idsandremoved_workspace_idsas set differences over the old vs new assignment, then emits oneworkspace.member_addedorworkspace.member_removedper 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 inMembershipRepo.list_user_workspaces(or anall_accessrow). 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-returningcheck_company_adminat:306and inline_is_company_adminonCompanySessionsAPIView) are now thin forwarders to the canonicalcore.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 consolidatedcompany_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 requireis_superuser AND is_activefor 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:71now rejects anycompany_idthat 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 raiseValueErrorbefore 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 createsco_foo; dropMongo 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_PATTERNaccepts canonical 32-hex UUIDs and rejects injection payloads, short/long strings, and uppercase variants.check_company_adminand_is_company_adminboth contain the canonical-forwarder code path.- All three DRF permission classes contain the
is_activeguard. TransferWorkspaceSchemaconfirmed absent from module namespace.get_session_timeout_seconds(None)+issue_scoped_access_tokenround-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_minuteswas previously a cosmetic field — declared, serialized, UI-writable, but never read by any auth path. Django'sSESSION_COOKIE_AGEandSIMPLE_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 aRefreshToken, mutates itsaccess_token.expclaim tonow + get_session_timeout_seconds(company_id), and returns the JWT string plus the matching cookiemax_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-tokenexpscoped at generation).
- Frontend cookie alignment (
frontend/src/app/api/auth/set-cookie/route.ts): the Next.js POST + GET handlers that setauth_tokennow decode the JWT'sexpclaim and computemaxAge = 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 hardcodedmaxAge: 43200/expiresIn: 43200values. HelpergetAccessTokenMaxAge(accessToken, fallbackSeconds)falls back gracefully if the token is malformed. - Net effect: a company setting
session_timeout_minutes=30now sees 30-minute JWTs and 30-minute cookies across every login path. A company setting it to480gets 8-hour sessions. The prior1h in prod / 24h in devDjango-level override is superseded per-company. - Dev validation:
ruff check+ruff format --checkclean on all seven touched Python files +core/services/*+__init__.py. Import-sanity smoke viadjango.setup()confirms all seven endpoint classes load. Unit-level smoke ofissue_scoped_access_tokenwith an anonymousRefreshTokenconfirms the returnedmax_ageequals the JWTexp - nowto within a 2-second clock-slew tolerance and equalsget_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) throughcore.services.company_security_service.update_security_settings(...)instead of DRF's defaultserializer.save(). The service writes PG first (canonical), mirrors every changed field into MongoCompany_Profile.settingsas a best-effort read-cache, and emits acompany.security_settings_updatedaudit event with a before/after diff. An_ALLOWED_UPDATE_FIELDSallow-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 readsrequire_2favia new_is_2fa_required_safe(company_id)helper, which delegates tocore.services.company_security_service.is_2fa_required(...). Previously the GET returned whatever was sitting in MongoCompany_Profile.settings.require_2fa— which could drift arbitrarily from the PG canonical. The helper fails closed (returnsFalse) 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_updatedwith{changed_fields: [...], diff: {field: {before, after}}}viaAuditRepo. SOC 2 gap on the most security-relevant setting is closed. - CW-P2-c Dead-code removal. Legacy
CompanySecurityUpdateSchema(declared atcompany_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 existingCompanySecuritySettingsrows, reads each tenant's currentCompany_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-runreports would-be changes without writing. - Dev validation:
ruff check+ruff format --checkclean on all three touched files. Import-sanity smoke viadjango.setup()confirms: view override present (update+_ALLOWED_UPDATE_FIELDS), deadCompanySecurityUpdateSchemagone,_is_2fa_required_safereturnsFalsefor unknown companies without raising. End-to-end DB-level validation ofupdate_security_settingsround-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_2faat 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 incore.services.company_security_serviceready to be consumed by the future workstream.- UI follow-up: company-level
enforce_2fatoggle inCompanySecuritySettingsadmin 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.mdandSECURITY_AUDIT_SECTIONS.mdSection 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)beforeset_password(...), replacing the prior Django-onlyvalidate_passwordcheck that silently ignoredCompanySecuritySettings(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— v1SetInitialPasswordView(/api/v1/user/set-initial-password).
- CW-P1-8 Credential-event audit trail. Every password write now emits a
user.password_changedevent toAuditRepoviacore.services.audit_service.log_password_changed(...), carrying{method, ip_address}wheremethodis one ofreset | change | set_initial | set_initial_via_token | force_change. Failures to write audit events are captured vialogfire.exceptionand never break the business-logic response (best-effort mirror pattern consistent with Section 3 B3). - Unused
validate_passwordandDjangoValidationErrorimports removed from both modules now that all sites route through the canonical policy enforcer. - Dev validation:
ruff check+ruff format --checkclean on both touched files.manage.py-free import-sanity smoke confirms all six endpoint classes load post-edit. Direct call toenforce_password_policy_for_userwith('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.pyintroducing the canonical loader + writer forCompanySecuritySettings:is_2fa_required(company_id)— readsenforce_2fafrom PG (source of truth); defaults toFalsewhen the row is missing. Prerequisite for CW-P0-1.get_session_timeout_seconds(company_id)— readssession_timeout_minutes, converts to seconds, clamps at 300s minimum; defaults to 3600s. Prerequisite for CW-P0-2.enforce_password_policy_for_user(user, password)— derivescompany_idfrom the user's active company membership and delegates to the existingonboarding_security.enforce_password_policyhelper. 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_updatedaudit event, best-effort mirror into MongoCompany_Profile.settings. Prerequisite for CW-P0-4.
- New module
backend/core/services/audit_service.pywithlog_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 swallowAuditRepofailures vialogfire.exceptionso audit-pipeline outages never break the business-logic response. core/services/__init__.pyexports 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) fromfrontend/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.tsso transient backend/network failures (5xx/transport errors) duringcheckAuth()no longer force an immediate logout redirect to/login. checkAuth()now only returns unauthenticated on explicit auth failures (401/403after 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 initializelast_activitybefore 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), B3check_company_admin/check_company_ownerforwarders, 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_invitationssuite 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.mdflipped toCompleted. All 4 P0 items shipped. 13 of 15 P1 items shipped; ON-P1-6 / ON-P1-7 (email-outbox migration forCompanyMemberInviteView+CompanyProvisionUserView) explicitly deferred as a follow-up because it requiresEmailDeliveryOutboxtemplate 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_adminandcheck_company_ownerthat lived inbackend/core/api/v1/company_management_views.py:401(predating the Section 2 B0 consolidation) are now thin forwarders tocore.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.postandInvitationDetailView.deletenow writecompany.invitation_sentandcompany.invitation_revokedevents toAuditRepo. Paired with the existingcompany.invitation_acceptedwrite inInvitationAcceptView, this provides the complete SOC 2 audit trail for invite create → revoke / accept transitions. Failures to write audit events are captured vialogfire.exceptionwithout 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) andCompanyProvisionUserView(rawsend_mail) ontoEmailDeliveryOutboxrequires template wiring forCompanyInvitationEmail/AccountCreatedEmailbeyond the immediate Section 3 scope. Tracked as a separate follow-up and noted indocs/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 —
RateLimitMiddlewareis now actually installed insettings.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.postnow performs an affected-row=1 update onset_password_token_claim_at__isnull=Truebefore 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 legacyuser.company_idFK match whenCompanyMembership.status != ACTIVE. Mirrors the Section 2 ON-P0-1 fix inaccess_scope.resolve_access_scope. Offboarded users with stale legacy columns now get a 403 instead of a tenant-scoped JWT. Verified on dev (403 withUser 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 theprocessingstate (previously a subtle stuck-invitation bug). Frontendaccept-invitation/[token]page now postsbody.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) andInvitationAcceptView(POST), plusSetupAccountDetailView/SetupAccountCompleteView, now querytoken_hash(HMAC-SHA256) first and fall back to plaintexttokenduring the Phase B rollout window. All new invitations created viaAuthRepo.create_invitationdual-writetoken_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 hardcodedlen(password) >= 8check withcore.services.onboarding_security.enforce_password_policy(company_id, password). Responses now return400with 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):CompanyProvisionUserViewno 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_credentialsis effectively always true. Response fieldstemporary_password,setup_url,warningare 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 returns410 Gonewith amigrationpayload pointing clients at the canonicalPOST /api/v1/invitations/{token}/accept/. This removes theX-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 returns410 Gonewith the same migration payload. Removes the parallel PGCompanyInvitationacceptance surface that had no rate limit, no atomic claim, no hashed token storage. - Dev validation:
manage.py checkclean; curl smoke confirms both legacy endpoints return410, nonexistent setup-token returns404(no leakage via policy response), weak passwords return400with rule_errors, policy-compliant password completes with200.
v0.4.91 - 2026-04-24
Security / Onboarding — Section 3 Phase B0 (foundations)
- New module
backend/core/services/onboarding_security.pyintroducing the canonical primitives that the rest of the Section 3 hardening will build on:hash_token(plaintext) -> strandverify_token(plaintext, stored)— HMAC-SHA256 keyed bysettings.SECRET_KEY, so a DB-only compromise cannot be used to hijack pending invitations / setup tokens (addressesON-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)— loadsCompanySecuritySettings(default min length 12, require upper/lower/number) and returns a structuredPasswordPolicyResultwith per-rule error keys + human messages (prerequisite forON-P0-1).consume_single_use_setup_token(plaintext)— atomic affected-row=1 claim that mirrors the invitation'sfind_one_and_updateflow and eliminates the setup-complete race (ON-P1-2). Dual-reads hash + plaintext during the rollout window.
CustomUsermodel — addedset_password_token_hash(unique, indexed) andset_password_token_claim_atfields;generate_set_password_tokennow 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-writestoken_hashalongside the existing plaintexttokenin the Mongoinvitationscollection. 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.mdfor 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.mdSection 3 flipped toIn Progresswithonboarding_invitationsas 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 HTTP500responses when Pydantic error context includes non-JSON-serializable exception objects (for exampleValueErrorinsidectx).- Validation error details are now normalized to JSON-safe structures before
JsonResponse, so invalid inputs (such as blankdue_date) correctly return HTTP400withVALIDATION_ERRORdetails. - Create Task Assist executive snapshot no longer displays provider model identifiers to end users.
- Removed legacy
Suggested TitleandSuggested Descriptioncards 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
MagicLinkRequestViewto 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 + Descriptionand one-clickCreate Split Subtasksfrom split recommendations, with immediate task save persistence behavior aligned to existing subtask actions. - Fixed task-activity proxy path for
POST /api/dashboard/tasks/{taskId}/activityto 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_rbacsuite upgraded from 2 callable-exists checks to 10 runtime checks (helpers, DRF permission classes, normalize aliases,check_project_roleproject 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.mdupdated. 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_membershiphelpers acrosscore/api/v1/views.py,meetings_views.py,calendar_views.py,task_actions_views.py, andworkspace_analytics_views.pyare now thin forwarders to the canonicalcore.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_membershipis architecturally distinct (DRF object-level permission resolver) and intentionally left unchanged. - P2-q
AuthRepo.__init__now ensures a unique index onusers.emailin the central Mongo database, so future email-based lookups (used by the auth path and byresolve_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
PresenceRepoRedis keys are now namespaced bycompany_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_countnow reads the per-companypresence:{company_id}:onlineset in O(1) instead of scanning every key in Redis DB 3. Legacy unscoped reads are preserved as a fallback during rollout.PresenceServiceand all HTTP + consumer call-sites now passcompany_id;chat/api/presence_views.py,chat/consumers/presence_consumer.py, andcore/api/v1/company_settings_views.py(force-logout) updated. - P1-2
FeedbackRepo(company_id=...)now injectscompany_idinto everylist/getfilter and stamps it on everycreate. 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 byis_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_stopnow reject anyconversation_idthe socket has not previously joined viachat.join_conversation(where membership is verified). This brings the WebSocket path to parity with the HTTPMessageViewSet.create403 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 viaMembershipRepo.has_workspace_access, closing the gap where any authenticated socket could claim an arbitraryworkspace_idat connect and pollute that workspace's presence/event groups. MatchesPresenceConsumerparity. - P1-7
MeetingConsumer._check_access— before theboard:viewshort-circuit fires, verify that the meeting'sproject_idmatches the one the client supplied in the query string. Previously a user with board:view on project A could attach?project_id=Ato a meeting scoped to project B within the same tenant. - P1-8
channels_middleware.py— WebSocket auth hardening:- Only
AccessTokenis accepted;refresh_tokencookie 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.
- Only
- 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_scopenow uses it in place of the cappedlist(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 directrequest.user.company_role not in allowed_roleschecks (project create/update/delete) now go throughnormalize_company_role, closing case-sensitivity andwatcher/contractoralias divergence. - P1-24
project_creation_ai.py::ProjectCreateWithAIView.postreads tenant from JWT claim only (not theX-Tenant-Idheader) and gates onrequire_company_role('owner','admin','manager').ProjectCreationProgressView.getnow requires an authenticated user + active company membership. - P1-25
comms/tasks.py— removed brokenint(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_rolenow honors itsproject_idparameter. 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 anymembercould 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 onscope.has_any_access()immediately afterresolve_access_scope, and onscope.is_read_only()for mutation-equivalent paths.billing-only users no longer leak AI policy summaries;viewer/contractor/guest/watcherroles 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 onrequire_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 ontask:updatefor the post's project. - P1-19
core/api/v1/snapshot_views.py::ProjectSnapshotView.getnow gates onrequire_project_role('board:view'). - P1-10
email_test_views._is_authorizedrestricted to Djangois_staff/is_superuser,@alesko.aiemail, or shared-secret header. Previously any authenticated user could trigger test-email blasts. - P1-11
_require_mutation_origin_guard(blob_documents_views.py) now validatesX-Internal-Proxy: 1againstINTERNAL_PROXY_SECRET; an unverified header is rejected with 403 rather than bypassing CSRF. - P1-12
ops_views._has_ops_accesstightened to superuser OR owner/admin of the caller's own company. Themanagergrant is removed and client-suppliedcompany_idquery parameters are no longer used for authorization (only for scoping the data view). - P1-13
AleskoFeedbackListViewrestricted to Djangois_staff/is_superuser; the@alesko.aiemail, dashboard-password, and arbitrarycompany_idquery 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.pynow rejects the legacyCustomUser.company_id/company_rolefallback when no ACTIVECompanyMembershipexists. Users whose membership had been moved toremoved/suspendedno longer silently retain access via stale legacy columns; access revocation viaCompanyMembership.statusis 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_idis taken from JWT claims only (no longer accepted from the request body), andreview-taskadditionally requires the caller to be an eligible project member viarequire_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.getnow 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 iteratingcompany_idin 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_membershiphelpers (PGCompanyMembership-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-standingcheck_project_rolegap whereproject_idwas 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_rolealias table (core/services/company_membership_service.py):watcherandread_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 coveringmembers,member_ids, andproject_lead_idfields. - 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_adminhelpers, and JWT/cookie/WebSocket auth paths. No code changes. - Produced
docs/architecture/rbac-audit-matrix.mdwith 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, unauthenticatedai_views.pyendpoints, openCompanyMembersAPIViewGET), 25 P1 items (Chat WS TOCTOU, presence Redis key namespace, feedback repo tenant scope,check_project_roleignoringproject_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.mdwith Section 2 Phase A completion, Phase B/C pass criteria, andauthorization_rbacorchestrator-suite key.
v0.4.80 - 2026-04-24
Fixed
- Hardened
POST /api/v1/ai/review-task/against transient model output-schema validation failures (for exampleExceeded maximum retries (1) for output validation). - The review endpoint now returns HTTP
200with a structured fallback review (fallback: true, conservative health/risk guidance, and diagnosticdetail) instead of bubbling a backend500, 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
TaskReviewschema to parse JSON-encoded string payloads for nested object/list fields, so provider outputs that stringifyprogress_insights/timeline_analysisno 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 Subtasksto 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-cleanmode that rebuilds images and wipes the named dep volumes (bluprint_frontend-node-modules,bluprint_frontend-next,bluprint_backend-node-modules) beforedocker compose up -d. Use this whenrequirements.*orpackage.jsonchanges, because the compose file mounts those named volumes over/app/node_modulesand/app/.nextand a normal--rebuildleaves the pre-upgrade volume contents in place — producing runtime failures likeCannot find module '@tailwindcss/postcss'even after a clean image build. scripts/sync-dev.shnow warns (non-fatal) whenbackend/requirements.*,backend/Dockerfile*,frontend/package*.json, orfrontend/Dockerfile.devhas 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.shandscripts/dev-server-git-sync.shnow:- Run under
set -euo pipefailand fail fast if the SSH key is missing. - Accept
EC2_HOST,SSH_KEY, andREMOTE_DIRenv overrides instead of a hardcoded configuration. - Support three modes:
--restart(default, mirror of prior behaviour),--up(docker compose up -dfor compose-file edits), and--rebuild(rebuild backend+frontend images andup -d— needed whenever Dockerfiles,requirements.*, or the Python/Node base versions change). - Restart the full service set (
backend daphne celery celery-beat frontend);celery-beatwas 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.
- Run under
scripts/dev-server-git-sync.shadditionally refuses to run if the server-side working tree is dirty (instead of silently losing changes ongit checkout/pull).
Removed
scripts/staging_diag.py. Azure-era wrapper aroundaz containerapp execagainstbp-backend-stagingin thekorali-aue-stg-rgresource group; superseded by running theaudit_rbacmanagement 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 thatinfra/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.pyfrom 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 directAsyncOpenAIxAI 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.tsto 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/Dockerfileandbackend/Dockerfile.dev: base imagepython: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.txtwith--python-version 3.14. - Rebuilt local
backend/.venvon 3.14.3 and resynced; confirmedpython manage.py checkpasses and the Auth & Sessions pytest suite passes (aside from the one case that requires a live Redis). - Ruff re-checked clean against the new
py314target.
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 tomodels.CheckConstraint(condition=...)in app models (billing_and_payments/models.py,companies/models.py) and in existing migrations (companies/migrations/0006_company_membership.py). Thecheck=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.into 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 recompiledbackend/requirements.txt. - Verified
python manage.py checkpasses 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.
- Django 5.2.11 → 6.0.4 (major). Renamed all
- Frontend dependency upgrade sweep:
- tailwindcss 3.4.x → 4.2.4 (major). Migrated via the official
@tailwindcss/upgradecodemod:tailwind.config.tsremoved (custombrand/purplepalette andgradient-radialbackground-image moved to a CSS-first@themeblock insrc/app/globals.css),@tailwind base/components/utilitiesreplaced with@import 'tailwindcss';, postcss config switched to@tailwindcss/postcssplugin, andautoprefixerremoved (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
baseUrlfromtsconfig.json(TypeScript 6 warns and will stop honouring it in 7.0); path aliases viapathsalone continue to work. - eslint-config-next 15.5.14 → 16.2.4 (major). Migrated
eslint.config.mjsfrom the legacyFlatCompat.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 --noEmitis clean andnext buildsucceeds on the full project.
- tailwindcss 3.4.x → 4.2.4 (major). Migrated via the official
- Held back: ESLint is pinned at 9 rather than 10 because
eslint-config-next@16transitively depends on aneslint-plugin-reactversion that does not yet support ESLint 10's rule-listener API (breaks onComponents.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
Decimalimport and a shadowedtimezonesymbol (datetime.timezonevs.django.utils.timezone) inbackend/core/api/v1/ops_views.py. Django'stimezoneimport is now aliased (django_timezone) andDecimalis explicitly imported. - Admin CRM panel no longer fails to compile.
CRMContainer.tsxwas referencing an undefined module-scopeaddPersoninAddPersonModal's prop typing and usingPersonSourcewithout importing it. Replaced with an explicitAddPersonInputtype alias and addedPersonSourceto the@/lib/crm/typesimport. - Associate chat hook (
useAssociateChat.ts) no longer fails TypeScript compilation:planRevealTimer,tokenFlushFrame, andstreamFinalizedare now declared before thetryblock so the matchingcatchcleanup path can reach them. - Onboarding setup modal (
OnboardingSetupModal.tsx)StepCompletiontype now includes theprojectkey to match its actual usage instepCompletionstate and the step-completion guards.
Changed
- Lifted CRM state into a provider (
@/lib/crm/context).CRMContainernow wraps inner tabs with<CRMProvider>and each tab consumes the shared store viauseCRM(), 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
localStoragereads/writes onto thestorage.tshelper 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.companyIdto 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
AdminBusinessOverviewAPIViewwith 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_idquery 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/loginresponse 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_tokencookie only (removedsessionidfallback) 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 & Sessionstest 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_sessionssuite to execute backend pytest target(s) (currentlybackend/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
standardandmaxlanes 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
doneevents. - 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
429responses by de-duplicating client timer sync loops (useTimersync 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_progressare 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 Changelogmodal loading failures by moving changelog JSON delivery to a non-/apiapp 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/performanceresolve 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/performancefrom 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
CompanyMembershipmodel (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.pyto createcompanies_companymembershipand backfill membership rows from legacyusers_customuser.company_id+company_rolemappings. - Added
backend/core/services/company_membership_service.pywith 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.mdcovering backend, websockets, Redis, frontend context UX, and notifications behavior.
Changed
- Updated
docs/api/README.mdtenant/company context section to document PostgreSQL membership as the new canonical multi-tenant foundation and compatibility posture during migration. - Updated
docs/architecture/feature-flows.mdto 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.pynow prioritizes PostgreSQLCompanyMembershipchecks for project/company authorization before legacy user-company fallback.backend/core/auth/access_scope.pynow derives scope company role from active membership first.backend/core/auth/token_generator.pynow 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.pynow prefer explicit request company context (X-Company-Idorcompany_id) before JWT fallback. - workspace analytics/activity endpoints in
backend/core/api/v1/workspace_analytics_views.pynow enforce explicit/request company context and membership validation.
- notifications endpoints in
- 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.pybackend/core/api/v1/calendar_views.pybackend/core/api/v1/meetings_views.pyThese 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.pybackend/meetings/consumers/meeting_consumer.pybackend/chat/consumers/presence_consumer.pybackend/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.pyto company-scoped feed channel naming. - updated frontend websocket hooks (
frontend/src/hooks/usePresence.ts,frontend/src/hooks/useCommsWebSocket.ts) to treat close code4004(membership denied) as non-retry auth failure.
- updated chat consumer feed-group test expectation in
- 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-companyuser.company_rolefallback. - restores Invite/Provision actions for users who are admin/owner in the selected company but not in the legacy primary company field.
- admin/manager role checks now prefer the active company role from
v0.4.72 - 2026-04-19
Fixed
- Fixed task reopen 500 errors when moving a task out of
doneafter completion by normalizingcompleted_atparsing in the/api/v1/tasks/{task_id}/reopen/handler. - Reopen time-limit checks now safely handle legacy/naive
completed_atvalues (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.tsxso 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 titlepill with cleaner inline job-title text to remove visual clutter in the member list. - Added a People modal
Provision Userflow 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
/indexas the canonical public landing page route with full landing content rendering directly atfrontend/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, sobluprint.alesko.online/indexis the stable homepage. - Hardened landing dark/light mode toggle behavior by persisting the selected mode in browser
localStorageand 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 walletpricing copy to fixed values with noAboutwording:Associate chat:$0.01(unchanged),Project document:$0.05,Health report / Gantt analysis:$0.03.
- Replaced login-page top-left
Bluprinttext 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
/indexnow 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
/indexto match the new canonical landing route.
v0.4.67 - 2026-04-16
Changed
- Refined landing-page
Pricingstructure and copy:- merged standalone
How it worksguidance into theUsage walletcard, - removed the separate pricing
How it worksblock 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.
- merged standalone
- Updated landing-page pricing language to match fixed pricing:
- changed table header from
Typical cost (wallet)toTypical cost, - changed
Associate chattypical price fromAbout 1 centto$0.01, - updated onboarding line to
Get $10 in credits instantly on company account creation.
- changed table header from
- 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
Philosophyfrom footer Product links.
- switched footer logo to use the same dark/light
v0.4.66 - 2026-04-15
Added
- Added EC2 dev server infrastructure for rapid iteration:
- Single
t3.largeinstance on Amazon Linux 2023 with Docker, PostgreSQL 16, Nginx, and Certbot. docker-compose.dev-server.ymlrunning frontend, backend, Daphne, Celery, Redis, MongoDB, and MinIO.- Hot-reload dev mode via volume mounts (
next dev, Djangorunserver). - Nginx reverse proxy with WebSocket support and Let's Encrypt SSL for
bluprint.alesko.online. scripts/sync-dev.shfor one-command rsync from local machine to EC2.scripts/dev-server-git-sync.shfor git-pull based updates on the server.backend/core/settings/dev_server.pyandbackend/.env.dev-serverfor dev-server-specific configuration.
- Single
Fixed
- Fixed Next.js dev-mode CSP error on the dev server by adding
'unsafe-eval'toscript-srcinnext.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-serveron 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_contentin assistant messages withtool_callsin conversation history. Addedreasoning_contentpreservation across turns by:- extending
ChatMessageSimpleandAssistantMessagemodels with areasoning_contentfield, - populating it from
ToolCall.reasoning_tokenswhen building chat history from the database, - threading it through
_build_structured_assistant_messageand the LLM loop so subsequent turns include the required reasoning block for Moonshot/Kimi thinking models.
- extending
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 workstrip for spend variability clarity, - added an in-section
How it worksexplainer anchor and beta-credit policy notes.
- new two-panel structure (
- Refined landing
Pricingonboarding and copy:- replaced closed-beta
Express Interestheader CTA with sign-up-now messaging, - renamed
Beta offertoWelcome offer, - updated top-up language to
Top up as requiredwith explicit$20 minimum top-upterms note, - removed decorative icons from
Usage walletheader and workload strip, and center-aligned workload strip text.
- replaced closed-beta
- Finalized landing
Pricingvisual 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 Philosophysection 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
Philosophypillar 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
Announcementstab timeline handling so announcement duration windows are enforced in heartbeat data:- announcements now drop from the feed after
pinned_untilexpires (24h/48h/7d), - legacy announcement records without
pinned_untilremain visible for backward compatibility.
- announcements now drop from the feed after
- Fixed Personal Dashboard
Daily Brieflanguage so announcements are treated as informational updates by default and are no longer framed asneeds attentionblockers without explicit urgency signals. - Fixed Associate task assignment self-identity handling so requests like
assign it to meresolve to the authenticated chat user instead of prompting for member identity. - Fixed Associate staging commit support for
complete_subtaskandadd_comment_to_taskso accepted staged changes now apply correctly. - Fixed Associate
complete_subtasktask 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 intool_usage. - Fixed Associate
complete_subtaskruntime path to use async Mongo access correctly (resolvesobject dict can't be used in 'await' expressionerrors). - 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_eventsaggregation fallback in usage APIs whenusage_rollups_dailyis missing/stale. - Fixed Associate
add_comment_to_tasktask resolution so non-ObjectId task references (task-title inputs) no longer fail early withInvalid task IDbefore fallback matching. - Fixed Project
Usagetab 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 & Costpanel to consume live usage endpoints (company/projects/users) instead of placeholder text. - Fixed Navbar
Changelogmodal API to avoid hard failure whendocs/CHANGELOG.mdis unavailable in runtime environments by returning a safe fallback payload. - Changed Company Settings
Billingtab UI to a simplified operational layout:- removed the non-actionable free-plan summary card,
- added focused controls for
Balance,Top Up, andManage 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
Logoutactions on admin console surfaces (/admin/managementand/admin/performance) that terminate the current session via/api/logoutand 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.Projectinstead of legacyblueprint.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 includebilling. - Aligned RBAC enforcement for project permissions:
contractor/guest/viewernow enforce read-only access incheck_project_role.billing/billing_onlynow enforce no project-role access.
- Aligned Associate model-tier policy:
member:standard+maxviewer/watcher:standardonlyguest/contractor:standardonlybilling/billing_only: no model access
- Expanded membership permission mapping to include explicit entries for
manager,viewer,guest, andbillingroles.
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 > Overviewtop layout for PM-first scan:- action queue cards now appear first with no section header,
Project Snapshotnow 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
1x5card 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 Snapshotand simplified snapshot styling to reduce nested card clutter. - Reworked
Project Snapshotstat tiles to a compact, left-aligned footprint so the section no longer feels visually over-stretched. - Consolidated
Project SnapshotandSupporting Evidenceinto a single KPI strip using the supporting-evidence card style. - Expanded the unified KPI strip from
1x5to1x7by addingOverdueandActive 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 Flowprogress bars,Priority Distribution->Priority Risk Matrixwith at-risk overlay,Team Velocity->Velocity vs Capacitycombo chart with capacity trend line.
- Added sprint-specific timeframe control behavior: when
Sprintis 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
capacityline 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/Confidencechips and narrative inference text; charts now present raw metrics only. - Replaced estimated
Priority Risk Matrixoverlays with rawPriority Loadcounts 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 taskestimatevalues bydue_dateacross 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 timechart range for project-lifetime visibility, using month-based buckets from the earliest tracked project task date to present. - Expanded capacity extraction to use both
estimateandestimated_efforttask fields and added explicit in-chart messaging when capacity is unavailable due to missing estimates/due dates. - Updated timeframe control wrapping so
All timeremains 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 supportssearch,role,status,page,page_sizeand returns pagination metadata.GET /api/v1/companies/{company_id}/pods/now supportssearch,status,page,page_sizeand returns pagination metadata.
- Upgraded Company Dashboard
People Managementpopout 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 Settingsnow follows the same disabled/tooltip UX pattern when the user lacks required owner/admin permissions.
- Added a dedicated premium
People Managementpopout on Company Dashboard quick links:- moved
Manage Peoplequick 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.
- moved
- 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:
Managebuttons 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 Projectactions that openProjectSettingsModal.
Fixed
- Raised
ProjectSettingsModaloverlay 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
Manageaction in expanded project rows on Company Dashboard workspaces table. - Wired project management action to open
ProjectSettingsModaldirectly from Company Dashboard, aligned with existing project settings UX patterns.
v0.4.57 - 2026-04-09
Changed
- Company Dashboard quick-link
Manage Workspacesnow opens a dedicated workspace management popout instead of routing users into the Company Settings modal tab flow. - Added a premium-style
Workspace Managementpopout with:- high-level workspace metrics,
- workspace search/filter,
- create-workspace action,
- direct per-workspace settings management actions.
- Removed the workspaces tab/surface from
CompanySettingsModalso 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=workspacessupport.
v0.4.56 - 2026-04-09
Fixed
- Fixed
usePresencecache upsert typing to avoidPresenceState | ""union leakage that broke production type-checking duringnext 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.mdwith item-by-itemPASS/PARTIAL/FAILcriteria 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.cssafter 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_PREVIEWnow defaults to enabled unless explicitly set tofalse).
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
Peopletab 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 inusePresence. - 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
Hometab to/admin/managementas 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
Homeoverview surface.
v0.4.51 - 2026-04-08
Added
- Added backend management command
bootstrap_alesko_adminsto create/repair a fully usable Alesko admin tenant across PostgreSQL + MongoDB:- upserts
jared@alesko.ai(owner) anddenis@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).
- upserts
- 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/loginexperiment. - Restored admin login UI to email/password mode for
jared@alesko.aianddenis@alesko.ai. - Restored
/api/admin/loginto 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/loginto validateADMIN_CONSOLE_PIN(default123456) and then perform backend service-user login using:ADMIN_CONSOLE_SERVICE_EMAIL(defaultjared@alesko.ai)ADMIN_CONSOLE_SERVICE_PASSWORD(fallback toADMIN_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_PASSWORDinfrontend/.env.local, - added
frontend/.env.stagingwithADMIN_CONSOLE_BACKEND_PASSWORD, - documented key in
frontend/.env.example.
- set
v0.4.47 - 2026-04-08
Fixed
- Hardened
/api/admin/loginbootstrap 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 withADMIN_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.
- if bootstrap email/password gate passes but backend
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/feedbackhandling 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 Contactblock:- clear submitter/company/contact display,
Copy Emailaction,Email Customeraction.
- Added
Issue Contextpanel on beta-feedback tickets with severity/repro/expected/actual plus attachment links. - Updated API docs for
/api/v1/feedbackoptional 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.
- added submitter metadata (
- 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_submissionsrecords intoops_support_tickets, - synced tickets are tagged with
source=beta_feedbackand 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).
- support ticket listing now idempotently syncs missing
- 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 Orchestratortab 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.
- release readiness decision panel (
- Updated planning checklist to mark Phase 3 Testing Orchestrator V1 hardening complete.
v0.4.42 - 2026-04-08
Changed
- Upgraded
Ops Commandtab 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) inadmin_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.
- billing credit apply (
v0.4.40 - 2026-04-08
Changed
- Implemented Phase 6
Customer/Billing Ops + Comms Centerfor/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 + Roadmapfor/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.
- request intake persistence (
- added internal product feedback APIs:
- Added frontend admin product feedback proxy routes:
/api/admin/feedback/requests/api/admin/feedback/requests/{requestId}
- Replaced
ProductFeedbackTabscaffold 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 + Jobsfor/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_servicewith:- 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).
- ticket persistence (
- added internal support operations APIs:
- 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
SupportDeskTabscaffold 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 Orchestratorfor/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_servicerun 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 internal ops testing backend contract:
- Added frontend admin testing proxy routes:
/api/admin/testing/suites/api/admin/testing/runs/api/admin/testing/runs/{runId}
- Upgraded
TestingOrchestratorTabfrom 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 Commandintegration 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/performancecontrol-plane surface directly insideOps 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
- replaced the prior 3-tab shell with 6 pillar tabs:
- 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/loginfooter 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.aianddenis@alesko.aiby default (env-overridable), - validates a bootstrap admin password (default
Alesko2026$, env-overridable), - on success, issues
auth_token/refresh_tokencookies and unlocks admin management cookie (alesko_perf_access=1).
- restricts login to
- Updated middleware public-route allowlist to include
/admin/login. - Added planning doc
docs/planning/MANAGEMENT_CONSOLE_6_PILLAR_PLAN.mdto 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 Taskssub-tab flicker/revert bug where clickingOverdue,This week, orAllcould briefly switch then snap back to the previous sub-tab. - Dashboard navigation URL-sync now updates
myTasksSubTabstate 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_idfrom 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
Announcementsheartbeat. - 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 happenedupdates 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_idmatching) instead of relying on task-levelworkspace_idfields. - Daily Brief activity feed now recognizes activity timestamps from both
created_atandtimestamp, 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.pyto repair existing comms feed postworkspace_idvalues 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
Projecteyebrow 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) whenOrigin/Refererare absent. - Resolved intermittent
forbidden_originfailures when updating Company Documents template lifecycle (for example switching a document back todraft). - Applied the same guard hardening to Company Documents
use-in-projectproxy 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
FormDatapassthrough, preventing profile picture uploads from dropping file payloads in transit. - User profile picture API now accepts both
fileandprofile_picturemultipart keys for compatibility across clients. - Added persisted user-level
date_formatandweek_starts_onfields 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.
- Next.js proxy now forwards multipart form uploads using
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=securityand persists accepted company/workspace context in local storage. - invite acceptance workspace selection now prefers backend-confirmed
workspace_idbefore fallbackpreferred_workspace_idto 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.
- onboarding default view options now align to workspace settings-compatible values (
- Company settings profile hydration:
- company profile retrieval now prioritizes
Company_Profilerecords scoped to currentcompany_id, improving consistency for website/profile fields from creation flow.
- company profile retrieval now prioritizes
v0.4.25 - 2026-04-08
Fixed
- Member project visibility hardening (second pass):
/api/v1/projectsand/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/menow returns normalizedname+display_namepayload 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
pinnedfirst, 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.
- board task ordering now sorts by
- Kanban default density fallback:
- board now falls back to user appearance preference (
/api/v1/user/preferencesview_density) when no per-project compact override exists in local storage.
- board now falls back to user appearance preference (
- Workflow status rename flow alignment:
- Project Settings
Workflow -> Task Statusessave 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.
- Project Settings
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.
- membership filtering now matches both PostgreSQL project UUID and MongoDB
- 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 Accessaction when creation is denied by permissions.
- new endpoint
- Health report RBAC tightened:
POST /api/v1/ai/projects/{project_id}/health-report/now blocks member role access with explicit403.- Project overview UI now hides
Generate Health Reportfor 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
0values and normalizes numeric-string budget values from metadata. - project members API now includes
profile_picture_pathin addition toprofile_picture_urlfor stronger avatar fallback compatibility.
- project settings budget hydration now preserves explicit
- 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 tomember, 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, resolvingNo file providedfailures. - Profile picture updates/removals now refresh
bp.currentUseravatar 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.
- Profile picture upload now sends the expected multipart key (
- 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.
- User profile API now defaults language/date format consistently (
- Invitation acceptance context hardening:
- Invitation accept response now returns resolved
company_id(not raw tenant fallback where mismatched), and auth tokencompany_idclaim aligns with resolved company context. - Accept-invitation frontend now falls back to loading a company workspace when
workspace_idis absent, reducing blank-state routing after acceptance.
- Invitation accept response now returns resolved
- 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_idsand 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_tabquery-param validation with a proper string-to-union type guard before callingsetPersonalSettingsInitialSection - removed unsafe cast path that failed under
next buildtype-checking
- tightened
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
Peopletab 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
Generaltemplate 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.
- Removed
- 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 Chatssection 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.tsfrontend/src/app/api/dashboard/projects/route.tsfrontend/src/app/api/dashboard/my-tenants/route.ts
- Next.js proxy routes now forward the full incoming cookie header (not only
- Hardened backend company-context parsing:
company_idnow 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_idas 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
403withmembers_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 Documentsexplorer 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 Documentssidebar search and toolbar controls now mirror project documents explorer spacing/size patterns for tighter visual parity. - Company Dashboard
Company Documentsfile 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 Documentstree now supports inline folder creation and inline rename directly in the explorer. - Company Dashboard
Company Documentstree rows now expose expanded hover actions:- folder: create file, create folder, rename
- file: rename, delete
- Company Dashboard
Company Documentssupports 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 Documentsexplorer now creates files inline in the tree (no browserpromptflow). - Company Dashboard
Company Documentstree rows now expose hover actions for quick file creation inside folders and quick file deletion. Newaction 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 Walletcard layout now showsCurrent balanceinline on the right side (no separate balance box). Manage Billingin the dashboard billing card now spans the full card width instead of being constrained to the left column.- Refined
Billing Walletbalance presentation so the right-sideCurrent balanceblock 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, andmember_idsagainst 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_idwithworkspace_id, preventing cross-company context drift that could hide announcements. - Navbar notification polling, list fetch, and read/read-all actions now include active
company_idcontext 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
CompanyWalletbalances (promo,purchased,debt) with debt-floor policy support - immutable
WalletLedgerEntryrecords with idempotency keys and balance-after snapshots PromoCreditGranttracking with expiry support- versioned
PricingCatalogEntryand scopedBillingLimitmodels
- shared
- 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:
$10welcome 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:
WalletTopUpOrdermodel 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
Billingsection 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
- Company Settings
- Admin testing dashboard now includes a
Billing Testpanel:- 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 Weeksection to prepare relocation into company-level surfaces. - Company Dashboard leaderboard card now excludes the
Associate AIranking tab and keeps task/activity leaderboard views. - Company Dashboard now includes a dedicated bottom
AI Usage & Costcard withCompany,Projects, andUserstabs in empty-state mode (no mocked values, backend wiring deferred).
Added
- Added reusable
AiValueThisWeekCardcomponent scaffold for later company-dashboard integration. - Added dashboard planning document for:
My Taskstab 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 Walleton the left andAI Usage & Coston the right. - Row 3 now shows
Company Informationon the left andStorageon the right.
- Row 2 now shows
v0.4.14 - 2026-04-07
Changed
- Company Dashboard
Billing Walletcard now uses a two-column credits layout with:- left-side explanatory empty-state content and
Manage Billingaction - right-side prominent
Current Balancedisplay area (large figure slot)
- left-side explanatory empty-state content and
- 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 Walletcard 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+ computedproject_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_savedto 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
ReviewandGenerate Reportcontrols 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
Progresslabel)
v0.4.7 - 2026-04-06
Fixed
- Task modal and task creation assist copy now consistently use
Associatewording 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 Analysisnaming 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
Splitlayout 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 Contextis renamed toAssociate 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 Calendarinside 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 Weekstrip 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) andFocus/Splitlayout 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 Glancenow exposes workspace analytics through a dedicated right-sideDetailsaction, removes the bottomRecent Tasks/Team Activity Feedrow, 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
Storagecard 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
Detailsnow 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/adminroles (non-admin company members are redirected) - Added
Company Documentsauthoring surface at/company/[companyId]/documentswith 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
.png)