Most teams that build software also manage a sales pipeline. And most teams that manage a pipeline also track the work that delivers on it. Putting both modules in the same app — with shared auth, shared teams, and shared audit logs — turns out to be more than a convenience. It changes what you can ask of your data.

Architectonic ships both. The Agile module handles sprints, jobs, tasks, and milestones. The CRM module handles contacts, companies, deals, and activities. They are independent enough to enable one without the other, but integrated enough to share the user and team model without any plumbing.

The Agile module

The Agile module is organized around a four-level hierarchy: milestones contain sprints, sprints contain jobs, jobs contain tasks. Comments are threaded at the job level. Every collection lives in MongoDB with a consistent naming convention — agile_milestones, agile_sprints, agile_jobs, agile_tasks.

Sprints move through five statuses: Planning → Active → Review → Completed → Cancelled. The sprint API response is not a raw document — it goes through a MongoDB aggregation rollup that attaches three computed fields to every sprint before it leaves the database:

committedEffort   sum of estimateHours across all tasks in the sprint
velocity          sum of estimateHours for tasks with status = 'Done'
completionPct     velocity / committedEffort × 100

The rollup is a single aggregation pipeline — two $lookup stages (jobs, then tasks via the job IDs) followed by $addFields with $sum and $cond expressions. There is no separate analytics job and no denormalized counter to drift. The numbers are always current because they are computed at read time from the source records.

Team assignment on sprints and jobs

Sprints and jobs both carry an optional teamId field. When teams exist, the sprint and job edit modals show a Team dropdown. The assigned team displays as a badge in the sprint header (next to status) and the job header (next to category). The Agile layout server fetches GET /teams once per page load and passes data.teams to every Agile page — no per-component fetch, no prop drilling.

The seed data wires this up for a realistic starting state: Backend team gets the foundational, core-features, data-layer, and analytics sprints plus all API-flavored jobs; Frontend team gets the UI-layer and polish sprints plus all UI-flavored jobs.

What the frontend surfaces

The Agile section exposes eight distinct views under /agile: a Kanban board, a timeline, a sprints list, a jobs list, a tasks table, a milestones page, a my-tasks personal queue, a planning page, and a reports panel. The board and timeline are the primary working surfaces. Reports pull from the same rollup pipeline to show velocity trends and completion rates across sprints.

The CRM module

The CRM module models a standard B2B pipeline: contacts are people, companies are organizations, deals link contacts to companies and move through stages, activities record interactions against any CRM entity.

Deals are the load-bearing model. Every deal has a stage drawn from a fixed vocabulary — Discovery, Proposal, Negotiation, Contract, Closed Won, Closed Lost — and each stage carries an automatic win-probability:

Discovery     10%
Proposal      30%
Negotiation   60%
Contract      85%
Closed Won   100%
Closed Lost    0%

The probability is stored as a field on the deal document and updated automatically whenever the stage changes. It is not a derived calculation on the frontend — the API writes it on every stage transition so aggregations (expected revenue, weighted pipeline) work directly in MongoDB without application-layer math.

Deal types are: New Business, Upsell, Renewal, Partnership. These feed the reports module but carry no behavioral logic — they are pure classification.

The pipeline view and activities

The CRM frontend exposes six routes under /crm: a pipeline view (Kanban-style deal board, one column per stage), contacts, companies, deals table, activities feed, and reports. The pipeline view is the primary selling surface. The activities feed is the audit trail for relationships — every call, email, meeting, or note is logged here against a contact, company, or deal.

Activities tie back to the same audit_logs infrastructure that records user management and permission changes. The schema is different — CRM activities are user-created records, not system events — but the pattern of "who did what to what resource at what time" is identical.

Shared infrastructure

Both modules sit behind the same RBAC layer. The requirePermission preHandler guards every route — agile_sprints, crm_deals, and so on are just resource names in the same permissions collection. Adding a user to a team gives them team-scoped visibility in Agile; that same team membership can be referenced in CRM to scope deal ownership.

The notification system (app.notify()) is available to both modules. A deal advancing to Contract can push a real-time notification to the assigned user. A sprint completing can notify the milestone owner. Both are one-liners against the same decorator — no module needs to know how notifications are delivered.

Enabling both in a new project

When you run node arch.js create myapp --modules agile,crm, both modules are merged into the scaffold, their permissions are seeded into MongoDB, and their nav entries appear in the sidebar — gated by hasPermission so they only show to users with the right roles. The containers restart and the modules are live. There is no migration to run, no schema to declare. MongoDB adds the collections the first time a document is inserted.

The point of putting these two modules in the same app is not feature density. It is that the people closing deals and the people shipping work are the same people — they should not have to leave the app to see both sides of the picture.