2025-04-16-網站從零開始到能跑起來的明確逐步作法

2025-04-16-網站從零開始到能跑起來的明確逐步作法

從零開始到能跑起來的明確逐步作法 釐清成一個可跟做的清單(以 Windows 為主力開發機 / 使用 C# (ASP.NET Core) 為預設後端,並同時給你 Python(FastAPI) 的快速替代路徑備選)。每一步都包含必需的指令、檔案或範例內容,你照著做就能把整個「Vue 前端 + 後端 API + MySQL + AI proxy」MVP 拉起來並互通。

我把流程分成三大階段:準備環境 → 建立資料庫與後端 → 建立前端並整合 AI。每一步都有可直接貼上的指令或檔案範例。

一覽(高層)

  1. 設環境:Windows 安裝必要工具(Node、.NET、Docker、VS Code、Git)
  2. 建 MySQL(用 Docker)並建立資料表 seed 資料
  3. Scaffold 後端(C# ASP.NET Core)含 AI proxy endpoint 與 DB 連線(若你要 Python,我也附 FastAPI 快速替代)
  4. Scaffold 前端(Vue 3 + Vite),設定 proxy 呼叫後端
  5. 本機測試:啟動 DB → 後端 → 前端;測 AI endpoint,確認能拿到回應
  6. 下一步(選項):加入認證、部署到雲、監控、備份

詳細步驟(請在 Windows 主力機上操作;PowerShell 為例)

第 0 節:先決條件(如果你已經裝好可跳過)

  • Visual Studio 2022 或 .NET SDK(建議 .NET 7/8 LTS)
    下載並安裝 .NET SDK:https://dotnet.microsoft.com (或用 Visual Studio Installer)
  • Node.js (LTS) 已安裝(你已完成)
  • Docker Desktop 已安裝並啟用(啟用 WSL2 integration 建議)
  • VS Code 已安裝(推薦安裝 Volar、C#、Docker、ESLint 等擴充)
  • Git 已安裝,並設定 SSH key 加到 GitHub

1. 建專案目錄結構(在你想放的位置)

1
2
3
4
5
6
# 建專案資料夾
mkdir psych-site
cd psych-site

# 建 frontend / backend / infra 目錄
mkdir frontend backend infra

2. 用 Docker 在 Windows 建 MySQL(開發用)

psych-site/infradocker-compose.yml(可直接複製):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version: "3.8"
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: RootPwd123!
MYSQL_DATABASE: psychdb
MYSQL_USER: appuser
MYSQL_PASSWORD: AppUserPwd123!
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-pRootPwd123!"]
interval: 10s
retries: 5

phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
PMA_HOST: mysql
PMA_USER: root
PMA_PASSWORD: RootPwd123!
ports:
- "8080:80"
depends_on:
- mysql

volumes:
mysql_data:

啟動:

1
2
3
4
cd infra
docker compose up -d
docker ps
# 等 mysql 容器健康後,打開 http://localhost:8080 用 root/RootPwd123! 登入 phpMyAdmin(開發用)

注意:本機開發用密碼示範,實務請用更強密碼且不要放 repo。


3. 建資料表(用 SQL seed)

infra 下建立檔案 init_seed.sql(或用 phpMyAdmin 匯入):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
USE psychdb;

CREATE TABLE IF NOT EXISTS readings (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200),
category VARCHAR(80),
text TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS history (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NULL,
reading_id BIGINT NULL,
custom_text TEXT,
picked_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO readings (title, category, text) VALUES
('暖心小語','心情','今天給自己一個微笑,你比想像中堅強。'),
('職場提醒','工作','用小步快跑的方式完成大目標,別怕分段執行。'),
('情感共鳴','情感','說出你的感受,也許會帶來意外的理解。'),
('小挑戰','成長','嘗試 10 分鐘的新習慣,給自己驚喜。');

匯入方式:

1
2
3
# 直接用 docker exec 匯入
docker exec -i $(docker ps -q -f name=psych-site_infra_mysql) mysql -uroot -pRootPwd123! psychdb < init_seed.sql
# 若容器名稱不同,先 docker ps 找 mysql container id/name 再代入

(或用 phpMyAdmin 匯入 SQL)


4. 建後端:C# ASP.NET Core Web API(主要範例)

4.1 scaffold 專案

1
2
3
cd ..\backend
dotnet new webapi -n psych.backend
cd psych.backend

4.2 安裝必要套件(EF Core + MySQL provider)

1
2
3
dotnet add package Pomelo.EntityFrameworkCore.MySql --version 6.0.0
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet tool install --global dotnet-ef

4.3 修改 appsettings.Development.json(加入 DB 連線)

appsettings.Development.json 加入:

1
2
3
4
5
{
"ConnectionStrings": {
"DefaultConnection": "server=localhost;port=3306;database=psychdb;user=appuser;password=AppUserPwd123!"
}
}

4.4 建 DbContext 與 Model(簡短範例)

Models/Reading.cs:

1
2
3
4
5
6
7
public class Reading {
public long Id { get; set; }
public string Title { get; set; }
public string Category { get; set; }
public string Text { get; set; }
public DateTime CreatedAt { get; set; }
}

Data/AppDbContext.cs:

1
2
3
4
5
6
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext {
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}
public DbSet<Reading> Readings { get; set; }
public DbSet<HistoryItem> History { get; set; }
}

Program.cs 註冊:

1
2
3
4
5
6
7
8
9
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseMySql(builder.Configuration.GetConnectionString("DefaultConnection"),
ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("DefaultConnection"))));
builder.Services.AddControllers();
builder.Services.AddCors(options => options.AddDefaultPolicy(pb => pb.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
var app = builder.Build();
app.MapControllers();
app.Run();

4.5 建簡單 Controller(Readings & AI proxy)

Controllers/ReadingsController.cs(簡潔示範):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[ApiController]
[Route("api/[controller]")]
public class ReadingsController : ControllerBase {
private readonly AppDbContext _db;
public ReadingsController(AppDbContext db) { _db = db; }

[HttpGet]
public async Task<IActionResult> Get() => Ok(await _db.Readings.ToListAsync());

[HttpGet("random")]
public async Task<IActionResult> Random() {
var list = await _db.Readings.ToListAsync();
var item = list[new Random().Next(list.Count)];
return Ok(item);
}
}

Controllers/AiController.cs(AI proxy 範例,需在環境變數放 API KEY):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[ApiController]
[Route("api/ai")]
public class AiController : ControllerBase {
private readonly IHttpClientFactory _http;
private readonly IConfiguration _config;
public AiController(IHttpClientFactory http, IConfiguration config) { _http = http; _config = config; }

[HttpPost("read")]
public async Task<IActionResult> Read([FromBody] AiRequest req) {
// 基本敏感詞檢查(示範)
if (!string.IsNullOrEmpty(req.Prompt) && req.Prompt.Contains("自殺")) {
return BadRequest(new { error = "偵測到危險文字,請求助專業機構" });
}

var client = _http.CreateClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _config["AI_API_KEY"]);
var payload = new { model = "gpt-like", input = $"請用溫柔語氣回覆:{req.Prompt}", max_tokens = 200 };
var resp = await client.PostAsJsonAsync(_config["AI_API_URL"], payload);
if (!resp.IsSuccessStatusCode) return StatusCode(502, "AI provider error");
var j = await resp.Content.ReadFromJsonAsync<JsonElement>();
var text = j.GetProperty("choices")[0].GetProperty("text").GetString(); // 根據 provider 調整
return Ok(new { text = text.Trim() });
}
}

将你的 AI_API_KEY、AI_API_URL 放在 Windows environment variable 或 secrets。不要放到前端。

4.6 建 DB migration 並執行

1
2
dotnet ef migrations add InitialCreate
dotnet ef database update

4.7 執行後端

1
2
dotnet run
# ASP.NET Core 會在 https://localhost:5001 或 http://localhost:5000

5. 建後端:Python FastAPI(如果你未來想用 Python 快速試 AI)

快速 scaffold(備選):

1
2
3
4
cd ..\backend
python -m venv venv
venv\Scripts\activate
pip install fastapi uvicorn sqlalchemy pymysql httpx python-dotenv

main.py 提供 /api/ai/read/api/readings;使用 httpx 呼叫 AI provider;DB 用 SQLAlchemy 連 mysql+pymysql://appuser:AppUserPwd123!@localhost:3306/psychdb


6. 建前端:Vue 3 + Vite(在 frontend

1
2
3
cd ..\frontend
npm create vite@latest . -- --template vue
npm install

vite.config.js 加 proxy,讓開發時呼叫 /api 轉到後端(以 C# 為例):

1
2
3
4
5
6
7
8
9
10
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
'/api': 'http://localhost:5000' // 或 http://localhost:5000 若後端在 5000
}
}
})

把之前提供給你的 App.vue(純前端版本)貼到 src/App.vue,但將 getReading() 改為呼叫後端 AI 或 readings:

  • 呼叫本地 /api/readings/api/ai/read(視你要哪個)

示例呼叫 AI(前端):

1
2
3
4
5
6
const res = await fetch('/api/ai/read', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: promptText })
});
const json = await res.json();

啟動前端:

1
2
npm run dev
# 打開 http://localhost:5173

7. 本機測試順序(非常重要)

  1. docker compose up -d (infra/mysql) → 等 mysql ready
  2. 在 backend 專案執行 dotnet run(或 uvicorn main:app --reload for FastAPI)
  3. 在 frontend 執行 npm run dev
  4. 用瀏覽器開 http://localhost:5173 測 UI;或直接呼叫 http://localhost:5000/api/readings 測後端

8. AI Key 與安全(必做)

  • 在 Windows 設環境變數(PowerShell):
1
2
3
setx AI_API_KEY "你的_api_key"
setx AI_API_URL "https://api.yourprovider/v1/generate"
# 重新啟動 shell 讓 env 生效
  • 後端只讀 env 的值,不寫在程式碼中。
  • 加速測試可先用 mock 回應,再接真實 provider。
  • 在後端實作「簡易敏感詞過濾」及速率限制(ASP.NET 可用 middleware 或套件)。

9. Dockerize 後端(快速 build & run)

backend/psych.backendDockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet","psych.backend.dll"]

建 image & run(示例):

1
2
docker build -t psych-backend:latest .
docker run -d -p 5000:80 --name psych-backend --env AI_API_KEY=... psych-backend:latest

10. 後續建議(短期 & 長期)

短期(先做 MVP):

  • 完成前端抽小語 / 新增小語 / 歷史儲存(DB)
  • 做 AI proxy endpoint 並測試(把 prompt 邏輯寫在後端)
  • 加速限制與簡易 moderation

長期(上線):

  • 把 DB 移到雲端 Managed DB(RDS / Azure Database)
  • 實作 JWT 認證、使用者系統
  • 加監控(Application Insights / Prometheus)與 log(Serilog)
  • 部署:Docker Compose / Kubernetes 或雲端 PaaS(Azure App Service / DigitalOcean App)

最後 — 我為你準備的「立即可複製」清單(三個立即任務)

  1. psych-site/infradocker-compose.yml(上面內容)並執行:
    docker compose up -d
  2. psych-site/backend scaffold C#(上面 dotnet 指令),把 appsettings.Development.json 的連線字串改成你 docker 的設定,執行 dotnet ef database update
  3. psych-site/frontend scaffold Vite、貼上 App.vue(或我之前給的完整前端程式),在 vite.config.js 設 proxy,然後 npm run dev 開前端。

你要我現在幫你做哪一件 我就直接把對應完整檔案內容貼給你(不用再問):
A. 把 backend 的 C# 專案 完整檔案(Program.cs、AppDbContext.cs、Model、Controllers、Dockerfile) 一次貼給你複製貼上;
B. 或把 FastAPI 版本的 backend 完整檔案一次貼給你;
C. 或把 前端 App.vue + vite.config.js(已優化可呼叫後端 AI)一次貼給你。

選 A、B 或 C,我立刻把那個部分的完整可運行檔案貼出來。