|
| 1 | +# Wishpicks |
| 2 | + |
| 3 | +A wishlist platform. Users create gift wishlists and share links with friends. Friends can reserve items to avoid duplicate gifts — the wishlist owner never sees who reserved what. |
| 4 | + |
| 5 | +## Stack |
| 6 | + |
| 7 | +| Layer | Technology | |
| 8 | +|-------|-----------| |
| 9 | +| Frontend | Nuxt 3, Pinia, Tailwind CSS v4, Nuxt UI | |
| 10 | +| Backend | FastAPI, SQLAlchemy 2 (async), Alembic, Pydantic v2 | |
| 11 | +| Database | PostgreSQL (Neon in production) | |
| 12 | +| Cache / Rate limiting | Redis (Upstash in production) | |
| 13 | +| Media | Cloudinary | |
| 14 | +| Frontend hosting | Vercel | |
| 15 | +| Backend hosting | Railway / Render | |
| 16 | + |
| 17 | +## Project structure |
| 18 | + |
| 19 | +``` |
| 20 | +wishpicks/ |
| 21 | +├── apps/ |
| 22 | +│ ├── web/ # Nuxt 3 frontend |
| 23 | +│ └── api/ # FastAPI backend |
| 24 | +├── .github/ |
| 25 | +│ ├── workflows/ # CI/CD (see below) |
| 26 | +│ └── cliff.toml # Changelog format config |
| 27 | +├── .ai/ # Architecture docs, conventions |
| 28 | +├── docker-compose.yml |
| 29 | +└── .env.example |
| 30 | +``` |
| 31 | + |
| 32 | +## Getting started |
| 33 | + |
| 34 | +**Prerequisites:** Docker, Docker Compose |
| 35 | + |
| 36 | +```bash |
| 37 | +# 1. Copy env file and fill in the required values |
| 38 | +cp .env.example .env |
| 39 | + |
| 40 | +# 2. Start all services (Postgres, Redis, API, Web) |
| 41 | +docker-compose up |
| 42 | +``` |
| 43 | + |
| 44 | +| Service | URL | |
| 45 | +|---------|-----| |
| 46 | +| Frontend | http://localhost:3000 | |
| 47 | +| Backend | http://localhost:8000 | |
| 48 | +| API docs | http://localhost:8000/docs | |
| 49 | + |
| 50 | +## Environment variables |
| 51 | + |
| 52 | +All variables are documented in `.env.example`. Required before first run: |
| 53 | + |
| 54 | +Variables without values in `.env.example` are optional for local development (the features that depend on them won't work, but the app will start). |
| 55 | + |
| 56 | +## Commit convention |
| 57 | + |
| 58 | +This project uses [Conventional Commits](https://www.conventionalcommits.org). The format is enforced locally via Husky and in CI via the commitlint workflow. |
| 59 | + |
| 60 | +``` |
| 61 | +<type>(<scope>): <subject> |
| 62 | +
|
| 63 | +feat(api): add reservation endpoint |
| 64 | +fix(web): correct auth redirect on 401 |
| 65 | +chore: update dependencies |
| 66 | +feat!: rename endpoint ← breaking change (! suffix) |
| 67 | +``` |
| 68 | + |
| 69 | +Allowed types: `feat`, `fix`, `chore`, `docs`, `refactor`, `test`, `style`, `perf`, `ci`, `build`, `revert` |
| 70 | + |
| 71 | +Scope is optional and must be kebab-case when provided. |
| 72 | + |
| 73 | +## CI/CD |
| 74 | + |
| 75 | +### Workflows |
| 76 | + |
| 77 | +**`ci.yml`** — runs on every PR to `main` |
| 78 | + |
| 79 | +Runs two parallel jobs: `Lint API` (ruff check + format check) and `Lint Web` (eslint + nuxt typecheck). Both jobs always run regardless of which files changed. |
| 80 | + |
| 81 | +**`commitlint.yml`** — runs on every PR to `main` |
| 82 | + |
| 83 | +Validates that every commit title in the PR follows the Conventional Commits format. Fails the PR if any commit message is invalid. |
| 84 | + |
| 85 | +**`release.yml`** — runs when a `v*.*.*` tag is pushed |
| 86 | + |
| 87 | +Generates a changelog from commits since the previous tag using [git-cliff](https://github.com/orhun/git-cliff), then creates a GitHub Release with that changelog as the release notes. |
| 88 | + |
| 89 | +### Creating a release |
| 90 | + |
| 91 | +Decide the version bump based on what changed: |
| 92 | + |
| 93 | +| Change type | Bump | Example | |
| 94 | +|-------------|------|---------| |
| 95 | +| Bug fixes only | patch | `v1.0.0` → `v1.0.1` | |
| 96 | +| New features, backward compatible | minor | `v1.0.0` → `v1.1.0` | |
| 97 | +| Breaking changes | major | `v1.0.0` → `v2.0.0` | |
| 98 | + |
| 99 | +Then push a tag: |
| 100 | + |
| 101 | +```bash |
| 102 | +git tag v1.1.0 -m "Release v1.1.0" |
| 103 | +git push origin v1.1.0 |
| 104 | +``` |
| 105 | + |
| 106 | +GitHub Actions picks up the tag, generates the changelog automatically, and publishes the release. No manual steps needed beyond pushing the tag. |
0 commit comments