From 8b3a8e19321d6d9af01ea8f8abcb06ed67693e55 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sat, 18 Apr 2026 22:10:09 +0700 Subject: [PATCH] docs: add project documentation set Seven canonical docs under docs/ per the project structure convention: - project-overview-pdr.md users, non-goals, requirements - codebase-summary.md directory layout, module responsibilities - system-architecture.md runtime phases, GraphQL flow, SVG primitives - code-standards.md YAGNI/KISS/DRY, Go conventions, commit rules - design-guidelines.md frame dimensions, theme roles, per-card specs - deployment-guide.md Action/binary/Docker paths, release process - project-roadmap.md done phases (0-5), planned phases (6-9) All files under the 800-line cap. Each leans on tables; grammar sacrificed for concision per project rules. --- docs/code-standards.md | 91 +++++++++++++++++++++++ docs/codebase-summary.md | 109 ++++++++++++++++++++++++++++ docs/deployment-guide.md | 137 +++++++++++++++++++++++++++++++++++ docs/design-guidelines.md | 108 +++++++++++++++++++++++++++ docs/project-overview-pdr.md | 68 +++++++++++++++++ docs/project-roadmap.md | 99 +++++++++++++++++++++++++ docs/system-architecture.md | 128 ++++++++++++++++++++++++++++++++ 7 files changed, 740 insertions(+) create mode 100644 docs/code-standards.md create mode 100644 docs/codebase-summary.md create mode 100644 docs/deployment-guide.md create mode 100644 docs/design-guidelines.md create mode 100644 docs/project-overview-pdr.md create mode 100644 docs/project-roadmap.md create mode 100644 docs/system-architecture.md diff --git a/docs/code-standards.md b/docs/code-standards.md new file mode 100644 index 00000000..102f4556 --- /dev/null +++ b/docs/code-standards.md @@ -0,0 +1,91 @@ +# Code Standards + +## Principles + +Applied in order: **YAGNI → KISS → DRY**. + +- No feature flags, no plugin systems, no abstractions for hypothetical callers. +- One way to do a thing. A helper emerges only after the second call site, never before. +- Three similar lines beats a premature abstraction. Extract when a fourth arrives. + +## Go conventions + +### File naming + +- Multi-word files use `snake_case` (Go ecosystem standard): `repos_per_language.go`, `contributions_all_time.go`. +- Single-word files stay single-word: `client.go`, `model.go`, `profile.go`. +- Test files adjacent to the unit under test with `_test.go` suffix. + +### Package structure + +- `main.go` at repo root — the CLI wrapper only. +- All reusable code under `internal/` so it can't accidentally become an API. +- Each package owns one concern: `github` = network, `card` = render, `theme` = palette data. + +### Error handling + +- Wrap errors with `fmt.Errorf("%w: …", err)` when adding context; bare return when the caller already has enough context. +- Sentinel errors (`errors.New`) only when callers need to type-check. We have none today — don't invent them. +- Network/API errors in fetchers bubble up; `main.go` decides whether to exit or warn. + +### No hidden state + +- Profile fetchers mutate the `*Profile` argument in-place (`FetchContributionsAllTime(p, opts)`) — explicit ownership, no package-level caches. +- Renderers are pure functions of `(*Profile, theme.Theme)`. No side effects, no goroutines. + +### Comments + +Default: **no comments**. Exceptions: + +- **Why non-obvious code is non-obvious.** Example: the `scaleFactor = 10_000` constant — a comment explains why fixed-point and not float. +- **Hidden invariant or constraint.** Example: the comment on `contributionYearQuery` noting the `maxRepositories: 100` cap. +- **Workaround for an upstream behavior.** Example: clamping the current year's `to` to `now` so GitHub doesn't reject future timestamps. + +Never write comments that describe what well-named code does (`// increment counter`). Never reference "the recent fix" or "for issue #42" — that belongs in git. + +### Function length + +- No hard limit. 200-line functions are fine when the logic is linear. +- Extract a helper only when (a) the same shape repeats twice, or (b) a block needs an independent name to be read at the call site. + +### Exported vs unexported + +- Start unexported. Export only when a test file or another package needs the symbol. +- Types on the public API: `Profile`, `RepoInfo`, `LangStat`, `LangEdge`, `DailyContribution`, `FetchOptions`, `Client`, `Theme`, `Card`. +- Everything else stays lowercase. + +## SVG output standards + +- Always XML-escape user-controlled strings through `escapeXML` (`&`, `<`, `>`, `"`, `'`). +- Numbers formatted via `formatInt` with thousands separators. +- Stable viewbox per card (`500×220` for most, `500×220` for profile too). +- No `