---
# System prepended metadata

title: Dev-in.tw 架構規劃
tags: [ArchPlan]

---

---
title: Dev-in.tw 架構規劃
description: Dev-in.tw是一個由HACO和OnCloud聯合構思的專案，打造一個給予台灣得開法者建立個人子網域的平台，提供 A、AAAA、CNAME、URI......等功能。
tag: Website
lang: zh-TW
---

![logo](https://www.lazco.dev/images/logo-long.png)

# Dev-in.tw 網域網站架構規劃

---

## 介紹
**Dev-in.tw是一個由HACO和OnCloud聯合構思的專案，
打造一個給予台灣的開發者建立個人子網域的平台，
提供 A、AAAA、CNAME、URI......等功能。**

---

## 發起人
**<a href="http://discord.com/users/508964901415550976" target="_blank">haco.tw</a>
<a href="http://discord.com/users/755269122597585018" target="_blank">OnCloud</a>**

---

## 聯絡方式

* 使用Discord私訊 [HACO#8888](http://discord.com/users/508964901415550976)
* 加入 [Discord](https://discord.gg/ZvwTZqXjYf) 在聊天之地提出問題
* Instagram搜尋 <a href="https://instagram.com/lazco.dev" target="_blank">lazco.dev</a> 並私訊我們
* 使用電子郵件寄送至 <a href="mailto:lazco.team@gmail.com" target="_blank">lazco.team@gmail.com</a>

<br />

聯絡時請遵守以下規則
* [No Hello](https://www.nohello.com/)
* [正確的提出技術問題](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)

---

## 網站架構

```
SubdomainName => 子網域名稱如 lazco
SubdomainID => 子網域申請後會自動生成的一組ID
```

#### 前端 - 客戶

`GET /` - 首頁

`GET /account` - 查看帳戶

`GET /account/edit` - 編輯帳戶

`GET /login` - 登入帳戶

`GET /logout` - 登出帳戶

`GET /account/verify` - 驗證帳戶

`GET /find?sub={SubdomainName}` - 子網域存在查詢

`GET /domain` - 管理子網域

`GET /domain/register` - 註冊子網域

`GET /domain/edit/{SubdomainID}` - 編輯子網域

<br />

#### 前端 - 管理

`GET /lazco/account` - 管理所有帳戶

`GET /lazco/account/{accountID}` - 管理單一帳戶

`GET /lazco/account/{accountID}/edit` - 編輯帳戶

`GET /lazco/account/{accountID}/verify` - 審查帳戶驗證

`GET /lazco/domain/` - 管理所有子網域

`GET /lazco/domain/verify` - 子網域申請審查列表

`GET /lazco/domain/verify/{SubdomainID}` - 審查單一子網域申請

`GET /lazco/domain/{SubdomainID}` - 管理單一子網域

`GET /lazco/domain/{SubdomainID}/edit` - 編輯子網域

<br />

#### 後端

##### Tech / Framework

- Language: TypeScript
- Schema validation: Zod
- Framework: NestJS
- Database: MongoDB

##### Database schema

**1. Domain**

```json
{
    _id: String, // 此欄位為DB自動生成之欄位, will be used as domain id.
    cloudflare_id: String, // POST到CF後所生成的id，預設 0
    name: String, // 子網域名稱 如：lazco
    description: String, // 子網域介紹
    owner: String, // 使用者採用id制抓id獲取資料
    verify: Boolean, // true 即代表申請通過，預設為 false
    status: String, //
    apply_time: Date, // 申請送出的timestamp
    last_update: Date, // 最後變更的timestamp，預設同apply_time
    expire_time: Date, // 到期timestamp，申請通過當下後一年
    ssl: String, // Will only be one of ["off", "flexible", "full", "strict"]
    premium: Boolean, // 是否否為精選子網域
    exclusive: Boolean, // 使否為特殊子網域
    disable: Boolean, // 是被管理員停用
}
```

**2. User**
```json
{
    _id: String, // 此欄位為DB自動生成之欄位, will be used as user id.
    githubId: String, // User's Github ID
    email: String, // User's email
    name: String, // User's display name.
    first_name: String, // 申請網域時身份驗證用
    last_name: String, // 申請網域時身份驗證用
    birth: Date, // 申請網域時身份驗證用
    identy_id: String, // 申請網域時身份驗證用
    address: String, // 申請網域時身份驗證用
    phone: String, // 申請網域時身份驗證用
    avatar: String, // Base64 encoded image.
    description: String, // User's description.
    domain_names: [String], // e.g. lazco, haco, oncloud.
    badage: [String], // Just for future. e.g. Premium badage, Domain badage.
    beta: Boolean, // Just for future. Get beta program.
    warn: Number, // Admin warning time.
    disable: Boolean, // Banned
    premium: Boolean, // Yup, VIP mode.
    ip: [String], // 記錄使用者 IP
    create_time: Date, // Account created time.
    last_update: Date, // Account last edit time.
}
```

Rate limit:
- `/search` 50reqs / 10min

<br />

##### Github

透過以下網址帶入`code`獲得Github `access_token`
https://github.com/login/oauth/access_token

<br />

以下兩個網址皆需帶入 Bearer `access_token`
https://api.github.com/user
https://api.github.com/user/emails

<br />

如果使用者有很多個email
就挑選primary = true
我們也需要GitHub ID
因為使用者有可能會改primary mail
因此每次登入都要抓取

<br />

範例程式碼 1 `code get acces_token from github`
```ts=
// GITHUB CLIENT ID 和 SECRET 請洽 HACO
const github_response = await fetch(
  "https://github.com/login/oauth/access_token",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    body: JSON.stringify({
      client_id: process.env.GITHUB_CLIENT_ID,
      client_secret: process.env.GITHUB_CLIENT_SECRET,
      scope: "user:email",
      code,
    }),
  }
);
const { access_token } = await github_response.json();
```

<br />

範例程式碼 2 `acces_token get user info from github`
```ts=
const github_user_response = 
    await fetch("https://api.github.com/user", {
        headers: {
            Authorization: `Bearer ${access_token}`,
        },
    });
const userData = await github_user_response.json();
```

<br />

範例程式碼 3 `acces_token get user email from github`
```ts=
const github_user_response = 
    await fetch("https://api.github.com/user", {
        headers: {
            Authorization: `Bearer ${access_token}`,
        },
    });
const userData = await github_user_response.json();
```

<br />

##### 路由

**Main**
`ANY` `/`
```json
200
{
  message: "Welcome to Dev-in.tw backend API"
}
```
`ANY` `/*`
```json
404
{
  message: "Welcome to Dev-in.tw backend API"
}
```

<br />

**Authentication**
`POST` `/auth/github`
> Pass in Github authentication code, return user's Bearer for dev-in.tw.
> Create new user if necessary.
> Please refer to [API Document](https://dev-in-tw-api-dev.zeabur.app/docs#/default/GithubController_getGitHubAccountData).

<br />

**User**
`GET` `/user` List all user, required bearer from lazco team member
`PATCH` `/user/${userId}` Update user, required bearer from lazco team member
`DELETE` `/user/${userId}` DELETE user, required bearer  from lazco member
`GET` `/user/info` Required Bearer to get user info
`PATCH` `/user/info` Required Bearer to update user info
`GET` `/user/info/${userId}` Get user public info 

<br />

**Domain**
`GET` `/domain/find/${SubdomainName}` Search the subdomain.
`POST` `/domain/register/${SubdomainName}` Register subdomain. Required user Bearer


<br />

dev-in.tw
www.dev-in.tw
api.dev-in.tw

{%hackmd @lazco/dracula %}