일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다.
먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까?
멀티 테넌트 SAAS 애플리케이션을 사용하면 단일 코드베이스에서 여러 고객에게 서비스를 제공 할 수 있습니다. 그러나이를 위해서는 안전하고 세입자 별 액세스를 관리해야하며 수동으로 수행 할 때는 어려울 수 있습니다. 그렇기 때문에이 프로세스를 단순화하는 현대적인 승인 도구 인 허가를 사용하기로 결정했습니다.
이 기사에서는 TENANT INLITATION을 사용하여 SAAS 애플리케이션에 대한 승인을 단순화하는 방법을 보여 드리겠습니다. TENANT DERINATION 및 APPWRITE를 사용하여 테넌트 격리 및 역할 기반 액세스 제어 (RBAC)를 갖춘 데모 앱을 구축하는 단계별 예를 들어 보겠습니다.
다음은 무엇입니까 JS와 AppWrite는 무엇입니까? 왜 우리는 그것들을 필요로합니까?
다음 .js
Next.js는 SSR (Server-Side Rendering), 정적 사이트 생성 (SSG), API 경로 및 성능 최적화를 제공하는 반응 기반 프레임 워크입니다.
이 프로젝트에서는 다음에 다음을 사용했습니다.
- 페이지를 사전 렌더링하여 성능과 SEO를 향상시킵니다.
- 내장 라우팅을 통해 페이지 전환 및 동적 컨텐츠를 쉽게 관리 할 수 있습니다.
- 인증 및 승인을 위해 AppWrite 및 Cermit.io와 같은 백엔드 서비스와 쉽게 통합됩니다.
appwrite
AppWrite는 사용자 인증, 데이터베이스, 스토리지 및 서버리스 기능을 제공하는 BAAAS (Backend-as-A-Service) 플랫폼입니다. AppWrite와 같은 서비스를 사용하면 백엔드를 처음부터 구축 할 필요가 없으므로 백엔드 기능에 액세스하면서 프론트 엔드 개발에 집중할 수 있습니다.
이 프로젝트에서는 AppWrite를 사용했습니다.
- 사용자 등록, 로그인 및 세션 관리를 처리합니다.
- 세입자 별 데이터를 저장하기위한 구조화 된 NOSQL 데이터베이스를 제공합니다.
Next.js와 AppWrite를 함께 사용하면 개발 프로세스를 효율적으로 유지하면서 확장 가능한 고성능 다중 테넌트 SaaS 앱을 만들 수있었습니다.
다중 테넌트 SaaS 승인 소개
멀티 테넌트 SAAS 앱은 응용 프로그램의 단일 소프트웨어 인스턴스를 사용하여 여러 사용자 또는 테넌트라고하는 사용자 그룹에 서비스를 제공하는 소프트웨어입니다.
의미는 다중 테넌트 SaaS 아키텍처에서 여러 고객 (테넌트)이 동일한 응용 프로그램 인프라를 공유하거나 동일한 응용 프로그램을 사용하지만 데이터 격리를 유지한다는 것입니다.
이것의 실질적인 예는 Trello와 같은 프로젝트 관리 도구입니다.
- 공유 서버에서 실행되며 모든 사용자와 동일한 코드베이스를 갖는 단일 인프라입니다.
- Trello (예 : 회사 A 및 회사 B)를 사용하는 각 회사는 임차인입니다.
- 데이터를 분리합니다.
- 회사 A의 직원은 프로젝트, 작업 및 이사회 만 볼 수 있습니다.
- 회사 B의 직원은 회사 A의 데이터에 액세스하거나 볼 수 없으며 그 반대도 마찬가지입니다.
이를 통해 리소스가 공유되는 동안 각 세입자의 데이터 및 활동은 개인적이고 안전합니다.
다중 테넌트 응용 프로그램에서는 임차인 내에서도 일부 사용자는 일부 정보에 대한 액세스 권한이 높고 일부 회원은 특정 리소스로 제한됩니다.
그러한 신청서에서 승인해야합니다.
- 사용자가 다른 임차인 또는 고객의 데이터 또는 리소스에 액세스 할 수 없도록합니다. 이것을 격리 세입자라고합니다.
- 세입자 내의 사용자가 세분화 된 액세스 제어를 제공하여 역할 허가 자원 만 액세스 할 수 있도록하십시오.
- 성능을 늦추거나 저하시키지 않고 더 많은 사용자, 임차인 및 역할을 처리합니다.
임차인 분리 및 세분화 액세스 제어의 중요성
테넌트 격리는 각 고객의 정보가 비공개로 유지되도록하여 데이터를 안전하게 유지합니다. 세분화 된 액세스 제어는 조직 내 사용자가 필요한 권한 만 받도록합니다.
SaaS 앱에서 권한을 구현하는 것은 복잡하고 까다로울 수 있지만 허가와 같은 인증 도구가있을 때는 필요하지 않습니다.
허가는 무엇이며 그 이점은 무엇입니까?
허가는 멀티 테넌트 앱을 포함하여 모든 응용 프로그램에서 액세스를 관리하기위한 사용하기 쉬운 권한 부여 도구입니다. 애플리케이션에서 permit.io를 사용하면 응용 프로그램 내 액세스 제어에 대한 특정 권한으로 역할을 쉽게 정의하고 할당 할 수 있습니다. 응용 프로그램 내에서 역할을 만드는 것 외에도 사용자 또는 리소스 속성을 기반으로 조건 및 규칙을 추가하여 각 사용자가 할 수있는 것과 수행 할 수없는 것을 지정할 수도 있습니다.
이제 허가와 그 혜택에 대해 알아야 할 대부분의 것을 알았으므로 주요 거래에 참여해 보겠습니다. SaaS 응용 프로그램을 Next.js와 함께 구축하고 승인 허가를 통합하십시오.
허가의 힘을 보여주기 위해, 우리는 멀티 테넌트 Edtech Saas 플랫폼을 구축 할 것입니다.
Edtech SaaS 플랫폼을 구축하려면 사용자 인증, 역할 기반 액세스 제어 (RBAC) 및 다중 테넌시를 포함한 몇 가지 과제가 필요합니다. 우리는 Frontend에 Next.js를 사용하고, 인증 및 데이터베이스 관리를위한 AppWrite 및 세밀한 승인 허가를받을 수 있습니다.
기술 스택 개요
시스템 아키텍처
응용 프로그램은 백엔드 우선 접근 방식을 따릅니다.
- 백엔드 (node.js Express)
- API 요청 및 비즈니스 로직을 처리합니다.
- 인증 및 데이터베이스 관리에 AppWrite를 사용합니다.
- 권한 부여 허가, 역할 및 권한을 정의합니다.
- 데이터 액세스 전에 모든 요청이 검증되도록합니다.
- 프론트 엔드 (Next.js)
- 백엔드에 연결하여 데이터를 단단히 가져옵니다.
- 역할 기반 UI 렌더링을 사용합니다. 즉, 사용자는 액세스 권한 만 볼 수 있습니다.
- 권한에 따라 작업 (과제 생성)을 제한합니다.
API 수준에서 승인을 시행함으로써 사용자는 프론트 엔드를 조작하더라도 제한을 우회 할 수 없도록합니다.
이 안내서의 끝에는 완벽하게 기능적인 다중 테넌트 Edtech SaaS 앱이 있습니다.
- 관리자는 학생들을 추가하고 볼 수 있습니다.
- 교사는 학생들을 추가하고보고 과제를 만들 수 있습니다.
- 학생들은 할당 된 교과 과정 만 볼 수 있습니다.
이 기사는이 프로젝트를 구축하기위한 승인을 처리 할 수있는 허가를 구현 한 방법에 대한 단계별 분석을 제공하므로 따라 가서 구축하십시오.
허가를 통한 백엔드 구현
역할 기반 액세스 제어 (RBAC) 및 테넌트 격리를 시행하려면 다음을 수행해야합니다.
- 허가를 설정하고 역할, 임차인 및 정책을 정의합니다.
- 백엔드 (node.js express)에 허가를 통합하십시오.
- 요청을 허용하기 전에 권한을 확인하는 미들웨어를 사용하여 API 경로를 보호하십시오.
단계별로 가자.
1. 허가 설정
코드를 작성하기 전에 필요합니다
- 허가에 계정을 만듭니다.

온 보딩이 제공되지만 조직 이름을 입력하면 설정을 건너 뛸 수 있습니다.
- 자원과 행동을 만듭니다
정책 섹션으로 이동하여 해당 리소스에서 수행 할 수있는 리소스 및 조치를 만들 수 있습니다.

자원을 만들면 다음과 같이 보일 것입니다.

- 역할 만들기
리소스를 작성한 후 역할 탭을 사용하여 역할 페이지로 이동하십시오. 일부 역할이 자동으로 할당되었음을 알 수 있습니다.

이러한 역할을 삭제하고 새로운 역할을 만듭니다. 각 역할에는 사용자가 할 수 있고 할 수없는 일에 대한 특정 규칙이 있습니다. 나중에 RBAC 조건의 빌딩 블록 역할을하므로 관리자 역할을 먼저 만듭니다. 상단에서 역할 추가 버튼을 클릭하고 역할을 만듭니다.

역할을 만들 때 다음과 같이 보일 것입니다.

엄청난!
리소스와 역할을 만들었으므로 이제 정책 편집기에서 권한을 구성 할 수 있습니다.
- 정책 편집기의 권한 구성
정책 편집기로 돌아가서 각 개별 리소스가 정의되고 선택할 수있는 조치와 함께 역할이 어떻게 보이는지입니다. 이제 리소스에서 선택한 작업을 수행하기 위해 역할에 대한 권한을 부여 할 준비가되었습니다.

각 역할에 대한 작업을 선택하면 페이지 오른쪽 하단의 변경 사항 저장 버튼을 클릭하십시오.
- API 키를 복사하십시오
마지막으로, Cloud PDP의 허가증을 사용하려면 현재 환경의 API 키가 필요합니다. 이 프로젝트의 경우 개발 환경 키를 사용할 것입니다. 설정을 진행하고 API 키를 클릭하고 환경 API 키로 스크롤 한 다음 "공개 키"를 클릭 한 다음 복사하십시오.

허가 대시 보드를 설정 한 후 이제 백엔드로 이동할 수 있습니다.
2. 종속성 설치
시작하려면 컴퓨터에 node.js를 설치해야합니다. Node.js가 시스템에 설치되는지 확인한 후 다음 단계를 따르십시오.
- 다음 명령을 사용하여 새 프로젝트를 작성하여 시작하십시오.
mkdir 백엔드 cd backendnpm init -y
- 그런 다음 다음 패키지를 설치하십시오.
NPM 설치 Express Dotenv Permitio Cors Appwwrite Axios Jsonwebtoken
- Express에서 허가를 구성하십시오. .env 파일에서 API 키를 저장하십시오.
permit_api_key = your-permit-key-you-copied-earlier
3. AppWrite 설정
- AppWrite로 이동하여 프로젝트 이름을 입력하고 지역을 선택하여 새 프로젝트를 만듭니다. 프로젝트 ID 및 API 엔드 포인트를 기록하십시오. 그것이 .env 파일의 값으로 입력 할 것입니다. ENV 파일은 다음과 같아야합니다.
permit_api_key = your-permit-key-you-copied-earlier appwrite_endpoint = https : //cloud.appwrite.io/v1 appwrite_project_id = your-project-id
- 이제 데이터베이스를 진행하여 데이터베이스를 작성한 다음 데이터베이스 ID를 복사하여 ENV 파일에 붙여 넣습니다.

ENV 파일은 이제 다음과 같습니다.
permit_api_key = your-permit-key-you-copied-earlier appwrite_endpoint = https : //cloud.appwrite.io/v1 appwrite_project_id = your-project-id appwrite_database_id = your-database-id
이제 다음 속성으로 AppWrite 데이터베이스에서 다음 컬렉션을 만듭니다.
- 프로파일 컬렉션

- 학생 컬렉션

- 과제 수집

이 시점에서 ENV 파일이 보이는 것 :
permit_api_key = your-permit-key-you-copied-earlier permit_project_id = copy-from-dashboard permit_env_id = copy-from-dashboard appwrite_endpoint = https : //cloud.appwrite.io/v1 appwrite_project_id = your-project-id appwrite_database_id = your-database-id appwrite_profile_collection_id = your-id appwrite_assignments_collection_id = your-id appwrite_students_collection_id = your-id jwt_secret = generate-this-s-running // OpenSSL rand -base64 16 포트 = 8080
4. 파일 구조 및 파일을 만듭니다
이제 파일 루트에 SRC 폴더를 만듭니다. 그런 다음 루트 폴더에서 tsconfig.json 파일을 생성하고 다음 코드를 붙여 넣습니다.
<span>{ </span><span>"컴파일러 옵션": { </span><span>"대상": "ES6", </span><span>"모듈": "commonjs", </span><span>"outdir": "./dist", </span><span>"EsmoduleInterop": True, </span><span>"ForCeconsentCasingInfilenames": True, </span><span>"엄격한": 사실, </span><span>"SkipLibCheck": True, </span><span>"ResolveJsonModule": True, </span><span>"baseurl": "./", </span><span>"경로": { </span><span>"@/*": [ "SRC/*"] </span><span>} </span><span>}, </span><span>"포함": [ "SRC/**/*"], </span><span>"제외": [ "node_modules", "dist"]]] </span><span>}</span>
이 tsconfig.json은 ES6을 대상으로 TypeScript 컴파일러를 구성하고 CommonJS 모듈을 사용하며 파일을 ./dist로 구성합니다. 엄격한 유형 확인을 강화하고 JSON 모듈 해상도를 활성화하고 SRC의 경로 별칭을 설정하며 Node_Modules 및 컴파일에서 DEST를 제외합니다.
SRC 폴더 내부에는 API, 구성, 컨트롤러, 미들웨어, 모델 및 유틸리티의 다음 폴더를 만듭니다.
- 폴더를 사용합니다
- 이제 UTILS 폴더 프로젝트에서 새 Cermit.ts 파일을 작성하여 다음 코드를 사용하여 허가를 초기화합니다.
<span>'permitio'에서 {refit} 가져 오기; </span><span>'../config/environment'에서 {permit_api_key} 가져 오기; </span><span>//이 라인은 SDK를 초기화하고 Node.js 앱을 연결합니다. </span><span>// 이전 단계에서 설정 한 PDP 컨테이너. </span><span>const 허가 = 새로운 허가 ({ </span><span>// API 키 </span> 토큰 <span>: permit_api_key, // API 키를 .env에 저장 </span><span>// 제작시 배포에 맞게이 URL을 변경해야 할 수도 있습니다. </span> pdp <span>: 'https://cloudpdp.api.permit.io', // default remit.io pdp url </span><span>// SDK가 로그를 방출하기를 원한다면 타협 : </span> 통나무 <span>: { </span> 레벨 <span>: "디버그", </span><span>}, </span><span>// 시간 초과 / 네트워크 오류가 발생하면 SDK가 거짓을 반환합니다. </span><span>// 대신 오류를 던지기를 원한다면이를 처리 할 수 있도록하십시오. </span><span>// ThrowOnerror : true, </span><span>}); </span> <span>수출 기본 허가;</span>
이 파일은 Node.js 용 SDK의 SDK를 초기화하여 환경에 저장된 API 키를 사용하여 허가 PDP 컨테이너에 연결합니다. 디버깅 로그 로그를 구성하고 SDK를 명시 적으로 던지지 않는 한 SDK를 조용히 처리하도록 설정합니다.
- 다음으로 ErrorHandler.ts라는 파일을 작성하고 다음 코드를 붙여 넣습니다.
<span>// 유틸리티 함수 (예 : 오류 처리) </span><span>'Express'에서 {request, response, nextfunction} import; </span> <span>내보내기 const errorhandler = (err : one, req : requ : res : responce, nextfunction) => { </span><span>console.error ( 'error :', err.message || err); </span> <span>res.status (err.status || 500) .json ({{ </span> 오류 <span>: err.message || '내부 서버 오류', </span><span>}); </span><span>};</span>
이 파일은 오류를 기록하고 오류 메시지 및 상태 코드로 JSON 응답을 보내는 Express Error 처리 미들웨어를 정의합니다. 특정 상태가 제공되지 않으면 기본적으로 500 상태 코드로 기본적으로 표시됩니다.
- 모델 폴더
- profile.ts라는 파일을 만들고 다음 코드를 붙여 넣습니다.
<span>인터페이스 프로필 내보내기 { </span> 이름 <span>: 문자열; </span> 이메일 <span>: 문자열; </span> 역할 <span>: '관리자'| '교사'| '학생'; </span> userID <span>: 문자열; </span><span>}</span>
이 파일은 이름, 이메일, 역할 및 userID의 속성이있는 TypeScript 프로파일 인터페이스를 정의하며, 여기서 역할은 관리, 교사 또는 학생으로 제한됩니다.
- 할당을 작성하고 다음 코드를 붙여 넣습니다.
<span>'../config/appwrite'에서 {database, id} 가져 오기; </span><span>import {database_id, antsamments_collection_id} from '../config/environment'; </span> <span>인터페이스 내보내기 할당 data { </span> 제목 <span>: 문자열; </span> 제목 <span>: 문자열; </span> ClassName <span>: 문자열; </span> 교사 <span>: 문자열; </span> 빙하 <span>: 문자열; </span> CreatorEmail <span>: 문자열; </span><span>} </span> <span>// 새 할당을 만듭니다 </span><span>Async 함수 createAssignmentIndb (data : antlodmentData) { </span><span>return await database.createdocument ( </span><span>database_id, </span><span>과제 _collection_id, </span><span>id.unique (), </span> 데이터 <span>); </span><span>} </span> <span>// 모든 과제를 가져옵니다 </span><span>내보내기 비동기 기능 fetchAssignmentsfromdb () { </span><span>const response = database.listDocuments (database_id, antlicments_collection_id); </span><span>반환 응답. </span><span>}</span>
이 파일은 할당을 관리하기 위해 AppWrite 데이터베이스와 상호 작용하는 기능을 제공합니다. 과제 데이터 인터페이스를 정의하고 새로운 할당을 생성하고 데이터베이스에서 모든 할당을 가져 오는 기능을 포함합니다.
- Student.ts 파일을 만들고 다음 코드를 붙여 넣습니다.
<span>import {데이터베이스, ID, 권한, 역할, 쿼리}에서 '../config/appwrite'; </span><span>'../config/environment'에서 {database_id, whitsing_collection_id}; </span> <span>인터페이스 수출 학생 데이터 { </span> FirstName <span>: 문자열; </span> 마지막 이름 <span>: 문자열; </span> 성별 <span>: '여자'| '소년'| '소년'| '소녀'; </span> ClassName <span>: 문자열; </span> 나이 <span>: 숫자; </span> CreatorEmail <span>: 문자열; </span><span>} </span> <span>// 새로운 학생을 만듭니다 </span><span>Async 함수 내보내기 createStudentIndb (data : windentdata) { </span><span>return await database.createdocument ( </span><span>database_id, </span><span>학생 _collection_id, </span><span>id.unique (), </span> 데이터 <span>, </span><span>[의 뜻 </span> 권한 <span>.Read (역할 .ANY ()), // 공개 읽기 권한 </span><span>]] </span><span>); </span><span>} </span> <span>// 모든 학생들을 가져 오십시오 </span><span>내보내기 비동기 기능 FetchStudentsfromdb () { </span><span>const response = database.listdocuments (database_id, whitsing_collection_id); </span><span>반환 응답. </span><span>}</span>
이 파일은 AppWrite 데이터베이스에서 학생 데이터를 관리하는 기능을 제공합니다. StudentData 인터페이스를 정의하고 공개 읽기 권한이있는 신입생을 만들고 데이터베이스에서 모든 학생을 가져 오는 기능을 포함합니다.
- 미들웨어 폴더
- Auth.ts 파일을 작성하고 다음 코드를 붙여 넣습니다.
<span>'Express'에서 {request, response, nextfunction} import; </span><span>'jsonwebtoken'에서 JWT 가져 오기; </span> <span>// '사용자'를 포함하도록 요청 유형 확장 </span><span>인터페이스 authenticatedRequest 확장 요청 { </span> 사용자 <span>? : { </span> ID <span>: 문자열; </span> 역할 <span>: 문자열; </span><span>}; </span><span>} </span> <span>const authmiddleware = (req : authenticatedrequest, res : response, nextfunction) : void => { </span><span>const token = req.headers.authorization? .split ( '') [1]; </span> <span>if (! token) { </span> <span>res.status (401) .json ({error : '무단. 토큰이 제공되지 않음'); </span><span>반품 </span><span>} </span> <span>노력하다 { </span><span>const decoded = jwt.verify (token, process.env.jwt_secret!) as {id : string; 역할 : 문자열}; </span> req <span>.user = 디코딩; </span><span>다음(); </span><span>} catch (오류) { </span> <span>res.status (403) .json ({error : 'invalid token'}); </span><span>반품 </span><span>} </span><span>}; </span> <span>기본 authmiddleware 내보내기;</span>
이 파일은 JWT 기반 인증을위한 Express Middleware를 정의합니다. 요청 헤더에서 유효한 토큰을 확인하고 비밀 키를 사용하여 확인하고 디코딩 된 사용자 정보 (ID 및 역할)를 요청 객체에 첨부합니다. 토큰이 누락되거나 유효하지 않으면 적절한 오류 응답을 반환합니다.
- permit.ts를 만들고 다음 코드를 붙여 넣습니다.
<span>'../utils/permit'의 수입 허가; </span> <span>내보내기 const checkusertopermitstudents = async (이메일 : 문자열, 동작 : 문자열, 자원 : 문자열) : 약속 <boolean> => { </boolean></span><span>노력하다 { </span><span>const 허가 = 대기 허가. 체크 (이메일, 조치, 자원); </span><span>Console.log ( "허가", 허용); </span><span>허용 된 반품; </span><span>} catch (오류) { </span><span>console.error ( <span>`erver user <span>$ {email}</span> recmit.io :`</span> , error); </span><span>거짓을 반환합니다. </span><span>} </span><span>}; </span> <span>내보내기 const checkusertopermitAssignment = async (이메일 : 문자열, 동작 : 문자열, 자원 : 문자열) : 약속 <boolean> => { </boolean></span><span>노력하다 { </span><span>const 허가 = 대기 허가. 체크 (이메일, 조치, 자원); </span><span>Console.log ( "허가", 허용); </span><span>허용 된 반품; </span><span>} catch (오류) { </span><span>console.error ( <span>`erver user <span>$ {email}</span> recmit.io :`</span> , error); </span><span>거짓을 반환합니다. </span><span>} </span><span>};</span>
이 파일은 유틸리티 기능, CheckuserTopermitStudents 및 CheckuserToPermitAssignment를 정의하여 특정 조치 및 리소스에 대한 허가의 사용자 권한을 확인합니다. 두 기능 모두 오류를 우아하게 처리하고 허가 확인이 실패하면 문제를 기록하고 거짓을 반환합니다. 응용 프로그램에서 승인을 집행하는 데 사용됩니다.
- 컨트롤러 폴더
- Auth.ts 파일을 작성하고 다음 코드를 붙여 넣습니다.
<span>'../config/appwrite'에서 {account, id} 가져 오기; </span><span>'Express'에서 {request, response} 가져 오기; </span><span>'jsonwebtoken'에서 JWT 가져 오기; </span> <span>const jwt_secret = process.env.jwt_secret로 문자열로; // 이것이 .env 파일에 설정되어 있는지 확인하십시오 </span> <span>// 가입 컨트롤러 </span><span>내보내기 const 가입 = async (req : request, res : response) => { </span><span>const {이메일, 비밀번호, 이름} = req.body; </span> <span>if (! email ||! password ||! name) { </span><span>return res.status (400) .json ({error : '이름, 이메일 및 비밀번호가 필요합니다.'}); </span><span>} </span> <span>노력하다 { </span><span>const user = await account.create (id.unique (), 이메일, 암호, 이름); </span><span>// JWT를 생성합니다 </span><span>const token = jwt.sign ({email}, jwt_secret, {expiresin : '8h'}); </span> res <span>.cookie ( '토큰', 토큰, { </span> httponly <span>: 사실, </span> Samesite <span>: 'Strict', </span> Secure <span>: True, </span><span>}); </span> <span>res.status (201) .json ({성공 : True, User, Token}); </span><span>} catch (오류 : Any) { </span><span>Console.error ( '서명 오류 :', 오류); </span> res <span>.status (500) .json ({성공 : false, message : error.message}); </span><span>} </span><span>}; </span> <span>// 로그인 컨트롤러 </span><span>내보내기 const login = async (req : request, res : response) => { </span><span>const {email, password} = req.body; </span> <span>if (! email ||! password) { </span><span>return res.status (400) .json ({error : '이메일과 암호가 필요합니다.'}); </span><span>} </span> <span>노력하다 { </span><span>const session = await account.createemailpasswordsession (이메일, 암호); </span> <span>// 역할없이 JWT를 생성합니다 </span><span>const token = jwt.sign ( </span><span>{userId : session.userid, email}, // 역할이 포함되어 있지 않습니다 </span><span>JWT_SECRET, </span><span>{expiresin : '8h'} </span><span>); </span> res <span>.cookie ( '토큰', 토큰, { </span> httponly <span>: 사실, </span> Samesite <span>: 'Strict', </span> Secure <span>: True, </span><span>}); </span> res <span>.Status (200) .json ({성공 : True, Token, Session}); </span><span>} catch (오류 : Any) { </span><span>console.error ( '로그인 오류 :', 오류); </span> <span>res.status (401) .json ({성공 : false, message : error.message}); </span><span>} </span><span>}; </span> <span>// 로그 아웃 컨트롤러 </span><span>내보내기 const logout = async (req : request, res : response) => { </span><span>노력하다 { </span><span>AWAIT Account.deletesession ( '현재 세션 ID'); </span> res <span>.clearCookie ( '토큰'); </span> <span>res.status (200) .json ({성공 : true, 메시지 : '성공적으로 로그 아웃'); </span><span>} catch (오류 : Any) { </span><span>console.error ( '로그 아웃 오류 :', 오류); </span> res <span>.status (500) .json ({성공 : false, message : error.message}); </span><span>} </span><span>};</span>
이 파일은 가입, 로그인 및 로그 아웃을위한 인증 컨트롤러를 정의하여 사용자 관리 용 AppWrite 및 세션 처리 용 JWT와 통합됩니다. 가입 및 로그인 컨트롤러는 입력을 유효성있게 검증하고 사용자 세션을 작성하며 JWT를 생성하는 반면 로그 아웃 컨트롤러는 세션 및 토큰을 지 웁니다. 모든 컨트롤러는 오류를 처리하고 적절한 응답을 반환합니다.
- 할당을 작성하고 다음 코드를 붙여 넣습니다.
<span>'Express'에서 {request, response} 가져 오기; </span><span>import {createAssignmentIndb, antlasmentData, fetchAssignmentsfromdb}에서 '../models/assignment'; </span><span>import {checkusertoPermitAssignment}에서 '../middleware/permit'; </span> <span>// 새 할당을 만듭니다 </span><span>내보내기 비동기 함수 createAssignment (req : request , res : response) : 약속 <void> { </void></span><span>노력하다 { </span><span>const {제목, 주제, 교사, 클래스 이름, deudate, creatoremail} : antlymentdata = req.body; </span> <span>const ispermitted = checkusertopermitAssignment (CreatorEmail, "Create", "할당"); </span><span>if (! IsPermitted) { </span> <span>res.status (403) .json ({error : 'Authorized'}); </span><span>반품; </span><span>} </span> <span>const newAssignment = reakeateSignmentIndb ({{ </span> 제목 <span>, </span> 주제 <span>, </span> 선생님 <span>, </span> Classname <span>, </span> 악마 <span>, </span> CreatorEmail <span>}); </span> <span>Console.log ( '새 과제가 만들어졌습니다 :', NewAssignment); </span> res <span>.Status (201) .json (NewAssignment); </span><span>} catch (오류) { </span><span>console.error ( '오류 생성 할당 :', 오류); </span> <span>res.status (500) .json ({error : (오류) .message}); </span><span>} </span><span>} </span> <span>// 모든 과제를 가져옵니다 </span><span>Async 함수 내보내기 FetchAssignments (req : request, res : response) : promise <void> { </void></span><span>노력하다 { </span><span>const {email} = req.params; </span> <span>const ispermitted = cheeckusertopermitassignment (이메일, "읽기", "과제"); </span><span>if (! IsPermitted) { </span> <span>res.status (403) .json ({메시지 : '승인되지 않음'}); </span><span>반품; </span><span>} </span> <span>const 할당 = AwetchAssignmentsFromdb (); </span> res <span>.Status (200) .json (과제); </span><span>} catch (오류) { </span> <span>res.status (500) .json ({error : (오류) .message}); </span><span>} </span><span>}</span>
이 파일은 데이터베이스와 통합하고 권한 확인 수표를 허용하기 위해 할당을 작성하고 가져 오기위한 컨트롤러를 정의합니다. CreateAssignment 컨트롤러는 입력을 확인하고 권한을 확인하며 새 할당을 생성하는 반면 FetchAssignments 컨트롤러는 액세스를 확인한 후 모든 할당을 검색합니다. 두 컨트롤러 모두 오류를 처리하고 적절한 응답을 반환합니다.
- Student.ts 파일을 만들고 다음 코드를 붙여 넣습니다.
<span>수입 { </span> CreateStudentIndb <span>, </span> Fetchstudentsfromdb <span>, </span> StudentData <span>} from '../models/student'; </span><span>'Express'에서 {request, response} 가져 오기; </span><span>'../middleware/permit'에서 {checkusertoPermitStudents} import; </span> <span>내보내기 비동기 함수 생성물 (req : request, res : response) : promise <void> { </void></span><span>노력하다 { </span><span>const {FirstName, LastName, Gender, ClassName, Age, CreatorEmail} : StudentData = Req.body; </span> <span>if (! [ 'girl', 'boy']. 포함 (gender)) { </span> <span>res.status (400) .json ({error : 'invalid gender type'}); </span><span>반품; </span><span>} </span> <span>const ispermitted = checkusertopermitstudents (CreatoreMail, "Create", "Student"); </span><span>if (! IsPermitted) { </span> <span>res.status (403) .json ({메시지 : '승인되지 않음'}); </span><span>반품; </span><span>} </span> <span>Const Newstudent = Await CreateStudentIndb ({ </span> FirstName <span>, </span> 성 <span>, </span> 성별 <span>, </span> Classname <span>, </span> 나이 <span>, </span> CreatorEmail <span>}); </span> res <span>.Status (201) .json (Newstudent); </span><span>} catch (오류) { </span> <span>res.status (500) .json ({error : (오류) .message}); </span><span>} </span><span>} </span> <span>// 모든 학생들을 가져 오십시오 </span><span>비동기 기능 FetchStudents (Req : request, res : response) : 약속 <void> { </void></span><span>노력하다 { </span><span>const {email} = req.params; </span> <span>const ispermitted = jebusertopermitstudents (이메일, "읽기", "학생"); </span><span>if (! IsPermitted) { </span> <span>res.status (403) .json ({메시지 : '승인되지 않음'}); </span><span>반품; </span><span>} </span> <span>Const 학생 = FetchStudentsffromdb ()를 기다립니다. </span> res <span>.Status (200) .json (학생); </span><span>} catch (오류) { </span> <span>res.status (500) .json ({error : (오류) .message}); </span><span>} </span><span>}</span>
이 파일은 학생들을 만들고 가져 오는 컨트롤러를 정의하고 데이터베이스와 통합하고 권한 수표에 대한 허가를받습니다. CreateStudent 컨트롤러는 입력을 검증하고 권한을 확인하며 새로운 학생을 생성하는 반면 FetchStudents 컨트롤러는 액세스를 확인한 후 모든 학생을 검색합니다. 두 컨트롤러 모두 오류를 처리하고 적절한 응답을 반환합니다.
- profile.ts 파일을 만들고 다음 코드를 붙여 넣습니다.
<span>'@/models/profile'에서 {profile} 가져 오기; </span><span>'axios'에서 axios 가져 오기; </span><span>'../config/appwrite'에서 {database, id, query} import; </span><span>'express'에서 가져 오기 {request, response, nextfunction, requestHandler}; </span><span>'../config/environment'에서 {permit_api_key} 가져 오기; </span> <span>const profileid = process.env.appwrite_profile_collection_id로 문자열로; // 이것이 .env에 있는지 확인하십시오 </span><span>const databaseid = process.env.appwrite_database_id로 문자열로; // 이것이 .env에 있는지 확인하십시오 </span><span>const projectid = process.env.permit_project_id로 문자열로 </span><span>const 환경 = process.env.permit_env_id로 문자열로 </span> <span>const permit_api_url = <span>`https://api.permit.io/v2/facts/ <span>$ {projectId}</span> / <span>$ {환경}</span> /users`</span> ; </span><span>const permit_auth_header = { </span> 권한 부여 <span>: <span>`bearer <span>$ {permit_api_key}</span> `</span> , </span><span>"Content-Type": "Application/JSON", </span><span>}; </span> <span>// 프로필 컨트롤러를 만듭니다 </span><span>consteprofile을 내보내기 : requestHandler = async (req : request, res : response, next : nextfunction) : promise <void> => { </void></span><span>const {firstName, lastName, 이메일, 역할, userId} = req.body; </span><span>Console.log (Req.body); </span> <span>if (! 이메일 ||! 역할 ||! userId) { </span> res <span>.status (400) .json ({error : 'firstName, lastName, 이메일, 역할 및 userID가 필요합니다.'}); </span><span>반품; </span><span>} </span> <span>// 역할을 확인합니다 </span><span>const allendroles : profile [ 'role'] [] = [ 'admin', '교사', '학생']; </span><span>if (! enlodroles.includes (역할)) { </span> res <span>.Status (400) .json ({오류 : '유효하지 않은 역할. 허용 된 역할 : 관리자, 교사, 학생'}); </span><span>반품; </span><span>} </span> <span>노력하다 { </span><span>const newUser = AWAIT Database.CreatEdocument ( </span> Databaseid <span>, </span> profileId <span>, </span><span>id.unique (), </span><span>{FirstName, LastName, 이메일, 역할, userID} </span><span>); </span><span>// 2 단계 : 사용자가 sync onecmit.io를 동기화합니다 </span><span>const permitpayload = { </span> 키 <span>: 이메일, </span> <span>이메일 </span> First_Name <span>: FirstName, </span> last_name <span>: lastname, </span> role_Assignments <span>: [{역할, 임차인 : "기본값"}], </span><span>}; </span> <span>PermitReponse를하자; </span><span>노력하다 { </span><span>const response = await ac </span> permitResponse <span>= response.data; </span><span>console.log ( "user synced to permit.io :", permitRepresponse); </span><span>} catch (permitError) { </span><span>if (axios.isaxioserror (permiterRor)) { </span><span>console.error ( "rectim.io를 동기화하지 못했습니다. </span><span>} 또 다른 { </span><span>console.error ( "recmit.io를 동기화하지 못했습니다 :", cermiterRor); </span><span>} </span> permitResponse <span>= {error : "permit.io와 동기화하지 못했습니다"}; </span><span>} </span> <span>// 3 단계 : 두 응답을 모두 반환합니다 </span> <span>res.status (201) .json ({{ </span> 메시지 <span>: "사용자 프로필이 성공적으로 생성", </span> 사용자 <span>: Newuser, </span> 허가 <span>: CermitRepponse, </span><span>}); </span><span>반품; </span><span>} catch (오류 : Any) { </span> res <span>.status (500) .json ({성공 : false, message : error.message}); </span><span>반품; </span><span>} </span><span>}; </span> <span>// 이메일로 프로필을 가져옵니다 </span><span>내보내기 const getProfileByemail = async (req : request, res : responce, nextfunction) : 약속 <void> => { </void></span><span>const {email} = req.params; </span> <span>if (! 이메일) { </span> <span>res.status (400) .json ({error : '이메일이 필요합니다.'}); </span><span>반품; </span><span>} </span> <span>노력하다 { </span><span>const profile = database.listDocuments ( </span> Databaseid <span>, </span> profileId <span>, </span><span>[query.eartal ( "이메일", 이메일)] </span><span>); </span> <span>if (profile.documents.length === 0) { </span> <span>res.status (404) .json ({error : 'profile found'}); </span><span>반품; </span><span>} </span> <span>res.status (200) .json ({성공 : true, profile : profile.documents [0]}); </span><span>} catch (오류 : Any) { </span><span>console.error ( '오류 페치 프로파일 :', 오류); </span> res <span>.status (500) .json ({성공 : false, message : error.message}); </span><span>} </span><span>};</span>
이 파일은 데이터베이스 작업을 위해 AppWrite와 통합 및 역할 동기화 허가를 통합하여 사용자 프로파일을 작성하고 가져 오기위한 컨트롤러를 정의합니다. CreateProfile 컨트롤러는 입력을 확인하고 프로필을 작성하며 사용자가 허용하도록 동기화하는 반면 GetProfileByemail 컨트롤러는 이메일로 프로필을 검색합니다. 두 컨트롤러 모두 오류를 처리하고 적절한 응답을 반환합니다.
- 구성 폴더
- AppWrite.ts 파일을 만들고 다음 코드를 붙여 넣습니다.
<span>import {클라이언트, 계정, 데이터베이스, 스토리지, ID, 권한, 역할, 쿼리}; </span><span>import {appwrite_endpoint, appwrite_project_id, appwrite_api_key} from './environment'; </span> <span>// AppWrite 클라이언트를 초기화합니다 </span><span>const client = new Client () </span><span>.setendpoint (appwrite_endpoint) // appwrite endpoint </span><span>.SetProject (AppWrite_Project_id); // AppWrite Project ID </span> <span>// 사용 가능한 경우 API 키 추가 (서버 측 작업의 경우) </span><span>if (appwrite_api_key) { </span><span>(클라이언트) .config.key = appwrite_api_key; // API 키를 설정하려는 해결 방법 </span><span>} </span> <span>// appwrite 서비스 초기화 </span><span>const 계정 = 새 계정 (클라이언트); </span><span>const 데이터베이스 = 새 데이터베이스 (클라이언트); </span><span>const Storage = 새로운 스토리지 (클라이언트); </span> <span>// appwrite 클라이언트 및 서비스를 내보내십시오 </span><span>내보내기 {클라이언트, 계정, 데이터베이스, 스토리지, ID, 권한, 역할, 쿼리};</span>
이 파일은 Project Endpoint, ID 및 옵션 API 키로 AppWrite 클라이언트를 초기화하고 구성합니다. 또한 ID, 권한, 역할 및 쿼리와 같은 유틸리티 상수와 함께 계정, 데이터베이스 및 스토리지와 같은 AppWrite 서비스를 설정하고 내 보냅니다.
- Environment.ts 파일을 작성하고 다음 코드를 붙여 넣습니다.
<span>'dotenv'에서 dotenv 가져 오기; </span>dotenv <span>.config (); // .env에서 환경 변수를로드합니다 </span> <span>const appwrite_endpoint = process.env.appwrite_endpoint || 내보내기 '';; </span><span>내보내기 const permit_api_key = process.env.permit_api_key || '';; </span><span>내보내기 const permit_project_id = process.env.permit_project_id || '';; </span><span>내보내기 const permit_env_id = process.env.permit_env_id || '';; </span><span>내보내기 const appwrite_project_id = process.env.appwrite_project_id || '';; </span><span>const database_id = process.env.appwrite_database_id || 내보내기 '';; </span><span>const withy whity_collection_id = process.env.appwrite_students_collection_id ||를 내보내십시오 '';; </span><span>내보내기 const ansastments_collection_id = process.env.appwrite_assignments_collection_id || '';; </span> <span>내보내기 const profile_collection_id = process.env.appwrite_profile_collection_id || '';;</span>
이 파일은 .env 파일에서 환경 변수를로드하고 AppWrite 및 허가 구성, 데이터베이스 ID 및 수집 ID와 같은 응용 프로그램에서 사용하기위한 상수로 내보내립니다. 환경 변수가 설정되지 않은 경우 기본값은 폴백으로 제공됩니다.
- API 폴더
- 학생 .ts를 만들고 다음 코드를 붙여 넣습니다.
<span>'Express'에서 Express 가져 오기; </span><span>'../controllers/student'에서 {CreateStudent, FetchStudents} import; </span><span>'../middleware/auth'에서 authmiddleware 가져 오기; </span> <span>const router = express.router (); </span> <span>// 학생 관련 엔드 포인트를 정의합니다 </span>라우터 <span>.post ( '/student', authmiddleware, createStudent); // 새로운 학생을 만듭니다 </span>라우터 <span>.get ( '/whitsing/: email', authmiddleware, fetchstudents); // 모든 학생들을 가져 오십시오 </span><span>기본 라우터 내보내기; // 라우터 인스턴스를 내보내십시오</span>
이 파일은 학생 데이터를 관리하기위한 엔드 포인트가 포함 된 Express 라우터를 설정합니다. 여기에는 새로운 학생을 만들고 인증 미들웨어 (Authmiddleware)로 보호되는 학생을위한 경로가 포함됩니다. 그런 다음 라우터가 응용 프로그램에 사용하기 위해 내보내립니다.
- Auth.ts 파일을 작성하고 다음 코드를 붙여 넣습니다.
<span>// src/loutes/authroutes.ts.ts </span><span>'Express'에서 Express 가져 오기; </span><span>'../controllers/auth'에서 가져 오기 {가입, 로그인, 로그 아웃}; </span> <span>const router = express.router (); </span> <span>// 인증 관련 엔드 포인트를 정의합니다 </span>라우터 <span>.post ( '/signup', (req, res, next) => {// 가입 경로 </span><span>가입 (req, res) .then (() => { </span><span>다음(); </span><span>}). catch ((err) => { </span><span>다음 (err); </span><span>}); </span><span>}); </span>라우터 <span>.post ( '/login', (req, res, next) => {// 로그인 경로 </span><span>로그인 (req, res) .then (() => { </span><span>다음(); </span><span>}). catch ((err) => { </span><span>다음 (err); </span><span>}); </span><span>}); </span>라우터 <span>.post ( '/logout', 로그 아웃); // 로그 아웃 경로 </span><span>기본 라우터 내보내기; // 라우터 인스턴스를 내보내십시오</span>
이 파일은 사용자 가입, 로그인 및 로그 아웃을 포함하여 인증 관련 작업을위한 엔드 포인트가있는 Express 라우터를 설정합니다. 가입 및 로그인 경로는 오류 처리로 비동기 작업을 처리하는 반면 로그 아웃 경로는 간단합니다. 라우터는 응용 프로그램에 사용하기 위해 내보내집니다.
- 할당을 작성하고 다음 코드를 붙여 넣습니다.
<span>"Express"에서 Express 가져 오기 </span><span>"../controllers/assignment"에서 {createAssignment, fetchassignments} import </span><span>"../middleware/auth"에서 authmiddleware 가져 오기 </span> <span>const router = express.router () </span> 라우터 <span>.post ( "/create", authmiddleware, createAssignment) </span>라우터 <span>.get ( "/: email", authmiddleware, fetchassignments) </span><span>기본 라우터 내보내기</span>
이 파일은 할당을 관리하기위한 엔드 포인트가 포함 된 Express 라우터를 설정합니다. 여기에는 Authentication Middleware (Authmiddleware)에 의해 보호되는 과제 및 가져 오기 할당을위한 경로가 포함됩니다. 라우터는 응용 프로그램에 사용하기 위해 내보내집니다.
- profile.ts 파일을 만들고 다음 코드를 붙여 넣습니다.
<span>'Express'에서 Express 가져 오기; </span><span>'../controllers/profile'에서 {createprofile, getProfileByemail}; </span><span>'../middleware/auth'에서 authmiddleware 가져 오기; </span> <span>const router = express.router (); </span> <span>// 프로파일 생성 경로 </span>라우터 <span>.post ( '/profile', authmiddleware, createprofile); </span> <span>// Route for getting a profile by email </span>router <span>.get('/profile/:email', authMiddleware, getProfileByEmail); </span><span>export default router;</span>
This file sets up an Express router with endpoints for managing user profiles. It includes routes for creating a profile and fetching a profile by email, both protected by an authentication middleware (authMiddleware). The router is exported for use in the application.
- Create index.ts file and paste the following code:
<span>import express, { Request, Response } from 'express'; </span><span>import dotenv from 'dotenv'; </span><span>import cors from 'cors'; // CORS middleware </span><span>import authRoutes from './auth'; // Import auth routes </span><span>import profileRoutes from './profile'; </span><span>import studentRoutes from './student'; </span><span>import assignmentRoutes from './assignment'; </span><span>import { errorHandler } from '../utils/errorHandler'; // Custom error handler middleware </span> dotenv <span>.config(); // Load environment variables from .env file </span> <span>const app = express(); </span><span>const PORT = process.env.PORT || 8080; </span> <span>// Middleware </span>app <span>.use(cors()); // Handle CORS </span>app <span>.use(express.json()); /// Parse incoming JSON requests </span> <span>// Routes </span>app <span>.use('/api/auth', authRoutes); // Authentication routes </span>app <span>.use('/api', profileRoutes); // Profile routes mounted </span>app <span>.use('/api', studentRoutes); // Student routes mounted </span>app <span>.use('/api/assignments', assignmentRoutes); // Assignment routes mounted </span> <span>// Global Error Handling Middleware </span>app <span>.use(errorHandler); // Handle errors globally </span> <span>// Default Route </span>app <span>.get('/', (req: Request, res: Response) => { </span> res <span>.send('Appwrite Express API'); </span><span>}); </span> <span>// Start Server </span>app <span>.listen(PORT, () => { </span><span>console.log( <span>`Server is running on port <span>${PORT}</span> `</span> ); </span><span>}); </span><span>export default app;</span>
This file sets up an Express server, configuring middleware like CORS and JSON parsing, and mounts routes for authentication, profiles, students, and assignments. It includes a global error handler and a default route to confirm the server is running. The server listens on a specified port, logs its status, and exports the app instance for further use.
- Finally, to run this project, change a part of package.json and install the following packages below so when you run npm run dev, it works.
- Install packages:
npm install concurrently ts-node nodemon --save-dev
- By updating the scripts in the package.json, when you start the server, the typescript files are compiled to JavaScript in a new folder that is automatically created called dist
"scripts": { "dev": "concurrently \"tsc --watch\" \"nodemon -q --watch src --ext ts --exec ts-node src/api/index.ts\"", "build": "tsc", "start": "node ./dist/api/index.js" },
Now run npm run dev to start your server. When you see this message, it means that you have successfully implemented the backend.

Congratulations, your backend is ready for requests.
Now that our backend is set up, move on to frontend integration, where you'll:
- Secure API requests from Next.js
- Dynamically show/hide UI elements based on user permissions.
Reason for creating an extensive backend service using Appwrite
Appwrite is often described as a backend-as-a-service (BaaS) solution, meaning it provides ready-made backend functionality like authentication, database management, and storage without requiring developers to build a traditional backend.
However, for this project, I needed more flexibility and control over how data was processed, secured, and structured, which led me to create an extensive custom backend using Node.js and Express while still leveraging Appwrite's services.
Instead of relying solely on Appwrite's built-in API calls from the frontend, I designed a Node.js backend that acted as an intermediary between the frontend and Appwrite. This allowed me to:
- Implement fine-grained access control with Permit.io before forwarding requests to Appwrite.
- Structure API endpoints for multi-tenancy to ensure tenant-specific data isolation.
- Create custom business logic, such as processing role-based actions before committing them to the Appwrite database.
- Maintain a centralized API layer, making it easier to enforce security policies, log activities, and scale the application.
Appwrite provided the core authentication and database functionality of this application, but this additional backend layer enhanced security, flexibility, and maintainability, to ensure strict access control before any action reached Appwrite.
결론
That's it for part one of this article series. In part 2, we'll handle the frontend integration by setting up API calls with authorization, initializing and installing necessary dependencies, writing out the component file codes, and handling state management & routes.
위 내용은 Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.

Python은 데이터 과학 및 기계 학습에 더 적합한 반면 JavaScript는 프론트 엔드 및 풀 스택 개발에 더 적합합니다. 1. Python은 간결한 구문 및 풍부한 라이브러리 생태계로 유명하며 데이터 분석 및 웹 개발에 적합합니다. 2. JavaScript는 프론트 엔드 개발의 핵심입니다. Node.js는 서버 측 프로그래밍을 지원하며 풀 스택 개발에 적합합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

드림위버 CS6
시각적 웹 개발 도구

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

WebStorm Mac 버전
유용한 JavaScript 개발 도구
