cari
Rumahhujung hadapan webtutorial jsMembina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Saya membina aplikasi SaaS multi-penyewa berfungsi (aplikasi edTech) dengan alat teknologi harian anda dan anda boleh melakukan perkara yang sama.

Pertama, apakah aplikasi SaaS multi-penyewa?

Aplikasi Multi-penyewa SaaS membolehkan anda melayani beberapa pelanggan dari satu kod tunggal. Tetapi untuk melakukan ini, anda perlu menguruskan akses yang selamat dan khusus, dan ini boleh mencabar apabila dilakukan secara manual. Itulah sebabnya saya memutuskan untuk menggunakan permit, alat kebenaran moden yang memudahkan proses ini.

Dalam artikel ini, saya akan menunjukkan kepada anda bagaimana untuk memudahkan kebenaran untuk aplikasi SaaS anda menggunakan permit, dengan contoh langkah demi langkah membina aplikasi demo yang memaparkan pengasingan penyewa dan kawalan akses berasaskan peranan (RBAC) dengan Next.js dan Appwrite.

Apa yang seterusnya.js dan appwrite, dan mengapa kita memerlukannya?

Next.js

Next.js adalah rangka kerja berasaskan React yang menyediakan penyampaian pelayan (SSR), penjanaan tapak statik (SSG), laluan API, dan pengoptimuman prestasi keluar dari kotak.

Untuk projek ini, saya menggunakan Next.js kerana:

  • Ia membolehkan pra-rendering halaman, yang meningkatkan prestasi dan SEO.
  • Peralihan terbina dalamnya menjadikannya mudah untuk menguruskan peralihan halaman dan kandungan dinamik.
  • Ia mengintegrasikan dengan mudah dengan perkhidmatan backend seperti Appwrite dan permit.io untuk pengesahan dan kebenaran.

Appwrite

AppWrite adalah platform backend-as-a-service (BAAS) yang menyediakan pengesahan pengguna, pangkalan data, penyimpanan, dan fungsi tanpa pelayan. Menggunakan perkhidmatan seperti AppWrite menghapuskan keperluan untuk membina backend dari awal, jadi anda boleh memberi tumpuan kepada pembangunan frontend sambil mempunyai akses ke keupayaan backend.

Untuk projek ini, saya menggunakan AppWrite:

  • Untuk mengendalikan pendaftaran pengguna, log masuk, dan pengurusan sesi.
  • Untuk menyediakan pangkalan data NoSQL berstruktur untuk menyimpan data khusus penyewa.

Menggunakan Next.js dan AppWrite bersama-sama membolehkan saya membuat aplikasi SaaS multi-penyewa yang berskala tinggi sambil mengekalkan proses pembangunan yang cekap.

Pengenalan kepada Kebenaran SaaS Multi-penyewa

Aplikasi SaaS multi-penyewa adalah perisian yang berfungsi dengan pelbagai pengguna atau kumpulan pengguna, yang dipanggil penyewa, menggunakan contoh perisian tunggal aplikasi.

Maksudnya ialah dalam seni bina SaaS multi-penyewa, pelbagai pelanggan (penyewa) berkongsi infrastruktur aplikasi yang sama atau menggunakan aplikasi yang sama tetapi mengekalkan pengasingan data.

Contoh praktikal ini adalah alat pengurusan projek seperti Trello.

  • Ia adalah infrastruktur tunggal yang berjalan pada pelayan bersama dan mempunyai asas yang sama untuk semua penggunanya.
  • Setiap syarikat menggunakan Trello (contohnya, Syarikat A dan Syarikat B) adalah penyewa.
  • Ia mengasingkan data:
    • Pekerja Syarikat A hanya dapat melihat projek, tugas, dan papan mereka.
    • Pekerja Syarikat B tidak dapat mengakses atau melihat data Syarikat A, dan sebaliknya.

Ini memastikan bahawa walaupun sumber dikongsi, data dan aktiviti setiap penyewa adalah swasta dan selamat.

Dalam aplikasi multi-penyewa, walaupun dalam penyewa, sesetengah pengguna akan mempunyai akses yang lebih tinggi kepada beberapa maklumat, sementara sesetengah ahli akan terhad kepada sumber tertentu.

Kebenaran dalam aplikasi tersebut mesti:

  • Memastikan pengguna tidak dapat mengakses data atau sumber pelanggan penyewa atau pelanggan. Ini dipanggil penyewa mengasingkan.
  • Memastikan pengguna dalam penyewa boleh mengakses hanya sumber yang dibenarkan oleh peranan mereka dengan menyediakan kawalan akses berbutir.
  • Mengendalikan lebih banyak pengguna, penyewa, dan peranan tanpa melambatkan atau merendahkan prestasi.

Kepentingan Pengasingan Penyewa dan Kawalan Akses Granular

Pengasingan penyewa menyimpan data dengan selamat dengan memastikan bahawa setiap maklumat pelanggan tetap peribadi. Walaupun kawalan akses granular memastikan pengguna dalam organisasi hanya mendapatkan kebenaran yang mereka perlukan.

Melaksanakan kebenaran dalam aplikasi SaaS anda boleh menjadi rumit dan rumit, tetapi ia tidak perlu apabila anda mempunyai alat kebenaran seperti permit.

Apakah permit, dan apakah faedahnya?

Permit adalah alat kebenaran yang mudah digunakan untuk menguruskan akses dalam sebarang aplikasi, termasuk aplikasi multi-penyewa. Menggunakan permit.io dalam aplikasi anda membolehkan anda dengan mudah menentukan dan memberikan peranan dengan keizinan khusus untuk kawalan akses dalam permohonan anda. Selain daripada membuat peranan dalam aplikasi, anda juga boleh menambah syarat dan peraturan berdasarkan atribut pengguna atau sumber untuk menentukan apa yang setiap pengguna boleh dan tidak boleh lakukan.

Sekarang bahawa anda tahu sebahagian besar daripada apa yang anda perlu tahu mengenai permit dan faedahnya, mari masuk ke dalam perjanjian utama -membina aplikasi SaaS dengan Next.js dan mengintegrasikan permit untuk kebenaran.

Untuk menunjukkan kuasa permit, kami akan membina platform edtech SaaS multi-penyewa.

Membina platform EDTech SaaS melibatkan beberapa cabaran, termasuk pengesahan pengguna, kawalan akses berasaskan peranan (RBAC), dan multi-tenancy. Kami akan menggunakan Next.js untuk Frontend, AppWrite untuk Pengesahan dan Pengurusan Pangkalan Data, dan membenarkan kebenaran halus.

Gambaran Keseluruhan Stack Tech

Technologypurposenext.jsfrontend frameworkshadcn tailwindcssui komponen dan stylingzustandstate ManagementAppwriteAuthentication & backendpermit.iorole berasaskan akses

Senibina Sistem

Aplikasi ini mengikuti pendekatan backend-pertama:

  1. Backend (Node.js Express)
    • Mengendalikan permintaan API dan logik perniagaan.
    • Menggunakan AppWrite untuk Pengesahan dan Pengurusan Pangkalan Data.
    • Permit membenarkan kebenaran, menentukan peranan dan keizinan.
    • Memastikan setiap permintaan disahkan sebelum akses data.
  2. Frontend (Next.js)
    • Menghubungkan ke backend untuk mengambil data dengan selamat.
    • Menggunakan rendering UI berasaskan peranan, yang bermaksud pengguna hanya melihat apa yang mereka dibenarkan untuk mengakses.
    • Mengehadkan tindakan (seperti membuat tugasan) berdasarkan keizinan.

Dengan menguatkuasakan kebenaran di peringkat API, kami memastikan pengguna tidak dapat memintas sekatan, walaupun mereka memanipulasi frontend.

Pada akhir panduan ini, anda akan mempunyai aplikasi edtech SaaS multi-penyewa yang berfungsi sepenuhnya, di mana:

  • Pentadbir boleh menambah dan melihat pelajar.
  • Guru boleh menambah dan melihat pelajar, serta membuat tugasan.
  • Pelajar hanya boleh melihat kursus kursus mereka.

Artikel ini menyediakan pecahan langkah demi langkah bagaimana saya melaksanakan permit untuk mengendalikan kebenaran untuk membina projek ini, jadi ikuti dan membina anda.

Pelaksanaan backend dengan permit

Untuk menguatkuasakan kawalan akses berasaskan peranan (RBAC) dan pengasingan penyewa, kita perlu:

  1. Sediakan permit dan tentukan peranan, penyewa, dan dasar.
  2. Mengintegrasikan permit di backend (Node.js Express).
  3. Melindungi laluan API menggunakan middleware yang memeriksa kebenaran sebelum membenarkan permintaan.

Mari pergi langkah demi langkah.

1. Menyediakan permit

Sebelum menulis sebarang kod, anda perlu

  • Buat akaun pada permit.
Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Anda akan dibentangkan dengan onboarding, tetapi sebaik sahaja anda memasukkan nama organisasi anda, anda hanya boleh melangkau persediaan.

  • Buat sumber dan tindakan

Navigasi ke bahagian dasar, di mana anda akan membuat sumber dan tindakan yang boleh anda lakukan pada sumber itu.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Sebaik sahaja anda selesai membuat sumber anda, ia sepatutnya kelihatan seperti ini:

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)
  • Mewujudkan peranan

Selepas membuat sumber, navigasi ke halaman Peranan menggunakan tab Peranan. Anda akan melihat bahawa beberapa peranan telah diberikan secara automatik.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Padamkan peranan tersebut dan buat peranan baru. Setiap peranan akan mempunyai peraturan khusus yang berkaitan dengannya, tentang apa yang pengguna boleh dan tidak boleh lakukan. Buat peranan pentadbir terlebih dahulu, kerana ia kemudiannya berfungsi sebagai blok bangunan untuk keadaan RBAC. Klik butang Tambah Peranan di bahagian atas dan buat peranan.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Apabila anda selesai membuat peranan anda, ia sepatutnya kelihatan seperti ini:

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Hebat!

Sekarang bahawa anda telah mencipta sumber dan peranan anda, kini anda boleh mengkonfigurasi keizinan dalam editor dasar.

  • Mengkonfigurasi Kebenaran dalam Editor Dasar

Kembali ke Editor Dasar dan inilah peranan yang akan kelihatan seperti sekarang, dengan setiap sumber individu yang ditakrifkan dan tindakan yang boleh anda pilih. Anda kini bersedia untuk memberikan keizinan kepada peranan untuk melaksanakan tindakan yang dipilih di sumber.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Apabila anda selesai memilih tindakan untuk setiap peranan, klik butang Simpan Perubahan di sebelah kanan bawah halaman.

  • Salin kekunci API

Akhirnya, untuk menggunakan PDP awan permit, anda akan memerlukan kunci API persekitaran semasa anda. Untuk projek ini, anda akan menggunakan kunci persekitaran pembangunan. Teruskan ke tetapan dan klik kekunci API, tatal ke Kunci API Alam Sekitar, klik "Mendedahkan Kekunci," kemudian salinnya.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Selepas menubuhkan papan pemuka permit anda, kini anda boleh beralih ke backend anda.

2. Memasang kebergantungan

Untuk memulakan, anda perlu memasang Node.js pada komputer anda. Setelah memastikan Node.js dipasang pada sistem anda, ikuti langkah -langkah ini:

  • Mulakan dengan membuat projek baru menggunakan arahan berikut:
 mkdir backend
cd backendnpm init -y
  • Kemudian, pasang pakej berikut:
 NPM Pasang Ekspres Dotenv Permitio Cors Appwwrite Axios JsonWebtoken
  • Konfigurasikan permit di Express. Dalam fail .env anda, simpan kekunci API anda:
 Permit_api_key = anda-permit-key-you-copied-earlier

3. Menyediakan AppWrite

  • Pergi ke AppWrite dan buat projek baru dengan memasukkan nama projek dan memilih rantau. Perhatikan ID projek dan titik akhir API anda; Itulah yang anda akan masukkan sebagai nilai dalam fail .env anda. Fail Env anda sepatutnya kelihatan seperti ini:
 Permit_api_key = anda-permit-key-you-copied-earlier
Appwrite_endpoint = https: //cloud.appwrite.io/v1
Appwrite_project_id = your-project-id
  • Sekarang teruskan ke pangkalan data untuk membuat pangkalan data anda, kemudian salin ID pangkalan data anda untuk menampalnya ke dalam fail ENV anda.
Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Fail env anda kini kelihatan seperti ini:

 Permit_api_key = anda-permit-key-you-copied-earlier
Appwrite_endpoint = https: //cloud.appwrite.io/v1
Appwrite_project_id = your-project-id
Appwrite_database_id = anda-data-id

Sekarang buat koleksi berikut dalam pangkalan data AppWrite dengan atribut berikut:

  • Koleksi Profil
Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)
  • Koleksi Pelajar
Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)
  • Koleksi tugasan
Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)

Apa fail env anda kelihatan seperti pada ketika ini:

 Permit_api_key = anda-permit-key-you-copied-earlier
Omment_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 = anda-data-id
Appwrite_profile_collection_id = your-id
Appwrite_assignments_collection_id = your-id
Appwrite_students_collection_id = your-id
Jwt_secret = penjana-ini-by-running // openssl rand -base64 16
Port = 8080

4. Buat struktur dan fail fail

Sekarang buat folder SRC dalam akar fail. Kemudian menghasilkan fail tsconfig.json dalam folder root dan tampal kod berikut ke dalamnya:

 <span>{
</span><span>"CompilerOptions": {
</span><span>"Sasaran": "ES6",
</span><span>"Modul": "Commonjs",
</span><span>"Outhir": "./dist",
</span><span>"EsmoduleInterop": Benar,
</span><span>"ForceConsistentCasingInfileNames": Benar,
</span><span>"ketat": benar,
</span><span>"Skiplibcheck": Benar,
</span><span>"ResolveJsonModule": Benar,
</span><span>"BaseUrl": "./",
</span><span>"jalan": {
</span><span>"@/*": ["src/*"]
</span><span>}
</span><span>},
</span><span>"Sertakan": ["src/**/*"],
</span><span>"tidak termasuk": ["node_modules", "dist"]
</span><span>}</span>

Tsconfig.json ini mengkonfigurasi pengkompil TypeScript untuk menyasarkan ES6, menggunakan modul CommonJS, dan output fail ke ./dist. Ia menguatkuasakan pemeriksaan jenis yang ketat, membolehkan resolusi modul JSON, menetapkan alias jalan untuk SRC, dan tidak termasuk node_modules dan dist dari kompilasi.

Di dalam folder SRC, buat folder berikut: API, Config, Controllers, Middleware, Model, dan Utils.

  • Util Folder
    • Sekarang, buat fail permit baru dalam projek folder utils untuk memulakan permit menggunakan kod berikut:
 <span>import {permit} dari 'permitio';
</span><span>import {permit_api_key} dari '../config/environment';
</span><span>// Baris ini memulakan SDK dan menghubungkan aplikasi Node.js anda
</span><span>// ke kontena PDP permit.io yang telah anda sediakan dalam langkah sebelumnya.
</span><span>permit const = permit baru ({
</span><span>// Kunci API anda
</span> token <span>: permit_api_key, // simpan kekunci API anda di .env
</span><span>// dalam pengeluaran, anda mungkin perlu menukar URL ini agar sesuai dengan penggunaan anda
</span> PDP <span>: 'https://cloudpdp.api.permit.io', // url pdp permit lalai
</span><span>// Jika anda mahu SDK memancarkan log, uncomment ini:
</span> log <span>: {
</span> Tahap <span>: "Debug",
</span><span>},
</span><span>// SDK mengembalikan palsu jika anda mendapat ralat masa tamat / rangkaian
</span><span>// Jika anda mahu ia membuang kesilapan, dan biarkan anda mengendalikan ini, uncomment ini:
</span><span>// lemparonerror: benar,
</span><span>});
</span>
<span>Permit lalai eksport;</span>

Fail ini memulakan SDK Permit untuk Node.js, menyambungkannya ke kontena PDP permit menggunakan kunci API yang disimpan di alam sekitar. Ia mengkonfigurasi pembalakan untuk menyahpepijat dan menetapkan SDK untuk mengendalikan kesilapan secara senyap -senyap kecuali dikonfigurasi secara eksplisit untuk membuangnya.

  • Seterusnya, buat fail yang dipanggil errorhandler.ts dan tampal kod berikut:
 <span>// fungsi utiliti (contohnya, pengendalian ralat)
</span><span>import {permintaan, respons, NextFunction} dari 'Express';
</span>
<span>Export const errorHandler = (err: any, req: request, res: response, next: nextfunction) => {
</span><span>console.error ('Ralat:', err.message || err);
</span> res <span>.status (err.status || 500) .json ({
</span> Ralat <span>: err.message || 'Ralat pelayan dalaman',
</span><span>});
</span><span>};</span>

Fail ini mentakrifkan middleware pengendalian ralat Express yang merumuskan kesilapan dan menghantar respons JSON dengan mesej ralat dan kod status. Ia mungkir kepada kod status 500 jika tiada status tertentu disediakan.

  • Folder Model
    • Buat fail yang dipanggil profil.ts dan tampal kod berikut:
 <span>profil antara muka eksport {
</span> Nama <span>: String;
</span> E -mel <span>: String;
</span> Peranan <span>: 'Admin' | 'Guru' | 'Pelajar';
</span> UserId <span>: String;
</span><span>}</span>

Fail ini mentakrifkan antara muka profil TypeScript dengan sifat untuk nama, e -mel, peranan, dan userid, di mana peranan terhad kepada nilai tertentu: admin, guru, atau pelajar.

  • Buat fail tugasan.ts dan tampal kod berikut:
 <span>import {pangkalan data, id} dari '../config/appwrite';
</span><span>import {database_id, tugasan_collection_id} dari '../config/environment';
</span>
<span>Tugasan Antara Muka EksportData {
</span> Tajuk <span>: String;
</span> Subjek <span>: String;
</span> ClassName <span>: String;
</span> Guru <span>: String;
</span> Duedate <span>: String;
</span> Pencipta <span>: String;
</span><span>}
</span>
<span>// Buat tugasan baru
</span><span>Eksport fungsi async createAsSignmentIndb (data: tugasanData) {
</span><span>pulangan menunggu pangkalan data.createdocument (
</span><span>Pangkalan data_id,
</span><span>Tugasan_collection_id,
</span><span>Id.unique (),
</span>   data
<span>);
</span><span>}
</span>
<span>// Ambil semua tugasan
</span><span>Eksport fungsi async fetchassignmentsFromdb () {
</span><span>Const Response = Await Database.ListDocuments (Database_ID, Tugasan_Collection_ID);
</span><span>pulangan respons.documents;
</span><span>}</span>

Fail ini menyediakan fungsi untuk berinteraksi dengan pangkalan data AppWrite untuk menguruskan tugasan. Ia mentakrifkan antara muka TugasanData dan termasuk fungsi untuk membuat tugasan baru dan mengambil semua tugasan dari pangkalan data.

  • Buat fail Student.ts dan tampal kod berikut:
 <span>import {pangkalan data, id, kebenaran, peranan, pertanyaan} dari '../config/appwrite';
</span><span>import {database_id, students_collection_id} dari '../config/environment';
</span>
<span>Pelajar Antara Muka Eksport {
</span> Name FirstName <span>: String;
</span> LastName <span>: String;
</span> Jantina <span>: 'Girl' | 'Boy' | 'Boy' | 'Girl';
</span> ClassName <span>: String;
</span> Umur <span>: Nombor;
</span> Pencipta <span>: String;
</span><span>}
</span>
<span>// Buat pelajar baru
</span><span>Eksport fungsi async createstudentindb (data: studentData) {
</span><span>pulangan menunggu pangkalan data.createdocument (
</span><span>Pangkalan data_id,
</span><span>Pelajar_collection_id,
</span><span>Id.unique (),
</span> data <span>,
</span><span>[
</span> Kebenaran <span>. Bacalah (Role.any ()), // Kebenaran membaca awam
</span><span>]
</span><span>);
</span><span>}
</span>
<span>// Ambil semua pelajar
</span><span>Eksport fungsi async fetchstudentsFromdb () {
</span><span>Const response = menunggu pangkalan data.ListDocuments (Database_ID, Students_Collection_ID);
</span><span>pulangan respons.documents;
</span><span>}</span>

Fail ini menyediakan fungsi untuk menguruskan data pelajar dalam pangkalan data AppWrite. Ia mentakrifkan antara muka PelajarData dan termasuk fungsi untuk membuat pelajar baru dengan kebenaran membaca awam dan mengambil semua pelajar dari pangkalan data.

  • Folder middleware
    • Buat fail Auth.ts dan tampal kod berikut:
 <span>import {permintaan, respons, NextFunction} dari 'Express';
</span><span>Import JWT dari 'JsonWebtoken';
</span>
<span>// melanjutkan jenis permintaan untuk memasukkan 'pengguna'
</span><span>Interface AuthenticateRequest memanjangkan permintaan {
</span> pengguna <span>?: {
</span>  ID <span>: String;
</span>  Peranan <span>: String;
</span><span>};
</span><span>}
</span>
<span>const AuthMidDleWare = (Req: AuthenticatedRequest, Res: Response, Next: NextFunction): void => {
</span><span>const token = req.headers.Authorization? .split ('') [1];
</span>
<span>jika (token) {
</span>  res <span>.Status (401) .json ({error: 'Unavorized. Tidak ada token yang disediakan'});
</span><span>kembali
</span><span>}
</span>
<span>Cuba {
</span><span>const decoded = jwt.verify (token, process.env.jwt_secret!) sebagai {id: string; Peranan: String};
</span>  req <span>.User = decoded;
</span><span>seterusnya ();
</span><span>} menangkap (ralat) {
</span>  res <span>.status (403) .json ({error: 'token tidak sah'});
</span><span>kembali
</span><span>}
</span><span>};
</span>
<span>Eksport lalai authmiddleware;</span>


Fail ini mentakrifkan middleware ekspres untuk pengesahan berasaskan JWT. Ia menyemak token yang sah di tajuk permintaan, mengesahkannya menggunakan kunci rahsia, dan melampirkan maklumat pengguna (ID dan peranan) yang diterangkan ke objek permintaan. Jika token hilang atau tidak sah, ia mengembalikan tindak balas ralat yang sesuai.

  • Buat permit.ts dan tampal kod berikut:
 <span>permit import dari '../utils/permit';
</span>
<span>Eksport Const CheckUserToperSmitStudents = Async (E -mel: String, Tindakan: String, Sumber: String): Janji <boolean> => {
</boolean></span><span>Cuba {
</span><span>const dibenarkan = menunggu permit.check (e -mel, tindakan, sumber);
</span><span>console.log ("dibenarkan", dibenarkan);
</span><span>pulangan yang dibenarkan;
</span><span>} menangkap (ralat) {
</span><span>console.error ( <span>`penyegerakan error <span>$ {email}</span> ke permit.io:`</span> , error);
</span><span>kembali palsu;
</span><span>}
</span><span>};
</span>
<span>Eksport Const CheckUserToperMitassignment = Async (Email: String, Tindakan: String, Sumber: String): Janji <boolean> => {
</boolean></span><span>Cuba {
</span><span>const dibenarkan = menunggu permit.check (e -mel, tindakan, sumber);
</span><span>console.log ("dibenarkan", dibenarkan);
</span><span>pulangan yang dibenarkan;
</span><span>} menangkap (ralat) {
</span><span>console.error ( <span>`penyegerakan error <span>$ {email}</span> ke permit.io:`</span> , error);
</span><span>kembali palsu;
</span><span>}
</span><span>};</span>

Fail ini mentakrifkan fungsi utiliti, CheckUserToperStudents dan CheckUserToperMitassignment, untuk memeriksa kebenaran pengguna dalam permit untuk tindakan dan sumber tertentu. Kedua -dua fungsi mengendalikan kesilapan dengan anggun, isu pembalakan dan kembali palsu jika cek kebenaran gagal. Mereka digunakan untuk menguatkuasakan kebenaran dalam permohonan itu.

  • Folder pengawal
    • Buat fail Auth.ts dan tampal kod berikut:
 <span>import {akaun, id} dari '../config/appwrite';
</span><span>import {permintaan, respons} dari 'Express';
</span><span>Import JWT dari 'JsonWebtoken';
</span>
<span>const jwt_secret = process.env.jwt_secret sebagai string; // Pastikan ini ditetapkan dalam fail .env anda
</span>
<span>// pengawal pendaftaran
</span><span>Eksport const signup = async (req: permintaan, res: respons) => {
</span><span>const {email, kata laluan, nama} = req.body;
</span>
<span>jika (! e -mel ||! kata laluan || name) {
</span><span>kembali res.status (400) .json ({error: 'Nama, e -mel, dan kata laluan diperlukan.'});
</span><span>}
</span>
<span>Cuba {
</span><span>const user = menunggu akaun.create (id.unique (), e -mel, kata laluan, nama);
</span><span>// menjana jwt
</span><span>const token = jwt.sign ({email}, jwt_secret, {extiresin: '8h'});
</span>   Res <span>.cokie ('token', token, {
</span>    httponly <span>: benar,
</span>    Samesite <span>: 'ketat',
</span>    selamat <span>: benar,
</span><span>});
</span>
  res <span>.status (201) .json ({kejayaan: benar, pengguna, token});
</span><span>} menangkap (ralat: mana -mana) {
</span><span>Console.error ('Ralat pendaftaran:', ralat);
</span>  res <span>.status (500) .json ({kejayaan: palsu, mesej: error.message});
</span><span>}
</span><span>};
</span>
<span>// Pengawal Log masuk
</span><span>Eksport Const Login = Async (Req: Permintaan, Res: Response) => {
</span><span>const {email, kata laluan} = req.body;
</span>
<span>jika (! e -mel ||! kata laluan) {
</span><span>kembali res.status (400) .json ({error: 'e -mel dan kata laluan diperlukan.'});
</span><span>}
</span>
<span>Cuba {
</span><span>sesi const = menunggu akaun.CreateEmailPassWordSession (e -mel, kata laluan);
</span>
<span>// menjana jwt tanpa peranan
</span><span>const token = jwt.sign (
</span><span>{userid: session.userid, e -mel}, // tidak ada peranan yang disertakan
</span><span>Jwt_secret,
</span><span>{Expiresin: '8H'}
</span><span>);
</span>
  Res <span>.cokie ('token', token, {
</span>   httponly <span>: benar,
</span>   Samesite <span>: 'ketat',
</span>   selamat <span>: benar,
</span><span>});
</span>
  res <span>.status (200) .json ({kejayaan: benar, token, sesi});
</span><span>} menangkap (ralat: mana -mana) {
</span><span>console.error ('ralat login:', ralat);
</span>  res <span>.status (401) .json ({kejayaan: palsu, mesej: error.message});
</span><span>}
</span><span>};
</span>
<span>// Pengawal Logout
</span><span>Eksport const logout = async (req: request, res: response) => {
</span><span>Cuba {
</span><span>menunggu akaun.deletession ('ID sesi semasa');
</span>  res <span>.clearCookie ('token');
</span>  res <span>.status (200) .json ({kejayaan: benar, mesej: 'Log keluar dengan jayanya'});
</span><span>} menangkap (ralat: mana -mana) {
</span><span>console.error ('ralat logout:', ralat);
</span>  res <span>.status (500) .json ({kejayaan: palsu, mesej: error.message});
</span><span>}
</span><span>};</span>

Fail ini mentakrifkan pengawal pengesahan untuk pendaftaran, log masuk, dan logout, mengintegrasikan dengan AppWrite untuk Pengurusan Pengguna dan JWT untuk pengendalian sesi. Pengawal pendaftaran dan log masuk mengesahkan input, membuat sesi pengguna, dan menghasilkan JWTS, manakala pengawal logout membersihkan sesi dan token. Semua pengawal mengendalikan kesilapan dan mengembalikan respons yang sesuai.

  • Buat fail tugasan.ts dan tampal kod berikut:
 <span>import {permintaan, respons} dari 'Express';
</span><span>import {createAsSignmentIndb, tugasanData, fetchassignmentsFromdb} dari '../models/assignment';
</span><span>import {checkusertopermitassignment} dari '../middleware/permit';
</span>
<span>// Buat tugasan baru
</span><span>Eksport Async Function CreateAsSignment (Req: Request , res: response): Janji <void> {
</void></span><span>Cuba {
</span><span>const {title, subjek, guru, classname, duedate, createoremail}: tugasandata = req.body;
</span>
<span>const ispermitted = menunggu checkUserTopermitAssignment (createoremail, "create", "tugasan");
</span><span>jika (! ispermitted) {
</span>      res <span>.status (403) .json ({error: 'tidak diberi kuasa'});
</span><span>kembali;
</span><span>}
</span>
<span>const newassignment = menunggu createAsSignmentIndb ({
</span>      tajuk <span>,
</span>      subjek <span>,
</span>      guru <span>,
</span>      nama kelas <span>,
</span>      Duedate <span>,
</span>      Pencipta
<span>});
</span>
<span>Console.log ('Tugasan Baru Dibuat:', Newassignment);
</span>
    Res <span>.Status (201) .Json (NewAssignment);
</span><span>} menangkap (ralat) {
</span><span>Console.error ('Ralat membuat tugasan:', ralat);
</span>    res <span>.status (500) .json ({error: (ralat sebagai mana -mana) .message});
</span><span>} 
</span><span>}
</span>
<span>// Ambil semua tugasan
</span><span>Eksport async Function fetchassignments (req: request, res: response): promise <void> {
</void></span><span>Cuba {
</span><span>const {email} = req.params;
</span> 
<span>const ispermitted = menunggu checkuserTopermitassignment (e -mel, "baca", "tugasan");
</span><span>jika (! ispermitted) {
</span>      res <span>.status (403) .json ({message: 'tidak diberi kuasa'});
</span><span>kembali;
</span><span>}
</span>
<span>tugasan const = menunggu fetchassignmentsFromdb ();
</span>    res <span>.status (200) .json (tugasan);
</span><span>} menangkap (ralat) {
</span>    res <span>.status (500) .json ({error: (ralat sebagai mana -mana) .message});
</span><span>}
</span><span>}</span>

Fail ini mentakrifkan pengawal untuk membuat dan mengambil tugasan untuk mengintegrasikan dengan pangkalan data dan permit untuk pemeriksaan kebenaran. Pengawal CreateAsSignment mengesahkan input, menyemak kebenaran, dan mewujudkan tugasan baru, sementara pengawal Fetchassignments mengambil semua tugasan selepas mengesahkan akses. Kedua -dua pengawal mengendalikan kesilapan dan mengembalikan respons yang sesuai.

  • Buat fail Student.ts dan tampal kod berikut:
 <span>import {
</span>  createstudentindb <span>,
</span>  fetchstudentsfromdb <span>,
</span>  StudentData
<span>} dari '../models/student';
</span><span>import {permintaan, respons} dari 'Express';
</span><span>import {checkusertopermitstudents} dari '../middleware/permit';
</span>
<span>Eksport fungsi async createstudent (req: permintaan, res: respons): janji <void> {
</void></span><span>Cuba {
</span><span>const {firstName, lastName, gender, classname, usia, createoremail}: studentData = req.body;
</span>
<span>jika (! ['Girl', 'Boy'] termasuk (jantina)) {
</span>      res <span>.status (400) .json ({error: 'jenis jantina tidak sah'});
</span><span>kembali;
</span><span>}
</span>
<span>const ispermitted = menunggu checkUserToperStudents (createoremail, "create", "pelajar");
</span><span>jika (! ispermitted) {
</span>      res <span>.status (403) .json ({message: 'tidak diberi kuasa'});
</span><span>kembali;
</span><span>}
</span>
<span>const newstudent = menunggu createStudentindb ({
</span>      nama pertama <span>,
</span>      nama terakhir <span>,
</span>      jantina <span>,
</span>      nama kelas <span>,
</span>      umur <span>,
</span>      Pencipta
<span>});
</span>    Res <span>.Status (201) .JSON (NewStudent);
</span><span>} menangkap (ralat) {
</span>    res <span>.status (500) .json ({error: (ralat sebagai mana -mana) .message});
</span><span>} 
</span><span>}
</span>
<span>// Ambil semua pelajar
</span><span>Eksport Fungsi Async FetchStudents (Req: Request, Res: Response): Janji <voich> {
</voich></span><span>Cuba {
</span><span>const {email} = req.params;
</span>
<span>const ispermitted = menunggu checkUserToPerMitStudents (e -mel, "baca", "pelajar");
</span><span>jika (! ispermitted) {
</span>      res <span>.status (403) .json ({message: 'tidak diberi kuasa'});
</span><span>kembali;
</span><span>}
</span>
<span>const students = menunggu fetchstudentsFromdb ();
</span>    Res <span>.Status (200) .json (pelajar);
</span><span>} menangkap (ralat) {
</span>    res <span>.status (500) .json ({error: (ralat sebagai mana -mana) .message});
</span><span>}
</span><span>}</span>

Fail ini mentakrifkan pengawal untuk membuat dan mengambil pelajar, mengintegrasikan dengan pangkalan data dan permit untuk pemeriksaan kebenaran. Pengawal Createstudent mengesahkan input, memeriksa kebenaran, dan mencipta pelajar baru, sementara pengawal perasmian mengambil semua pelajar selepas mengesahkan akses. Kedua -dua pengawal mengendalikan kesilapan dan mengembalikan respons yang sesuai.

  • Buat fail profil.ts dan tampal kod berikut:
 <span>import {profil} dari '@/model/profil';
</span><span>import axios dari 'axios';
</span><span>import {pangkalan data, id, pertanyaan} dari '../config/appwrite';
</span><span>import {permintaan, respons, NextFunction, RequestHandler} dari 'Express';
</span><span>import {permit_api_key} dari '../config/environment';
</span>
<span>const profileId = process.env.appwrite_profile_collection_id as String; // Pastikan ini ada di .env
</span><span>const databaseId = process.env.appwrite_database_id as String; // Pastikan ini ada di .env
</span><span>const projectId = process.env.permit_project_id sebagai rentetan
</span><span>const ercekneksi = process.env.permit_env_id sebagai rentetan
</span>
<span>const_api_url = <span>`https://api.permit.io/v2/facts/ <span>$ {projectId}</span> / <span>$ {EnvironmentId}</span> /users`</span> ;
</span><span>const permit_auth_header = {
</span> Kebenaran <span>: <span>`Pembawa <span>$ {permit_api_key}</span> `</span> ,
</span><span>"Jenis kandungan": "aplikasi/json",
</span><span>};
</span>
<span>// Buat pengawal profil
</span><span>Eksport Const CreateProfile: RequestHandler = Async (Req: Request, Res: Response, Next: NextFunction): Janji <void> => {
</void></span><span>const {firstName, lastName, e -mel, peranan, userId} = req.body;
</span><span>console.log (req.body);
</span>
<span>jika (! Email ||! Peranan || userId) {
</span>  res <span>.Status (400) .json ({error: 'FirstName, LastName, E -mel, Peranan, dan UserId diperlukan.'});
</span><span>kembali;
</span><span>}
</span>
<span>// Mengesahkan peranan
</span><span>const dibenarkan rroles: profil ['peranan'] [] = ['admin', 'guru', 'pelajar'];
</span><span>jika (! dibenarkanRoles.includes (peranan)) {
</span>  res <span>.status (400) .json ({error: 'peranan tidak sah yang dibenarkan peranan: admin, guru, pelajar'});
</span><span>kembali;
</span><span>}
</span>
<span>Cuba {
</span><span>const newuser = menunggu pangkalan data.createdocument (
</span>   pangkalan data <span>,
</span>   ProfileId <span>,
</span><span>Id.unique (),
</span><span>{FirstName, LastName, E -mel, Peranan, UserId}
</span><span>);
</span><span>// Langkah 2: Penyegerakan pengguna ke permit.io
</span><span>const permitpayload = {
</span>   Kunci <span>: E -mel,
</span>   e -mel <span>,
</span>   First_name <span>: NameName,
</span>   last_name <span>: lastname,
</span>   role_assignments <span>: [{role, penyewa: "lalai"}],
</span><span>};
</span>
<span>Biarkan PermitResponse;
</span><span>Cuba {
</span><span>Const response = menunggu axios.post (permit_api_url, permitpayload, {headers: permit_auth_header});
</span>   permitResponse <span>= response.data;
</span><span>console.log ("Pengguna disegerakkan ke permit.io:", permitResponse);
</span><span>} tangkapan (permitError) {
</span><span>jika (axios.isaxiosError (permitError)) {
</span><span>Console.error ("Gagal menyegerakkan pengguna ke permit.io:", permiterror.response? .data || permiterror.message);
</span><span>} else {
</span><span>Console.error ("Gagal menyegerakkan pengguna ke permit.io:", permiterror);
</span><span>}
</span>   permitResponse <span>= {error: "gagal menyegerakkan dengan permit.io"};
</span><span>}
</span>
<span>// Langkah 3: Kembalikan kedua -dua jawapan
</span>  Res <span>.Status (201) .JSON ({{
</span>   Mesej <span>: "Profil Pengguna Dibuat dengan jayanya",
</span>   Pengguna <span>: Newuser,
</span>   Permit <span>: PermitResponse,
</span><span>});
</span><span>kembali;
</span><span>} menangkap (ralat: mana -mana) {
</span>  res <span>.status (500) .json ({kejayaan: palsu, mesej: error.message});
</span><span>kembali;
</span><span>}
</span><span>};
</span>
<span>// Ambil profil melalui e -mel
</span><span>Export const getProfileBeByMail = Async (Req: Request, Res: Response, Next: NextFunction): Promise <void> => {
</void></span><span>const {email} = req.params;
</span> 
<span>jika (! e -mel) {
</span>  res <span>.status (400) .json ({error: 'e -mel diperlukan.'});
</span><span>kembali;
</span><span>}
</span>
<span>Cuba {
</span><span>Const Profil = menunggu pangkalan data.ListDocuments (
</span>   pangkalan data <span>,
</span>   ProfileId <span>,
</span><span>[Query.equal ("e -mel", e -mel)]
</span><span>);
</span>
<span>jika (profil.documents.length === 0) {
</span>   res <span>.status (404) .json ({error: 'profil tidak dijumpai'});
</span><span>kembali;
</span><span>}
</span>
  res <span>.status (200) .json ({kejayaan: benar, profil: profil.documents [0]});
</span><span>} menangkap (ralat: mana -mana) {
</span><span>Console.error ('Ralat mengambil profil:', ralat);
</span>  res <span>.status (500) .json ({kejayaan: palsu, mesej: error.message});
</span><span>}
</span><span>};</span>

Fail ini mentakrifkan pengawal untuk membuat dan mengambil profil pengguna, mengintegrasikan dengan AppWrite untuk operasi pangkalan data dan permit untuk penyegerakan peranan. Pengawal CreateProfile mengesahkan input, mencipta profil, dan menyegerakkan pengguna untuk membenarkan, sementara pengawal getProfilebyemail mengambil profil melalui e -mel. Kedua -dua pengawal mengendalikan kesilapan dan mengembalikan respons yang sesuai.

  • Folder konfigurasi
    • Buat fail appwrite.ts dan tampal kod berikut:
 <span>import {klien, akaun, pangkalan data, penyimpanan, id, kebenaran, peranan, pertanyaan} dari 'appwrite';
</span><span>import {appwrite_endpoint, appwrite_project_id, appwrite_api_key} dari './environment';
</span>
<span>// Inisialisasi pelanggan AppWrite
</span><span>const client = pelanggan baru ()
</span><span>.setendpoint (appwrite_endpoint) // AppWrite Endpoint
</span><span>.setProject (appWrite_project_id); // ID Projek AppWrite
</span>
<span>// Tambah kekunci API jika tersedia (untuk operasi sisi pelayan)
</span><span>jika (appwrite_api_key) {
</span><span>(pelanggan sebagai mana -mana) .config.key = appwrite_api_key; // penyelesaian untuk menetapkan kunci API
</span><span>}
</span>
<span>// Inisialisasi Perkhidmatan AppWrite
</span><span>const account = akaun baru (klien);
</span><span>const pangkalan data = pangkalan data baru (klien);
</span><span>penyimpanan const = penyimpanan baru (klien);
</span>
<span>// Eksport Pelanggan dan Perkhidmatan AppWrite
</span><span>eksport {klien, akaun, pangkalan data, penyimpanan, id, kebenaran, peranan, pertanyaan};</span>

Fail ini memulakan dan mengkonfigurasi klien AppWrite dengan kunci API, ID, dan pilihan API pilihan. Ia juga menubuhkan dan mengeksport perkhidmatan AppWrite seperti akaun, pangkalan data, dan penyimpanan, bersama -sama dengan pemalar utiliti seperti ID, kebenaran, peranan, dan pertanyaan.

  • Buat fail Alam Sekitar.ts dan tampal kod berikut:
 <span>import dotenv dari 'dotenv';
</span>dotenv <span>.config (); // Pembolehubah persekitaran beban dari .env
</span>
<span>Eksport const appwrite_endpoint = process.env.appwrite_endpoint || '';
</span><span>Eksport Const EMPIT_API_KEY = process.env.permit_api_key || '';
</span><span>Eksport const ival_project_id = process.env.permit_project_id || '';
</span><span>Eksport const ival_env_id = process.env.permit_env_id || '';
</span><span>Eksport const appwrite_project_id = process.env.appwrite_project_id || '';
</span><span>Eksport const database_id = process.env.appwrite_database_id || '';
</span><span>eksport const students_collection_id = process.env.appwrite_students_collection_id || '';
</span><span>Eksport Const Tugasan_collection_id = process.env.appwrite_assignments_collection_id || '';
</span>
<span>Export const profile_collection_id = process.env.appwrite_profile_collection_id || '';</span>

Fail ini memuatkan pembolehubah persekitaran dari fail .Env dan mengeksportnya sebagai pemalar untuk digunakan dalam aplikasi, seperti AppWrite dan konfigurasi permit, ID pangkalan data, dan ID pengumpulan. Nilai lalai disediakan sebagai sandaran jika pembolehubah persekitaran tidak ditetapkan.

  • Folder API
    • Buat student.ts dan tampal kod berikut:
 <span>Import Express dari 'Express';
</span><span>import {createstudent, perolehan} dari '../controllers/student';
</span><span>import authmiddleware dari '../middleware/Auth';
</span>
<span>const router = express.Router ();
</span>
<span>// Tentukan titik akhir yang berkaitan dengan pelajar
</span>Router <span>.Post ('/Pelajar', AuthMiddleWare, Createstudent); // Buat pelajar baru
</span>router <span>.get ('/pelajar/: e -mel', authMiddleWare, perasmian); // Ambil semua pelajar
</span><span>Eksport router lalai; // mengeksport contoh penghala</span>

Fail ini menetapkan penghala ekspres dengan titik akhir untuk menguruskan data pelajar. Ia termasuk laluan untuk membuat pelajar baru dan mengambil pelajar, kedua -duanya dilindungi oleh middleware pengesahan (AuthMiddleWare). Penghala kemudian dieksport untuk digunakan dalam aplikasi.

  • Buat fail Auth.ts dan tampal kod berikut:
 <span>// src/routes/authroutes.ts
</span><span>Import Express dari 'Express';
</span><span>import {pendaftaran, login, logout} dari '../controllers/Auth';
</span>
<span>const router = express.Router ();
</span>
<span>// Tentukan titik akhir yang berkaitan dengan auth
</span>Router <span>.Post ('/signup', (req, res, next) => {// Laluan pendaftaran
</span><span>pendaftaran (req, res) .then (() => {
</span><span>seterusnya ();
</span><span>}). Catch ((err) => {
</span><span>seterusnya (err);
</span><span>});
</span><span>});
</span>Router <span>.Post ('/Login', (Req, Res, Next) => {// Log Masuk Log Masuk
</span><span>Log masuk (req, res) .theR (() => {
</span><span>seterusnya ();
</span><span>}). Catch ((err) => {
</span><span>seterusnya (err);
</span><span>});
</span><span>});
</span>router <span>.post ('/logout', logout); // Laluan Logout
</span><span>Eksport router lalai; // mengeksport contoh penghala</span>

Fail ini menetapkan penghala ekspres dengan titik akhir untuk tindakan yang berkaitan dengan pengesahan, termasuk pendaftaran pengguna, log masuk, dan logout. Laluan pendaftaran dan log masuk mengendalikan operasi tak segerak dengan pengendalian ralat, sementara laluan logout adalah mudah. Penghala dieksport untuk digunakan dalam aplikasi.

  • Buat fail tugasan.ts dan tampal kod berikut:
 <span>Import Express dari "Express"
</span><span>import {createAsSignment, fetchassignments} dari "../controllers/assignment"
</span><span>Import AuthMiddleWare dari "../middleware/Auth"
</span>
<span>const router = express.Router ()
</span>
Router <span>.Post ("/create", AuthMidDleWare, CreateAsSignment)
</span>Router <span>.get ("/: e -mel", authMiddleWare, fetchassignments)
</span><span>Eksport penghala lalai</span>

Fail ini menetapkan penghala ekspres dengan titik akhir untuk menguruskan tugasan. Ia termasuk laluan untuk mewujudkan tugasan dan pengambilan tugasan, kedua -duanya dilindungi oleh middleware pengesahan (AuthMiddleWare). Penghala dieksport untuk digunakan dalam aplikasi.

  • Create profile.ts file and paste the following code:
 <span>import express from 'express';
</span><span>import { createProfile, getProfileByEmail } from '../controllers/profile';
</span><span>import authMiddleware from '../middleware/auth';
</span>
<span>const router = express.Router();
</span>
<span>// Route for creating a profile
</span>router <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.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi 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.

Kesimpulan

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.

Atas ialah kandungan terperinci Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Enjin JavaScript: Membandingkan PelaksanaanEnjin JavaScript: Membandingkan PelaksanaanApr 13, 2025 am 12:05 AM

Enjin JavaScript yang berbeza mempunyai kesan yang berbeza apabila menguraikan dan melaksanakan kod JavaScript, kerana prinsip pelaksanaan dan strategi pengoptimuman setiap enjin berbeza. 1. Analisis leksikal: Menukar kod sumber ke dalam unit leksikal. 2. Analisis Tatabahasa: Menjana pokok sintaks abstrak. 3. Pengoptimuman dan Penyusunan: Menjana kod mesin melalui pengkompil JIT. 4. Jalankan: Jalankan kod mesin. Enjin V8 mengoptimumkan melalui kompilasi segera dan kelas tersembunyi, Spidermonkey menggunakan sistem kesimpulan jenis, menghasilkan prestasi prestasi yang berbeza pada kod yang sama.

Beyond the Browser: JavaScript di dunia nyataBeyond the Browser: JavaScript di dunia nyataApr 12, 2025 am 12:06 AM

Aplikasi JavaScript di dunia nyata termasuk pengaturcaraan sisi pelayan, pembangunan aplikasi mudah alih dan Internet of Things Control: 1. Pengaturcaraan sisi pelayan direalisasikan melalui node.js, sesuai untuk pemprosesan permintaan serentak yang tinggi. 2. Pembangunan aplikasi mudah alih dijalankan melalui reaktnatif dan menyokong penggunaan silang platform. 3. Digunakan untuk kawalan peranti IoT melalui Perpustakaan Johnny-Five, sesuai untuk interaksi perkakasan.

Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)Membina aplikasi SaaS Multi-penyewa dengan Next.js (Integrasi Backend)Apr 11, 2025 am 08:23 AM

Saya membina aplikasi SaaS multi-penyewa berfungsi (aplikasi edTech) dengan alat teknologi harian anda dan anda boleh melakukan perkara yang sama. Pertama, apakah aplikasi SaaS multi-penyewa? Aplikasi SaaS Multi-penyewa membolehkan anda melayani beberapa pelanggan dari Sing

Cara Membina Aplikasi SaaS Multi-Tenant dengan Next.js (Integrasi Frontend)Cara Membina Aplikasi SaaS Multi-Tenant dengan Next.js (Integrasi Frontend)Apr 11, 2025 am 08:22 AM

Artikel ini menunjukkan integrasi frontend dengan backend yang dijamin oleh permit, membina aplikasi edtech SaaS yang berfungsi menggunakan Next.Js. Frontend mengambil kebenaran pengguna untuk mengawal penglihatan UI dan memastikan permintaan API mematuhi dasar peranan

JavaScript: meneroka serba boleh bahasa webJavaScript: meneroka serba boleh bahasa webApr 11, 2025 am 12:01 AM

JavaScript adalah bahasa utama pembangunan web moden dan digunakan secara meluas untuk kepelbagaian dan fleksibiliti. 1) Pembangunan front-end: Membina laman web dinamik dan aplikasi satu halaman melalui operasi DOM dan kerangka moden (seperti React, Vue.js, sudut). 2) Pembangunan sisi pelayan: Node.js menggunakan model I/O yang tidak menyekat untuk mengendalikan aplikasi konkurensi tinggi dan masa nyata. 3) Pembangunan aplikasi mudah alih dan desktop: Pembangunan silang platform direalisasikan melalui reaktnatif dan elektron untuk meningkatkan kecekapan pembangunan.

Evolusi JavaScript: Trend Semasa dan Prospek Masa DepanEvolusi JavaScript: Trend Semasa dan Prospek Masa DepanApr 10, 2025 am 09:33 AM

Trend terkini dalam JavaScript termasuk kebangkitan TypeScript, populariti kerangka dan perpustakaan moden, dan penerapan webassembly. Prospek masa depan meliputi sistem jenis yang lebih berkuasa, pembangunan JavaScript, pengembangan kecerdasan buatan dan pembelajaran mesin, dan potensi pengkomputeran IoT dan kelebihan.

Demystifying JavaScript: Apa yang berlaku dan mengapa pentingDemystifying JavaScript: Apa yang berlaku dan mengapa pentingApr 09, 2025 am 12:07 AM

JavaScript adalah asas kepada pembangunan web moden, dan fungsi utamanya termasuk pengaturcaraan yang didorong oleh peristiwa, penjanaan kandungan dinamik dan pengaturcaraan tak segerak. 1) Pengaturcaraan yang didorong oleh peristiwa membolehkan laman web berubah secara dinamik mengikut operasi pengguna. 2) Penjanaan kandungan dinamik membolehkan kandungan halaman diselaraskan mengikut syarat. 3) Pengaturcaraan Asynchronous memastikan bahawa antara muka pengguna tidak disekat. JavaScript digunakan secara meluas dalam interaksi web, aplikasi satu halaman dan pembangunan sisi pelayan, sangat meningkatkan fleksibiliti pengalaman pengguna dan pembangunan silang platform.

Adakah Python atau JavaScript lebih baik?Adakah Python atau JavaScript lebih baik?Apr 06, 2025 am 12:14 AM

Python lebih sesuai untuk sains data dan pembelajaran mesin, manakala JavaScript lebih sesuai untuk pembangunan front-end dan penuh. 1. Python terkenal dengan sintaks ringkas dan ekosistem perpustakaan yang kaya, dan sesuai untuk analisis data dan pembangunan web. 2. JavaScript adalah teras pembangunan front-end. Node.js menyokong pengaturcaraan sisi pelayan dan sesuai untuk pembangunan stack penuh.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Cara Membuka Segala -galanya Di Myrise
4 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

Dreamweaver Mac版

Dreamweaver Mac版

Alat pembangunan web visual

MinGW - GNU Minimalis untuk Windows

MinGW - GNU Minimalis untuk Windows

Projek ini dalam proses untuk dipindahkan ke osdn.net/projects/mingw, anda boleh terus mengikuti kami di sana. MinGW: Port Windows asli bagi GNU Compiler Collection (GCC), perpustakaan import yang boleh diedarkan secara bebas dan fail pengepala untuk membina aplikasi Windows asli termasuk sambungan kepada masa jalan MSVC untuk menyokong fungsi C99. Semua perisian MinGW boleh dijalankan pada platform Windows 64-bit.

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Penyesuai Pelayan SAP NetWeaver untuk Eclipse

Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.

VSCode Windows 64-bit Muat Turun

VSCode Windows 64-bit Muat Turun

Editor IDE percuma dan berkuasa yang dilancarkan oleh Microsoft

PhpStorm versi Mac

PhpStorm versi Mac

Alat pembangunan bersepadu PHP profesional terkini (2018.2.1).