Altsis ํ๊ต ์ ๋ณด ์์คํ ์ ๋ฐฑ์๋ API ์ค๊ณ ์์น๊ณผ ๊ณตํต ์ฌํญ์ ์ค๋ช ํฉ๋๋ค.
Altsis API๋ REST ์ํคํ ์ฒ ์คํ์ผ์ ๋ฐ๋ฅด๋ฉฐ, ๋ค์ ์์น์ ์ค์ํฉ๋๋ค:
- ๋ฆฌ์์ค ์ค์ฌ URL: URL์ ๋ฆฌ์์ค(๋ช ์ฌ)๋ฅผ ๋ํ๋ด๋ฉฐ, HTTP ๋ฉ์๋๋ก ํ์๋ฅผ ํํํฉ๋๋ค.
- ํ์ค HTTP ๋ฉ์๋:
GET(์กฐํ),POST(์์ฑ),PUT(์์ ),DELETE(์ญ์ )๋ฅผ ์ฌ์ฉํฉ๋๋ค. - ์ผ๊ด๋ ์๋ต ํ์: ๋ชจ๋ ์๋ต์ JSON ํ์์ ๋๋ค.
- ์ํ ์ฝ๋ ํ์ฉ: HTTP ์ํ ์ฝ๋๋ก ์์ฒญ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋ ๋๋ค.
/api/{๋ฆฌ์์ค๋ช
}
/api/{๋ฆฌ์์ค๋ช
}/{๋ฆฌ์์คID}
/api/{๋ฆฌ์์ค๋ช
}/{๋ฆฌ์์คID}/{ํ์๋ฆฌ์์ค ๋๋ ์ก์
}
| ๋ฆฌ์์ค ๊ฒฝ๋ก | ์ค๋ช |
|---|---|
/api/academies |
์์นด๋ฐ๋ฏธ ๊ด๋ฆฌ |
/api/users |
์ฌ์ฉ์ ๊ด๋ฆฌ |
/api/schools |
ํ๊ต ๊ด๋ฆฌ |
/api/seasons |
ํ๊ธฐ ๊ด๋ฆฌ |
/api/registrations |
ํ๊ธฐ ๋ฑ๋ก |
/api/syllabuses |
๊ฐ์๊ณํ์ |
/api/enrollments |
์๊ฐ ๊ด๋ฆฌ |
/api/boards |
๋ณด๋ (Alt Board) |
/api/posts |
๊ฒ์๊ธ |
/api/comments |
๋๊ธ |
/api/notifications |
์๋ฆผ |
/api/reminders |
๋ฆฌ๋ง์ธ๋ โ reminders.md |
/api/goals |
๋ชฉํ/์งํ ์์ฝ โ goals.md |
/api/calendar-events |
์บ๋ฆฐ๋ ์ผ์ |
/api/user-calendars |
์ฌ์ฉ์ ์บ๋ฆฐ๋ |
/api/chats |
์ฑํ (DM, ๊ทธ๋ฃน, ๋ณด๋์ฑํ ) |
/api/forms |
์์ |
/api/archives |
๊ธฐ๋ก |
/api/files |
ํ์ผ ์ ๋ก๋/๋ค์ด๋ก๋ |
/api/ai |
AI / Alter โ ai.md |
/api/theme-settings |
ํ ๋ง ์ค์ โ theme-settings.md |
/api/memos |
๋ฑ๋ก ์๊ฐํ ๋ฉ๋ชจ โ calendar.md |
/api/alt-forms |
Alt Form (์์ ๋น๋) |
/api/alt-sheet-rows |
Alt Sheet Row (์ํธ ํ ๋ฐ์ดํฐ) |
/api/board-favorites |
๋ณด๋ ์ฆ๊ฒจ์ฐพ๊ธฐ |
/api/survey-responses |
์ค๋ฌธ ์๋ต |
Altsis API๋ **์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ(์ฟ ํค)**์ ์ฌ์ฉํฉ๋๋ค. Passport.js๋ฅผ ํตํด ์ธ์ฆ์ด ์ฒ๋ฆฌ๋๋ฉฐ, ์ธ์ ์ ๋ณด๋ Redis์ ์ ์ฅ๋ฉ๋๋ค.
1. ํด๋ผ์ด์ธํธ --> POST /api/users/login/local (์์นด๋ฐ๋ฏธID, ์ฌ์ฉ์ID, ๋น๋ฐ๋ฒํธ)
2. ์๋ฒ: ์ฌ์ฉ์ ๊ฒ์ฆ --> ์ธ์
์์ฑ --> ์ธ์
์ฟ ํค ๋ฐ๊ธ
3. ํด๋ผ์ด์ธํธ: ์ดํ ๋ชจ๋ ์์ฒญ์ ์ฟ ํค ์๋ ํฌํจ
4. ์๋ฒ: ๋ฏธ๋ค์จ์ด์์ ์ธ์
์ฟ ํค ๊ฒ์ฆ
POST /api/users/login/local
Content-Type: application/json
{
"academyId": "my-academy",
"userId": "user01",
"password": "mypassword"
}์๋ต (200):
{
"user": {
"_id": "507f1f77bcf86cd799439011",
"userId": "user01",
"userName": "ํ๊ธธ๋",
"auth": "member",
"academyId": "my-academy",
"academyName": "ํ
์คํธ ์์นด๋ฐ๋ฏธ",
"schools": [
{
"school": "507f1f77bcf86cd799439012",
"schoolId": "school01",
"schoolName": "ํ
์คํธ ํ๊ต"
}
]
}
}๋ชจ๋ API ์๋ํฌ์ธํธ๋ ์ธ์ฆ ๋ฏธ๋ค์จ์ด๋ฅผ ํตํด ์ ๊ทผ ๊ถํ์ ์ ์ดํฉ๋๋ค.
| ๋ฏธ๋ค์จ์ด | ์๊ตฌ ๊ถํ | ์ค๋ช |
|---|---|---|
isLoggedIn |
๋ก๊ทธ์ธ๋ ์ฌ์ฉ์ | ์ธ์ฆ ์ฌ๋ถ๋ง ํ์ธ |
isOwner |
owner |
์ต๊ณ ๊ด๋ฆฌ์๋ง ์ ๊ทผ ๊ฐ๋ฅ |
isAdmin |
admin |
์์นด๋ฐ๋ฏธ ๊ด๋ฆฌ์๋ง ์ ๊ทผ ๊ฐ๋ฅ |
isOwAdmin |
owner ๋๋ admin |
์ต๊ณ ๊ด๋ฆฌ์ ๋๋ ์์นด๋ฐ๋ฏธ ๊ด๋ฆฌ์ |
isAdManager |
admin ๋๋ manager |
๊ด๋ฆฌ์ ๋๋ ์ด์์ |
isOwAdManager |
owner, admin ๋๋ manager |
์ต๊ณ ๊ด๋ฆฌ์, ๊ด๋ฆฌ์ ๋๋ ์ด์์ |
forceNotLoggedIn |
๋น์ธ์ฆ | ๋ก๊ทธ์ธ ์ํ๋ฉด ๊ฐ์ ๋ก๊ทธ์์ ํ ์งํ |
owner (์ต๊ณ ๊ด๋ฆฌ์)
|
+-- admin (์์นด๋ฐ๋ฏธ ๊ด๋ฆฌ์)
|
+-- manager (์ด์์)
|
+-- member (์ผ๋ฐ ์ฌ์ฉ์)
| ๋ฑ๊ธ | ์ฝ๋ | ์ค๋ช |
|---|---|---|
| ์ต๊ณ ๊ด๋ฆฌ์ | owner |
์์คํ ์ ์ฒด๋ฅผ ๊ด๋ฆฌ. ์์นด๋ฐ๋ฏธ ์์ฑ/์ญ์ ๊ฐ๋ฅ |
| ์์นด๋ฐ๋ฏธ ๊ด๋ฆฌ์ | admin |
ํน์ ์์นด๋ฐ๋ฏธ ๋ด ์ฌ์ฉ์/ํ๊ต ๊ด๋ฆฌ |
| ์ด์์ | manager |
ํ๊ธฐ/์์ ๊ด๋ฆฌ, ๊ฒ์ํ ์ด์ |
| ์ผ๋ฐ ์ฌ์ฉ์ | member |
์์ ์ฐธ์ฌ, ๊ฒ์๊ธ ์์ฑ ๋ฑ ๊ธฐ๋ณธ ๊ธฐ๋ฅ |
๋ชจ๋ ์์ฒญ ๋ณธ๋ฌธ(body)์ JSON ํ์์ ๋๋ค.
Content-Type: application/json๋ชฉ๋ก ์กฐํ ์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ํํฐ๋งํฉ๋๋ค:
GET /api/registrations?season=507f1f77bcf86cd799439011&role=student๋จ์ผ ๋ฆฌ์์ค ์ ๊ทผ ์ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค:
GET /api/users/507f1f77bcf86cd799439011
GET /api/seasons/507f1f77bcf86cd799439011์ผ๋ถ API๋ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ ์์ด ํธ์ถํ๋ฉด ๋ชฉ๋ก์ ๋ฐํํ๊ณ , ํฌํจํ๋ฉด ๋จ์ผ ๋ฆฌ์์ค๋ฅผ ๋ฐํํฉ๋๋ค:
GET /api/schools --> { schools: [...] } (๋ชฉ๋ก)
GET /api/schools/:_id --> { school: {...} } (๋จ์ผ)๋ชจ๋ ์๋ต์ JSON ํ์์ด๋ฉฐ, ๋ฆฌ์์ค๋ช ์ ํค๋ก ์ฌ์ฉํฉ๋๋ค.
๋จ์ผ ๋ฆฌ์์ค ์๋ต:
{
"academy": {
"_id": "...",
"academyId": "my-academy",
"academyName": "ํ
์คํธ ์์นด๋ฐ๋ฏธ"
}
}๋ชฉ๋ก ์๋ต:
{
"academies": [
{ "_id": "...", "academyId": "academy1", "academyName": "์์นด๋ฐ๋ฏธ 1" },
{ "_id": "...", "academyId": "academy2", "academyName": "์์นด๋ฐ๋ฏธ 2" }
]
}์๋ฌ ์๋ต:
{
"message": "FIELD_REQUIRED(academyId)"
}| ์ํ ์ฝ๋ | ์๋ฏธ | ์ค๋ช |
|---|---|---|
200 |
์ฑ๊ณต | ์์ฒญ์ด ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋จ |
400 |
์๋ชป๋ ์์ฒญ | ํ์ ํ๋ ๋๋ฝ, ์ ํจ์ฑ ๊ฒ์ฌ ์คํจ |
401 |
์ธ์ฆ ํ์ | ๋ก๊ทธ์ธ๋์ง ์์ ์ํ์์ ์ธ์ฆ์ด ํ์ํ API ํธ์ถ |
403 |
๊ถํ ์์ | ํด๋น API์ ๋ํ ๊ถํ์ด ๋ถ์กฑํจ |
404 |
๋ฆฌ์์ค ์์ | ์์ฒญํ ๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์ |
409 |
์ถฉ๋ | ์ค๋ณต๋ ๋ฐ์ดํฐ (์: ์ด๋ฏธ ์ฌ์ฉ ์ค์ธ ID) |
500 |
์๋ฒ ์ค๋ฅ | ์๋ฒ ๋ด๋ถ ์ค๋ฅ ๋ฐ์ |
๋ชจ๋ ์๋ฌ ์๋ต์ message ํ๋๋ฅผ ํฌํจํฉ๋๋ค:
{
"message": "PERMISSION_DENIED"
}| ๋ฉ์์ง | ์ค๋ช |
|---|---|
PERMISSION_DENIED |
๊ถํ์ด ๊ฑฐ๋ถ๋จ |
FIELD_REQUIRED({ํ๋๋ช
}) |
ํ์ ํ๋๊ฐ ๋๋ฝ๋จ |
FIELD_INVALID({ํ๋๋ช
}) |
ํ๋ ๊ฐ์ด ์ ํจํ์ง ์์ |
FIELD_IN_USE({ํ๋๋ช
}) |
ํด๋น ๊ฐ์ด ์ด๋ฏธ ์ฌ์ฉ ์ค |
{๋ฆฌ์์ค}_NOT_FOUND |
๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์ |
์๋ฒ๋ validate ์ ํธ๋ฆฌํฐ๋ฅผ ํตํด ์
๋ ฅ๊ฐ์ ๊ฒ์ฆํฉ๋๋ค. ์ฃผ์ ๊ฒ์ฆ ๋์:
| ํ๋ | ๊ฒ์ฆ ๊ท์น |
|---|---|
academyId |
์๋ฌธ, ์ซ์, ํ์ดํ ์กฐํฉ |
userId |
์๋ฌธ, ์ซ์ ์กฐํฉ |
userName |
ํ๊ธ, ์๋ฌธ |
password |
์ต์ ๊ธธ์ด ์๊ตฌ |
email |
์ด๋ฉ์ผ ํ์ |
tel |
์ ํ๋ฒํธ ํ์ |
schoolId |
์๋ฌธ, ์ซ์ ์กฐํฉ |
schoolName |
ํ๊ธ, ์๋ฌธ |
ํ๋ก ํธ์๋์์๋ useAPIv2 ์ปค์คํ
ํ
์ ํตํด API๋ฅผ ํธ์ถํฉ๋๋ค. ์ด ํ
์ axios ๊ธฐ๋ฐ์ useDatabase ํ
์ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ๋ฉฐ, ๋ชจ๋ API ํจ์๋ฅผ CRUD ์ ๋์ฌ ๋ช
๋ช
๊ท์น์ ๋ฐ๋ผ ์ ๊ณตํฉ๋๋ค.
import useAPIv2 from "hooks/useAPIv2";
function MyComponent() {
const {
CAcademy, // ์์นด๋ฐ๋ฏธ ์์ฑ
RAcademies, // ์์นด๋ฐ๋ฏธ ๋ชฉ๋ก ์กฐํ
UAcademy, // ์์นด๋ฐ๋ฏธ ์์
DAcademy, // ์์นด๋ฐ๋ฏธ ์ญ์
} = useAPIv2();
// API ํธ์ถ ์์
const handleCreate = async () => {
const { academy, admin } = await CAcademy({
data: {
academyId: "new-academy",
academyName: "์ ์์นด๋ฐ๋ฏธ",
adminId: "admin01",
adminName: "๊ด๋ฆฌ์",
},
});
};
}| ์ ๋์ฌ | HTTP ๋ฉ์๋ | ์๋ฏธ | ์์ |
|---|---|---|---|
C |
POST |
Create (์์ฑ) | CAcademy, CUser, CSyllabus |
R |
GET |
Read (์กฐํ) | RAcademies, RUser, RMySelf |
U |
PUT |
Update (์์ ) | UActivateAcademy, UPassword |
D |
DELETE |
Delete (์ญ์ ) | DAcademy, DUser, DEnrollment |
useAPIv2๋ ๋ด๋ถ์ ์ผ๋ก useDatabase ํ
์ C, R, U, D ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค:
// useDatabase ํ
๋ฉ์๋
database.C({ location, data }) // POST /api/{location}
database.R({ location, params }) // GET /api/{location}?{params}
database.U({ location, data }) // PUT /api/{location}
database.D({ location, params }) // DELETE /api/{location}?{params}ํ๋ก ํธ์๋์์๋ ALERT_ERROR ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ API ์๋ฌ๋ฅผ ์ฌ์ฉ์์๊ฒ ํ์ํฉ๋๋ค:
import { ALERT_ERROR } from "hooks/useAPIv2";
try {
await CAcademy({ data: { ... } });
} catch (err) {
ALERT_ERROR(err);
// ์๋ฒ์ ์๋ฌ ๋ฉ์์ง๋ฅผ ํ๊ตญ์ด๋ก ๋ณํํ์ฌ alert() ํ์
}์๋ฌ ๋ฉ์์ง ๋งคํ์ _message.ts ํ์ผ์์ ๊ด๋ฆฌ๋ฉ๋๋ค. ์๋ฒ๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ ์๋ฌธ ์๋ฌ ์ฝ๋๊ฐ ํ๊ตญ์ด ๋ฉ์์ง๋ก ๋ณํ๋์ด ์ฌ์ฉ์์๊ฒ ํ์๋ฉ๋๋ค.
useAPIv2 ๋ด๋ถ์์๋ QUERY_BUILDER ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด๋ฅผ ์ฟผ๋ฆฌ ์คํธ๋ง์ผ๋ก ๋ณํํฉ๋๋ค:
// ์
๋ ฅ
QUERY_BUILDER({ season: "abc123", role: "student" })
// ์ถ๋ ฅ
"?season=abc123&role=student&"๋ฐฑ์๋ ์์ค ์ฝ๋์๋ JSDoc ํ์์ ์ฃผ์์ด ํฌํจ๋์ด ์์ผ๋ฉฐ, ์ด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก API ๋ฌธ์๋ฅผ ์๋ ์์ฑํ ์ ์์ต๋๋ค.
cd backend
npm run jsdoc/**
* @memberof APIs.AcademyAPI
* @function CAcademy API
* @description ์์นด๋ฐ๋ฏธ ์์ฑ API
* @version 2.0.0
*
* @param {Object} req
* @param {"POST"} req.method
* @param {"/academies"} req.url
*
* @param {Object} req.body
* @param {string} req.body.academyId
* @param {string} req.body.academyName
*
* @param {Object} res
* @param {TAcademy} res.academy - ์์ฑ๋ ์์นด๋ฐ๋ฏธ
*
* @throws {}
* | status | message | description |
* | :----- | :--------------- | :------------------------ |
* | 409 | ACADEMYID_IN_USE | academyId๊ฐ ์ด๋ฏธ ์ฌ์ฉ ์ค |
*/JSDoc ๋ฌธ์๋ ๋ค์ ๋ค์์คํ์ด์ค๋ก ๊ตฌ์ฑ๋ฉ๋๋ค:
Models.*: ๋ฐ์ดํฐ ๋ชจ๋ธ (์:Models.Academy,Models.User)APIs.*: API ์ปจํธ๋กค๋ฌ (์:APIs.AcademyAPI,APIs.UserAPI)
Altsis๋ ๋ฉํฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํคํ ์ฒ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์์นด๋ฐ๋ฏธ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ์ต์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๋ค.
Academy์ปฌ๋ ์ ๋ง ํฌํจ
๊ฐ ์์นด๋ฐ๋ฏธ๋ง๋ค ๋
๋ฆฝ์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์์ฑ๋ฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ์ {academyId}-db ํ์์
๋๋ค.
User,School,Season,Registration,Syllabus,Enrollment๋ฑ ๋ชจ๋ ๋๋ฉ์ธ ์ปฌ๋ ์ ํฌํจ- ์์นด๋ฐ๋ฏธ ๊ฐ ๋ฐ์ดํฐ๊ฐ ์์ ํ ๋ถ๋ฆฌ๋จ
๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ mongoose-encryption ํ๋ฌ๊ทธ์ธ์ผ๋ก ์ํธํ๋์ด ์ ์ฅ๋ฉ๋๋ค:
| ๋ชจ๋ธ | ์ํธํ ํ๋ | ์ค๋ช |
|---|---|---|
Enrollment |
evaluation |
ํ์ ํ๊ฐ ๋ฐ์ดํฐ |
Archive |
data |
ํ์ ๊ธฐ๋ก ๋ฐ์ดํฐ |
๋น๋ฐ๋ฒํธ๋ bcrypt๋ก ํด์ํ๋์ด ์ ์ฅ๋ฉ๋๋ค:
| ๋ชจ๋ธ | ํด์ ํ๋ | ์ค๋ช |
|---|---|---|
User |
password |
์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ (API ์๋ต์์ ์ ์ธ) |