Work queue: 41 done, 2 in review, 3 in progress, 9 queued, 1 blocked, 56 tasks.
Repository, database, login, API, worker, design shells, and a proven backup. Later phases build on this.
DoneM0.1Repository boots cleanly
A clean clone installs, lints, typechecks, tests, and builds.
No task has been queued for this yet.
DoneM0.2Compose foundation on loopback
MySQL, Redis, Keycloak, the API, the worker, and the three web shells start on loopback.
No task has been queued for this yet.
DoneM0.3Empty database migrates
An empty database migrates the foundation tables.
No task has been queued for this yet.
DoneM0.4API health, logging, and tracing
Health checks, structured logs, tracing, and problem responses.
1 task
DoneAP-0003M0.4 part 2 tracing
queue step validate · milestone M0.4
commit 18fd451
- OpenTelemetry and Sentry are wired through configuration
- A missing DSN or endpoint disables export and does not crash boot
- No DSN, token, or secret is committed
DoneM0.5Keycloak login resolves to a person
A Keycloak login resolves to a person record.
No task has been queued for this yet.
DoneM0.6Sample protected endpoint
A protected sample endpoint allows one caller and denies another.
No task has been queued for this yet.
DoneM0.7OpenAPI client and admin sign-in
The generated API client calls that endpoint from the admin sign-in shell.
No task has been queued for this yet.
DoneM0.8Worker, Redis, and outbox consumer
The worker consumes one outbox event exactly once.
1 task
DoneAP-0002M0.8 worker outbox consumer
queue step validate · milestone M0.8
commit 67a3df0
- A module spec exists at docs/modules/platform/worker-outbox.md before the code
- apps/api and apps/worker import a shared package and do not import each other (D-0042)
- The worker claims an unpublished identity.person_linked v1 row, records one inbox row, and marks the outbox row published
- A second delivery of the same event does not create a second inbox row
- No provider call, no schema change beyond the existing ops_outbox_events and ops_event_inbox tables, and no deploy
DoneM0.9Design-system shells
Design tokens and the public, portal, admin, and mobile shells.
1 task
DoneAP-0004M0.9 design-system shells
queue step validate · milestone M0.9
commit 330a6a0
- packages/design-tokens exposes the approved token v1 values
- web shells use those tokens and do not hard-code brand hex
- White text and white icons are not used on Impact Orange #FF6A00 (D-0027)
BlockedM0.10Backup and restore proven
An encrypted off-host backup can be restored. This step stays manual.
1 task
BlockedAP-0005M0.10 backup and restore
queue step implement · milestone M0.10
Blocked: Restore drills stay manual. The autopilot must not dump or restore the live database.
- A backup and a restore are proven on an isolated ci-test database
- The live codeimpact_v2 database is not overwritten
A person can become a lead, get admitted and enrolled, be invoiced, pay, join a cohort, and be marked present.
In reviewP1-01Reference data (holidays, sequences, settings, flags)
Holidays, number sequences, settings, and feature flags. No legal entity or campus data.
4 tasks
In reviewAP-0048Staff number sequence list and allocation
Platform · queue step validate · milestone P1-01b
Pull request #16 · checks not passed yet · autopilot/ap-0048
- docs/modules/system/number-sequences.md exists before the code and names listNumberSequences plus the internal ensure and allocate services
- A new ADR and a system-owned migration create only sys_number_sequences and insert no sequence rows
- listNumberSequences requires system.config.read and does not change next_value
- allocateHumanNumber locks the row, returns the prefixed padded number, advances next_value by one, and does not insert a missing sequence
- OpenAPI lists listNumberSequences and the slice adds no HTTP create or increment
QueuedAP-0049Staff settings read and put
queue step implement · milestone P1-01c
- docs/modules/system/settings.md exists before the code and names listSettings, getSetting, and putSetting
- A new ADR and a system-owned migration create only sys_settings, with one global row per key and is_secret false
- putSetting accepts only platform.timezone Asia/Kolkata and platform.currency INR
- An update requires If-Match, a missing header is 428, a stale tag is 412, and a real change appends one audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three setting operations
QueuedAP-0050Staff feature flag create and list
queue step implement · milestone P1-01d
- docs/modules/system/feature-flags.md exists before the code and names listFeatureFlags and createFeatureFlag
- No new migration is added; createFeatureFlag uses the existing sys_feature_flags table
- createFeatureFlag requires features.manage, stores status active, and rejects a client status
- A duplicate flag key returns 409 and a success appends one system.feature_flag_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the two feature-flag operations
DoneAP-0047Staff holiday create and list
queue step validate · milestone P1-01a
commit 9b301b0
- docs/modules/system/holidays.md exists before the code and names listHolidays and createHoliday
- A new ADR and a system-owned migration create only sys_holidays, with campus_id null, no campus foreign key, and a database unique on global date and name
- createHoliday requires system.calendar.manage, stores status active, and rejects campusId
- A duplicate global date and name returns 409 and a success appends one system.holiday_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the two holiday operations
A signed-in person can read and update their own profile.
1 task
DoneAP-0006Self profile update
queue step validate · milestone P1-02
commit c4c5644
- docs/modules/identity/self-profile.md exists and names updateCurrentPerson
- PATCH /me updates only the self-editable profile fields and increments version_no
- A missing If-Match returns 428 and a stale If-Match returns 412
- A successful update appends an audit event and does not change keycloak_subject or status
- The OpenAPI document lists updateCurrentPerson and unit tests cover the forbidden and concurrency cases
DoneP1-02bPerson email addresses
A person can hold more than one email address.
1 task
DoneAP-0007Current person email addresses
queue step validate · milestone P1-02b
commit ed875b4
- docs/modules/identity/person-emails.md exists before the code
- listCurrentEmails, addCurrentEmail, and removeCurrentEmail operate only on the signed-in person
- A new email is stored unverified and no email provider is called
- Exactly one primary email remains when the person has any email, and the last email cannot be removed
- OpenAPI lists the three operationIds and unit tests cover a second person's denial
DoneP1-02cConsent records
Consent is append-only.
1 task
DoneAP-0008Append-only consent records
queue step validate · milestone P1-02c
commit 41a3e90
- docs/modules/identity/consents.md exists before the code
- A new identity-owned migration creates idn_consents and the applied migrations are unchanged
- recordCurrentConsent appends a row, and a withdrawal is a new row rather than an update
- The same Idempotency-Key replays and a different body returns 409 idempotency_conflict
- OpenAPI lists listCurrentConsents and recordCurrentConsent, and unit tests cover replay and conflict
QueuedP1-02dRelationships
Relationships and guardians.
1 task
QueuedAP-0051Staff person relationship create and list
queue step implement · milestone P1-02d
- docs/modules/identity/person-relationships.md exists before the code and names createPersonRelationship and listCurrentRelationships
- A new ADR and an identity-owned migration create only idn_person_relationships, with restrict foreign keys to idn_people
- createPersonRelationship requires relationships.manage, stores status active, and accepts only parent, guardian, spouse, and mentor
- A self-link returns 422, a duplicate active triple returns 409, and a success appends one identity.relationship_created audit event
- The self list returns only the caller's relationships, the same Idempotency-Key replays, and OpenAPI lists the two relationship operations
DoneP1-03Role and assignment administration
Staff can create roles and scoped assignments.
1 task
DoneAP-0009Role and assignment administration
queue step validate · milestone P1-03
commit c6db77a
- docs/modules/authorization/role-administration.md exists before the code
- createRole, getRole, and createRoleAssignment enforce authorization.manage or authorization.read as specified
- super_admin succeeds and a learner, a campus-only grant, and a global deny are forbidden
- Idempotent replay returns the original result and a changed body returns 409
- Successful role creation and assignment append audit events, and OpenAPI lists the three operationIds
Create a lead, assign a counsellor, record activity and tasks, and move the stage.
6 tasks
DoneAP-0010Staff lead create list and detail
queue step validate · milestone P1-04
commit 98c0ecf
- docs/modules/crm/staff-leads.md exists before the code
- A new crm-owned migration creates crm_leads and no campus, legal-entity, or catalogue table is added
- createLead, listLeads, and getLead require crm.leads.create or crm.leads.read, and a learner receives 403
- A created lead has status new, nullable campus and program ids, an audit event, and idempotent replay
- OpenAPI lists the three operationIds and unit tests cover denial, replay, and idempotency conflict
DoneAP-0011Staff lead counsellor assignment
queue step validate · milestone P1-05
commit 01262df
- docs/modules/crm/lead-assignment.md exists before the code and names updateLead
- A new crm-owned migration creates crm_lead_assignments and applied migrations are unchanged
- updateLead with crm.leads.update sets owner_person_id, closes the open assignment, and appends one history row
- A missing If-Match returns 428 and a stale If-Match returns 412
- A learner receives 403 without the lead being loaded, OpenAPI lists updateLead, and unit tests cover denial, hidden existence, and a repeat assignment of the same owner
DoneAP-0012Lead activity timeline
queue step validate · milestone P1-06
commit ddc5fe1
- docs/modules/crm/lead-activities.md exists before the code
- A new crm-owned migration creates crm_activities and no other crm table
- createLeadActivity and listLeadActivities enforce crm.activities.create and crm.activities.read, and a learner receives 403
- activity_type is only call, message, meeting, note, or demo, and the lead last_activity_at is updated in the same transaction
- The same Idempotency-Key replays and a different body returns 409, and OpenAPI lists both operationIds
DoneAP-0013Lead follow-up tasks
queue step validate · milestone P1-07
commit c436a6e
- docs/modules/crm/lead-tasks.md exists before the code and an ADR sets the created task status to open
- A new crm-owned migration creates crm_tasks and applied migrations are unchanged
- createLeadTask and listLeadTasks enforce crm.tasks.create and crm.tasks.read, and a learner receives 403
- A created task has status open, an existing assignee, an audit event, and idempotent replay
- OpenAPI lists both operationIds and unit tests cover denial, hidden existence, replay, and conflict
DoneAP-0014Lead task reminder job
queue step validate · milestone P1-08
commit 68063fb
- docs/modules/crm/lead-task-reminder.md and an ADR name the internal event crm.task_due version 1
- A successful createLeadTask writes one ops_outbox_events row in the same transaction, and a replay does not write another
- The worker records one inbox row and marks the outbox row published
- A second delivery of the same event does not create a second inbox row
- No provider is called, no notification table is added, and no migration is added
DoneAP-0015Lead stage transitions
queue step validate · milestone P1-09
commit 81ce899
- docs/modules/crm/lead-stage.md exists before the code and names transitionLeadStage
- Allowed lead edges follow Domain §42.1 and any other edge returns 422 invalid_state_transition
- transitionLeadStage requires crm.leads.update, and a learner receives 403 without the lead being loaded
- Entering lost stores lost_at and lost_reason_code, entering converted stores converted_at, and a success appends one audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists transitionLeadStage
DoneP1-05aCatalogue categories
Catalogue categories.
1 task
DoneAP-0016Staff catalogue categories
queue step validate · milestone P1-10
commit 10043f0
- docs/modules/catalogue/categories.md and the next ADR exist before the code and name listCategories, createCategory, and updateCategory
- A catalogue-owned migration creates only cat_categories, with created_at, updated_at, and version_no, and status has no CHECK
- createCategory requires catalogue.manage, stores status active, and a duplicate code or slug returns 409 without finishing idempotency
- updateCategory requires If-Match, a learner receives 403 without the row being loaded, and a real change appends one audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three category operations
DoneP1-05bCatalogue programs
Catalogue programs.
1 task
DoneAP-0017Staff catalogue programs
queue step validate · milestone P1-11
commit ee99c39
- docs/modules/catalogue/programs.md exists before the code and names listPrograms, createProgram, and getProgram
- A catalogue-owned migration creates only cat_programs, with a restrict foreign key to cat_categories and unique code and slug
- createProgram requires catalogue.manage, stores status active and public_visibility private, and rejects any other programType
- An unknown category is 404, a learner receives 403 without the program being loaded, and a success appends one audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three program operations
DoneP1-05cCatalogue program update
Update a program without changing its code.
1 task
DoneAP-0018Catalogue program update
queue step validate · milestone P1-12
commit 6e83365
- docs/modules/catalogue/program-update.md exists before the code and names updateProgram
- updateProgram requires catalogue.manage and If-Match, and a learner receives 403 without the program being loaded
- The body cannot change code, status, categoryId, or public_visibility
- A real change bumps version_no and appends one catalogue.program_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updateProgram
DoneP1-05dCatalogue tracks
Tracks under a program.
1 task
DoneAP-0019Staff catalogue tracks
queue step validate · milestone P1-13
commit 35a5dd2
- docs/modules/catalogue/tracks.md exists before the code and names listProgramTracks, createProgramTrack, and updateTrack
- A catalogue-owned migration creates only cat_tracks, with a restrict foreign key to cat_programs and uniqueness of code and slug within the program
- createProgramTrack requires catalogue.manage, stores status active, and an unknown program returns 404
- updateTrack requires If-Match, a learner receives 403 without the track being loaded, and a real change appends one audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three track operations
DoneP1-05eCatalogue skills
Skills the catalogue can attach.
1 task
DoneAP-0020Staff catalogue skills
queue step validate · milestone P1-14
commit ae80d45
- docs/modules/catalogue/skills.md exists before the code and names listSkills, createSkill, and updateSkill
- A catalogue-owned migration creates only cat_skills, with created_at, updated_at, and version_no, and category is not a foreign key
- createSkill requires catalogue.manage, stores status active, and a duplicate skillKey or slug returns 409 without finishing idempotency
- updateSkill requires If-Match, a learner receives 403 without the skill being loaded, and a real change appends one audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three skill operations
In reviewP1-06Products, offers, prices, and payment plans
Products, offers, prices, payment plans, tax, promotions, and scholarships.
14 tasks
In reviewAP-0052Staff promotion update
Commerce · queue step validate · milestone P1-25
Pull request #18 · checks not passed yet · autopilot/ap-0052
- docs/modules/commerce/promotion-update.md exists before the code and names updatePromotion
- updatePromotion requires commerce.promotions.manage and If-Match, and a learner receives 403 without the promotion being loaded
- The body cannot change code, status, or conditions, and a replaced discount still follows the ADR-0013 percentage or INR fixed rules
- A real change bumps version_no and appends one commerce.promotion_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updatePromotion
QueuedAP-0054Staff scholarship program create and list
queue step implement · milestone P1-27
- docs/modules/commerce/scholarship-programs.md exists before the code and names listScholarshipPrograms and createScholarshipProgram
- A new ADR and a commerce-owned migration create only prd_scholarship_programs
- createScholarshipProgram requires scholarships.manage, stores status active, and stores no amount and no GST rate
- An authenticated learner can list active programs, and an anonymous caller receives 401 authentication_required
- A duplicate code returns 409, a success appends one commerce.scholarship_program_created audit event, and OpenAPI lists both operations
QueuedAP-0055Staff scholarship application create and list
queue step implement · milestone P1-28
- docs/modules/commerce/scholarship-applications.md exists before the code and names listScholarshipApplications and createScholarshipApplication
- A new ADR and a commerce-owned migration create only prd_scholarship_applications, with restrict foreign keys to prd_scholarship_programs and idn_people
- A person can apply for themselves, another person's id without scholarships.manage is 403, and the stored status is submitted
- The owner list returns only that person's rows, and global scholarships.read returns the queue
- A success appends one commerce.scholarship_application_created audit event and OpenAPI lists both operations
QueuedAP-0056Staff scholarship application decision
queue step implement · milestone P1-29
- docs/modules/commerce/scholarship-decision.md exists before the code and names decideScholarshipApplication
- A new ADR and a commerce-owned migration create only prd_scholarship_awards
- decideScholarshipApplication requires scholarships.decide, and a learner receives 403 without the application being loaded
- Approval from submitted writes one award and sets the application approved; rejection writes no award; any other status is 422 invalid_state_transition
- The same Idempotency-Key replays one award at most, and OpenAPI lists decideScholarshipApplication
DoneAP-0021Staff commercial product create list and detail
queue step validate · milestone P1-15
commit a47c1f6
- docs/modules/commerce/products.md and the next ADR exist before the code and name listProducts, createProduct, and getProduct
- A commerce-owned migration creates only prd_products and prd_product_programs, with restrict foreign keys to cat_programs and cat_tracks
- createProduct requires commerce.catalogue.manage, stores status active and product_type program, and an unknown program returns 404
- A learner receives 403 without the product being loaded, and a success appends one commerce.product_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three product operations
DoneAP-0022Commercial product update
queue step validate · milestone P1-16
commit 5635508
- docs/modules/commerce/product-update.md exists before the code and names updateProduct
- updateProduct requires commerce.catalogue.manage and If-Match, and a learner receives 403 without the product being loaded
- The body cannot change productCode, productType, status, programId, or trackId
- A real change bumps version_no and appends one commerce.product_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updateProduct
DoneAP-0023Staff commercial offer create list and detail
queue step validate · milestone P1-17
commit 21e6b31
- docs/modules/commerce/offers.md exists before the code and names listOffers, createOffer, and getOffer
- A commerce-owned migration creates only prd_offers, with a restrict foreign key to prd_products and entitlement_bundle_id nullable
- createOffer requires commerce.offers.manage, stores status active, and rejects campusId, salesChannel, and entitlementBundleId
- An unknown product is 404, a learner receives 403 without the offer being loaded, and a success appends one commerce.offer_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three offer operations
DoneAP-0024Commercial offer update
queue step validate · milestone P1-18
commit 983f717
- docs/modules/commerce/offer-update.md exists before the code and names updateOffer
- updateOffer requires commerce.offers.manage and If-Match, and a learner receives 403 without the offer being loaded
- The body cannot change code, productId, status, campusId, salesChannel, or entitlementBundleId
- A real change bumps version_no and appends one commerce.offer_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updateOffer
DoneAP-0025Staff offer price create and list
queue step validate · milestone P1-19
commit c23f288
- docs/modules/commerce/offer-prices.md exists before the code and names listOfferPrices and createOfferPrice
- A commerce-owned migration creates only prd_prices, with a restrict foreign key to prd_offers, DECIMAL(19,4) amount, and CHAR(3) currency_code
- createOfferPrice requires commerce.pricing.manage, stores status active, and accepts only currency INR
- An overlapping active price for the same offer and currency returns 409, and a success appends one commerce.price_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the two price operations
DoneAP-0026Staff offer price update
queue step validate · milestone P1-20
commit 9f5ca54
- docs/modules/commerce/price-update.md exists before the code and names updatePrice
- updatePrice requires commerce.pricing.manage and If-Match, and a learner receives 403 without the price being loaded
- The body cannot change offerId, status, or countryCode, and currency stays INR
- A real change bumps version_no and appends one commerce.price_updated audit event; an overlapping active window returns 409
- A stale If-Match returns 412 and OpenAPI lists updatePrice
DoneAP-0027Staff payment plan create and list
queue step validate · milestone P1-21
commit e2ae7cc
- docs/modules/commerce/payment-plans.md exists before the code and names listPaymentPlans and createPaymentPlan
- A new ADR and a commerce-owned migration create only prd_payment_plans and prd_payment_plan_parts
- createPaymentPlan requires commerce.pricing.manage, stores status active, and each part uses exactly one of percent or fixed amount
- A duplicate code returns 409 and a success appends one commerce.payment_plan_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the two payment-plan operations
DoneAP-0028Staff payment plan update
queue step validate · milestone P1-22
commit f831c6d
- docs/modules/commerce/payment-plan-update.md exists before the code and names updatePaymentPlan
- updatePaymentPlan requires commerce.pricing.manage and If-Match, and a learner receives 403 without the plan being loaded
- The body cannot change code or status, and a replaced part still uses exactly one of percent or fixed amount
- A real change bumps version_no and appends one commerce.payment_plan_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updatePaymentPlan
DoneAP-0029Staff offer payment plan attach
queue step validate · milestone P1-23
commit c1d1507
- docs/modules/commerce/offer-payment-plans.md exists before the code and names attachOfferPaymentPlan
- A new ADR and a commerce-owned migration create only prd_offer_payment_plans, with restrict foreign keys to prd_offers and prd_payment_plans
- attachOfferPaymentPlan requires commerce.pricing.manage, and a learner receives 403 without the offer or the plan being loaded
- The first attach appends one commerce.offer_payment_plan_attached audit event, and a second attach of the same pair inserts neither a row nor an audit event
- An unknown offer or an unknown plan returns 404 and OpenAPI lists attachOfferPaymentPlan
DoneAP-0030Staff promotion create and list
queue step validate · milestone P1-24
commit 3ab9b24
- docs/modules/commerce/promotions.md exists before the code and names listPromotions and createPromotion
- A new ADR and a commerce-owned migration create only prd_promotions
- createPromotion requires commerce.promotions.manage, stores status active, keeps a percentage as a normalized rate, and accepts only INR for a fixed discount
- A duplicate code returns 409 and a success appends one commerce.promotion_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the two promotion operations
Not startedP1-07Admissions
Applications, documents, and admission decisions.
No task has been queued for this yet.
Not startedP1-08Enrollment, cohorts, and sessions
Enrollment, cohorts, timetable rules, and sessions.
No task has been queued for this yet.
Not startedP1-09Orders, invoices, and payments
Orders, invoices, payment schedules, and receipts.
No task has been queued for this yet.
Not startedP1-10Razorpay webhooks and reconciliation
Razorpay webhooks and reconciliation.
No task has been queued for this yet.
Not startedP1-11Refunds and credit notes
Refunds and credit notes.
No task has been queued for this yet.
Not startedP1-12Attendance
Student and staff attendance.
No task has been queued for this yet.
Not startedP1-13Notifications
Templates, in-app notifications, and unwired email and WhatsApp adapters.
No task has been queued for this yet.
Not startedP1-14Audit read models
Audit and operational read models.
No task has been queued for this yet.
In progressP1-UIStaff admin screens
Admin screens for APIs that are already merged.
5 tasks
In progressAP-0040Admin lead activity timeline
Admin screens · queue step implement
builder is still writing the branch · autopilot/ap-0040
- docs/modules/crm/admin-lead-activities.md exists and names listLeadActivities and createLeadActivity
- The timeline calls those client methods through the BFF, with CSRF and Idempotency-Key on create
- activityType is only call, message, meeting, note, or demo, and occurredAt is UTC ending in Z
- Empty, validation, conflict, and forbidden states are text
- Vitest covers the empty timeline and the activity types, and apps/api is unchanged
QueuedAP-0041Admin lead follow-up tasks
queue step implement
- docs/modules/crm/admin-lead-tasks.md exists and names listLeadTasks and createLeadTask
- The screen calls those client methods through the BFF, with CSRF and Idempotency-Key on create
- The form does not send status and does not call updateCrmTask or a people directory
- Empty, validation, not-found, and forbidden states are text
- Vitest covers the empty list and the labels, and apps/api is unchanged
DoneAP-0037Admin lead list and detail
queue step validate
commit 111da60
- docs/modules/crm/admin-lead-list.md exists and the screens follow it
- /leads calls listLeads and /leads/{leadId} calls getLead through the BFF session and packages/api-client
- The access token is not rendered, and a signed-out visitor does not call the API
- Loading, empty, forbidden, and unavailable states are text, and each lead has an accessible link name
- Vitest markup tests cover those states, and apps/api, OpenAPI, and the generated client are unchanged
DoneAP-0038Admin lead create form
queue step validate
commit 516fe9b
- docs/modules/crm/admin-lead-create.md exists before the form
- The form calls createLead with Idempotency-Key through the BFF and a CSRF check
- The body omits status, personId, campusId, sourceId, and interestProgramId
- validation_error, idempotency_conflict, forbidden, and success are visible as text, and submit cannot double-send
- Vitest covers labels and those states, and apps/api is unchanged
DoneAP-0039Admin lead counsellor assignment
queue step validate
commit 1a19cdf
- docs/modules/crm/admin-lead-assignment.md exists and names updateLead
- The form sends ownerPersonId, optional reason, and the lead versionNo through the BFF with CSRF
- 412 stale_version offers a reload, and 404 says the lead or person was not found
- The screen does not call listPeople or getPerson and does not send status or contact fields
- Vitest covers the labels and those states, and apps/api is unchanged
In progressP1-QADatabase integration test coverage
MySQL integration tests for slices that are already merged.
5 tasks
In progressAP-0036Lead task outbox MySQL integration
Integration tests · queue step implement
builder is still writing the branch · autopilot/ap-0036
- docs/modules/crm/lead-tasks.md Tests section names this Testcontainers file
- createLeadTaskFor commits one open task, one crm.task_created audit row, one finished idempotency row, and one crm.task_due version 1 outbox row
- The outbox payload is taskId, leadId, and dueAt, and the lead version_no is unchanged
- A replay returns the same task and does not insert a second task, audit row, or outbox row
- A different body returns idempotency_conflict
- An unknown assignee rolls back the task, the audit row, the outbox row, and the idempotency row
- No worker, inbox, or production behavior changes unless a failing test proves a bug
DoneAP-0032Consent append-only MySQL integration
queue step validate
commit d5c694b
- docs/modules/identity/consents.md Tests section names this Testcontainers file
- A grant and a later withdrawal are two idn_consents rows, and the grant row stays granted
- The consent insert and its audit_events row commit together; a replay adds neither
- A reused header with a different body returns idempotency_conflict and inserts nothing
- A status outside granted and withdrawn is rejected by the CHECK constraint
- No outbox row is written and no production behavior changes unless a failing test proves a bug
DoneAP-0033Role key uniqueness MySQL integration
queue step validate
commit 09d7554
- docs/modules/authorization/role-administration.md Tests section names this Testcontainers file
- A duplicate role_key is rejected by MySQL and the failed create leaves no finished idempotency row
- Replaying the same header and body returns the original role and does not insert a second role or audit row
- A different body with the same header returns idempotency_conflict
- An assignment to an unknown person rolls back; a global assignment commits one row and one audit row
- No production behavior changes unless a failing test proves a bug
DoneAP-0034Lead create transaction MySQL integration
queue step validate
commit 245ce71
- docs/modules/crm/staff-leads.md Tests section names this Testcontainers file
- createLeadFor commits one crm_leads row, one crm.lead_created audit row, and one finished idempotency row
- A replay returns the same lead id and does not insert a second lead or audit row
- A different body returns idempotency_conflict and leaves that one lead
- An unknown personId rolls the lead, the audit row, and the idempotency row back
- No outbox row is written and no production behavior changes unless a failing test proves a bug
DoneAP-0035Lead assignment locking MySQL integration
queue step validate
commit 501dda9
- docs/modules/crm/lead-assignment.md Tests section names this Testcontainers file
- A real assignment bumps version_no and commits the lead, one open history row, and one crm.lead_assigned audit row
- The same owner again does not bump version_no and writes no history or audit row
- A stale If-Match returns stale_version and a missing If-Match returns precondition_required
- After reassignment exactly one assignment has ends_at null
- An unknown owner leaves the lead unchanged and no production behavior changes unless a failing test proves a bug
An enrolled learner gets a pinned curriculum, lessons, video, assessments, projects, and a verifiable certificate.
DoneP2-01Program and track versions
Draft program versions and track versions.
3 tasks
DoneAP-0042Staff program curriculum version create list and detail
queue step validate · milestone CUR-01
commit 7055d81
- docs/modules/curriculum/program-versions.md and the next ADR exist before the code and name listProgramCurriculumVersions, createProgramCurriculumVersion, and getCurriculumVersion
- A curriculum-owned migration creates only cur_program_versions, with a restrict foreign key to cat_programs, unique (program_id, version_number), and a status CHECK of draft, review, published, and retired
- createProgramCurriculumVersion requires curriculum.manage, stores status draft, assigns the next version_number, and an unknown program returns 404
- A learner receives 403 without the version being loaded, and a success appends one curriculum.program_version_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the three version operations
DoneAP-0043Program curriculum version update
queue step validate · milestone CUR-02
commit 9d66214
- docs/modules/curriculum/program-version-update.md exists before the code and names updateCurriculumVersion
- updateCurriculumVersion requires curriculum.manage and If-Match, and a learner receives 403 without the version being loaded
- The body cannot change versionNumber, status, programId, or the publication fields, and a version that is not draft returns 409
- A real change bumps version_no and appends one curriculum.program_version_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updateCurriculumVersion
DoneAP-0044Curriculum track versions on program version create
queue step validate · milestone CUR-03
commit 4557171
- docs/modules/curriculum/track-versions.md exists before the code and adds no operationId
- A curriculum-owned migration creates only cur_track_versions, with restrict foreign keys and unique (track_id, program_version_id, version_number)
- createProgramCurriculumVersion writes one draft track version per catalogue track of the program in the same transaction
- A program with no tracks writes none, and an idempotent replay does not insert track rows again
- getCurriculumVersion includes those track versions, and OpenAPI still lists only the program-version operations
In progressP2-02Entry routes and lessons
Entry routes on a draft program version. Lessons come after this.
2 tasks
In progressAP-0045Staff curriculum entry route create and list
Curriculum · queue step implement · milestone CUR-04
builder is still writing the branch · autopilot/ap-0045
- docs/modules/curriculum/entry-routes.md exists before the code and names listEntryRoutes and createEntryRoute
- A curriculum-owned migration creates only cur_entry_routes, with the generated track_version_scope unique across program version, track version, and code
- createEntryRoute requires curriculum.manage, stores status active, and a parent version that is not draft returns 409
- An unknown version is 404, a learner receives 403 without the version being loaded, and a success appends one curriculum.entry_route_created audit event
- The same Idempotency-Key replays, a different body returns 409, and OpenAPI lists the two entry-route operations
QueuedAP-0046Curriculum entry route update
queue step implement · milestone CUR-05
- docs/modules/curriculum/entry-route-update.md exists before the code and names updateEntryRoute
- updateEntryRoute requires curriculum.manage and If-Match, and a learner receives 403 without the route being loaded
- The body cannot change code or status, and a parent version that is not draft returns 409
- A real change bumps version_no and appends one curriculum.entry_route_updated audit event; an unchanged patch does neither
- A stale If-Match returns 412 and OpenAPI lists updateEntryRoute
Not startedP2-03Publishing
Publishing a curriculum version so learners can be pinned to it.
No task has been queued for this yet.
Not startedP2-04Entitlements
Entitlement grants and the access check.
No task has been queued for this yet.
Not startedP2-05Journeys and progress
Learner journeys and progress.
No task has been queued for this yet.
Lesson files in object storage.
No task has been queued for this yet.
Not startedP2-07Mux video
Video upload and playback authorization.
No task has been queued for this yet.
Not startedP2-08Assessments
Assessments and the question bank.
No task has been queued for this yet.
Not startedP2-09Projects and rubrics
Projects, rubrics, and reviews.
No task has been queued for this yet.
Not startedP2-10Certificates
Certificates and public verification.
No task has been queued for this yet.
Not startedP2-11Faculty delivery
Faculty delivery workflow.
No task has been queued for this yet.
Not startedP2-12Learner web and mobile
Learner web and mobile.
No task has been queued for this yet.
Not startedP2-13Notes and offline
Notes, bookmarks, and offline access.
No task has been queued for this yet.
Community: tips, challenges, spaces, moderation, reputation, mentorship, and events.
No task has been queued for this yet.
Not startedP3-02Challenges
No task has been queued for this yet.
Not startedP3-03Spaces and posts
No task has been queued for this yet.
Not startedP3-04Moderation
No task has been queued for this yet.
Not startedP3-05Reputation
No task has been queued for this yet.
Not startedP3-06Mentorship
No task has been queued for this yet.
No task has been queued for this yet.
No task has been queued for this yet.
No task has been queued for this yet.
Not startedP3-10Recommendations
No task has been queued for this yet.
Career profile, jobs, membership, referrals, and a wallet that does not double-credit.
Not startedP4-01Career profile
No task has been queued for this yet.
Not startedP4-02Resume builder
No task has been queued for this yet.
Not startedP4-03Employers
No task has been queued for this yet.
No task has been queued for this yet.
Not startedP4-05Applications
No task has been queued for this yet.
Not startedP4-06Membership
No task has been queued for this yet.
Not startedP4-07Referrals
No task has been queued for this yet.
No task has been queued for this yet.
Not startedP4-09Public profile consent
No task has been queued for this yet.
AI mentor, retrieval, coding runner, and autograding. Each part can be switched off on its own.
Not startedP5-01AI Gateway
No task has been queued for this yet.
Not startedP5-02AI Mentor
No task has been queued for this yet.
Not startedP5-03Retrieval
No task has been queued for this yet.
Not startedP5-04Resume and interview AI
No task has been queued for this yet.
Not startedP5-05CodingRunner
No task has been queued for this yet.
Not startedP5-06Autograding
No task has been queued for this yet.
Not startedP5-07Mock interviews
No task has been queued for this yet.
Not startedP5-08Recommendations
No task has been queued for this yet.
Screens still to build
Seven product surfaces are locked. Website, learner, and mobile screens are not being queued while their APIs are still being built. Admin screens are queued only for APIs already merged, and those tasks do not change the API. A row here moves to Queued, In progress, In review, or Done only when a real task is using it.
Marketing website
apps/web-public. Master §2.1. The app shell from M0.9 exists. A row changes when a task uses its id as the milestone.
| Status | Screen | Where it sits |
|---|
| Shell | App shell | Phase 0 |
| Not started | Program and track discovery | Phase 1, after catalogue is merged |
| Not started | Skill landing pages | After catalogue skills are merged |
| Not started | Career paths | Phase 4 |
| Not started | Admissions and enquiries | Phase 1 |
| Not started | Campus information | Needs owner campus facts |
| Not started | Events and workshops | Phase 3 |
| Not started | Free resources and IT Tips | Phase 3 |
| Not started | Instructor profiles | No API queued yet |
| Not started | Project and learner showcases | Phase 2 and Phase 4 |
| Not started | Jobs and employer information | Phase 4 |
| Not started | Public certificate verification | Phase 2 |
| Not started | Pricing and payment entry | Phase 1, after public offers exist |
| Not started | Public support content | No API queued yet |
| Not started | Blogs, FAQs, and SEO pages | Needs the website CMS |
Learner website
apps/web-portal. Master §2.2 and Appendix A, on the web. Phase 2 names “learner web” as one line. Each row is queued on its own after its API is merged.
| Status | Screen | Where it sits |
|---|
| Shell | App shell | Phase 0 |
| Not started | Today and home dashboard | Phase 2 |
| Not started | Smart onboarding | Phase 2 |
| Not started | My Learning | Phase 2 |
| Not started | Live learning and timetable | Phase 1 cohorts, screen after the API |
| Not started | Lesson experience | Phase 2 |
| Not started | Protected and offline learning | Phase 2 |
| Not started | Practice and quizzes | Phase 2 |
| Not started | Browser coding lab | Phase 5 |
| Not started | Autograding | Phase 5 |
| Not started | Projects and capstones | Phase 2 |
| Not started | Portfolio and showcase | Phase 4 |
| Not started | AI Learning Mentor | Phase 5 |
| Not started | AI academic-integrity controls | Phase 5 |
| Not started | Progress and mastery | Phase 2 |
| Not started | IT Tips feed | Phase 3 |
| Not started | Daily and weekly challenges | Phase 3 |
| Not started | Community spaces | Phase 3 |
| Not started | Peer learning | Phase 3 |
| Not started | Mentor access and doubts | Phase 3 |
| Not started | Events | Phase 3 |
| Not started | Career centre | Phase 4 |
| Not started | AI mock interview | Phase 5 |
| Not started | Jobs and internships | Phase 4 |
| Not started | Credentials | Phase 2 |
| Not started | Attendance | Phase 1 |
| Not started | Digital student ID | No API queued yet |
| Not started | Fees and billing | Phase 1 |
| Not started | Referral programme | Phase 4 |
| Not started | Wallet | Phase 4 |
| Not started | Membership | Phase 4 |
| Not started | Calendar | Phase 1 |
| Not started | Notifications | Phase 1 |
| Not started | Bookmarks and notes | Phase 2 |
| Not started | Support | No API queued yet |
| Not started | Accessibility and language | Cross-cutting, no task yet |
| Not started | Low-bandwidth mode | Cross-cutting, no task yet |
Learner Android and iOS
apps/mobile-learner. Same learner screens as the website, in the Android and iOS app. M0.9 is a shell with auth routing. Each screen is its own task after its API is merged.
| Status | Screen | Where it sits |
|---|
| Shell | App shell | Phase 0 |
| Not started | Today and home dashboard | Phase 2 |
| Not started | Smart onboarding | Phase 2 |
| Not started | My Learning | Phase 2 |
| Not started | Live learning and timetable | Phase 1 cohorts, screen after the API |
| Not started | Lesson experience | Phase 2 |
| Not started | Protected and offline learning | Phase 2 |
| Not started | Practice and quizzes | Phase 2 |
| Not started | Browser coding lab | Phase 5 |
| Not started | Autograding | Phase 5 |
| Not started | Projects and capstones | Phase 2 |
| Not started | Portfolio and showcase | Phase 4 |
| Not started | AI Learning Mentor | Phase 5 |
| Not started | AI academic-integrity controls | Phase 5 |
| Not started | Progress and mastery | Phase 2 |
| Not started | IT Tips feed | Phase 3 |
| Not started | Daily and weekly challenges | Phase 3 |
| Not started | Community spaces | Phase 3 |
| Not started | Peer learning | Phase 3 |
| Not started | Mentor access and doubts | Phase 3 |
| Not started | Events | Phase 3 |
| Not started | Career centre | Phase 4 |
| Not started | AI mock interview | Phase 5 |
| Not started | Jobs and internships | Phase 4 |
| Not started | Credentials | Phase 2 |
| Not started | Attendance | Phase 1 |
| Not started | Digital student ID | No API queued yet |
| Not started | Fees and billing | Phase 1 |
| Not started | Referral programme | Phase 4 |
| Not started | Wallet | Phase 4 |
| Not started | Membership | Phase 4 |
| Not started | Calendar | Phase 1 |
| Not started | Notifications | Phase 1 |
| Not started | Bookmarks and notes | Phase 2 |
| Not started | Support | No API queued yet |
| Not started | Accessibility and language | Cross-cutting, no task yet |
| Not started | Low-bandwidth mode | Cross-cutting, no task yet |
Team workspace and admin console
apps/web-admin. Master §2.3 and §2.4 share this app. Appendix B is the screen list. A row follows the tasks that name its id.
| Status | Screen | Where it sits |
|---|
| Shell | App shell and sign-in | Phase 0 |
| Done | Lead list, detail, and create | Phase 1 |
| In progress | Lead assignment, activity, and tasks | Phase 1 |
| Not started | Executive dashboard | No API queued yet |
| Not started | Communication timeline | Phase 1 |
| Not started | Demo and counselling | Phase 1 |
| Not started | Admissions | Phase 1 |
| Not started | Cohort and batch management | Phase 1 |
| Not started | Program and LMS management | Phase 2 |
| Not started | Reusable content graph | Phase 2 |
| Not started | Content library | Phase 2 |
| Not started | Assessment engine | Phase 2 |
| Not started | Coding administration | Phase 5 |
| Not started | Projects | Phase 2 |
| Not started | Student management | Phase 1 |
| Not started | Attendance | Phase 1 |
| Not started | Faculty management | Phase 2 |
| Not started | Fees and accounts receivable | Phase 1 |
| Not started | Refunds and credit notes | Phase 1 |
| Not started | Expenses and vendors | No API queued yet |
| Not started | Reconciliation | Phase 1 |
| Not started | Referral administration | Phase 4 |
| Not started | Wallet ledger | Phase 4 |
| Not started | Membership | Phase 4 |
| Not started | Events | Phase 3 |
| Not started | Community administration | Phase 3 |
| Not started | Career and placement | Phase 4 |
| Not started | Employer management | Phase 4 |
| Not started | Certificate engine | Phase 2 |
| Not started | Communications centre | Phase 1 notifications |
| Not started | Notification automation | Phase 1 |
| Not started | Helpdesk | No API queued yet |
| Not started | Website CMS | No API queued yet |
| Not started | SEO management | No API queued yet |
| Not started | HR and staff operations | No API queued yet |
| Not started | Rooms and assets | No API queued yet |
| Not started | Reports and BI | No API queued yet |
| Not started | Risk and intervention | No API queued yet |
| Not started | Import and export | No API queued yet |
| Not started | Approval workflows | No API queued yet |
| Not started | Audit log | Phase 1 |
| Not started | System settings | Phase 1 |
| Not started | Feature management | Phase 1 |
| Not started | Integrations | No API queued yet |
Team Android and iOS
apps/mobile-team. Master §2.3. One team app for faculty, mentors, counsellors, front desk, finance, placement, and campus work. The shell exists. Each role screen waits for its API.
| Status | Screen | Where it sits |
|---|
| Shell | App shell | Phase 0 |
| Not started | Role-aware home | Phase 1 operational admin |
| Not started | Admissions counsellor work | Phase 1 |
| Not started | Faculty delivery | Phase 2 |
| Not started | Attendance and front desk | Phase 1 |
| Not started | Finance and receipts | Phase 1 |
| Not started | Placement and career team | Phase 4 |
| Not started | Community and support | Phase 3 |
Partner website
apps/web-portal. Master §2.5. Responsive web only, no partner mobile apps. Phase 4 mentions an employer portal as one line. Each page is queued after its API is merged.
| Status | Screen | Where it sits |
|---|
| Not started | Guardian and parent views | No API queued yet |
| Not started | Employer and recruiter portal | Phase 4 |
| Not started | College and corporate partners | No API queued yet |
| Not started | Campus or centre operations | Not approved as a launch surface |