# The Professor's sample articles

<!-- Role: the ten pieces that show the client what an article centre looks like, and the
     exact commands that put them on staging and take them off again. Stream AW5.2. -->

Ten pieces in the Professor's own voice, written so the client can see a populated article
centre before he hands in his own copy. They are editorial furniture, not the client's work:
every one is imported with `--sample`, which marks it on its card and at the top of its page
and makes the launch step one command instead of ten slugs in a checklist.

Every file's name is its slug: the title on the first line folds to exactly the file's stem,
and `tests/test_articles.py` pins that, so the publish line below can never drift from the
folder.

**Nothing here carries a hero picture.** The pictures the client supplied are licensed per
brand and per product line, and none of these pieces is about one brand or one line, so using
a bottle shot as the hero would imply an aboutness the piece does not have. The card draws its
own stand-in. To give one a picture later, re-import it with `--hero-image <address>` and
`--hero-credit "<attribution>"`; the credit prints as a caption under the hero, on the page
and in the server-rendered body alike.

`import/` is mounted read-only in the container at `/srv/import/`, so the commands below run
as they are written.

## Import the ten (drafts)

The first command may print `note: public.articles_id_seq was behind the rows that exist`.
That is expected and it is the repair, not a warning: a staging refresh replays the rows
people wrote by natural key, ids included, and leaves the id sequence where it stood, so
without the lift the first insert collides with a row that is already there. The import does
it once, idempotently, and says so.

```bash
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/how-airport-pricing-works.md --sample --category "Duty free basics" --standfirst "Who sets the shelf price at an airport, which taxes actually come off, and why the same bottle costs two different amounts two gates apart." --tag pricing --tag basics
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/allowances-and-why-they-differ.md --sample --category "Duty free basics" --standfirst "The limit that binds is set by the country you land in, not the one you fly out of. How to read yours before you buy." --tag allowances --tag basics
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/reading-a-shelf-price.md --sample --category "Duty free basics" --standfirst "Loyalty tiers, destination pricing and the currency on the ticket: what stands between the number on the shelf and the number on your receipt." --tag pricing --tag basics
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/the-pre-flight-shopping-checklist.md --sample --category "Duty free basics" --standfirst "Six things to settle before you leave the house, so the twenty minutes you have airside are spent choosing rather than working it out." --tag basics --tag checklist
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/which-categories-are-worth-buying-airside.md --sample --category "Buying guides" --standfirst "Duty falls unevenly, and that single fact decides most of what is worth putting in a bag at the airport." --tag buying --tag categories
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/litre-bottles-and-travel-exclusives.md --sample --category "Buying guides" --standfirst "The two things the airport shelf has that your supermarket does not, and how to tell which of them is worth the trip." --tag buying --tag exclusives
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/what-a-competition-medal-tells-you.md --sample --category "Buying guides" --standfirst "A medal is an independent opinion on what is in the bottle. What the judging measures, and how much weight to give it." --tag awards --tag buying
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/how-to-read-an-airport-shopping-guide.md --sample --category "Airport guides" --standfirst "Terminals, airside and landside, arrivals halls and opening hours: the sections of an airport guide, and the ones to read first." --tag airports --tag guides
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/reading-a-whisky-age-statement.md --sample --category "Whisky" --standfirst "What the number on the label promises, what it does not, and why a bottle without one is not automatically the lesser buy." --tag whisky --tag labels
docker exec dutyfreeprofessor-app python -m app.cli articles import /srv/import/articles/samples/is-perfume-a-bargain-at-the-airport.md --sample --category "Perfume" --standfirst "Fragrance is the category travellers buy on impulse and regret on arithmetic. The checks that separate a saving from a souvenir." --tag perfume --tag buying
```

The last two carry a taxonomy category name (`Whisky`, `Perfume`) rather than a kicker, so the
piece links through to that category's own page. The other eight carry a kicker.

## Publish them

```bash
docker exec dutyfreeprofessor-app python -m app.cli articles publish \
  how-airport-pricing-works allowances-and-why-they-differ reading-a-shelf-price \
  the-pre-flight-shopping-checklist which-categories-are-worth-buying-airside \
  litre-bottles-and-travel-exclusives what-a-competition-medal-tells-you \
  how-to-read-an-airport-shopping-guide reading-a-whisky-age-statement \
  is-perfume-a-bargain-at-the-airport
```

Check what landed, samples only, drafts included:

```bash
docker exec dutyfreeprofessor-app python -m app.cli articles list --samples
```

## The launch step

Before production's database is replaced, take every sample back to draft. One command, and it
reads the column rather than this file, so a sample imported later is covered too:

```bash
docker exec dutyfreeprofessor-app python -m app.cli articles unpublish --samples
```

A draft exists nowhere on the site, not even at its own address, so this is the whole step.

## Re-importing

An import is idempotent on slug: running a line above twice replaces the text and leaves the
status and the publication date alone. `--sample` is the one field the command always wins,
so re-import with the flag. A re-import that drops it un-flags the row, which is the
behaviour the launch step needs: no sample can hide from `--samples` because somebody once
imported it without the flag.
