Skip to content

Commit 8acb100

Browse files
Add initial setup for Appwrite integration and state management
1 parent 9c94009 commit 8acb100

16 files changed

+390
-8
lines changed

package-lock.json

Lines changed: 62 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,23 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"appwrite": "^17.0.1",
13+
"immer": "^10.1.1",
14+
"next": "15.2.3",
15+
"node-appwrite": "^15.0.1",
1216
"react": "^19.0.0",
1317
"react-dom": "^19.0.0",
14-
"next": "15.2.3"
18+
"zustand": "^5.0.3"
1519
},
1620
"devDependencies": {
17-
"typescript": "^5",
21+
"@eslint/eslintrc": "^3",
22+
"@tailwindcss/postcss": "^4",
1823
"@types/node": "^20",
1924
"@types/react": "^19",
2025
"@types/react-dom": "^19",
21-
"@tailwindcss/postcss": "^4",
22-
"tailwindcss": "^4",
2326
"eslint": "^9",
2427
"eslint-config-next": "15.2.3",
25-
"@eslint/eslintrc": "^3"
28+
"tailwindcss": "^4",
29+
"typescript": "^5"
2630
}
2731
}

src/app/env.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const env = {
2+
appwrite: {
3+
endpoint : String(process.env.NEXT_PUBLIC_APPWRITE_HOST_URL),
4+
projectId : String(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID),
5+
apiKey: String(process.env.APPWRITE_API_KEY)
6+
}
7+
}
8+
9+
export default env;

src/middleware.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { NextResponse } from "next/server";
2+
import type { NextRequest } from "next/server";
3+
import getOrCreateDB from "./models/server/dbSetup";
4+
import getOrCreateStorage from "./models/server/storageSetup";
5+
6+
//as this is my middleware this function can everywhere we want
7+
export async function middleware(request: NextRequest){
8+
9+
await Promise.all([
10+
getOrCreateDB(),
11+
getOrCreateStorage()
12+
])
13+
14+
return NextResponse.next();
15+
}
16+
17+
//wherever the matches matches the path our code will not run there
18+
export const config = {
19+
/*
20+
match all req path except for the ones start with
21+
- api
22+
- next/static
23+
- next/image
24+
- favicon
25+
*/
26+
matcher: [
27+
"/((?!api|_next/static|_next/image|favicon.ico).*)"
28+
]
29+
}

src/models/client/config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { Client, Account , Avatars, Databases, Storage} from "appwrite";
2+
import env from "@/app/env";
3+
4+
const client = new Client()
5+
.setEndpoint(env.appwrite.endpoint) // Your API Endpoint
6+
.setProject(env.appwrite.projectId); // Your project ID
7+
8+
const account = new Account(client);
9+
const databases = new Databases(client);
10+
const avatars = new Avatars(client);
11+
const storage = new Storage(client);
12+
13+
export {client, databases, account, avatars, storage};

src/models/index.ts

Whitespace-only changes.

src/models/name.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const db = "appwrite-overflow";
2+
export const questionCollection = "questions";
3+
export const answerCollection = "answers";
4+
export const commentCollection = "comments";
5+
export const voteCollection = "votes";
6+
export const questionAttachmentbucket = "question-attachments";;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {db, answerCollection} from "../name";
2+
import { databases } from "./config";
3+
import { Permission } from "appwrite";
4+
5+
export default async function createAnswerCollection(){
6+
await databases.createCollection(
7+
db,
8+
answerCollection,
9+
answerCollection,
10+
[
11+
Permission.read("any"),
12+
Permission.read("users"),
13+
Permission.write("users"),
14+
Permission.create("users"),
15+
Permission.delete("users")
16+
]
17+
)
18+
console.log("Answer collection is created")
19+
20+
await Promise.all([
21+
databases.createStringAttribute(db, answerCollection, "content", 10000, true),
22+
databases.createStringAttribute(db, answerCollection, "authorId", 100, true),
23+
databases.createStringAttribute(db, answerCollection, "questionId", 100, true),
24+
])
25+
console.log("Answer attributes are created")
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {db, commentCollection} from "../name";
2+
import { databases } from "./config";
3+
import { Permission } from "appwrite";
4+
5+
export default async function createCommentCollection(){
6+
await databases.createCollection(
7+
db,
8+
commentCollection,
9+
commentCollection,
10+
[
11+
Permission.read("any"),
12+
Permission.read("users"),
13+
Permission.write("users"),
14+
Permission.create("users"),
15+
Permission.delete("users")
16+
]
17+
)
18+
console.log("comment collection is created")
19+
20+
await Promise.all([
21+
databases.createStringAttribute(db, commentCollection, "content", 10000, true),
22+
databases.createStringAttribute(db, commentCollection, "authorId", 100, true),
23+
databases.createStringAttribute(db, commentCollection, "typeId", 100, true),
24+
databases.createEnumAttribute(db, commentCollection, "type", ["answer", "question"], true)
25+
])
26+
console.log("comment attributes are created")
27+
}

src/models/server/config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import env from "@/app/env";
2+
import {Avatars, Client, Databases, Storage, Users} from "node-appwrite";
3+
4+
const client = new Client();
5+
client
6+
.setEndpoint(env.appwrite.endpoint) // Your API Endpoint
7+
.setProject(env.appwrite.projectId) // Your project ID
8+
.setKey(env.appwrite.apiKey) // Your secret API key
9+
;
10+
11+
const databases = new Databases(client);
12+
const storage = new Storage(client);
13+
const users = new Users(client);
14+
const avatars = new Avatars(client);
15+
16+
export { client, databases, storage, users, avatars };

src/models/server/dbSetup.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { db } from "../name";
2+
import createQuestionCollection from "./question.collection";
3+
import createAnswerCollection from "./answer.collection";
4+
import createCommentCollection from "./comment.collection";
5+
import createVoteCollection from "./vote.collection";
6+
import {databases} from "./config";
7+
//for sedding the databse with some intial data
8+
export default async function getOrCreateDB(){
9+
try {
10+
await databases.get(db);
11+
console.log("Database is already created")
12+
} catch (error) {
13+
try {
14+
await databases.create(db, db);
15+
console.log("Database is created");
16+
Promise.all([
17+
createQuestionCollection(),
18+
createAnswerCollection(),
19+
createVoteCollection(),
20+
createCommentCollection()
21+
])
22+
console.log("Collections are created")
23+
} catch (error) {
24+
console.log("Error in creating collections", error)
25+
}
26+
console.log("Error in getting database", error)
27+
}
28+
return databases;
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { IndexType } from "node-appwrite";
2+
3+
import {db, questionCollection} from "../name";
4+
import { databases } from "./config";
5+
import { Permission } from "appwrite";
6+
7+
export default async function createQuestionCollection() {
8+
//create collection
9+
await databases.createCollection(
10+
db,
11+
questionCollection,
12+
questionCollection,
13+
[
14+
Permission.read("any"),
15+
Permission.read("users"),
16+
Permission.write("users"),
17+
Permission.create("users"),
18+
Permission.delete("users")
19+
]
20+
)
21+
console.log("Question collection is created")
22+
23+
//creating attributes and indesxes
24+
await Promise.all([
25+
databases.createStringAttribute(db, questionCollection, "title", 100, true),
26+
databases.createStringAttribute(db, questionCollection, "content", 10000, true),
27+
databases.createStringAttribute(db, questionCollection, "authorId", 100, true),
28+
databases.createStringAttribute(db, questionCollection, "tags", 100, true, undefined, true),
29+
databases.createStringAttribute(db, questionCollection, "attachmentId", 100, false),
30+
])
31+
console.log("Question attributes are created")
32+
33+
//create index
34+
//as we are creating a lot of indexes, we are using a batch operation
35+
await Promise.all([
36+
databases.createIndex(db, questionCollection, "title", IndexType.Fulltext, ["title"],['asc']),
37+
databases.createIndex(db, questionCollection, "content", IndexType.Fulltext, ["content"],['asc']),
38+
])
39+
}

src/models/server/storageSetup.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { questionAttachmentbucket} from "../name";
2+
import { storage } from "./config";
3+
import { Permission } from "appwrite";
4+
5+
export default async function getOrCreateStorage(){
6+
try {
7+
await storage.getBucket(questionAttachmentbucket);
8+
console.log("Bucket already exists")
9+
} catch (error) {
10+
try {
11+
await storage.createBucket(
12+
questionAttachmentbucket,
13+
questionAttachmentbucket,
14+
[
15+
Permission.read("any"),
16+
Permission.read("users"),
17+
Permission.write("users"),
18+
Permission.create("users"),
19+
Permission.delete("users")
20+
],
21+
false,
22+
undefined,
23+
undefined,
24+
["jpeg", "png", "gif", "jpeg", "webp", "heic"]
25+
)
26+
console.log("Bucket is created")
27+
console.log("Storage connected")
28+
} catch (error) {
29+
console.error("error creating storage: ", error)
30+
}
31+
console.error("error creating storage: ", error)
32+
}
33+
}

0 commit comments

Comments
 (0)