Compare commits
236 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0cb013f54 | ||
|
|
dfe248ea5f | ||
|
|
ff775e3b8a | ||
|
|
0e51630439 | ||
|
|
bd0e9e4a20 | ||
|
|
c5972b9f04 | ||
|
|
e1b6cba1d4 | ||
|
|
0ff42c3c70 | ||
|
|
a6a9046457 | ||
|
|
40ae75808c | ||
|
|
fbede956e9 | ||
|
|
3793fca65e | ||
|
|
78d0eaa739 | ||
|
|
180ed41e68 | ||
|
|
ce2c90070e | ||
|
|
de63e9f216 | ||
|
|
7187631ebc | ||
|
|
5fa78fbdf6 | ||
|
|
f85ff79a2c | ||
|
|
a3ec7d63f2 | ||
|
|
9d5a463d93 | ||
|
|
d958933250 | ||
|
|
4aa7ba5d9b | ||
|
|
272a25fb05 | ||
|
|
d9411eb00e | ||
|
|
78ad32e93a | ||
|
|
d6e176bcd9 | ||
|
|
8d59f09cb2 | ||
|
|
30317326ce | ||
|
|
1fe35a2ea6 | ||
|
|
cd0f33f603 | ||
|
|
8b429be857 | ||
|
|
49d7f860de | ||
|
|
39c5a89ca7 | ||
|
|
ade2128a73 | ||
|
|
e5b354e322 | ||
|
|
be672b6ca9 | ||
|
|
a580314583 | ||
| 92a30b11db | |||
| fcee0f9213 | |||
| 4ca35de7ef | |||
| ad1c09f139 | |||
| 2b82d1918b | |||
| 8a047e8d9f | |||
|
|
03ca966708 | ||
|
|
b64c42ebde | ||
| c825d99b0a | |||
| cd5fd2d998 | |||
| e738fe484a | |||
| 31da1d557c | |||
| bfd45842fe | |||
|
|
6a44afd6b6 | ||
|
|
c380bebdd6 | ||
|
|
93e0d089f9 | ||
|
|
77c3407792 | ||
|
|
fe83c47e37 | ||
|
|
63d195ddf7 | ||
|
|
f06f4bf3a9 | ||
|
|
3c0ca485b8 | ||
|
|
1a7267ca4a | ||
|
|
b61a440994 | ||
|
|
f433b21bc1 | ||
| 1031a76099 | |||
| df160f1f72 | |||
| de1e9ac02b | |||
|
|
b27b5bdb40 | ||
|
|
30cdb48491 | ||
|
|
37667db2f6 | ||
|
|
f665df578c | ||
|
|
f9acdc8ada | ||
|
|
19dfad5ab5 | ||
|
|
633550f808 | ||
|
|
2b69c99d54 | ||
|
|
1f43f48276 | ||
|
|
9862d1cff4 | ||
|
|
c9a02dbedf | ||
|
|
d469c07250 | ||
|
|
76380d32c3 | ||
|
|
7162244454 | ||
|
|
b2095e7bdd | ||
|
|
5fd60b33f7 | ||
|
|
ec770aa724 | ||
|
|
8e7ecf2fc3 | ||
|
|
901f30ffd8 | ||
| b20852bcd4 | |||
|
|
08a75d6ed0 | ||
|
|
10aed47def | ||
|
|
1699da6b74 | ||
|
|
cd99c1fbc3 | ||
|
|
254431928f | ||
|
|
07aedcb866 | ||
|
|
fd341e332c | ||
|
|
5cf4df1fd8 | ||
|
|
34ba7e8271 | ||
|
|
60a7b790d4 | ||
|
|
4554fff534 | ||
|
|
86a0c50f6e | ||
|
|
3034020d56 | ||
| 6a66619c70 | |||
| 2ee7b3d2a2 | |||
| b7c0b1c8d4 | |||
| b8ebe03921 | |||
| 26635ace84 | |||
| 031be8ad5d | |||
| f316fabcb0 | |||
| b1dc8e0b5d | |||
| 641a479b6a | |||
| d80e15b55e | |||
|
|
1fcaf6e174 | ||
|
|
ef97bf0a75 | ||
|
|
4c8a8e43ed | ||
|
|
8db6992296 | ||
|
|
7925fc6caf | ||
|
|
b1f4ff2641 | ||
|
|
a852beff21 | ||
|
|
e17afe909f | ||
|
|
9ed37806dd | ||
|
|
5a21589029 | ||
|
|
189bce040b | ||
| e8c5b8a80c | |||
|
|
d47e3ed7f0 | ||
|
|
92ec16ce93 | ||
|
|
c2db65d9b1 | ||
|
|
1f008f1237 | ||
|
|
898cc8971b | ||
|
|
fd3c172e35 | ||
|
|
581863d69b | ||
|
|
9238036042 | ||
|
|
431e11e052 | ||
|
|
f1194d3da8 | ||
|
|
17eb04e20c | ||
|
|
50c2f5dfda | ||
|
|
c5683df4b6 | ||
|
|
2cad88e3f6 | ||
|
|
0d52c937ce | ||
|
|
6b66f5680f | ||
|
|
82f0d26200 | ||
|
|
7129e5679e | ||
|
|
584fe6282f | ||
|
|
8c61069b7d | ||
|
|
674f91cbdf | ||
|
|
a54d2a6da0 | ||
|
|
954c9c389c | ||
|
|
d942d92db5 | ||
|
|
c80eae694f | ||
|
|
94061c6d84 | ||
|
|
caf13de36e | ||
|
|
2cb8f1d918 | ||
|
|
f728514a7c | ||
|
|
4f92741b4f | ||
|
|
a038a12fca | ||
|
|
74c5528ea2 | ||
|
|
f48b8452d3 | ||
|
|
2411841bdc | ||
|
|
215824d4b6 | ||
|
|
99b13e2742 | ||
|
|
3a32f326bf | ||
|
|
b2cf21399b | ||
|
|
109ade474c | ||
|
|
07a62a0c99 | ||
|
|
31e67ebad8 | ||
|
|
c74b20079b | ||
|
|
2b0f9876bc | ||
|
|
8a4b833943 | ||
|
|
656981003b | ||
|
|
ff1ce15419 | ||
|
|
881a94893f | ||
|
|
8abacb5572 | ||
|
|
027e130fcd | ||
|
|
243931eb6a | ||
|
|
b22e1e5702 | ||
|
|
b07cec8c7e | ||
|
|
92628290da | ||
|
|
ca2d7c453f | ||
|
|
2076935ee2 | ||
|
|
5c49611bff | ||
|
|
ae6002bbe0 | ||
|
|
a1ea6391bc | ||
|
|
6d812638ba | ||
|
|
17bf29700a | ||
|
|
393e57af7f | ||
|
|
e0af25f17c | ||
|
|
9bfbed9b92 | ||
|
|
2ae99d5224 | ||
|
|
b994201a18 | ||
|
|
e4560f8d80 | ||
|
|
dbd3b6ce0a | ||
|
|
ee53cc60d8 | ||
|
|
954e224c34 | ||
|
|
9474fb7811 | ||
|
|
77bb1f6733 | ||
|
|
1af3d6f987 | ||
|
|
2332f9f9b5 | ||
|
|
0053d84de8 | ||
|
|
754578c84c | ||
|
|
ca49d19bf7 | ||
|
|
cf9f048daa | ||
|
|
a8c0ae6358 | ||
|
|
52643c1173 | ||
|
|
24b059ea3d | ||
|
|
97c093c4bc | ||
|
|
45f64f613d | ||
|
|
084f68da7a | ||
|
|
ea92735146 | ||
|
|
54788b1a6d | ||
|
|
7dc7ef4b1a | ||
|
|
a6702c89fd | ||
|
|
68ff549635 | ||
|
|
a56ea77861 | ||
|
|
14cb05e992 | ||
|
|
53a7569ed5 | ||
|
|
82db763951 | ||
|
|
fd544dbd34 | ||
|
|
89da531c48 | ||
|
|
c5aaf8cd05 | ||
|
|
b8cd855916 | ||
|
|
60ef65ec52 | ||
|
|
da84492aa4 | ||
|
|
b5ab6f6893 | ||
|
|
7fbdfbf542 | ||
|
|
43dcf0844d | ||
|
|
c928ddecb5 | ||
|
|
372aac897a | ||
|
|
8d6b903aa7 | ||
|
|
00a0f6c4ef | ||
|
|
afefdb9e3d | ||
|
|
fc2e8c9b6d | ||
|
|
b86607e37a | ||
|
|
a200164609 | ||
|
|
4e2c9836c9 | ||
|
|
b7f22fcc66 | ||
|
|
f0c9cff8be | ||
|
|
33db1368ec | ||
|
|
8975044034 | ||
|
|
738c055bf7 | ||
|
|
2f0bfd90b2 |
52
.claude/skills/doc-drift-pipeline/SKILL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: doc-drift-pipeline
|
||||
description: Checks whether recent changes under tooling/pipeline/ have made docs/pipeline/ stale. Use when the user asks to check for doc drift on the pipeline, before committing changes to tooling/pipeline, or when asked "does this need a doc update" for the C++ seed-data pipeline.
|
||||
---
|
||||
|
||||
# Doc Drift Check — Pipeline
|
||||
|
||||
Given a diff scoped to `tooling/pipeline/` (uncommitted changes, a range of
|
||||
commits, or a specific PR), determine whether it invalidates any factual
|
||||
claim in `docs/pipeline/`.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run `git diff -- tooling/pipeline/` (or
|
||||
`git diff <base>...<head> -- tooling/pipeline/` if a range is given) to
|
||||
see what changed. If the diff also touches `web/**`, note that it's out of
|
||||
scope here — use the `doc-drift-web` skill for that half.
|
||||
2. Based on which files changed, identify the relevant doc(s):
|
||||
- `tooling/pipeline/src/**`, `includes/**` (implemented behavior) →
|
||||
`docs/pipeline/README.md`, `docs/pipeline/diagrams/current/*.mmd`
|
||||
(activity, class)
|
||||
- Work that's scaffolded/flagged but not wired into the default run path
|
||||
(roadmap-only) → `docs/pipeline/ROADMAP.md`,
|
||||
`docs/pipeline/diagrams/planned/*.mmd` — do not touch `current/` for
|
||||
planned work that hasn't landed
|
||||
- Changes to pipeline bias/hallucination handling, model prompts, sampling
|
||||
logic, or known-limitation workarounds →
|
||||
`docs/pipeline/ETHICS-AND-KNOWN-ISSUES.md`
|
||||
- `tooling/pipeline/runpod/Dockerfile`, build/run scripts →
|
||||
`docs/pipeline/README.md` (setup/usage sections)
|
||||
- `docs/pipeline/french-cities.example` — check it still matches the input
|
||||
schema the pipeline actually reads
|
||||
- A new file added under `docs/pipeline/**` → also check `docs/index.md`
|
||||
and `mkdocs.yml` nav are updated to reference it
|
||||
3. Read the relevant doc section(s) and check each specific factual claim
|
||||
(tables, "currently X", "not yet implemented", roadmap checkboxes) against
|
||||
the diff. For diagrams, this means reading the `.mmd` source (not just the
|
||||
wrapping `.md`) and checking nodes/edges/labels against the diff — a
|
||||
pipeline stage or control-flow change can invalidate a diagram without
|
||||
touching any prose.
|
||||
4. When a diff adds real behavior that was previously only in
|
||||
`diagrams/planned/`, check whether that planned diagram/roadmap entry
|
||||
should now move to `current/`/README rather than just adding a duplicate
|
||||
claim in both places.
|
||||
5. Report only what's actually stale — do not rewrite unrelated prose, do not
|
||||
invent claims not grounded in the diff.
|
||||
6. If nothing is affected, say so plainly and make no edits.
|
||||
7. For confirmed drift, propose the exact edit (old text → new text, or the
|
||||
changed `.mmd` node/edge) rather than committing directly, unless
|
||||
explicitly told to apply it. Flag `.mmd` changes separately since they may
|
||||
need a re-render (`docs/rendered-diagrams/pipeline/**`) via
|
||||
`docs/makefile`.
|
||||
55
.claude/skills/doc-drift-web/SKILL.md
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: doc-drift-web
|
||||
description: Checks whether recent changes under web/ have made docs/web/ stale. Use when the user asks to check for doc drift on the web app, before committing changes to web/backend or web/frontend, or when asked "does this need a doc update" for web/API/frontend work.
|
||||
---
|
||||
|
||||
# Doc Drift Check — Web
|
||||
|
||||
Given a diff scoped to `web/` (uncommitted changes, a range of commits, or a
|
||||
specific PR), determine whether it invalidates any factual claim in
|
||||
`docs/web/`.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run `git diff -- web/` (or `git diff <base>...<head> -- web/` if a range is
|
||||
given) to see what changed. If the diff also touches `tooling/pipeline/**`,
|
||||
note that it's out of scope here — use the `doc-drift-pipeline` skill for
|
||||
that half.
|
||||
2. Based on which files changed, identify the relevant doc(s):
|
||||
- `web/backend/API/**`, `Features.*/**` (general) → `docs/web/architecture.md`
|
||||
- `web/backend/Features/Features.Users/**/Authentication/**`,
|
||||
identity/token code (`ITokenService`, `RefreshToken*`, `ConfirmEmail*`,
|
||||
login/registration handlers) → `docs/web/token-validation.md`,
|
||||
`docs/web/diagrams/auth/*.mmd` (pick the matching flow: login,
|
||||
registration, refresh-token, confirm-user, delete-account,
|
||||
update-email/password/profile/username, resend-confirmation,
|
||||
error-handling)
|
||||
- `web/backend/Database/**` (entities, `Database.Migrations/scripts/**`) →
|
||||
`docs/web/database.md`, `docs/web/diagrams/database-schema/*.mmd` (pick
|
||||
the matching schema: beer, brewery, identity, location, media)
|
||||
- Host wiring / DI registration (`API/**Program.cs`,
|
||||
`Database.Seed/**Program.cs`) → `docs/web/diagrams/vertical-slice/host-wiring.mmd`
|
||||
- New project references between `Features.*`/`Shared.*`/`Domain.*`
|
||||
projects (new `.csproj` `<ProjectReference>`) →
|
||||
`docs/web/diagrams/vertical-slice/project-references.mmd`
|
||||
- `web/backend/Dockerfile*`, `web/frontend/Dockerfile*`, compose/deploy
|
||||
config → `docs/web/docker.md`, `docs/web/diagrams/deployment/*.mmd`
|
||||
(dev, test, minimal, db-only, prod), `docs/web/diagrams/deployment.md`
|
||||
- `web/.env.example`, `web/.env.test`, appsettings → `docs/web/environment-variables.md`
|
||||
- `web/backend/API/API.Specs/**`, test infra/fixtures → `docs/web/testing.md`
|
||||
- New backend project setup, dev tooling → `docs/web/getting-started.md`
|
||||
- `web/frontend/**` → `docs/web/architecture.md` (Frontend architecture section)
|
||||
- A new file added under `docs/web/**` → also check `docs/index.md` and
|
||||
`mkdocs.yml` nav are updated to reference it
|
||||
3. Read the relevant doc section(s) and check each specific factual claim
|
||||
(tables, "currently X", "not yet implemented", roadmap checkboxes) against
|
||||
the diff. For diagrams, this means reading the `.mmd` source (not just the
|
||||
wrapping `.md`) and checking nodes/edges/labels against the diff — a
|
||||
schema or flow change can invalidate a diagram without touching any prose.
|
||||
4. Report only what's actually stale — do not rewrite unrelated prose, do not
|
||||
invent claims not grounded in the diff.
|
||||
5. If nothing is affected, say so plainly and make no edits.
|
||||
6. For confirmed drift, propose the exact edit (old text → new text, or the
|
||||
changed `.mmd` node/edge) rather than committing directly, unless
|
||||
explicitly told to apply it. Flag `.mmd` changes separately since they may
|
||||
need a re-render (`docs/rendered-diagrams/web/**`) via `docs/makefile`.
|
||||
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
archive/** linguist-vendored
|
||||
33
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Feature Request (BDD)
|
||||
about: Create a new feature using user story + BDD acceptance criteria
|
||||
title: "[Feature] "
|
||||
labels: ["feature", "BDD"]
|
||||
assignees: []
|
||||
---
|
||||
|
||||
## User Story
|
||||
|
||||
**As a** (who wants to accomplish something)
|
||||
**I want to** (what they want to accomplish)
|
||||
**So that** (why they want to accomplish that thing)
|
||||
|
||||
## Acceptance Criteria (BDD)
|
||||
|
||||
### Scenario 1
|
||||
|
||||
Given ... When ... Then ...
|
||||
|
||||
### Scenario 2
|
||||
|
||||
Given ... When ... Then ...
|
||||
|
||||
### Scenario 3
|
||||
|
||||
Given ... When ... Then ...
|
||||
|
||||
## Subtasks
|
||||
|
||||
- [ ] Task 1
|
||||
- [ ] Task 2
|
||||
- [ ] Task 3
|
||||
101
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
## Summary
|
||||
|
||||
<!--
|
||||
State WHAT is changing and WHY, in two to five sentences.
|
||||
A reader should understand the change without opening the diff.
|
||||
Describe the problem first, then the outcome.
|
||||
-->
|
||||
|
||||
## Type of change
|
||||
|
||||
<!-- Tick the one option that best describes this PR. -->
|
||||
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Refactor (no change in behaviour)
|
||||
- [ ] Performance improvement
|
||||
- [ ] Documentation
|
||||
- [ ] Tests only
|
||||
- [ ] Build, CI or dependency update
|
||||
- [ ] Other (please specify):
|
||||
|
||||
## Related issues
|
||||
|
||||
<!--
|
||||
Link the issue(s) this PR relates to. Use one keyword per issue so that each is closed on merge:
|
||||
|
||||
Fixes #123
|
||||
Fixes #124, fixes #125
|
||||
Fixes owner/other-repo#456
|
||||
|
||||
Closing keywords only take effect when the PR targets the repository's default branch.
|
||||
Use "Related to #123" if the PR should not close the issue.
|
||||
If there is no issue, write "N/A" and explain the motivation in the Summary.
|
||||
-->
|
||||
|
||||
## Approach and context
|
||||
|
||||
<!--
|
||||
Explain how the change works and why this approach was chosen.
|
||||
Include, where relevant:
|
||||
- The decisions you made that are not obvious from the code.
|
||||
- Alternatives you considered and why you rejected them.
|
||||
- Known limitations or shortcomings, and any planned follow-up work.
|
||||
- Background such as benchmark results or design documents.
|
||||
|
||||
Summarise the key points of any external link. Links may be inaccessible to future readers.
|
||||
-->
|
||||
|
||||
## How this was tested
|
||||
|
||||
<!--
|
||||
Describe what you ran and what you observed. Be specific, and state only what you actually did.
|
||||
For example: the automated tests added or changed, manual steps and their outcome,
|
||||
environments or platforms covered, and anything you were unable to test.
|
||||
For a bug fix, note the test that fails without the fix.
|
||||
-->
|
||||
|
||||
## Compatibility and risk
|
||||
|
||||
- [ ] This change is backwards compatible.
|
||||
- [ ] This change is **breaking** (complete the details below).
|
||||
- [ ] This change deprecates existing behaviour (complete the details below).
|
||||
|
||||
<!--
|
||||
If breaking or deprecating, describe: what changes, who is affected,
|
||||
and the migration path or recommended alternative.
|
||||
Also note any deployment, configuration, data migration or rollback considerations.
|
||||
-->
|
||||
|
||||
## User-facing change
|
||||
|
||||
<!--
|
||||
Does this PR change behaviour that users, operators or API consumers will notice?
|
||||
If not, write "None".
|
||||
If so, write one or two sentences suitable for release notes, in plain language and from the
|
||||
user's point of view. If users must take action when upgrading, state clearly that action is required.
|
||||
-->
|
||||
|
||||
```release-note
|
||||
|
||||
```
|
||||
|
||||
## Notes for reviewers
|
||||
|
||||
<!--
|
||||
Help reviewers focus. For example:
|
||||
- Where to start, or a suggested order in which to read the files.
|
||||
- Areas where you would particularly value scrutiny, or where you are uncertain.
|
||||
- How any mechanical, generated or bulk changes were produced (for example a search-and-replace
|
||||
or a code generator), so that reviewers can reproduce the steps.
|
||||
- Screenshots or recordings for visual changes (include before and after where useful).
|
||||
-->
|
||||
|
||||
## Checklist
|
||||
- [ ] The PR has a single, focused purpose and contains no unrelated changes.
|
||||
- [ ] The title is a clear, imperative summary of the change (for example, "Add retry to payment client").
|
||||
- [ ] I have added or updated tests that cover this change.
|
||||
- [ ] The build succeeds and the tests pass locally.
|
||||
- [ ] The code follows the existing patterns and style of this repository.
|
||||
- [ ] I have updated documentation, changelogs or API references where required.
|
||||
- [ ] I have reviewed my own diff, and this description reflects the final state of the change.
|
||||
51
.github/workflows/deploy-docs.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Deploy Docs to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- docs
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "mkdocs.yml"
|
||||
- ".github/workflows/deploy-docs.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install mkdocs mkdocs-material mkdocs-glightbox mkdocs-panzoom-plugin mkdocs-minify-plugin
|
||||
|
||||
- name: Build site
|
||||
run: mkdocs build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: "site"
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
19
.github/workflows/github-actions-demo.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: Node.js CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
61
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
containerized-tests:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: web
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Generate test environment file
|
||||
run: ./generate-env.sh .env.test
|
||||
|
||||
- name: Build test images
|
||||
run:
|
||||
docker compose --env-file .env.test -f docker-compose.test.yaml build
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
docker compose --env-file .env.test -f docker-compose.test.yaml up -d
|
||||
docker compose --env-file .env.test -f docker-compose.test.yaml wait api.specs unit.tests frontend.tests || true
|
||||
|
||||
- name: Check test container exit codes
|
||||
if: always()
|
||||
run: |
|
||||
status=0
|
||||
for name in test-env-database-migrations test-env-database-seed test-env-api-specs test-env-unit-tests test-env-frontend-tests; do
|
||||
code="$(docker inspect -f '{{.State.ExitCode}}' "$name" 2>/dev/null || echo 1)"
|
||||
echo "$name exited with $code"
|
||||
if [ "$code" != "0" ]; then
|
||||
status=1
|
||||
fi
|
||||
done
|
||||
exit $status
|
||||
|
||||
- name: Show service logs on failure
|
||||
if: failure()
|
||||
run:
|
||||
docker compose --env-file .env.test -f docker-compose.test.yaml logs
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-results
|
||||
path: web/test-results
|
||||
|
||||
- name: Tear down
|
||||
if: always()
|
||||
run:
|
||||
docker compose --env-file .env.test -f docker-compose.test.yaml down
|
||||
-v
|
||||
463
.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
scratchpad.txt
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
@@ -15,6 +15,15 @@
|
||||
# production
|
||||
/build
|
||||
|
||||
# project-specific build artifacts
|
||||
/web/frontend/build/
|
||||
/web/frontend/storybook-static/
|
||||
/web/frontend/.react-router/
|
||||
/web/frontend/playwright-report/
|
||||
/web/frontend/test-results/
|
||||
/test-results/
|
||||
/docs/rendered-diagrams/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
@@ -42,7 +51,459 @@ next-env.d.ts
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
/cloudinary-images
|
||||
|
||||
.obsidian
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.env
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
|
||||
[Dd]ebug/x64/
|
||||
[Dd]ebugPublic/x64/
|
||||
[Rr]elease/x64/
|
||||
[Rr]eleases/x64/
|
||||
bin/x64/
|
||||
obj/x64/
|
||||
|
||||
[Dd]ebug/x86/
|
||||
[Dd]ebugPublic/x86/
|
||||
[Rr]elease/x86/
|
||||
[Rr]eleases/x86/
|
||||
bin/x86/
|
||||
obj/x86/
|
||||
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
[Aa][Rr][Mm]64[Ee][Cc]/
|
||||
bld/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Build results on 'Bin' directories
|
||||
**/[Bb]in/*
|
||||
# Uncomment if you have tasks that rely on *.refresh files to move binaries
|
||||
# (https://github.com/github/gitignore/pull/3736)
|
||||
#!**/[Bb]in/*.refresh
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
*.trx
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Approval Tests result files
|
||||
*.received.*
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.idb
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||
!Directory.Build.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
**/.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
**/.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
**/.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
**/__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
#tools/**
|
||||
#!tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
MSBuild_Logs/
|
||||
|
||||
# AWS SAM Build and Temporary Artifacts folder
|
||||
.aws-sam
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
**/.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
**/.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
**/.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
.DS_Store
|
||||
|
||||
*/data_source/other
|
||||
.fake
|
||||
.idea
|
||||
|
||||
*.feature.cs
|
||||
|
||||
.env
|
||||
.env.dev
|
||||
.env.test
|
||||
.env.prod
|
||||
|
||||
*storybook.log
|
||||
storybook-static
|
||||
web/test-results/frontend/vitest-storybook.xml
|
||||
web/test-results/frontend/playwright-storybook.xml
|
||||
|
||||
# mkdocs build output
|
||||
/site
|
||||
|
||||
905
LICENSE.md
299
README.md
@@ -1,219 +1,182 @@
|
||||
# The Biergarten App
|
||||
|
||||
## About
|
||||
The Biergarten App is a full-stack directory and discovery platform for
|
||||
breweries. It provides:
|
||||
|
||||
The Biergarten App is a web application designed for beer lovers to share their favorite
|
||||
brews and breweries with like-minded people online.
|
||||
- JWT-based user authentication, with email confirmation and refresh-token
|
||||
reissue
|
||||
- A searchable database of brewery locations
|
||||
- An offline data-generation pipeline that uses large language models (LLMs)
|
||||
via Llama.cpp and Wikipedia to synthesize realistic seed data
|
||||
|
||||
This application's stack consists of Next.js, Prisma and Neon Postgres. I'm motivated to
|
||||
learn more about these technologies while exploring my passion for beer.
|
||||
The repository is organized into:
|
||||
|
||||
I've also incorporated different APIs into the application, such as the Cloudinary API for
|
||||
image uploading, the SparkPost API for email services as well as Mapbox for geolocation
|
||||
and map data.
|
||||
- A .NET backend (Web API + database migrations/seed) under `web/backend/`
|
||||
- A server-rendered React website (React Router + Vite) under `web/frontend/`
|
||||
- A C++20 data-generation CLI under `tooling/pipeline/`
|
||||
|
||||
To handle serverless functions (API routes), I use the next-connect package.
|
||||
Specialized documentation (setup, architecture, docker, testing, diagrams, and
|
||||
pipeline notes) lives under `docs/`.
|
||||
|
||||
On the client-side, I use Tailwind CSS, Headless UI and Daisy UI for styling to create a
|
||||
visually appealing and user-friendly interface.
|
||||
## Documentation
|
||||
|
||||
I'm sharing my code publicly so that others can learn from it and use it as a reference
|
||||
for their own projects.
|
||||
Website + backend (active stack):
|
||||
|
||||
### Some beer terminology
|
||||
- [Getting Started](docs/web/getting-started.md)
|
||||
- [Architecture](docs/web/architecture.md)
|
||||
- [Database](docs/web/database.md)
|
||||
- [Docker Guide](docs/web/docker.md)
|
||||
- [Testing](docs/web/testing.md)
|
||||
- [Environment Variables](docs/web/environment-variables.md)
|
||||
- [Token Validation](docs/web/token-validation.md)
|
||||
|
||||
In this app you will encounter various beer related terms. Here is a list of terms used in
|
||||
this app and their definitions.
|
||||
Data generation pipeline (C++):
|
||||
|
||||
#### ABV
|
||||
- [Pipeline README](docs/pipeline/README.md)
|
||||
- [Ethics & Known Issues](docs/pipeline/ETHICS-AND-KNOWN-ISSUES.md)
|
||||
|
||||
[Alcohol by volume](https://en.wikipedia.org/wiki/Alcohol_by_volume) (abbreviated as ABV)
|
||||
is a standard measure of how much alcohol (ethanol) is contained in a given volume of an
|
||||
alcoholic beverage (expressed as a volume percent).
|
||||
## Current status
|
||||
|
||||
#### IBU
|
||||
Active areas in the repository:
|
||||
|
||||
The
|
||||
[International Bitterness Units](https://en.wikipedia.org/wiki/Beer_measurement#Bitterness)
|
||||
scale, or IBU, is used to approximately quantify the bitterness of beer. This scale is not
|
||||
measured on the perceived bitterness of the beer, but rather the amount of a component of
|
||||
beer known as iso-alpha acids.
|
||||
- .NET 10 backend (vertical-slice architecture with MediatR) + SQL Server
|
||||
- React 19 website (React Router 8 + Vite)
|
||||
- Shared Biergarten theme system + Storybook coverage
|
||||
- Auth flows and account/email integration (local Mailpit in dev compose)
|
||||
- Photo upload to S3-compatible object storage (local SeaweedFS in dev compose)
|
||||
- Data generation pipeline with C++ and Llama.cpp
|
||||
|
||||
## Database Schema
|
||||
Archived/reference areas:
|
||||
|
||||

|
||||
- `archive/next-js-web-app/` contains an older Next.js frontend retained for
|
||||
reference
|
||||
|
||||
## Technologies
|
||||
## Tech stack
|
||||
|
||||
### General
|
||||
- **Backend**: .NET 10, ASP.NET Core, SQL Server 2022, DbUp
|
||||
- **Frontend**: React 19, React Router 8, Vite 7, Tailwind CSS 4, DaisyUI 5,
|
||||
Leaflet/React Leaflet (brewery maps)
|
||||
- **UI Documentation**: Storybook 10, Vitest browser mode, Playwright
|
||||
- **Testing**: xUnit, Reqnroll (BDD), FluentAssertions, Moq
|
||||
- **Infrastructure**: Docker, Docker Compose
|
||||
- **Security**: Argon2id password hashing, JSON Web Tokens (JWT) for
|
||||
access/refresh/confirmation
|
||||
- **Data Pipeline**: C++20, CMake, Boost, libcurl, SQLite, llama.cpp
|
||||
|
||||
- [Next.js](https://nextjs.org/)
|
||||
- A React based framework for building web applications offering several features such
|
||||
as server side rendering, static site generation and API routes.
|
||||
## Requirements
|
||||
|
||||
### Client
|
||||
- .NET SDK 10 or later
|
||||
- Node.js 22 or later
|
||||
- Docker Desktop, or an equivalent Docker Engine setup
|
||||
|
||||
- [SWR](https://swr.vercel.app/)
|
||||
- A React Hooks library for fetching data with support for caching, revalidation and
|
||||
error handling.
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
- A popular open-source utility-first CSS framework that provides pre-defined classes to
|
||||
style HTML elements.
|
||||
- [Headless UI](https://headlessui.dev/)
|
||||
- A set of completely unstyled, fully accessible UI components, designed to integrate
|
||||
beautifully with Tailwind CSS.
|
||||
- [Daisy UI](https://daisyui.com/)
|
||||
- A component library for Tailwind CSS that provides ready-to-use components for
|
||||
building user interfaces.
|
||||
See [Getting Started](docs/web/getting-started.md) for the full
|
||||
prerequisite list, including the pipeline's C++ toolchain.
|
||||
|
||||
### Server
|
||||
## Quick start
|
||||
|
||||
- [Prisma](https://www.prisma.io/)
|
||||
- An open-source ORM for Node.js and TypeScript applications.
|
||||
- [Neon Postgres](https://neon.tech/)
|
||||
- A managed PostgreSQL database service powered by Neon.
|
||||
- [Cloudinary](https://cloudinary.com/)
|
||||
- A cloud-based image and video management service that provides developers with an easy
|
||||
way to upload, store, and manipulate media assets.
|
||||
- [SparkPost](https://www.sparkpost.com/)
|
||||
- A cloud-based email delivery service that provides developers with an easy way to send
|
||||
transactional and marketing emails.
|
||||
- [Mapbox](https://www.mapbox.com/)
|
||||
- A suite of open-source mapping tools that allows developers to add custom maps,
|
||||
search, and navigation into their applications.
|
||||
- [next-connect](https://github.com/hoangvvo/next-connect#readme)
|
||||
- A promise-based method routing and middleware layer for Next.js.
|
||||
For full setup details, use [Getting Started](docs/web/getting-started.md).
|
||||
This section is the shortest path to a working dev environment.
|
||||
|
||||
## How to run locally
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you can run this application locally, you will need to have the following installed
|
||||
on your machine:
|
||||
|
||||
- [Node.js](https://nodejs.org/en/)
|
||||
- [npm (version 8 or higher)](https://www.npmjs.com/get-npm)
|
||||
|
||||
You will also need to create a free account with the following services:
|
||||
|
||||
- [Cloudinary](https://cloudinary.com/users/register/free)
|
||||
- [SparkPost](https://www.sparkpost.com/)
|
||||
- [Neon Postgres](https://neon.tech/)
|
||||
- [Mapbox](https://account.mapbox.com/auth/signup/)
|
||||
|
||||
### Setup
|
||||
|
||||
1. Clone this repository and navigate to the project directory.
|
||||
### Full stack (Docker)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/aaronpo97/the-biergarten-app
|
||||
cd the-biergarten-app
|
||||
|
||||
cd web && ./generate-env.sh .env.dev && cd ..
|
||||
docker compose --env-file web/.env.dev -f web/docker-compose.dev.yaml up --build -d
|
||||
```
|
||||
|
||||
2. Run the following command to install the dependencies.
|
||||
`generate-env.sh` copies `.env.example` and replaces the secret-bearing values
|
||||
with freshly randomized ones; a plain `cp` leaves placeholder secrets in
|
||||
place. See [Environment Variables](docs/web/environment-variables.md#generating-an-env-file)
|
||||
for details.
|
||||
|
||||
Access:
|
||||
|
||||
- Website: http://localhost:3000
|
||||
- API Swagger: http://localhost:8080/swagger
|
||||
- Health Check: http://localhost:8080/health
|
||||
- Mailpit UI (dev SMTP): http://localhost:8025
|
||||
- SeaweedFS S3 API (dev object storage): http://localhost:8333
|
||||
|
||||
### Frontend (Node, outside Docker)
|
||||
|
||||
```bash
|
||||
cd web/frontend
|
||||
npm install
|
||||
API_BASE_URL=http://localhost:8080 SESSION_SECRET=dev-secret-change-me npm run dev
|
||||
```
|
||||
|
||||
3. Run the following script to create a `.env` file in the root directory of the project
|
||||
and add the following environment variables. Update these variables with your own
|
||||
values.
|
||||
Optional frontend tools:
|
||||
|
||||
```bash
|
||||
echo "BASE_URL=
|
||||
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=
|
||||
CLOUDINARY_KEY=
|
||||
CLOUDINARY_SECRET=
|
||||
CONFIRMATION_TOKEN_SECRET=
|
||||
RESET_PASSWORD_TOKEN_SECRET=
|
||||
SESSION_SECRET=
|
||||
SESSION_TOKEN_NAME=
|
||||
SESSION_MAX_AGE=
|
||||
NODE_ENV=
|
||||
|
||||
POSTGRES_PRISMA_URL=
|
||||
POSTGRES_URL_NON_POOLING=
|
||||
SHADOW_DATABASE_URL=
|
||||
|
||||
ADMIN_PASSWORD=
|
||||
|
||||
MAPBOX_ACCESS_TOKEN=
|
||||
|
||||
SPARKPOST_API_KEY=
|
||||
SPARKPOST_SENDER_ADDRESS=" > .env
|
||||
cd web/frontend
|
||||
npm run storybook
|
||||
npm run test:storybook
|
||||
npm run test:storybook:playwright
|
||||
```
|
||||
|
||||
### Explanation of environment variables
|
||||
## Repository structure
|
||||
|
||||
- `BASE_URL` is the base URL of the application.
|
||||
- For example, if you are running the application locally, you can set this to
|
||||
`http://localhost:3000`.
|
||||
- `NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_KEY`, and `CLOUDINARY_SECRET` are the
|
||||
credentials for your Cloudinary account.
|
||||
- You can create a free account [here](https://cloudinary.com/users/register/free).
|
||||
- `CONFIRMATION_TOKEN_SECRET` is the secret used to sign the confirmation token used for
|
||||
email confirmation.
|
||||
- You can generate a random string using the`openssl rand -base64 127` command.
|
||||
- `RESET_PASSWORD_TOKEN_SECRET` is the secret used to sign the reset password token.
|
||||
- You can generate a random string using the `openssl rand -base64 127` command.
|
||||
- `SESSION_SECRET` is the secret used to sign the session cookie.
|
||||
- Use the same command as above to generate a random string.
|
||||
- `SESSION_TOKEN_NAME` is the name of the session cookie.
|
||||
- You can set this to `biergarten`.
|
||||
- `SESSION_MAX_AGE` is the maximum age of the session cookie in seconds.
|
||||
- You can set this to `604800` (1 week).
|
||||
- `POSTGRES_PRISMA_URL`is a pooled connection string for your Neon Postgres database.
|
||||
- `POSTGRES_URL_NON_POOLING` is a non-pooled connection string for your Neon Postgres
|
||||
database used for migrations.
|
||||
- `SHADOW_DATABASE_URL` is a connection string for a secondary database used for
|
||||
migrations to detect schema drift.
|
||||
- You can create a free account [here](https://neon.tech).
|
||||
- Consult the [docs](https://neon.tech/docs/guides/prisma) for more information.
|
||||
- `MAPBOX_ACCESS_TOKEN` is the access token for your Mapbox account.
|
||||
- You can create a free account [here](https://account.mapbox.com/auth/signup/).
|
||||
- `NODE_ENV` is the environment in which the application is running.
|
||||
- You can set this to `development` or `production`.
|
||||
- `SPARKPOST_API_KEY` is the API key for your SparkPost account.
|
||||
- You can create a free account [here](https://www.sparkpost.com/).
|
||||
- `SPARKPOST_SENDER_ADDRESS` is the email address that will be used to send emails.
|
||||
- `ADMIN_PASSWORD` is the password for the admin account created when seeding the
|
||||
database.
|
||||
```text
|
||||
web/
|
||||
backend/ .NET API: API.Core (host), Features.* (vertical slices),
|
||||
Shared.*, Domain.*, Infrastructure.*, Database.* projects
|
||||
frontend/ React Router website + Storybook + Playwright/Vitest
|
||||
|
||||
1. Initialize the database and run the migrations.
|
||||
tooling/
|
||||
pipeline/ C++20 seed-data generation CLI (CMake)
|
||||
|
||||
docs/
|
||||
web/ Architecture, setup, docker, testing, diagrams
|
||||
pipeline/ Pipeline docs, ethics notes, diagrams
|
||||
|
||||
archive/
|
||||
next-js-web-app/ Older Next.js frontend (reference only)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Create a test environment file, then run the full test stack (backend and
|
||||
frontend) with Docker:
|
||||
|
||||
```bash
|
||||
npx prisma generate
|
||||
npx prisma migrate dev
|
||||
cd web && ./generate-env.sh .env.test && cd ..
|
||||
docker compose --env-file web/.env.test -f web/docker-compose.test.yaml up --abort-on-container-exit
|
||||
```
|
||||
|
||||
5. Seed the database with some initial data.
|
||||
The same command runs in CI via
|
||||
[`.github/workflows/tests.yml`](.github/workflows/tests.yml) on every push
|
||||
and pull request to `main`. See [Testing](docs/web/testing.md) for the
|
||||
full command list.
|
||||
|
||||
```bash
|
||||
npm run seed
|
||||
```
|
||||
## Configuration
|
||||
|
||||
6. Start the application.
|
||||
Common active variables:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
- Backend/Docker: `DB_SERVER`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`,
|
||||
`ACCESS_TOKEN_SECRET`, `REFRESH_TOKEN_SECRET`, `CONFIRMATION_TOKEN_SECRET`,
|
||||
`WEBSITE_BASE_URL`
|
||||
- Frontend runtime: `API_BASE_URL`, `SESSION_SECRET`, `NODE_ENV`
|
||||
|
||||
See [Environment Variables](docs/web/environment-variables.md) for details.
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
||||
4. Run the checks in [Testing](docs/web/testing.md) (backend tests,
|
||||
`npm run lint`, `npm run typecheck`)
|
||||
5. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
6. Open a Pull Request
|
||||
|
||||
## Support
|
||||
|
||||
Report bugs and request features via
|
||||
[GitHub Issues](https://github.com/aaronpo97/the-biergarten-app/issues).
|
||||
|
||||
## License
|
||||
|
||||
The Biergarten App is licensed under the GNU General Public License v3.0. This means that
|
||||
anyone is free to use, modify, and distribute the code as long as they also distribute
|
||||
their modifications under the same license.
|
||||
|
||||
I encourage anyone who uses this code for educational purposes to attribute me as the
|
||||
original author, and to provide a link to this repository.
|
||||
|
||||
By contributing to this repository, you agree to license your contributions under the same
|
||||
license as the project.
|
||||
|
||||
If you have any questions or concerns about the license, please feel free to submit an
|
||||
issue to this repository.
|
||||
|
||||
I hope that this project will be useful to other developers and beer enthusiasts who are
|
||||
interested in learning about web development with Next.js, Prisma, Postgres, and other
|
||||
technologies.
|
||||
GPL-3.0. See [LICENSE.md](LICENSE.md).
|
||||
|
||||
219
archive/next-js-web-app/README.old.md
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
# The Biergarten App
|
||||
|
||||
## About
|
||||
|
||||
The Biergarten App is a web application designed for beer lovers to share their favorite
|
||||
brews and breweries with like-minded people online.
|
||||
|
||||
This application's stack consists of Next.js, Prisma and Neon Postgres. I'm motivated to
|
||||
learn more about these technologies while exploring my passion for beer.
|
||||
|
||||
I've also incorporated different APIs into the application, such as the Cloudinary API for
|
||||
image uploading, the SparkPost API for email services as well as Mapbox for geolocation
|
||||
and map data.
|
||||
|
||||
To handle serverless functions (API routes), I use the next-connect package.
|
||||
|
||||
On the client-side, I use Tailwind CSS, Headless UI and Daisy UI for styling to create a
|
||||
visually appealing and user-friendly interface.
|
||||
|
||||
I'm sharing my code publicly so that others can learn from it and use it as a reference
|
||||
for their own projects.
|
||||
|
||||
### Some beer terminology
|
||||
|
||||
In this app you will encounter various beer related terms. Here is a list of terms used in
|
||||
this app and their definitions.
|
||||
|
||||
#### ABV
|
||||
|
||||
[Alcohol by volume](https://en.wikipedia.org/wiki/Alcohol_by_volume) (abbreviated as ABV)
|
||||
is a standard measure of how much alcohol (ethanol) is contained in a given volume of an
|
||||
alcoholic beverage (expressed as a volume percent).
|
||||
|
||||
#### IBU
|
||||
|
||||
The
|
||||
[International Bitterness Units](https://en.wikipedia.org/wiki/Beer_measurement#Bitterness)
|
||||
scale, or IBU, is used to approximately quantify the bitterness of beer. This scale is not
|
||||
measured on the perceived bitterness of the beer, but rather the amount of a component of
|
||||
beer known as iso-alpha acids.
|
||||
|
||||
## Database Schema
|
||||
|
||||

|
||||
|
||||
## Technologies
|
||||
|
||||
### General
|
||||
|
||||
- [Next.js](https://nextjs.org/)
|
||||
- A React based framework for building web applications offering several features such
|
||||
as server side rendering, static site generation and API routes.
|
||||
|
||||
### Client
|
||||
|
||||
- [SWR](https://swr.vercel.app/)
|
||||
- A React Hooks library for fetching data with support for caching, revalidation and
|
||||
error handling.
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
- A popular open-source utility-first CSS framework that provides pre-defined classes to
|
||||
style HTML elements.
|
||||
- [Headless UI](https://headlessui.dev/)
|
||||
- A set of completely unstyled, fully accessible UI components, designed to integrate
|
||||
beautifully with Tailwind CSS.
|
||||
- [Daisy UI](https://daisyui.com/)
|
||||
- A component library for Tailwind CSS that provides ready-to-use components for
|
||||
building user interfaces.
|
||||
|
||||
### Server
|
||||
|
||||
- [Prisma](https://www.prisma.io/)
|
||||
- An open-source ORM for Node.js and TypeScript applications.
|
||||
- [Neon Postgres](https://neon.tech/)
|
||||
- A managed PostgreSQL database service powered by Neon.
|
||||
- [Cloudinary](https://cloudinary.com/)
|
||||
- A cloud-based image and video management service that provides developers with an easy
|
||||
way to upload, store, and manipulate media assets.
|
||||
- [SparkPost](https://www.sparkpost.com/)
|
||||
- A cloud-based email delivery service that provides developers with an easy way to send
|
||||
transactional and marketing emails.
|
||||
- [Mapbox](https://www.mapbox.com/)
|
||||
- A suite of open-source mapping tools that allows developers to add custom maps,
|
||||
search, and navigation into their applications.
|
||||
- [next-connect](https://github.com/hoangvvo/next-connect#readme)
|
||||
- A promise-based method routing and middleware layer for Next.js.
|
||||
|
||||
## How to run locally
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you can run this application locally, you will need to have the following installed
|
||||
on your machine:
|
||||
|
||||
- [Node.js](https://nodejs.org/en/)
|
||||
- [npm (version 8 or higher)](https://www.npmjs.com/get-npm)
|
||||
|
||||
You will also need to create a free account with the following services:
|
||||
|
||||
- [Cloudinary](https://cloudinary.com/users/register/free)
|
||||
- [SparkPost](https://www.sparkpost.com/)
|
||||
- [Neon Postgres](https://neon.tech/)
|
||||
- [Mapbox](https://account.mapbox.com/auth/signup/)
|
||||
|
||||
### Setup
|
||||
|
||||
1. Clone this repository and navigate to the project directory.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/aaronpo97/the-biergarten-app
|
||||
cd the-biergarten-app
|
||||
```
|
||||
|
||||
2. Run the following command to install the dependencies.
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Run the following script to create a `.env` file in the root directory of the project
|
||||
and add the following environment variables. Update these variables with your own
|
||||
values.
|
||||
|
||||
```bash
|
||||
echo "BASE_URL=
|
||||
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=
|
||||
CLOUDINARY_KEY=
|
||||
CLOUDINARY_SECRET=
|
||||
CONFIRMATION_TOKEN_SECRET=
|
||||
RESET_PASSWORD_TOKEN_SECRET=
|
||||
SESSION_SECRET=
|
||||
SESSION_TOKEN_NAME=
|
||||
SESSION_MAX_AGE=
|
||||
NODE_ENV=
|
||||
|
||||
POSTGRES_PRISMA_URL=
|
||||
POSTGRES_URL_NON_POOLING=
|
||||
SHADOW_DATABASE_URL=
|
||||
|
||||
ADMIN_PASSWORD=
|
||||
|
||||
MAPBOX_ACCESS_TOKEN=
|
||||
|
||||
SPARKPOST_API_KEY=
|
||||
SPARKPOST_SENDER_ADDRESS=" > .env
|
||||
```
|
||||
|
||||
### Explanation of environment variables
|
||||
|
||||
- `BASE_URL` is the base URL of the application.
|
||||
- For example, if you are running the application locally, you can set this to
|
||||
`http://localhost:3000`.
|
||||
- `NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_KEY`, and `CLOUDINARY_SECRET` are the
|
||||
credentials for your Cloudinary account.
|
||||
- You can create a free account [here](https://cloudinary.com/users/register/free).
|
||||
- `CONFIRMATION_TOKEN_SECRET` is the secret used to sign the confirmation token used for
|
||||
email confirmation.
|
||||
- You can generate a random string using the`openssl rand -base64 127` command.
|
||||
- `RESET_PASSWORD_TOKEN_SECRET` is the secret used to sign the reset password token.
|
||||
- You can generate a random string using the `openssl rand -base64 127` command.
|
||||
- `SESSION_SECRET` is the secret used to sign the session cookie.
|
||||
- Use the same command as above to generate a random string.
|
||||
- `SESSION_TOKEN_NAME` is the name of the session cookie.
|
||||
- You can set this to `biergarten`.
|
||||
- `SESSION_MAX_AGE` is the maximum age of the session cookie in seconds.
|
||||
- You can set this to `604800` (1 week).
|
||||
- `POSTGRES_PRISMA_URL`is a pooled connection string for your Neon Postgres database.
|
||||
- `POSTGRES_URL_NON_POOLING` is a non-pooled connection string for your Neon Postgres
|
||||
database used for migrations.
|
||||
- `SHADOW_DATABASE_URL` is a connection string for a secondary database used for
|
||||
migrations to detect schema drift.
|
||||
- You can create a free account [here](https://neon.tech).
|
||||
- Consult the [docs](https://neon.tech/docs/guides/prisma) for more information.
|
||||
- `MAPBOX_ACCESS_TOKEN` is the access token for your Mapbox account.
|
||||
- You can create a free account [here](https://account.mapbox.com/auth/signup/).
|
||||
- `NODE_ENV` is the environment in which the application is running.
|
||||
- You can set this to `development` or `production`.
|
||||
- `SPARKPOST_API_KEY` is the API key for your SparkPost account.
|
||||
- You can create a free account [here](https://www.sparkpost.com/).
|
||||
- `SPARKPOST_SENDER_ADDRESS` is the email address that will be used to send emails.
|
||||
- `ADMIN_PASSWORD` is the password for the admin account created when seeding the
|
||||
database.
|
||||
|
||||
1. Initialize the database and run the migrations.
|
||||
|
||||
```bash
|
||||
npx prisma generate
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
5. Seed the database with some initial data.
|
||||
|
||||
```bash
|
||||
npm run seed
|
||||
```
|
||||
|
||||
6. Start the application.
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The Biergarten App is licensed under the GNU General Public License v3.0. This means that
|
||||
anyone is free to use, modify, and distribute the code as long as they also distribute
|
||||
their modifications under the same license.
|
||||
|
||||
I encourage anyone who uses this code for educational purposes to attribute me as the
|
||||
original author, and to provide a link to this repository.
|
||||
|
||||
By contributing to this repository, you agree to license your contributions under the same
|
||||
license as the project.
|
||||
|
||||
If you have any questions or concerns about the license, please feel free to submit an
|
||||
issue to this repository.
|
||||
|
||||
I hope that this project will be useful to other developers and beer enthusiasts who are
|
||||
interested in learning about web development with Next.js, Prisma, Postgres, and other
|
||||
technologies.
|
||||
10881
archive/next-js-web-app/package-lock.json
generated
vendored
Normal file
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 203 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 515 B After Width: | Height: | Size: 515 B |
|
Before Width: | Height: | Size: 961 B After Width: | Height: | Size: 961 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |