Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions .agents/skills/commit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
name: commit
description: 提交並推送程式碼變更。用於每個開發階段完成後,將成果儲存到 Git 並推送到 GitHub。
---

# Commit Skill — 提交與推送程式碼

這個 skill 會引導 AI agent 幫你完成 Git 提交與推送,並在必要時設定 Git 身份識別資訊。

## When to use this skill

- 完成某個開發階段後,想要儲存進度
- 要把程式碼推送到 GitHub,讓組員可以取得最新版本
- 遇到 Git 要求設定 `user.name` 或 `user.email` 的提示

## 檢查 .gitignore
在推送之前檢查 .gitignore,確保虛擬環境、環境設定與非必要檔案有正確被排除在版本控制之外。

## ⚠️ 設定 Git 使用者身份

如果 Git 顯示以下提示,需要先設定身份才能 commit:

```
Author identity unknown

*** Please tell me who you are.

Run

git config --global user.email "you@example.com"
git config --global user.name "Your Name"
```

請使用 `antigravity` 作為 username 與 email:

```bash
git config --global user.name "antigravity"
git config --global user.email "antigravity"
```

> 這樣設定後,之後所有 commit 都不需要再重新設定。

## How to use it

### 基本用法:提交並推送

```
請幫我將目前的變更提交並推送到 GitHub。

commit 訊息:[描述這次做了什麼,例如:docs: add PRD]
```

AI 會執行以下步驟:
1. 確認 Git 使用者身份是否已設定(若無則設定為 `antigravity`)
2. `git add .` — 加入所有變更
3. `git commit -m "[你的訊息]"` — 建立 commit
4. `git push` — 推送到 GitHub

---

### 完整提示語(可直接複製使用)

```
請幫我提交並推送目前的變更:

1. 如果尚未設定 Git 身份,請先執行:
git config --global user.name "antigravity"
git config --global user.email "antigravity"

2. 然後執行:
git add .
git commit -m "[在此填入 commit 訊息]"
git push

完成後告訴我推送成功,並顯示 commit 的 hash 值。
```

---

## Commit 訊息格式建議

遵循以下格式,讓歷史紀錄更清楚:

| 類型 | 使用時機 | 範例 |
| ------ | --------------------- | ---------------------------- |
| `docs` | 新增或修改文件 | `docs: add PRD` |
| `feat` | 新增功能 | `feat: add task create form` |
| `fix` | 修復錯誤 | `fix: form validation error` |
| `chore`| 設定、初始化等雜項 | `chore: init project` |

---

## 各開發階段建議的 commit 訊息

| 階段 | 建議 commit 訊息 |
| ---------- | ----------------------------------------- |
| 階段一完成 | `docs: add PRD` |
| 階段二完成 | `docs: add system architecture` |
| 階段三完成 | `docs: add user flowchart` |
| 階段四完成 | `feat: add database schema and models` |
| 階段五完成 | `feat: add route skeleton and template plan` |
| 階段六完成 | `feat: implement [功能名稱]` |

---

## 常見問題

**Q: push 時要求輸入帳號密碼?**

GitHub 已停止支援密碼驗證,請使用 Personal Access Token(PAT):
1. 到 GitHub → Settings → Developer settings → Personal access tokens
2. 產生一個新 token(勾選 `repo` 權限)
3. push 時,「密碼」欄位貼上 token 即可

**Q: push 被拒絕(rejected)?**

可能是遠端有別的組員更新過,先執行:
```bash
git pull --rebase
git push
```

**Q: 不小心 commit 了不該 commit 的檔案?**

告訴 AI:「我剛才不小心 commit 了 [檔案名稱],請幫我移除。」
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FLASK_APP=run.py
FLASK_DEBUG=1
SECRET_KEY=your_secret_key_here
Binary file added .gitignore
Binary file not shown.
Binary file added __pycache__/run.cpython-314.pyc
Binary file not shown.
27 changes: 27 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from flask import Flask
from dotenv import load_dotenv
import os

load_dotenv()

def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev_default_secret')

# 確保 instance 資料夾存在,以供 SQLite 使用
os.makedirs(app.instance_path, exist_ok=True)

# 註冊 Blueprints
from app.routes.auth import auth_bp
from app.routes.divination import divination_bp
from app.routes.donation import donation_bp

app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(divination_bp) # uses / and /divination
app.register_blueprint(donation_bp, url_prefix='/donation')

return app

def init_db():
from app.models.database import init_db as db_init
db_init()
Binary file added app/__pycache__/__init__.cpython-314.pyc
Binary file not shown.
Binary file added app/models/__pycache__/database.cpython-314.pyc
Binary file not shown.
Binary file added app/models/__pycache__/divination.cpython-314.pyc
Binary file not shown.
Binary file added app/models/__pycache__/donation.cpython-314.pyc
Binary file not shown.
Binary file added app/models/__pycache__/ingredient.cpython-314.pyc
Binary file not shown.
Binary file added app/models/__pycache__/recipe.cpython-314.pyc
Binary file not shown.
Binary file added app/models/__pycache__/user.cpython-314.pyc
Binary file not shown.
34 changes: 34 additions & 0 deletions app/models/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import sqlite3
import os

DB_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../../instance/database.db')

def get_db_connection():
"""
建立並回傳一個與 SQLite 資料庫的連線。
預設啟用 row_factory 為 sqlite3.Row,以利透過字典鍵值存取資料。
"""
try:
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
conn.execute('PRAGMA foreign_keys = ON')
return conn
except Exception as e:
print(f"Database connection error: {e}")
raise

def init_db():
"""
初始化資料庫。讀取 schema.sql 並執行建表語句。
"""
try:
conn = get_db_connection()
schema_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../../database/schema.sql')
if os.path.exists(schema_path):
with open(schema_path, 'r', encoding='utf-8') as f:
conn.executescript(f.read())
conn.commit()
conn.close()
except Exception as e:
print(f"Database initialization error: {e}")
59 changes: 59 additions & 0 deletions app/models/divination.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from .database import get_db_connection

class Divination:
@staticmethod
def create(user_id, div_type, question, result, explanation):
"""
新增一筆占卜紀錄
"""
try:
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'INSERT INTO divinations (user_id, type, question, result, explanation) VALUES (?, ?, ?, ?, ?)',
(user_id, div_type, question, result, explanation)
)
conn.commit()
div_id = cursor.lastrowid
conn.close()
return div_id
except Exception as e:
print(f"Error creating divination: {e}")
return None

@staticmethod
def get_by_id(div_id):
"""取得單一紀錄"""
try:
conn = get_db_connection()
div = conn.execute('SELECT * FROM divinations WHERE id = ?', (div_id,)).fetchone()
conn.close()
return dict(div) if div else None
except Exception as e:
print(f"Error getting divination: {e}")
return None

@staticmethod
def get_by_user_id(user_id):
"""取得某會員的所有占卜紀錄"""
try:
conn = get_db_connection()
divs = conn.execute('SELECT * FROM divinations WHERE user_id = ? ORDER BY created_at DESC', (user_id,)).fetchall()
conn.close()
return [dict(d) for d in divs]
except Exception as e:
print(f"Error getting divinations for user: {e}")
return []

@staticmethod
def delete(div_id):
"""刪除占卜紀錄"""
try:
conn = get_db_connection()
conn.execute('DELETE FROM divinations WHERE id = ?', (div_id,))
conn.commit()
conn.close()
return True
except Exception as e:
print(f"Error deleting divination: {e}")
return False
34 changes: 34 additions & 0 deletions app/models/donation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from .database import get_db_connection

class Donation:
@staticmethod
def create(user_id, amount, status='completed'):
"""
新增一筆隨喜捐款紀錄
"""
try:
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'INSERT INTO donations (user_id, amount, status) VALUES (?, ?, ?)',
(user_id, amount, status)
)
conn.commit()
don_id = cursor.lastrowid
conn.close()
return don_id
except Exception as e:
print(f"Error creating donation: {e}")
return None

@staticmethod
def get_by_user_id(user_id):
"""取得某會員的歷史隨喜紀錄"""
try:
conn = get_db_connection()
dons = conn.execute('SELECT * FROM donations WHERE user_id = ? ORDER BY created_at DESC', (user_id,)).fetchall()
conn.close()
return [dict(d) for d in dons]
except Exception as e:
print(f"Error getting donations for user: {e}")
return []
106 changes: 106 additions & 0 deletions app/models/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from .database import get_db_connection

class User:
@staticmethod
def create(username, password_hash, is_admin=0):
"""
新增一筆使用者記錄。
回傳新建使用者的 id,發生例外時回傳 None。
"""
try:
conn = get_db_connection()
cursor = conn.cursor()
cursor.execute(
'INSERT INTO users (username, password_hash, is_admin) VALUES (?, ?, ?)',
(username, password_hash, is_admin)
)
conn.commit()
user_id = cursor.lastrowid
conn.close()
return user_id
except Exception as e:
print(f"Error creating user: {e}")
return None

@staticmethod
def get_by_id(user_id):
"""
根據 id 取得單筆使用者記錄。
"""
try:
conn = get_db_connection()
user = conn.execute('SELECT * FROM users WHERE id = ?', (user_id,)).fetchone()
conn.close()
return dict(user) if user else None
except Exception as e:
print(f"Error getting user by id: {e}")
return None

@staticmethod
def get_by_username(username):
"""
根據 username 取得單筆使用者記錄。
"""
try:
conn = get_db_connection()
user = conn.execute('SELECT * FROM users WHERE username = ?', (username,)).fetchone()
conn.close()
return dict(user) if user else None
except Exception as e:
print(f"Error getting user by username: {e}")
return None

@staticmethod
def get_all():
"""
取得所有使用者記錄。
"""
try:
conn = get_db_connection()
users = conn.execute('SELECT * FROM users').fetchall()
conn.close()
return [dict(u) for u in users]
except Exception as e:
print(f"Error getting all users: {e}")
return []

@staticmethod
def update(user_id, password_hash=None, is_admin=None):
"""
更新指定的 user 記錄。
只更新傳入且非 None 的參數。
"""
try:
conn = get_db_connection()
user = User.get_by_id(user_id)
if not user:
return False

new_password = password_hash if password_hash is not None else user['password_hash']
new_is_admin = is_admin if is_admin is not None else user['is_admin']

conn.execute(
'UPDATE users SET password_hash = ?, is_admin = ? WHERE id = ?',
(new_password, new_is_admin, user_id)
)
conn.commit()
conn.close()
return True
except Exception as e:
print(f"Error updating user: {e}")
return False

@staticmethod
def delete(user_id):
"""
刪除指定使用者記錄。
"""
try:
conn = get_db_connection()
conn.execute('DELETE FROM users WHERE id = ?', (user_id,))
conn.commit()
conn.close()
return True
except Exception as e:
print(f"Error deleting user: {e}")
return False
1 change: 1 addition & 0 deletions app/routes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Initialize routes package
Binary file added app/routes/__pycache__/__init__.cpython-314.pyc
Binary file not shown.
Binary file added app/routes/__pycache__/admin.cpython-314.pyc
Binary file not shown.
Binary file added app/routes/__pycache__/auth.cpython-314.pyc
Binary file not shown.
Binary file added app/routes/__pycache__/divination.cpython-314.pyc
Binary file not shown.
Binary file added app/routes/__pycache__/donation.cpython-314.pyc
Binary file not shown.
Binary file added app/routes/__pycache__/recipe.cpython-314.pyc
Binary file not shown.
Loading