Add README, screenshots, tri-lingual wiki and wiki workflow (MIL-003)

README from the framework template, three terminal screenshots rendered by
script, wiki pages in English, Danish and Bahasa Malaysia, the publish-wiki
workflow, and the milestone links in the Project Plan.

Refs #13
Refs #14
Refs #15
Refs #16
Refs #17
Refs #18
This commit is contained in:
2026-10-17 15:41:15 +08:00
parent 5937dc2725
commit 457b84c6da
26 changed files with 523 additions and 4 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+6 -3
View File
@@ -29,9 +29,9 @@ This plan schedules the three phases that deliver the birthday wisher of [BC-001
| Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone |
| --- | --- | --- | --- | --- | --- | --- | --- |
| G1 Project setup | [MIL-001] | 2026-10-17 to 2026-10-18 | 2026-10-18 | S01 | none (plain tasks) | Skeleton, tooling, repository metadata | |
| G2 Core | [MIL-002] | 2026-10-18 to 2026-10-19 | 2026-10-19 | S01 | none (plain tasks) | Working, tested birthday wisher | |
| G3 Documentation | [MIL-003] | 2026-10-19 to 2026-10-20 | 2026-10-20 | S01 | none (plain tasks) | README, tri-lingual wiki, screenshots | |
| G1 Project setup | [MIL-001] | 2026-10-17 to 2026-10-18 | 2026-10-18 | S01 | none (plain tasks) | Skeleton, tooling, repository metadata | [M-188] |
| G2 Core | [MIL-002] | 2026-10-18 to 2026-10-19 | 2026-10-19 | S01 | none (plain tasks) | Working, tested birthday wisher | [M-189] |
| G3 Documentation | [MIL-003] | 2026-10-19 to 2026-10-20 | 2026-10-20 | S01 | none (plain tasks) | README, tri-lingual wiki, screenshots | [M-190] |
```plantuml
@startgantt
@@ -85,3 +85,6 @@ A No-Go at a gate moves every later date by the time needed to fix and re-review
[MIL-002]: ./milestones/mil-002-birthday-wisher-core.md
[MIL-003]: ./milestones/mil-003-documentation-and-publication.md
[052008f]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/commit/052008f21364120a7c4d5ebbff26b8c16e05a21c
[M-188]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/milestones/188
[M-189]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/milestones/189
[M-190]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/milestones/190
+14
View File
@@ -0,0 +1,14 @@
# Arkitektur
🌐 [English](Architecture) · **Dansk** · [Bahasa Melayu](Architecture-ms)
Koden følger en lille clean architecture. Imports peger indad.
| Lag | Mappe | Indeholder |
| --- | --- | --- |
| Domæne | `src/birthday_wisher/domain/` | `Person` og fejlene |
| Applikation | `src/birthday_wisher/application/` | Use casen `send_birthday_wishes` og portene (`BirthdayRepository`, `LetterSource`, `MailSender`) |
| Infrastruktur | `src/birthday_wisher/infrastructure/` | CSV-læser, brevfiler, SMTP-afsender, indstillinger |
| Præsentation | `src/birthday_wisher/presentation/` | Kommandolinjen og composition root |
Testene afspejler lagene: `tests/unit`, `tests/integration`, `tests/e2e`. Kursets hint om en ordbog med `(month, day)` som nøgle er `birthdays_by_day`.
+14
View File
@@ -0,0 +1,14 @@
# Seni Bina
🌐 [English](Architecture) · [Dansk](Architecture-da) · **Bahasa Melayu**
Kod mengikut seni bina bersih yang kecil. Import menuju ke dalam.
| Lapisan | Folder | Mengandungi |
| --- | --- | --- |
| Domain | `src/birthday_wisher/domain/` | `Person` dan ralat |
| Aplikasi | `src/birthday_wisher/application/` | Kes guna `send_birthday_wishes` dan port (`BirthdayRepository`, `LetterSource`, `MailSender`) |
| Infrastruktur | `src/birthday_wisher/infrastructure/` | Pembaca CSV, fail surat, penghantar SMTP, tetapan |
| Pembentangan | `src/birthday_wisher/presentation/` | Baris arahan dan composition root |
Ujian mencerminkan lapisan: `tests/unit`, `tests/integration`, `tests/e2e`. Petunjuk kursus tentang kamus berkunci `(month, day)` ialah `birthdays_by_day`.
+14
View File
@@ -0,0 +1,14 @@
# Architecture
🌐 **English** · [Dansk](Architecture-da) · [Bahasa Melayu](Architecture-ms)
The code follows a small clean architecture. Imports point inward.
| Layer | Folder | Holds |
| --- | --- | --- |
| Domain | `src/birthday_wisher/domain/` | `Person` and the errors |
| Application | `src/birthday_wisher/application/` | The use case `send_birthday_wishes` and the ports (`BirthdayRepository`, `LetterSource`, `MailSender`) |
| Infrastructure | `src/birthday_wisher/infrastructure/` | CSV reader, letter files, SMTP mailer, settings |
| Presentation | `src/birthday_wisher/presentation/` | The command line and the composition root |
The tests mirror the layers: `tests/unit`, `tests/integration`, `tests/e2e`. The course hint of a dictionary keyed by `(month, day)` is `birthdays_by_day`.
+18
View File
@@ -0,0 +1,18 @@
# Konfiguration
🌐 [English](Configuration) · **Dansk** · [Bahasa Melayu](Configuration-ms)
**Personer.** `birthdays.csv` har overskriften `name,email,year,month,day`. Filen i repositoryet indeholder opdigtede data. Erstat den med dine egne, og hold rigtige adresser ude af git.
**Breve.** `letter_templates/letter_1.txt` til `letter_3.txt`. Teksten `[NAME]` erstattes af personens navn. Ét brev vælges tilfældigt.
**Afsender.** To miljøvariabler:
| Variabel | Betydning |
| --- | --- |
| `GMAIL_ADDRESS` | Adressen, e-mailen sendes fra |
| `GMAIL_TOKEN` | Gmail-app-adgangskode |
`.env.example` viser navnene. Læg aldrig en rigtig `.env` i git; den ignoreres af git. Programmet læser kun miljøet og udskriver aldrig tokenet.
**Konstanter.** Server, port, emne og filnavne står i `src/birthday_wisher/constants.py`.
+18
View File
@@ -0,0 +1,18 @@
# Konfigurasi
🌐 [English](Configuration) · [Dansk](Configuration-da) · **Bahasa Melayu**
**Orang.** `birthdays.csv` mempunyai pengepala `name,email,year,month,day`. Fail dalam repositori mengandungi data rekaan. Gantikan dengan data anda sendiri, dan jauhkan alamat sebenar daripada git.
**Surat.** `letter_templates/letter_1.txt` hingga `letter_3.txt`. Teks `[NAME]` diganti dengan nama orang itu. Satu surat dipilih secara rawak.
**Penghantar.** Dua pemboleh ubah persekitaran:
| Pemboleh ubah | Maksud |
| --- | --- |
| `GMAIL_ADDRESS` | Alamat e-mel dihantar daripadanya |
| `GMAIL_TOKEN` | Kata laluan aplikasi Gmail |
`.env.example` menunjukkan namanya. Jangan sekali-kali komit `.env` sebenar; git mengabaikannya. Program hanya membaca persekitaran dan tidak pernah mencetak token.
**Pemalar.** Pelayan, port, subjek dan nama fail ada dalam `src/birthday_wisher/constants.py`.
+18
View File
@@ -0,0 +1,18 @@
# Configuration
🌐 **English** · [Dansk](Configuration-da) · [Bahasa Melayu](Configuration-ms)
**People.** `birthdays.csv` has the header `name,email,year,month,day`. The file in the repository holds dummy data. Replace it with your own, and keep real addresses out of git.
**Letters.** `letter_templates/letter_1.txt` to `letter_3.txt`. The text `[NAME]` is replaced by the person's name. One letter is chosen at random.
**Sender.** Two environment variables:
| Variable | Meaning |
| --- | --- |
| `GMAIL_ADDRESS` | Address the e-mail is sent from |
| `GMAIL_TOKEN` | Gmail app password |
`.env.example` shows the names. Never commit a real `.env`; it is ignored by git. The program reads the environment only and never prints the token.
**Constants.** Server, port, subject and file names are in `src/birthday_wisher/constants.py`.
+17
View File
@@ -0,0 +1,17 @@
# Fødselsdagshilsner
🌐 [English](Home) · **Dansk** · [Bahasa Melayu](Home-ms)
Sender et tilfældigt fødselsdagsbrev på e-mail til alle i `birthdays.csv`, der har fødselsdag i dag. Det er "normal"-niveauet på dag 32 af Udemys *100 Days of Code: The Complete Python Pro Bootcamp*.
![En prøvekørsel](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/dry-run.png)
| Side | Læs den, når du vil |
| --- | --- |
| [Setup](Setup-da) | Oprette et lokalt `.venv` og installere projektet |
| [Usage](Usage-da) | Køre programmet og læse dets output |
| [Configuration](Configuration-da) | Ændre personerne, brevene og afsenderen |
| [Testing](Testing-da) | Køre testene |
| [Architecture](Architecture-da) | Se, hvordan koden er opbygget |
Programmet bruger kun Pythons standardbibliotek: der er ingen runtime-afhængigheder. Kildekode: [repository](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher).
+17
View File
@@ -0,0 +1,17 @@
# Pengucap Hari Lahir
🌐 [English](Home) · [Dansk](Home-da) · **Bahasa Melayu**
Menghantar surat hari jadi rawak melalui e-mel kepada semua orang dalam `birthdays.csv` yang berhari jadi hari ini. Ini ialah tahap "normal" hari ke-32 kursus Udemy *100 Days of Code: The Complete Python Pro Bootcamp*.
![Larian percubaan](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/dry-run.png)
| Halaman | Baca apabila anda ingin |
| --- | --- |
| [Setup](Setup-ms) | Mencipta `.venv` setempat dan memasang projek |
| [Usage](Usage-ms) | Menjalankan program dan membaca outputnya |
| [Configuration](Configuration-ms) | Menukar senarai orang, surat dan penghantar |
| [Testing](Testing-ms) | Menjalankan ujian |
| [Architecture](Architecture-ms) | Melihat bagaimana kod disusun |
Program ini hanya menggunakan pustaka standard Python: tiada kebergantungan masa larian. Kod sumber: [repositori](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher).
+17
View File
@@ -0,0 +1,17 @@
# Birthday Wisher
🌐 **English** · [Dansk](Home-da) · [Bahasa Melayu](Home-ms)
Sends a random birthday letter by e-mail to everyone in `birthdays.csv` whose birthday is today. It is the "normal" level of day 32 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*.
![A dry run](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/dry-run.png)
| Page | Read it when you want to |
| --- | --- |
| [Setup](Setup) | Create a local `.venv` and install the project |
| [Usage](Usage) | Run the program and read its output |
| [Configuration](Configuration) | Change the people, the letters and the sender |
| [Testing](Testing) | Run the tests |
| [Architecture](Architecture) | See how the code is organised |
The program uses only the Python standard library: there are no runtime dependencies. Source: [repository](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher).
+20
View File
@@ -0,0 +1,20 @@
# Opsætning
🌐 [English](Setup) · **Dansk** · [Bahasa Melayu](Setup-ms)
Du skal bruge Python 3.13 eller nyere.
```bash
python -m venv .venv
```
Aktivér miljøet. Windows PowerShell: `.venv\Scripts\Activate.ps1`. Windows cmd: `.venv\Scripts\activate`. Linux og macOS: `source .venv/bin/activate`.
```bash
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
![Oprettelse af .venv](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/venv-setup.png)
Tilvalget `dev` installerer pytest, ruff og mypy. Selve programmet kræver intet.
+20
View File
@@ -0,0 +1,20 @@
# Persediaan
🌐 [English](Setup) · [Dansk](Setup-da) · **Bahasa Melayu**
Anda memerlukan Python 3.13 atau lebih baharu.
```bash
python -m venv .venv
```
Aktifkan persekitaran. Windows PowerShell: `.venv\Scripts\Activate.ps1`. Windows cmd: `.venv\Scripts\activate`. Linux dan macOS: `source .venv/bin/activate`.
```bash
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
![Mencipta .venv](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/venv-setup.png)
Tambahan `dev` memasang pytest, ruff dan mypy. Program itu sendiri tidak memerlukan apa-apa.
+20
View File
@@ -0,0 +1,20 @@
# Setup
🌐 **English** · [Dansk](Setup-da) · [Bahasa Melayu](Setup-ms)
You need Python 3.13 or newer.
```bash
python -m venv .venv
```
Activate the environment. Windows PowerShell: `.venv\Scripts\Activate.ps1`. Windows cmd: `.venv\Scripts\activate`. Linux and macOS: `source .venv/bin/activate`.
```bash
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
```
![Creating the .venv](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/venv-setup.png)
The `dev` extra installs pytest, ruff and mypy. Nothing is needed to run the program itself.
+18
View File
@@ -0,0 +1,18 @@
# Test
🌐 [English](Testing) · **Dansk** · [Bahasa Melayu](Testing-ms)
```bash
python -m pytest
```
![Testkørslen](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/tests.png)
Testene bruger en falsk SMTP-forbindelse og midlertidige filer. De kræver intet netværk, ingen `.env` og ingen adgangskoder. Valgfri kontrol:
```bash
python -m ruff check src tests
python -m mypy src tests
```
API-dokumentation fra Doxygen-kommentarerne: `doxygen Doxyfile` (output i `docs/doxygen/`).
+18
View File
@@ -0,0 +1,18 @@
# Ujian
🌐 [English](Testing) · [Dansk](Testing-da) · **Bahasa Melayu**
```bash
python -m pytest
```
![Larian ujian](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/tests.png)
Ujian menggunakan sambungan SMTP palsu dan fail sementara. Ia tidak memerlukan rangkaian, `.env` atau kelayakan. Semakan pilihan:
```bash
python -m ruff check src tests
python -m mypy src tests
```
Dokumentasi API daripada komen Doxygen: `doxygen Doxyfile` (output dalam `docs/doxygen/`).
+18
View File
@@ -0,0 +1,18 @@
# Testing
🌐 **English** · [Dansk](Testing-da) · [Bahasa Melayu](Testing-ms)
```bash
python -m pytest
```
![The test run](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/tests.png)
The tests use a fake SMTP connection and temporary files. They need no network, no `.env` and no credentials. Optional checks:
```bash
python -m ruff check src tests
python -m mypy src tests
```
API documentation from the Doxygen comments: `doxygen Doxyfile` (output in `docs/doxygen/`).
+26
View File
@@ -0,0 +1,26 @@
# Brug
🌐 [English](Usage) · **Dansk** · [Bahasa Melayu](Usage-ms)
Udskriv brevene i stedet for at sende dem. `--today` lader som om, det er en anden dag:
```bash
python -m birthday_wisher --dry-run --today 2000-10-17
```
![En prøvekørsel](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/dry-run.png)
Send brevene til dagens fødselsdage (kræver [afsenderindstillingerne](Configuration-da)):
```bash
python -m birthday_wisher
```
| Valgmulighed | Betydning |
| --- | --- |
| `--dry-run` | Udskriv e-mailene i stedet for at sende dem |
| `--today YYYY-MM-DD` | Lad som om, det er denne dato |
| `--csv FILE` | Brug en anden fødselsdagsfil |
| `--letters FOLDER` | Brug en anden mappe med brevskabeloner |
Slutstatus 0 betyder succes. Status 1 betyder, at opsætningen er forkert (manglende fil eller indstilling), eller at et brev ikke kunne sendes. En fødselsdag den 29. februar fejres den 28. februar i år, der ikke er skudår.
+26
View File
@@ -0,0 +1,26 @@
# Penggunaan
🌐 [English](Usage) · [Dansk](Usage-da) · **Bahasa Melayu**
Cetak surat tanpa menghantarnya. `--today` berpura-pura hari ini ialah tarikh lain:
```bash
python -m birthday_wisher --dry-run --today 2000-10-17
```
![Larian percubaan](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/dry-run.png)
Hantar surat untuk hari jadi hari ini (memerlukan [tetapan penghantar](Configuration-ms)):
```bash
python -m birthday_wisher
```
| Pilihan | Maksud |
| --- | --- |
| `--dry-run` | Cetak e-mel tanpa menghantarnya |
| `--today YYYY-MM-DD` | Berpura-pura hari ini ialah tarikh ini |
| `--csv FILE` | Guna fail hari jadi lain |
| `--letters FOLDER` | Guna folder templat surat lain |
Status keluar 0 bermaksud berjaya. Status 1 bermaksud persediaan salah (fail atau tetapan tiada) atau satu surat gagal dihantar. Hari jadi pada 29 Februari disambut pada 28 Februari dalam tahun yang bukan tahun lompat.
+26
View File
@@ -0,0 +1,26 @@
# Usage
🌐 **English** · [Dansk](Usage-da) · [Bahasa Melayu](Usage-ms)
Print the letters instead of sending them. `--today` pretends it is another day:
```bash
python -m birthday_wisher --dry-run --today 2000-10-17
```
![A dry run](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/032-birthday-wisher/raw/branch/main/docs/images/dry-run.png)
Send the letters for today's birthdays (needs the [sender settings](Configuration)):
```bash
python -m birthday_wisher
```
| Option | Meaning |
| --- | --- |
| `--dry-run` | Print the e-mails instead of sending them |
| `--today YYYY-MM-DD` | Pretend today is this date |
| `--csv FILE` | Use another birthdays file |
| `--letters FOLDER` | Use another folder of letter templates |
Exit status 0 means success. Status 1 means the setup is wrong (missing file or setting) or a letter could not be sent. A birthday on 29 February is celebrated on 28 February in years that are not leap years.
+14
View File
@@ -0,0 +1,14 @@
**Birthday Wisher**
- [Home](Home)
- [Setup](Setup)
- [Usage](Usage)
- [Configuration](Configuration)
- [Testing](Testing)
- [Architecture](Architecture)
**Languages**
- English: [Home](Home)
- Dansk: [Home](Home-da)
- Bahasa Melayu: [Home](Home-ms)