Skip to content

Commit d393fbc

Browse files
committed
first commit
0 parents  commit d393fbc

43 files changed

Lines changed: 5938 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.dockerignore‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.git
2+
.github
3+
.idea
4+
.dart_tool
5+
build
6+
.sisyphus
7+
*.iml

‎.github/workflows/docker-build.yml‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Docker Build
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- Dockerfile
7+
- docker/**
8+
- scripts/generate_recommendation.py
9+
- web/**
10+
- lib/**
11+
- pubspec.yaml
12+
- pubspec.lock
13+
- .github/workflows/docker-build.yml
14+
workflow_dispatch:
15+
16+
jobs:
17+
build:
18+
runs-on: ubuntu-latest
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Set up Docker Buildx
25+
uses: docker/setup-buildx-action@v3
26+
27+
- name: Build image
28+
uses: docker/build-push-action@v6
29+
with:
30+
context: .
31+
file: ./Dockerfile
32+
platforms: linux/amd64
33+
push: false
34+
load: false
35+
cache-from: type=gha
36+
cache-to: type=gha,mode=max
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Docker Publish
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
tags: ["v*"]
7+
workflow_dispatch:
8+
9+
env:
10+
REGISTRY: ghcr.io
11+
IMAGE_NAME: ${{ github.repository }}
12+
13+
jobs:
14+
build-and-push:
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
packages: write
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Set up QEMU
25+
uses: docker/setup-qemu-action@v3
26+
27+
- name: Set up Docker Buildx
28+
uses: docker/setup-buildx-action@v3
29+
30+
- name: Log in to GHCR
31+
uses: docker/login-action@v3
32+
with:
33+
registry: ${{ env.REGISTRY }}
34+
username: ${{ github.actor }}
35+
password: ${{ secrets.GITHUB_TOKEN }}
36+
37+
- name: Extract Docker metadata
38+
id: meta
39+
uses: docker/metadata-action@v5
40+
with:
41+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
42+
tags: |
43+
type=ref,event=branch
44+
type=ref,event=tag
45+
type=sha
46+
type=raw,value=latest,enable={{is_default_branch}}
47+
48+
- name: Build and push
49+
uses: docker/build-push-action@v6
50+
with:
51+
context: .
52+
file: ./Dockerfile
53+
platforms: linux/amd64,linux/arm64
54+
push: true
55+
tags: ${{ steps.meta.outputs.tags }}
56+
labels: ${{ steps.meta.outputs.labels }}

‎.gitignore‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.build/
9+
.buildlog/
10+
.history
11+
.svn/
12+
.swiftpm/
13+
migrate_working_dir/
14+
15+
# IntelliJ related
16+
*.iml
17+
*.ipr
18+
*.iws
19+
.idea/
20+
21+
# The .vscode folder contains launch configuration and tasks you configure in
22+
# VS Code which you may wish to be included in version control, so this line
23+
# is commented out by default.
24+
#.vscode/
25+
26+
# Flutter/Dart/Pub related
27+
**/doc/api/
28+
**/ios/Flutter/.last_build_id
29+
.dart_tool/
30+
.flutter-plugins-dependencies
31+
.pub-cache/
32+
.pub/
33+
/build/
34+
/coverage/
35+
36+
# Symbolication related
37+
app.*.symbols
38+
39+
# Obfuscation related
40+
app.*.map.json
41+
42+
# Android Studio will place build artifacts here
43+
/android/app/debug
44+
/android/app/profile
45+
/android/app/release
46+
47+
# Python/tooling
48+
__pycache__/
49+
*.pyo
50+
*.pyd
51+
.pytest_cache/
52+
53+
# Local environment/config
54+
.env
55+
.env.*
56+
docker-compose.yaml
57+
58+
# Project-local tooling
59+
.sisyphus/
60+
61+
# Generated localization files
62+
lib/l10n/app_localizations*.dart

‎Dockerfile‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
FROM ghcr.io/cirruslabs/flutter:stable AS builder
2+
3+
WORKDIR /app
4+
COPY pubspec.yaml pubspec.lock ./
5+
RUN flutter pub get
6+
7+
COPY . .
8+
RUN flutter build web --wasm --no-source-maps --no-web-resources-cdn --no-wasm-dry-run
9+
10+
FROM python:3.12-slim
11+
12+
ARG SUPERCRONIC_VERSION=v0.2.29
13+
ARG TARGETARCH
14+
ENV PYTHONDONTWRITEBYTECODE=1
15+
ENV PYTHONUNBUFFERED=1
16+
ENV WEB_PORT=8080
17+
ENV TZ=Asia/Shanghai
18+
19+
RUN apt-get update \
20+
&& apt-get install -y --no-install-recommends ca-certificates curl nginx \
21+
&& rm -rf /var/lib/apt/lists/*
22+
23+
RUN ARCH="${TARGETARCH}" \
24+
&& if [ -z "${ARCH}" ]; then ARCH="$(uname -m)"; fi \
25+
&& case "${ARCH}" in \
26+
amd64|x86_64) SC_ARCH=amd64 ;; \
27+
arm64|aarch64) SC_ARCH=arm64 ;; \
28+
*) echo "Unsupported architecture: ${ARCH}"; exit 1 ;; \
29+
esac \
30+
&& curl -fsSL "https://github.com/aptible/supercronic/releases/download/${SUPERCRONIC_VERSION}/supercronic-linux-${SC_ARCH}" -o /usr/local/bin/supercronic \
31+
&& chmod +x /usr/local/bin/supercronic
32+
33+
WORKDIR /app
34+
35+
COPY --from=builder /app/build/web /app/site
36+
COPY web/favicon.svg /app/site/favicon.svg
37+
COPY web/manifest.json /app/site/manifest.json
38+
COPY web/public/menu.md /app/defaults/menu.md
39+
COPY scripts/generate_recommendation.py /app/scripts/generate_recommendation.py
40+
COPY docker/entrypoint.sh /app/docker/entrypoint.sh
41+
42+
RUN chmod +x /app/docker/entrypoint.sh \
43+
&& rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf
44+
45+
EXPOSE 8080
46+
47+
ENTRYPOINT ["/app/docker/entrypoint.sh"]

‎README.md‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# UniqueDing Kitchen
2+
3+
Flutter Web ordering app with markdown-driven menu/recommendations.
4+
5+
## Key Directories
6+
7+
- `lib/`: app UI and runtime config loader
8+
- `web/public/`: editable markdown data source (`menu.md`, `recommend.md`)
9+
- `scripts/`: runtime/ops scripts used by the app lifecycle
10+
- `tools/branding/`: one-off branding/logo generation helpers
11+
- `docker/`: container entrypoint scripts
12+
- `deploy/`: deployment examples (`docker-compose.example.yaml`)
13+
- `.github/workflows/`: CI workflow for Docker publishing
14+
15+
## Common Commands
16+
17+
- Local verify: `flutter analyze && flutter test`
18+
- Build web: `flutter build web --wasm --no-source-maps --no-web-resources-cdn --no-wasm-dry-run`
19+
- Generate recommendation markdown: `python3 scripts/generate_recommendation.py`
20+
21+
## Script vs Tooling
22+
23+
- `scripts/generate_recommendation.py`: production-facing helper used by Docker startup/cron to refresh `recommend.md`
24+
- `tools/branding/generate_logo_candidates_v4.py`: one-off logo candidate generator, not used by runtime or deploy flow
25+
26+
`generate_recommendation.py` path behavior:
27+
28+
- `PUBLIC_DIR` controls base directory (supports relative path; default prefers `public`, then `web/public`)
29+
- output defaults to `${PUBLIC_DIR}/recommend.md`
30+
- can override output via `RECOMMEND_FILE`
31+
- script writes to a temporary file first, then atomically replaces target
32+
33+
`generate_recommendation.py` menu source behavior:
34+
35+
- `MENU_SOURCE=local` reads `${PUBLIC_DIR}/menu.md`
36+
- `MENU_SOURCE=trillium` fetches and parses `TRILLIUM_URL` (uses `TRILLIUM_TITLE`)
37+
- generated recommendation format is markdown table (`| 名称 | 描述 | 口味 | 小料 |`)
38+
39+
`generate_recommendation.py` OpenAI env behavior:
40+
41+
- URL supports `OPENAI_BASE_URL` / `OPENAI_URL` / `API_URL` / `BASE_URL`
42+
- API key supports `OPENAI_API_KEY` / `API_KEY`
43+
- model supports `OPENAI_MODEL` / `MODEL`
44+
- URL can be either base (for example `https://api.openai.com/v1`) or full endpoint (for example `https://api.openai.com/v1/chat/completions`)
45+
46+
## Docker Compose Example
47+
48+
Use `deploy/docker-compose.example.yaml` as a template:
49+
50+
`docker compose -f deploy/docker-compose.example.yaml up -d`
51+
52+
If you host behind a reverse proxy subpath (for example `/cook/`), set:
53+
54+
- `WEB_BASE_HREF=/cook/`
55+
56+
The value must start and end with `/`.
57+
58+
## Trillium Menu Source
59+
60+
Runtime config supports switching menu source via env vars:
61+
62+
- `MENU_SOURCE`: `local` (default) or `trillium`
63+
- `TRILLIUM_URL`: HTML article URL, for example `https://note.uniqueding.xyz/share/cooklist`
64+
- `TRILLIUM_TITLE`: article title marker used to locate the content section, for example `cooklist`
65+
66+
## Recommend Scheduler
67+
68+
- `RECOMMEND_CRON_SCHEDULE`: cron expression for daily recommendation generation, default `0 0 * * *`

‎agent.md‎

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# UniqueDingKitchen Agent Notes
2+
3+
## Project Scope
4+
5+
- Flutter Web ordering app.
6+
- Menu/recommendation are data-driven from markdown-like sources.
7+
- Recommendation can be generated by Python script with OpenAI-compatible API.
8+
9+
## Key Files
10+
11+
- App entry:
12+
- `lib/main.dart`
13+
- `lib/app.dart`
14+
- Main UI:
15+
- `lib/views/ordering_view.dart`
16+
- Data loading/parsing:
17+
- `lib/services/menu_repository.dart`
18+
- `lib/services/markdown_menu_parser.dart`
19+
- `lib/services/runtime_config.dart`
20+
- `lib/services/trillium_menu_parser.dart`
21+
- Script:
22+
- `scripts/generate_recommendation.py`
23+
- Tooling:
24+
- `tools/branding/generate_logo_candidates_v4.py`
25+
- Runtime/deploy:
26+
- `docker/entrypoint.sh`
27+
- `docker-compose.yaml`
28+
- `deploy/docker-compose.example.yaml`
29+
30+
## Runtime Config (from `public/runtime_config.json`)
31+
32+
- `site_name`
33+
- `MENU_SOURCE`: `local` or `trillium`
34+
- `TRILLIUM_URL`
35+
- `TRILLIUM_TITLE`
36+
37+
Lowercase compatibility keys still parsed:
38+
39+
- `menu_source`, `trillium_url`, `trillium_title`
40+
41+
## Menu Source Modes
42+
43+
- `MENU_SOURCE=local`
44+
- Read menu from local public markdown (`public/menu.md` path candidates).
45+
- `MENU_SOURCE=trillium`
46+
- Fetch HTML from `TRILLIUM_URL`
47+
- Extract article section by `TRILLIUM_TITLE`
48+
- Parse table rows -> convert to markdown table -> reuse parser.
49+
50+
## Markdown Parser
51+
52+
`lib/services/markdown_menu_parser.dart` supports both:
53+
54+
- List rows (`- 名称 | 描述 | 口味 | 小料`)
55+
- Table rows (`| 名称 | 描述 | 口味 | 小料 |`)
56+
57+
Mixed format in one category is supported.
58+
59+
## Localization Rule
60+
61+
- Any UI text change must keep the same semantic meaning across all supported locales.
62+
- When updating user-facing copy, update `app_zh.arb`, `app_en.arb`, `app_ja.arb`, `app_ko.arb`, and the generated localization Dart files in the same change.
63+
64+
## Recommendation Script
65+
66+
`scripts/generate_recommendation.py`:
67+
68+
- Inputs:
69+
- `OPENAI_BASE_URL` / `BASE_URL`
70+
- `OPENAI_API_KEY` / `API_KEY`
71+
- `OPENAI_MODEL` / `MODEL`
72+
- Path defaults:
73+
- base dir from `PUBLIC_DIR` (default `web/public`)
74+
- output from `RECOMMEND_FILE` or `${PUBLIC_DIR}/recommend.md`
75+
- Writes via temp file then atomic replace.
76+
77+
`tools/branding/generate_logo_candidates_v4.py`:
78+
79+
- Generates batch SVG logo candidates for design exploration.
80+
- Not used by app runtime, Docker startup, or deploy flow.
81+
82+
## Docker Env Highlights
83+
84+
- `SITE_NAME`
85+
- `OPENAI_BASE_URL`
86+
- `OPENAI_API_KEY`
87+
- `OPENAI_MODEL`
88+
- `MENU_SOURCE`
89+
- `TRILLIUM_URL`
90+
- `TRILLIUM_TITLE`
91+
- `RECOMMEND_CRON_SCHEDULE`
92+
93+
## Common Commands
94+
95+
- `flutter analyze`
96+
- `flutter test`
97+
- `flutter build web --wasm --no-source-maps --no-web-resources-cdn --no-wasm-dry-run`
98+
- `python3 scripts/generate_recommendation.py`
99+
100+
## Current UI Notes
101+
102+
- Bottom bar is floating and blurred.
103+
- Selected dishes popup and order summary list include category grouping headers.

0 commit comments

Comments
 (0)