6. Documentation and presentation

A capstone that no one else can run isn't done. The deliverables in this section -- README, API docs, architecture diagram, demo video, written reflection -- are what make the system explainable to a stranger and reproducible without you in the room. Treat them as part of the build, not as packaging on top.

The test for "done" on each of these is concrete: somebody who has never seen the repo before should be able to clone it, follow the README, and have the system running locally inside fifteen minutes; the architecture diagram should let them locate any of the components from §2 by sight; the demo video should let someone who can't run it understand what it does; the reflection should let them see which decisions were load-bearing and which weren't.

Writing the README

The README has two jobs. First: get someone to a running copy of the system on their own machine. Second: explain what the system is and what its load-bearing decisions were, in roughly the order someone would ask if they were sitting across from you. A reader who only reads the first paragraph should know what the project does; a reader who reads the whole thing should be able to operate it.

Required README sections.

  • Project title and tagline. Name plus a one-sentence summary of what the system does. The summary names the verb (aggregates, normalises, serves), the subject (news articles from three sources), and the operating environment (deployed on AWS).
  • Live links. The deployed API URL, the auto-generated docs at /docs, and the demo video link. Test all three before you ship the README; a broken link at the top is the loudest possible signal that the project isn't actually wired up.
  • Overview. Two paragraphs covering what the system does and why each component is in the architecture. Lead with the architecture diagram described below; a reader who only looks at the picture should still be able to follow the prose.
  • Tech stack. Grouped by layer: application (FastAPI, Pydantic, SQLAlchemy), data (PostgreSQL, Redis), infrastructure (ECS Fargate, RDS, ElastiCache, ALB), pipeline (GitHub Actions), observability (CloudWatch). One line per component is enough; the reader can drill into specifics elsewhere.
  • Quick start. Copy-pasteable: clone, create a venv, copy .env.example to .env with credentials, docker compose up, alembic upgrade head, hit /health. Include one example curl against the API that works immediately on a fresh install.
  • API surface. Document the main endpoints with one example request and response each. Authentication shape, the three article-fetch parameters, the sentiment filter if you shipped it. Anything more lives at /docs; the README is the index, not the reference.
  • Deployment. AWS services used and why each one is there. Include the rough monthly cost for the deployed environment and what the Free Tier covers; the pipeline stages from commit through ECS service-stable; the rollback path if a deploy fails health checks.
  • Performance numbers. Cite numbers that your own load test produced, not numbers you wished you had. The shape that lands is "Apache Bench, 100 concurrent connections, 1000 requests: p50 = Xms, p99 = Yms, cache hit rate Z%" -- with the command in the README so anyone can rerun it.
  • Project layout. A short directory tree with one line of annotation per top-level folder. The reader navigating the codebase shouldn't have to guess what's where.
  • Operations and known limits. CloudWatch dashboards and alarms; the security model (where secrets live, how rotation works); and an honest list of what the system doesn't do (free-tier rate limits on the upstream APIs, sentiment accuracy bounded by TextBlob, no PII handling). The known-limits section is the one that makes the project look real instead of polished.

Walls of text. Break paragraphs with headers, bullets, and code blocks. A reader who can't skim won't read.

Vague claims. "Fast" is unfalsifiable; "p50 = 12ms on the deployed environment" isn't. Replace adjectives with the number you actually measured.

No visuals. At least the architecture diagram and one screenshot of /docs rendering live. Diagrams carry more information per pixel than prose for a reader who's evaluating quickly.

Broken links. Test every URL in the README, the demo video link, and the example curl against the live API right before you submit. Dead links read as "this person didn't check their own work."

Creating architecture diagrams

A diagram carries more architectural information per second of attention than the prose that surrounds it. The job of these diagrams is to let a reader locate any component the README mentions in the system, follow a request through it, and see where the deployment lives. They aren't decoration; they're the index.

Tools.

  • Excalidraw (excalidraw.com): free, web-based, hand-drawn aesthetic, fast to iterate.
  • Draw.io / diagrams.net: free, formal shape libraries including the official AWS icon set, exports cleanly.
  • Lucidchart: paid, templates and collaboration; reach for it if the other two run out of room.
  • Five diagrams worth drawing.
  • 1. High-level architecture. The six-component view from §2. FastAPI, PostgreSQL, Redis, the three external APIs, the load balancer, and the arrows that connect them. Anyone landing on the repo for the first time should be able to look at this diagram and answer "what does this system do?"
  • 2. Request flow. The numbered steps from §2's request-flow section, drawn as a sequence. User request, cache lookup, parallel fan-out, dedup, write, cache populate, response. Include the rough timings (5ms cache hit vs 800ms cache miss) so the reader sees where time goes.
  • 3. Database schema (ER diagram). The five-table schema with foreign keys and indexes. Crow's-foot notation for the relationships. The reader should be able to answer "how does a saved article connect back to the user who saved it?" from the diagram alone.
  • 4. Deployment architecture. The AWS layout: VPC, public and private subnets, security groups, ECS tasks, the RDS Multi-AZ pair, ElastiCache, ALB, CloudWatch. Every box labelled with the actual resource name from the deployed environment.
  • 5. CI/CD pipeline. The GitHub Actions workflow as a flowchart: test stage, build stage, ECR push, ECS task definition register, service update, stability wait, automatic rollback on health check failure. The failure paths matter as much as the happy path.

Export everything at 1920px wide or larger as PNG, commit to docs/diagrams/, and reference from the README with relative paths. SVGs are better if your diagramming tool produces them cleanly because they scale on retina displays without re-export.

Recording the demo video

The demo video is for the reader who can't or won't run the system themselves. Five to ten minutes is the sweet spot; the goal is to show what the system does end-to-end, not to walk every line of code. Treat the script the same way you treated the README: lead with what the system does, then how it does it.

  • 0:00-0:30 introduction. Your name plus a one-sentence description that names the verb, the subject, and the environment. Same shape as the README tagline so the two reinforce each other.
  • 0:30-2:00 architecture overview. Hold on the high-level architecture diagram and walk the components in the same order the README does. Name the load-bearing decisions (FastAPI for async, Redis for the cache layer, ECS Fargate over EC2) and give the why in one sentence each.
  • 2:00-6:00 live demo. Open /docs on the deployed URL. Execute a search; show the response shape. Repeat the same search to demonstrate the cache hit. Walk the OAuth flow if you implemented it. Show the extension feature end-to-end with a real query.
  • 6:00-8:00 infrastructure tour. Open the AWS Console: ECS service with running tasks, CloudWatch dashboard with the four golden-signal widgets, GitHub Actions showing a recent successful run, Logs Insights running a query against the application log group. This is what proves the system isn't a screenshot.
  • 8:00-9:30 one code walkthrough. Pick the most interesting integration: the parallel asyncio.gather() fan-out, the cache decorator, the OAuth refresh token handling. Explain the design decision in a couple of sentences. Don't try to walk every file.
  • 9:30-10:00 close. Where the code lives. What you'd change in the next iteration (one or two items, not five). That's it.

Recording tools.

  • Loom (loom.com): free tier is generous; web-based; produces a shareable link with built-in captions.
  • OBS Studio (obsproject.com): free, more control over resolution and audio routing; the right pick if you want a clean local file.
  • macOS QuickTime: built-in (Cmd+Shift+5); the lowest-friction option on Mac.

Production: write the script, then read it through twice before recording. Record at 1920x1080. Zoom in when the action moves into a small region (a terminal pane, a code block) so the viewer isn't squinting. Add captions; YouTube auto-generates them but they're worth correcting before publishing. Upload as unlisted and link from the README.

Writing the reflection

The reflection is a short document (two to three pages, committed as docs/REFLECTION.md) that captures the decisions behind the code. The code shows what you did; the reflection shows why. A reader who's already read the README and watched the demo turns to the reflection to find out whether you understand the tradeoffs you made.

  • 1. The hardest technical problem. Pick one and walk it. What broke, how you diagnosed it, what the fix actually was, what you'd recognise next time. Example shape: "Redis connection exhaustion under load. The first version opened a new connection per request; under ab -c 50 the cluster ran out of available connections inside three minutes. The fix was a singleton redis.asyncio.ConnectionPool with max_connections=50 created at startup. The lesson is that anything stateful in an async handler probably needs to be pooled at the application level."
  • 2. What you'd do differently. If you started the build from scratch, what would change? The honest answer here is more valuable than the polished one. Example: "Secrets handling from day one. The first deploy ran with API keys in the task definition's environment; retrofitting Secrets Manager into the running ECS service meant rolling every task to pick up the new task definition revision. Cheaper to set it up correctly at the start."
  • 3. The thing you didn't know going in. The lesson that surprised you, not the lesson you expected to write down. Example: "Saturation is a leading indicator, not a lagging one. The CloudWatch CPU graph trended up for forty-five minutes before request latency moved at all; if the alarm had been on latency rather than on saturation, the autoscaler would have triggered too late to matter."
  • 4. The questions you can answer about your own system. Not interview prep. The list of questions that, if a colleague asked you, you should be able to answer without looking at the code: why FastAPI rather than Flask; why a 5-minute TTL rather than 1 or 60; what happens when the Reddit OAuth refresh token expires; what the failure mode is when one of the three upstream APIs is down; what the cost is to add a fourth source. Writing the list is the exercise; if you can't answer one of your own questions, that's where to spend the next hour.

What "documented" actually means

A documented project is one where a stranger can do four things without you in the room: clone and run it on their own machine; describe what it does after looking at the diagrams; reproduce the deployment from the committed configuration; and locate the load-bearing decisions by reading the reflection. Those four bars are the test for whether the documentation is done.

The order they're done in matters too. Run it before you write about it -- a README written before the system runs end-to-end tends to lie in the corners where the author didn't notice. Draw the diagrams off the working system. Record the demo against the deployed environment, not against a local stub. The reflection comes last because by then you actually know what was hard.

Next, in section 7, we self-assess the project against the rubric -- core implementation, production deployment, extension feature, code quality, documentation -- and decide what to fix before submitting versus what to ship and note as a deferred improvement.