Advanced System Design Tutorial 0/70 lessons ~6 min read Lesson 70

    Enterprise System Design Capstone Project

    The earlier lessons asked you to design one mechanism at a time: a conditional update, a shortener, a feed, a payment timeout, a tenant predicate, a review finding. Production syst

    Course progress0%
    Focus
    15 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Enterprise System Design Capstone Project

    Advanced System Design & Software Architecture · Lesson 70 · Architecture Practice, Interviews and Capstone

    Lesson Overview

    The earlier lessons asked you to design one mechanism at a time: a conditional update, a shortener, a feed, a payment timeout, a tenant predicate, a review finding. Production systems arrive as a pile. A university tenant asks TechLearningPro for cohorts: a start date, a capacity, an enrollment that must not oversell the last seat, assignments, grades a registrar can export, and a live-session link that does not become an open redirect. They ask for it on the same Cloud platform that already hosts every other tenant. The spreadsheet they use today is the migration source, and it is wrong in small ways the new system will be blamed for.

    This lesson is the capstone brief for that pile. You will produce an architecture packet for Campus Cohort, a multi-tenant increment on the platform from Design a Multi-Tenant SaaS Platform. The packet is the one Enterprise Architecture Review Checklist can accept or send back: requirements, SLOs, a capacity model, C4 diagrams, a sequence, API and data ownership, an ADR pack, a threat model, a migration plan, and a self-review. The clock from lessons 66 through 68 is gone. The standard of evidence is not.

    An approved alternate is Order Desk, an enterprise order system for TechLearningPro's physical workbook business, if your instructor assigns it instead. The deliverables and the rubric are the same. Marketplace payouts, which lesson 55 left open, are an optional extension on either brief, not a way to skip the core packet.

    You are graded on decisions you can defend, on exclusions you keep, and on findings you file against your own draft. A packet that copies a case-study chapter and swaps nouns will not meet the rubric. The case studies are inputs. The packet is yours.

    Learning Objectives

    By the end of this lesson you will be able to:

    1. Turn a multi-week brief into a scope sentence, an exclusion list, and a pilot tenant.
    2. Write quality scenarios and SLOs for enrollment and for grade export, with signals you could actually page on.
    3. Build a capacity and cost sketch from labeled assumptions, including the log and export lines.
    4. Draw a C4 context and container diagram whose containers match data owners.
    5. Specify enroll, waitlist, submit, grade, and export contracts, including idempotency and tenant identity.
    6. Record an ADR pack of at least four decisions with a rejected option and a reopen condition.
    7. Draw the sequence for the last seat in a cohort, including the losing caller.
    8. Produce a threat model whose abuses include cross-tenant grade reads and a caller-supplied join URL.
    9. Plan a migration off spreadsheets or a monolith module one tenant at a time, with a rollback that is not a full restore.
    10. Run the lesson 69 checklist on your own packet and close or explicitly defer every blocker.
    11. Present the packet in twenty minutes: bottleneck, two ADRs, one threat, one migration step.
    12. Apply the same deliverable contract to the Order Desk alternate without diluting the rubric.

    Prerequisites

    • Module 1, especially lessons 3, 5, 8, and 10: drivers, boundaries, domain language, and ADRs. The packet is an ADR pack plus the views those ADRs require.
    • Module 2, for the enrollment and grading state machines. You may include a short class sketch. You do not submit a full LLD of a learning management system.
    • Module 3, lessons 23 through 37: the design sequence, capacity, data, consistency, sagas only if a workflow truly crosses owners, queues, and idempotency.
    • Module 4, lessons 38 through 48: you choose a modular boundary. A modular monolith is an acceptable ADR. A microservice per noun is not required and will be graded on operational cost.
    • Module 5, lessons 55, 56, 57, 58, and 60 as neighboring systems. You integrate with them. You do not redesign them.
    • Lessons 61 through 69. The capstone is where those reviews become a single submission. Lesson 69's finding format is how you record the self-review.

    Detailed Core Concepts

    The product you are designing

    Campus Cohort runs inside TechLearningPro Cloud. A tenant is a university or company, resolved from the host and the token, as lesson 60 requires. A cohort is a scheduled offering of a catalog course: capacity, start, end, time zone, and a roster. A learner enrolls. If the cohort is full, the learner is waitlisted. An instructor publishes an assignment and records a grade. A registrar exports grades for that tenant. A live session is a row with a start time and an https join URL whose host is on a tenant-approved allowlist. You are not designing a new video platform. Playback, if you mention it, is lesson 51's boundary: the cohort stores an identifier, the media system owns the bytes.

    In scope:

    • Create and update a cohort, with an audit record for capacity and date changes.
    • Enroll and withdraw. Exactly one outcome for the last seat. Waitlist is FIFO unless an ADR says otherwise.
    • Submit an assignment once per learner per assignment, idempotent on client retry.
    • Record a grade. Grades are append-only revisions, not a silent overwrite. The current grade is the latest revision.
    • Export grades for one cohort as a file the registrar downloads through a short-lived signed URL.
    • Store a live-session join URL that passes the allowlist.
    • Tenant isolation on every one of these, pool by default.
    • Migration of one pilot tenant off the spreadsheet or the old module.

    Out of scope, unless an ADR pulls one item back in with a reason:

    • Authoring the course catalog and the video pipeline.
    • A new chat system. If learners discuss work, point at lesson 50 and stop.
    • A new notification platform. Enrollment mail is a command to lesson 56's boundary, or a port with the same outcome rules as lesson 67.
    • Proctoring, plagiarism detection, and calendar federation.
    • Payments for free cohorts. Paid enrollment is optional and must use the lesson 55 boundary: no PAN, idempotency key, UNCONFIRMED on timeout.
    • Multi-region active-active writes.
    • A public consumer social network. The feed in lesson 57 is not the roster.

    Write these exclusions in your packet in your own words. A diagram that adds a recommendation engine has left the brief.

    Stakeholders and the conflict you must resolve

    The registrar wants an export that matches the student information system, yesterday's data is acceptable, and a wrong grade is not. The instructor wants to enter grades during a lab, with a responsive page. The learner wants to know immediately whether they are enrolled or waitlisted. The tenant admin wants a pilot that can fall back to the spreadsheet for a week. Finance wants the cost of the pilot called out before the all-tenant rollout. Support wants a trace id. Security wants grades out of logs.

    These conflict. Immediate enrollment and a nightly batch cannot both own the seat count. Your SLO section picks a target for enroll and a different target for export. That split is a design. A single sentence that says "the system will be fast and consistent" is not.

    Quality scenarios you must write

    Use lesson 62's shape. At least these two, with numbers you choose and label as targets, not as measurements.

    1. Enroll. A learner in the pilot tenant enrolls during a two-minute add/drop rush. They receive enrolled or waitlisted within two seconds at p95, excluding their network. Two learners never both receive the last seat. The losing caller receives a waitlist result, not an error page.
    2. Export. A registrar requests a grade export for a cohort of up to 5,000 learners. The file is available within fifteen minutes. A second click with the same idempotency key does not create a second file with different contents. Other tenants' exports continue while this file builds.
    3. Isolation. A caller authenticated for tenant A cannot read or write tenant B's grades, including through a guessed cohort id, a cache, or an export URL.

    Add a fourth only if your design needs it, such as assignment submit. Every scenario names the signal: a histogram, a SQL assertion in a test, a cross-tenant test. A target without a signal cannot be graded as met.

    The decisions the ADR pack must contain

    You need at least four accepted ADRs. These questions must be answered somewhere in the pack. You may split or combine them.

    QuestionA defensible directionWhat the reviewer will challenge
    Where is seat capacity enforced?One transaction: increment seats_taken where it is still below capacity, else insert a waitlist rowA check in the application, then a separate insert
    Who owns a grade?An append-only revision table, current grade is the latest row, registrar export reads thatAn update in place with no history
    What isolation tier is the pilot?Pool with row-level security; bridge only if the pilot contract requires a dedicated databaseA silo per tenant "for safety" with no cost line
    How does export run?Async job, signed download, idempotent requestA synchronous query that holds a request thread for 5,000 rows
    How do join URLs work?Allowlisted https hosts, stored as a URI the browser opensThe server fetches the URL to "validate it"
    What is the migration unit?One tenant, flag-gated, spreadsheet remains read-only fallback for a dated windowAll tenants on a Monday, rollback equals restore

    Rejected options belong in the ADR. "We chose a database" is not an ADR. The seat-capacity ADR is the model of the depth expected. A sample is in the walkthrough. Yours must match your numbers and your failure behavior, not paste the sample.

    What "synthesizing the course" means

    The reviewer looks for mechanisms you already studied, applied to this product.

    • Lesson 8's language: cohort, enrollment, grade revision, not a generic "entity."
    • Lesson 23's sequence: behavior before boxes.
    • Lesson 24 and 65: assumptions, peak, bottleneck.
    • Lesson 30 and 31 only if a number forces a partition. Most pilots do not.
    • Lesson 37: enroll and export retries.
    • Lesson 44 and 63: trust boundaries and the grade asset.
    • Lesson 48: one-tenant migration.
    • Lesson 55, if you include fees: the payment port, untouched card data.
    • Lesson 56: mail is a port, and a timeout is an unknown outcome for a message that must not double-send a one-time code. A duplicate "you are enrolled" mail is a product choice you must state.
    • Lesson 60: tenant source, SET LOCAL or equivalent, quotas.
    • Lesson 69: your self-review.

    A packet that mentions these lesson numbers without the mechanism fails the item. A packet that uses the mechanism and cites nothing still passes the item. Prefer the mechanism.

    The alternate brief: Order Desk

    If your instructor assigns Order Desk instead, the product is TechLearningPro's warehouse for printed workbooks sold to campus bookstores. In scope: place an order, reserve stock, capture payment through the lesson 55 boundary, ship or cancel, and a daily reconciliation of what the warehouse picked versus what the ledger captured. Out of scope: the consumer storefront's merchandising, a new carrier network, and marketplace payouts unless you take the optional extension.

    The same conflicts exist under new names. Two clerks must not sell the last carton. Payment timeout is UNCONFIRMED. Export becomes a pick list. Tenant becomes bookstore account, still isolated. Migration is off the shared inbox of spreadsheets the warehouse uses now. Do not mix Order Desk and Campus Cohort in one packet. The rubric does not give credit for two half-designs.

    Optional extension: instructor marketplace payouts

    Lesson 55 stopped at merchant capture. If your cohort or order design is already meeting the rubric and your instructor agrees, add an ADR for payouts: an instructor's share is a ledger posting, not a column on the payment row; payout runs are idempotent; a failed provider transfer is a case. This extension can raise the grade from meets to exceeds. It cannot replace a missing threat model.

    Academic and professional rules for the packet

    The packet is individual unless the syllabus says otherwise. You may discuss invariants. You may not share diagrams to submit. Public RFCs, PostgreSQL documentation, the C4 model, and this course are citable sources. A vendor's marketing diagram is not an architecture. Do not invent a private API for a university's student-information system. Define a port: GradeSink.submit(batch), with outcomes accepted, rejected, or unknown, and state that the real campus will map that port to whatever published interface that campus actually has. If they have only a CSV upload, the port's adapter writes the CSV you already specified.

    Architecture and Design Diagrams

    Your packet needs a context diagram and a container diagram. The context below is the bar for scope, not a stencil to trace. If your containers differ, the ADR says why. Containers that appear here and nowhere in your data ownership table are decoration.

    mermaid
    flowchart TB
    Learner[Learner]
    Instructor[Instructor]
    Registrar[Registrar]
    Admin[Tenant admin]
    Cohort[Campus Cohort]
    IdP[Company identity provider]
    Mail[Notification port]
    Media[Existing media identifiers]
    Pay[Payment port optional]
    SIS[Campus grade sink port]
    Learner --> Cohort
    Instructor --> Cohort
    Registrar --> Cohort
    Admin --> Cohort
    Cohort --> IdP
    Cohort --> Mail
    Cohort --> Media
    Cohort --> Pay
    Cohort --> SIS

    A container split that matches the owners in this brief:

    mermaid
    flowchart LR
    Edge[Edge: host and token]
    App[Cohort application]
    DB[(Cohort database RLS)]
    Jobs[Export and mail workers]
    Obj[(Export files)]
    Edge --> App
    App --> DB
    App --> Jobs
    Jobs --> DB
    Jobs --> Obj
    Jobs --> Mail[Notification port]
    Jobs --> Sink[Grade sink port]

    The sequence you must include is the last seat. Draw the loser. A sequence that shows only the happy enrollment will lose points under the consistency row of the rubric.

    mermaid
    sequenceDiagram
    participant L1 as Learner A
    participant L2 as Learner B
    participant App as Cohort application
    participant DB as Database
    L1->>App: POST /enrollments Idempotency-Key
    L2->>App: POST /enrollments Idempotency-Key
    App->>DB: update seats where seats_taken less than capacity
    DB-->>App: one row updated
    App->>DB: insert waitlist for the loser
    App-->>L1: 201 enrolled
    App-->>L2: 200 waitlisted

    The migration view is a state diagram per tenant, not a Gantt chart of the whole company.

    mermaid
    stateDiagram-v2
    [*] --> Spreadsheet
    Spreadsheet --> ShadowRead: pilot flag on, backfill
    ShadowRead --> NewWrite: dual-read matches for a dated window
    NewWrite --> CohortOnly: spreadsheet read-only, then retired
    NewWrite --> Spreadsheet: rollback flag, in-flight enrollments drained

    Order Desk swaps learner for bookstore buyer and grade export for pick list. The last-carton sequence has the same shape as the last seat. Draw the one your brief uses.

    Technical Explanation

    Week plan

    Four weeks is the intended cadence. Instructors may compress it. Do not compress by deleting the threat model or the migration.

    WeekYou produceReview gate
    1Stakeholders, workflows, exclusions, four quality scenarios, assumption logA reader can say what is out of scope without asking
    2C4 context and containers, enroll sequence, API table, data ownership, four ADRsEvery box has an owner; every ADR has a rejected option
    3Capacity math, cost formula, SLO signals, threat model, log data classesThe bottleneck sentence matches the diagram
    4Migration phases, lesson 69 self-review, twenty-minute briefingEvery blocker you found is fixed or explicitly deferred by a named risk acceptor

    Bring week 2's draft to a peer using the lesson 69 roles. Author, reviewer, scribe. The peer files findings in the IMP format. You may not reject a cross-tenant finding because the deadline is close.

    Capacity method

    Label every input. For a pilot, resist planet-scale numbers. Example assumptions you may replace, not copy as if they were measurements:

    • 1 pilot tenant, 200 cohorts a year, median roster 40, one large cohort 5,000.
    • Add/drop rush: the large cohort's roster tries to enroll in a ten-minute window, peak factor 5 on that window.
    • Grade export: the large cohort, once a day during finals week, plus a long tail of small exports.
    • Grade revisions: three revisions per learner per course is a guess. Say so.
    • Raw export CSV retained 7 days. Application logs retained 14 days and do not contain grade rows.

    Compute enroll attempts per second on the rush, steady reads, and export bytes. End with a bottleneck sentence. A likely sentence, if your numbers resemble the example, is that the rush is still a single primary, and the risk is lock contention on one cohort row, not a need to shard. If your sentence says "shard by tenant" at 200 cohorts, the reviewer will ask you to show the write rate that forces it. You may not find one. That is a successful estimate.

    Cost uses the formula, not a stale price page. Drivers: database size, export object storage, egress of exports, log volume, notification fees if the mail port bills per message. One line for "idle microservices" if you chose a process per noun. That line is how the modular-monolith ADR earns its keep.

    API shape

    Use ordinary HTTP. Minimum set:

    OperationRule
    POST /cohorts/{id}/enrollmentsIdempotency-Key. Tenant from token. 201 enrolled, 200 waitlisted if you document it, 409 if the learner is already enrolled and the body differs, 403 if the token's tenant does not own the cohort
    POST /cohorts/{id}/enrollments/{enrollmentId}/withdrawIdempotent. Frees a seat and promotes the oldest waitlist row in the same transaction if your ADR says so
    PUT /assignments/{id}/submissions/{learnerId}One submission; replay replaces only while state is DRAFT; 409 after SUBMITTED for a different body
    POST /submissions/{id}/gradesAppends a revision. Instructor role. Does not update in place
    POST /cohorts/{id}/grade-exports202 with export id. Idempotent. Download via short-lived signed URL
    POST /cohorts/{id}/sessionsJoin URL must be https and allowlisted. 400 otherwise

    202 is the right signal for export because the work is not finished. Returning 200 with a partial file is a bug. Pagination, if rosters are listed, uses a cursor.

    Data ownership

    FactOwnerNotes
    Cohort, capacity, seats_takenCohort moduleSingle writer. Cache of "is it full?" is derived and may be stale only if the UI tolerates a 409 or a waitlist correction
    Enrollment and waitlist positionCohort moduleUnique (cohort_id, learner_id)
    Submission bodyCohort module or object storageLarge files go to object storage under a tenant prefix. The database holds the key
    Grade revisionCohort moduleAppend-only. Export reads the latest
    Export fileExport workerTenant-prefixed object key. Signed URL expires
    Join URLCohort moduleAllowlist owned by the tenant admin workflow
    IdentityCompany IdPYou store subject and tenant ids, not passwords
    Mail deliveryNotification portYou store the command id and the outcome
    Payment, if anyPayment port from lesson 55Token, amount, charge id. No PAN

    Row-level security on cohort, enrollment, submission, and grade tables is the pool default. Show the policy the way lesson 69 showed it, with set_config local to the transaction. A repository-only WHERE clause, with no database policy and no test, is a blocker in your self-review.

    Threat model you must actually write

    Assets: grade revisions, roster membership, export files, join URLs, tokens. Actors: learner, instructor, registrar, tenant admin, anonymous internet, a noisy tenant.

    Walk at least these abuses. Lesson 63's method is the one to use; the rows below are the minimum content, not a substitute for the method.

    AbuseMitigation the packet must show
    Token for tenant A presented with a cohort id from tenant BRLS and an ownership check; test name
    Cache key grade:{cohortId} shared across tenantsTenant id in the key; authz on hit
    Export URL forwarded to another personShort lifetime, tenant-prefixed object, no public list bucket
    Join URL pointing at an internal hostAllowlist of https hosts; the server does not fetch the URL
    Registrar downloads an export, logs contain the CSVLog data class; denylist test
    Learner retries enroll and takes two seatsIdempotency key and unique (cohort_id, learner_id)
    Instructor script writes grades for another cohortRole check and cohort ownership in the same transaction as the insert
    One tenant's export saturates the worker poolFair queue or a per-tenant concurrency cap

    If you include payments, add double capture and PAN storage as abuses, mitigated the way lesson 55 mitigates them.

    Migration plan

    Pilot tenant only. Phases:

    1. Shadow. Backfill cohorts and rosters from the spreadsheet into the new tables. Writes still go to the spreadsheet. A diff job reports mismatches. People do not use the new UI yet.
    2. New write, dual read. The pilot's staff use Campus Cohort. A job writes a spreadsheet copy for the systems that still expect it, if any. The diff must be empty for a window you set, such as ten business days.
    3. Cohort only. Spreadsheet is read-only, then retired for that tenant. Rollback during phase 2 is the flag off. In-flight enrollments drain. You do not restore the platform database, because other tenants may already be scheduled.

    State the system of record in each phase. Two writers of seats_taken during phase 2 are a blocker unless the ADR's reconciliation is real. Prefer the new table as the only seat authority the moment the UI is on, and treat the spreadsheet as an export.

    Data errors in the spreadsheet, duplicate student ids, missing emails, are a written policy: reject the row, count it, do not invent a learner. The registrar sees the count.

    SLO signals

    Enroll latency histogram by tenant. A counter of waitlist outcomes versus enrolled outcomes. A gauge of seats_taken versus capacity that alerts if seats_taken ever exceeds capacity. That last alert is a correctness page, not a performance page. Export job age. RLS denial count. Traceparent from the edge to the export worker, as in lesson 69.

    Write the alert in a sentence an on-call engineer can follow at night. "Page if any cohort has seats_taken greater than capacity" is enough. "Page if CPU is high" is not.

    How the twenty-minute briefing works

    Minute 0 to 3: who the pilot is, what is out of scope. Minute 3 to 8: the bottleneck sentence and the container diagram. Minute 8 to 14: the seat ADR and the grade ADR, including what you rejected. Minute 14 to 18: one threat and the migration flag. Minute 18 to 20: self-review blockers you closed, and residual risks you kept. Questions afterward are part of the oral grade. "We will use a cloud" is not an answer. The conditional update, the tenant source, and the rollback flag are answers.

    Practical Implementation or Design Walkthrough

    This walkthrough shows the depth of one slice, the last seat, so you can see the bar. It is not a complete packet. Submitting it unchanged fails the rubric's originality and completeness rows.

    The slice's assumptions

    Pilot tenant Northwind. One cohort, capacity 40, used to explain the mechanism. The large-cohort number, 5,000, is for the export SLO and the lock discussion, not for this trace. Rush of 40 enroll attempts in a minute is trivial for a database and still has a race, which is why the mechanism matters at small scale. Correctness bugs are not a reward for waiting until you are large.

    ADR-001, the bar for an ADR

    Title. Seat capacity is a single conditional update.

    Status. Accepted for the pilot.

    Context. Two learners can submit enrollment at the same time for the last seat. A read of seats_taken followed by a later insert allows both to enroll. The spreadsheet already did this, and the registrar noticed. The cohort row and the enrollment row live in the same database. We do not have a second writer.

    Decision. In one transaction, after setting the transaction-local tenant id:

    sql
    UPDATE cohort
    SET seats_taken = seats_taken + 1
    WHERE id = :cohortId
    AND tenant_id = :tenantFromToken
    AND seats_taken < capacity;

    If the update count is 1, insert the enrollment row with a unique (tenant_id, cohort_id, learner_id). If the update count is 0, insert a waitlist row and return waitlisted. If the unique enrollment insert conflicts, the learner is already enrolled: roll back the seat increment if this transaction took it, and return the original enrollment. The idempotency key replays the stored HTTP result for an identical body.

    Rejected. A distributed lock service. The invariant is one row. An application-level check without the WHERE clause. A queue that serializes all enrollments for all tenants, which would couple Northwind's rush to every other tenant for no integrity benefit.

    Consequences. Waitlist order is the order of committed inserts. A withdrawn enrollment decrements seats_taken and promotes the oldest waitlist row in the same transaction. A crash between decrement and promote is not allowed because they share the transaction. Lock waits on a single hot cohort row are the scaling limit. Reopen a per-cohort partition or a queue only if a measured rush shows lock waits breaching the two-second SLO. At 40 seats this will not happen. At 5,000 simultaneous last-seat attempts against one row, it might, and the export size is not the same problem.

    That is an ADR. Your packet needs three more of similar density, on grades, isolation, and export or migration.

    What the slice still owes the packet

    The ADR does not name the SLO signal, the threat of a body-supplied tenant id, the migration phase, or the cost. Those are the other weeks. A student who submits four ADRs and no diagram has half a packet. A student who submits the sample SQL and nothing else has a citation.

    Self-review of the slice, done properly

    Finding CAP-01, major, checklist reliability: the ADR does not say what the learner sees if the database statement times out. The seat might have incremented. Close it by treating timeout as UNCONFIRMED for the idempotency key and reconciling by reading the enrollment row before retrying the increment. That is the same unknown-outcome idea as payments, applied to a seat. Finding CAP-02, blocker if true: the sample UPDATE trusts :tenantFromToken but the packet has not yet said the token is the only source. Close it in the tenancy ADR, not with a comment. Filing these against yourself is how week 4 earns the self-review points.

    Order Desk slice, same bar

    Replace cohort with stock item and seats with cartons on hand. The conditional update is on_hand >= :qty. The loser sees backorder, which your ADR defines. Payment capture is a second transaction coordinated with an outbox, not a second writer inside the stock update, unless you can honestly put them on one database and you accept the coupling. Lesson 32's saga is justified here if stock and the payment provider are different owners. It is not justified for a waitlist promotion that shares the cohort database. Choosing a saga for the seat problem is a misunderstanding of the boundary, and the rubric will mark it down.

    Enterprise Real-World Scenarios

    Scenario 1: Northwind pilot that almost oversold

    Northwind's add/drop week sends 800 learners at a cohort of 600 seats. The team skipped the conditional update because "the application server is single threaded" and then ran three instances. Forty learners received enrolled for seats that did not exist. The registrar compared the export to the room size. The fix is ADR-001, plus the alert on seats_taken > capacity, plus a compensating transaction that moves the newest excess enrollments to the waitlist in front of later names and emails those learners through the notification port with an idempotent template. The compensating job is audited. It is not a quiet update.

    Your packet should make this incident hard to cause and easy to see. If the oral exam asks "what page fires," the answer is the capacity invariant, not CPU. The migration plan should say this pilot runs at three instances, so a single-threaded assumption is invalid. Write that in the threat or the reliability section so the reviewer knows you noticed.

    Scenario 2: Eastbridge export and the shared worker

    Eastbridge requests a 5,000-row export at 08:00. The worker pool is four threads, all busy rendering Eastbridge's file because someone generated the CSV in one transaction that also locks grade rows. Northwind's instructor cannot save a grade. The SLO for enroll is burning because grade writes queue behind the export lock.

    The design that avoids this is the one the checklist already asked for: export is a snapshot read, not a lock held for the whole file; the job runs off the request thread; a per-tenant concurrency cap leaves a worker free; grade writes do not wait on export. The signed URL is issued when the file is complete. If your packet's sequence shows the registrar's browser waiting on a 5,000-row transaction, scenario 2 is the review comment you will receive. Fix it in week 2, not in the oral.

    The same shape hits Order Desk when a pick-list report locks the stock row that clerks are selling. Say the isolation level and the lock duration out loud. "Read committed snapshot for the export, short transactions for the seat or the carton" is a complete answer.

    What the scenarios grade

    Scenario 1 grades the invariant and the page. Scenario 2 grades the boundary between interactive writes and bulk reads. Packets that only draw services, and never a transaction, fail both. That is why the sequence diagram is a required deliverable and not an illustration.

    Best Practices

    • Pick Campus Cohort or Order Desk and hold the exclusion list for four weeks.
    • Pilot one tenant. Write every rate for that pilot and one heavy cohort or warehouse.
    • Put the last-seat or last-carton conditional update in an ADR with the losing caller's response.
    • Make grades or stock movements reconstructable. Append revisions or a ledger. Do not only update a column.
    • Take tenant identity from the token. Enable row-level security. Put the tenant in object keys and cache keys.
    • Allowlist join URLs. Do not fetch them from the server.
    • Run exports and mail off the interactive transaction, with idempotency and a fairness cap.
    • Name the system of record in each migration phase. Roll back one tenant.
    • File lesson 69 findings against your week-2 draft. Close blockers with tests you name.
    • Cite mechanisms, not lesson numbers. Keep the twenty-minute briefing inside the bottleneck, two ADRs, one threat, and the flag.
    • Use a modular monolith unless an ADR shows an operational reason to split processes.
    • Label every number as assumption, target, or measurement. Almost all of yours are assumptions. Say so.

    Common Mistakes and Anti-Patterns

    The noun explosion. A service per cohort, enrollment, assignment, grade, and export, with no traffic to justify the deploys. It happens because Module 4 showed microservices and the capstone feels like a place to perform them. The consequence is a cost line and an on-call surface you cannot explain. Start with one application and one database. Split only the worker if the export SLO requires it. That split is easy to defend.

    The copied case study. Lesson 60's prose with "cohort" pasted over "tenant platform," or lesson 54's store pasted over Order Desk, without a seat invariant. It happens under time pressure. The consequence is a failing originality and consistency score. The reviewer can tell. Write the conditional update in your own schema names.

    Planet scale for a pilot. Worldwide regions, active-active grades, and a cell architecture for 200 cohorts. It happens because the course discussed them. The consequence is no time for the threat model. Put regions in a reopen condition tied to a residency requirement you do not currently have.

    Check-then-act enrollment. Read capacity, then insert, with optimism as the only control. It happens because it is the first code that works on one laptop. Scenario 1 is the result. The ADR exists to prevent it.

    Grades as a mutable column. The second save destroys the first, and the export cannot explain a dispute. Append a revision. The current grade is a query. Storage is cheap next to a registrar dispute.

    Server-side fetch of the join URL. "Validation" becomes an SSRF bug. Allowlist the host. Let the browser open it.

    Big-bang migration. All tenants, Monday, rollback is restore. One bad spreadsheet row blocks the company, and a restore drops a different tenant's new data. Phase the pilot. Reject bad rows with a count.

    Self-review with no findings. A blank lesson 69 form claims perfection. The rubric treats that as a missed review. Every real packet has at least one major in week 2. File it.

    Optional extension as a substitute. Payouts are designed in detail, and enrollment is a box. The extension is extra. The core packet is the grade.

    Troubleshooting and Design Review

    Use this table in week 4 before you ask for a peer review.

    Symptom in the draftLikely causeWhat to change
    Diagram has more boxes than ADRsTools were drawn before decisionsDelete any box that no ADR and no data owner mentions
    Enroll SLO and export SLO are one numberTwo workloads were averagedSplit the scenarios. They fail differently
    seats_taken can exceed capacity in a test you have not writtenThe update is not conditionalAdopt the slice's WHERE clause and add the test
    Tenant id appears in the JSON exampleIdentity was copied from a tutorialRemove the field. Document the token claim
    Export sequence holds a lockThe file builder shares the write transactionSnapshot read, worker, signed URL
    Migration has no flagCutover was imagined as a weekendAdd the per-tenant flag and the drain rule
    Threat model is a list of productsSTRIDE was recited without assetsOne row per abuse in the table in this lesson, with your mitigation
    Cost section is a single monthly totalNo driversReplace the total with the formula and the assumptions
    Peer says "looks senior" and files nothingThe review skipped lesson 69Ask them to try to read another tenant's grade. Write down what they did
    Oral practice runs 40 minutesThe briefing includes the whole courseCut back to bottleneck, two ADRs, one threat, one flag

    If the peer review approves a packet that still has a body-supplied tenant id, the peer review does not count. Run it again with the checklist open. The point of the capstone is that you can reject your own draft. Politeness is not a deliverable.

    Interview Questions and Answers

    Q1. What is the capstone actually grading?

    It grades whether you can assemble a reviewable packet for one product increment: scope, SLO, capacity, owners, contracts, decisions, a threat model, and a migration, then survive the lesson 69 checklist. It does not grade how many services you drew or how closely you paraphrased lesson 60. A modular monolith with a correct seat update, row-level security, and a one-tenant rollback outscores a microservice poster that double-enrolls. The oral checks that you can defend two ADRs without reading them aloud in full.

    Q2. How do you keep a four-week design from absorbing the whole platform?

    Write the exclusion list in week 1 and put it on the first page of every later draft. Video bytes, chat, a new notification platform, and a new identity provider are already owned elsewhere. You integrate through ports. When a diagram grows a bus "for later," delete it unless an ADR names a current workflow that needs it. The pilot tenant is the other constraint. Numbers that describe every future university are speculation. Numbers that describe Northwind's heavy cohort are enough to find the bottleneck.

    Q3. Why is a conditional update the center of the Campus Cohort packet?

    Because the product's painful invariant is a scarce seat, and the failure is two writers of that count who did not coordinate. The rest of the packet exists to carry that update honestly: tenant predicate in the same statement, idempotent retry, a waitlist path for the loser, an alert if the invariant breaks, and a migration that does not leave the spreadsheet as a second writer. A beautiful C4 diagram that omits the WHERE seats_taken < capacity clause has missed the product. Order Desk has the same center under the name of a carton.

    Q4. When would you choose a saga instead of one transaction?

    When the owners are different databases or a third party, and a single commit is impossible. Stock decrement plus a payment provider is the usual Order Desk case: an outbox, a payment state including UNCONFIRMED, and a compensating restock if the charge fails for real. Seat decrement plus waitlist insert is not that case. Both rows are yours. A saga there adds failure modes, dual seats or a lost promotion, without a benefit. Lesson 32 is the method. The capstone wants you to know when not to open it.

    Q5. What does a sufficient threat model look like for grades?

    Assets named, actors named, and a mitigation you can point at in the design for cross-tenant reads, cache keys, export URLs, log contents, and role checks on write. A paragraph that says "we use HTTPS and JWT" is not a model. The cross-tenant test name is part of the model because an untested RLS policy is a picture. Lesson 63 is the method. This brief's abuse table is the minimum coverage. Add abuses your design invented, such as a support impersonation feature, if you added that feature.

    Q6. How do you write an SLO you will not be ashamed of in the oral?

    Separate interactive enroll from bulk export. Give each a target, an exclusion, and a signal. Say that the target is a choice, not a measurement, because the pilot has not run. Explain what you do when the signal breaches: page on invariant breaks immediately; page on latency when the error budget lesson 62 would use is burning. Do not promise 99.999% because it sounded strong. A two-second enroll p95 and a fifteen-minute export are honest for this brief if your capacity math supports them. If the math does not, change the target or the design, and record the ADR.

    Q7. What belongs in the migration plan, and what is a fantasy?

    The unit of migration, the system of record in each phase, how mismatches are shown to the registrar, how one tenant turns the flag off, and what happens to in-flight enrollments. A fantasy is a date without those facts, or a rollback that restores a shared database. Spreadsheet rows that fail validation are counted and rejected, not repaired by a hidden script. If the old module remains a writer of seats after the new UI is live, say so as a risk. Better, stop the old writer. Lesson 48's strangler is the pattern. One tenant is the slice.

    Q8. How should a reviewer score two packets that chose different isolation tiers?

    Compare each packet to its own ADR and its cost line. Pool with RLS, a cross-tenant test, and a cost model that fits the pilot is a meets or an exceeds. Bridge with a dedicated database is a meets if the contract or the threat model required it and the operational cost is written down. Silo for every tenant, with no contract and no cost, is an approaching on the tenancy and cost rows even if the diagrams are polished. The rubric does not have a preferred vendor. It has a preferred evidence standard. Lesson 60's definitions are the vocabulary both packets must use correctly.

    Q9. What will the oral examiner ask that the document cannot hide?

    They will change one assumption. "The heavy cohort is 50,000 enrollments in ten minutes." You recompute contention and say whether the single-row update still meets the SLO. They will ask who is paged when seats exceed capacity. They will ask what a timeout after the update committed returns to the client. They will ask where the tenant id comes from. They will ask what rollback does to a second tenant. Answers that quote a product name fail. Answers that quote the statement, the token, the flag, and the idempotency record pass. Practice those four aloud in week 4.

    Q10. How do you integrate mail and payments without inventing vendor APIs?

    Define a port with outcomes you control: accepted, rejected, throttled, unknown. Pass an idempotency key. For mail, state whether a duplicate "you are enrolled" message is acceptable. For payments, follow lesson 55: the provider holds card data, timeout is UNCONFIRMED, the ledger posts with the state change if money is in scope. The adapter, which you do not have to write, will map those calls onto the provider's published HTTP API. If you do not know a field, you leave it in the adapter. You do not put a fictional endpoint in the ADR. The examiner will ask what unknown means. That answer is yours, and it is in the port definition.

    Q11. How does the self-review affect the grade?

    A packet with no self-review loses the communication row and usually hides a blocker that costs the tenancy or consistency row as well. A self-review that files real findings and closes them shows the habit lesson 69 exists to teach. A self-review that files only spelling nits is treated as no review. Deferred majors need a name and a date. Deferred blockers on cross-tenant reads are not available as a deferral. You cannot accept that risk inside this assignment. Fix the design.

    Q12. How would you explain this capstone in a staff interview a year later?

    Describe the invariant, the decision you rejected, the migration unit, and the review finding you filed against yourself. For example: "I kept enrollment on one conditional update because a lock service added a dependency the seat did not need. I piloted one university and left the spreadsheet as a read-only fallback with a flag. I had missed timeout handling on that update, found it in self-review, and mapped it to an unknown state keyed by the idempotency record." That story matches how lesson 66 asks a staff candidate to talk. The capstone is rehearsal for that answer, with the drawings attached.

    Hands-On Exercises

    Exercise: submit the architecture packet

    Problem. Produce the Campus Cohort packet, or Order Desk if assigned, over the four-week plan. Present it in twenty minutes.

    Required deliverables.

    1. Scope, stakeholders, workflows, and exclusions.
    2. Quality scenarios and SLOs for the interactive path and the bulk path, each with a signal.
    3. Assumption log, capacity math, bottleneck sentence, and a cost formula.
    4. C4 context and container diagrams, plus the last-seat or last-carton sequence, including the loser.
    5. API table and data ownership table, including what is not stored.
    6. At least four ADRs in the lesson 10 shape.
    7. Threat model covering the abuses listed in this lesson, plus any your design adds.
    8. Migration plan with phases, system of record, and one-tenant rollback.
    9. Lesson 69 self-review: findings, severities, and closures.
    10. A twenty-minute briefing outline that fits the clock in the technical section.

    Done when. A reviewer who was not in the room can find the conditional update, the tenant source, the export path, and the rollback flag without your narration.

    Evaluation rubric

    Scores are analytic. The band is the weighted total. Exceeds is 90 to 100. Meets is 75 to 89. Approaching is 60 to 74. Unsatisfactory is below 60. A missing required deliverable caps the packet at Approaching, regardless of the other rows. A cross-tenant write that the design still allows caps Tenancy and threat model at 0 for that row and caps the packet at Unsatisfactory until it is fixed. Originality is a multiplier: a packet that is a lightly edited case study is scored, then reduced by 20 points.

    AreaWeightExceedsMeetsApproachingUnsatisfactory
    Scope and exclusions8Exclusions stop a real scope creep; pilot is concreteWorkflows and exclusions are clearScope is broad but findableCannot tell what is being built
    SLO and signals10Interactive and bulk targets differ and each has a pageTargets and signals exist and match the designTargets exist, signals are vague"Fast and reliable" only
    Capacity and cost10Bottleneck sentence changes the diagram; cost has drivers including logsLabeled math and a bottleneck; formula presentNumbers without units or without a conclusionNo math
    Diagrams and boundaries12Context, containers, and the losing sequence match the ADRsAll three diagrams exist and agree with ownersDiagrams exist and contradict the APIBoxes only
    API and data ownership12Idempotency, status codes, append-only grades or stock ledger, single writerContracts and owners are complete enough to buildEndpoints named, retry fuzzyNo contracts
    ADR pack12Four or more decisions, each with a real rejection and a reopen number or conditionFour ADRs, rejections presentDecisions are statements of toolsNo ADRs
    Tenancy and threat model12RLS or equivalent, token source, cache and object keys, tests named, abuses mappedIsolation and the major abuses are mitigated on paperTenant id exists as a columnBody-trusted tenant or no model
    Reliability and operations10Timeouts, unknown outcomes, fair export, correctness pageFailure of the database and of the export job is describedHappy path plus "we replicate"Not addressed
    Migration8Phased, one tenant, system of record per phase, rollback drainsPhases and a flag existBig bang with a storyNot addressed
    Self-review and briefing6Real findings, closures, briefing hits the four beatsChecklist run, briefing fits twenty minutesChecklist ticked without findingsNo self-review

    Oral defense can move a row by one band, up or down, when the spoken answer shows the author does or does not understand the packet. It cannot repair a missing deliverable that was never written.

    Instructor notes for applying the rubric

    Grade the packet before the oral, from the page, the way lesson 66 grades from the board. During the oral, change one assumption and ask the four questions from Q9. If the student cannot recompute, lower Capacity one band. If they cannot say where the tenant comes from, Tenancy is not a Meets, no matter how polished the RLS screenshot is. Give the optional payout extension at most four extra points, and only after the core packet is already at Meets. Do not trade the extension for a missing threat model.

    Lesson Summary

    The capstone is a four-week architecture packet for Campus Cohort on TechLearningPro's multi-tenant platform, or for Order Desk if that brief is assigned. You scope a pilot, split the enroll SLO from the export SLO, enforce the last seat with a conditional update, keep grades reconstructable, take tenant identity from the token, allowlist join URLs, and migrate one tenant with a flag. The deliverables are the diagrams, the contracts, the ADR pack, the capacity and cost model, the threat model, the migration, and a lesson 69 self-review. The oral is twenty minutes on the bottleneck, two decisions, one threat, and the rollback.

    A microservice poster, a copied case study, and a blank self-review do not meet the bar. A modular monolith that a reviewer can test against a double enroll and a cross-tenant read does. That is the standard the rest of the course was building.

    Further Reading

    Ready to mark this lesson complete?Track your journey across the entire course.