feat: initial backend MVP (auth, habits, village, leaderboard)
This commit is contained in:
parent
f0177d31c0
commit
de30f96c57
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
* text=auto eol=lf
|
||||
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
/app/generated/prisma
|
||||
|
||||
prisma/dev.db
|
||||
109
GEMINI/ARCHITECTURE.md
Normal file
109
GEMINI/ARCHITECTURE.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# Architecture
|
||||
|
||||
## 1. High-Level Architecture
|
||||
|
||||
The application follows a fullstack SPA architecture:
|
||||
|
||||
- Nuxt 3 frontend
|
||||
- Nitro backend (Node.js)
|
||||
- REST API
|
||||
- MySQL database
|
||||
- Prisma ORM
|
||||
|
||||
Frontend and backend live in a single repository.
|
||||
|
||||
---
|
||||
|
||||
## 2. Architectural Principles
|
||||
|
||||
- Clear separation of concerns:
|
||||
- UI
|
||||
- State
|
||||
- Domain logic
|
||||
- Persistence
|
||||
- Backend is the source of truth
|
||||
- Frontend does not calculate time-based progression
|
||||
- No real-time connections (WebSockets not required)
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontend Structure
|
||||
|
||||
- Pages:
|
||||
- Habits
|
||||
- Quests
|
||||
- Village
|
||||
- Leaderboard
|
||||
- Components:
|
||||
- HabitCard
|
||||
- QuestItem
|
||||
- VillageGrid
|
||||
- VillageObject
|
||||
- BuildModeOverlay
|
||||
- State:
|
||||
- userStore
|
||||
- habitsStore
|
||||
- questsStore
|
||||
- villageStore
|
||||
- leaderboardStore
|
||||
|
||||
---
|
||||
|
||||
## 4. Backend Structure
|
||||
|
||||
- API routes grouped by domain:
|
||||
- /auth
|
||||
- /user
|
||||
- /habits
|
||||
- /quests
|
||||
- /village
|
||||
- /leaderboard
|
||||
- Domain services:
|
||||
- HabitService
|
||||
- QuestService
|
||||
- VillageService
|
||||
- CropGrowthService
|
||||
- All time-based logic is calculated on request
|
||||
|
||||
---
|
||||
|
||||
## 5. Village Logic
|
||||
|
||||
- Village grid is logical (cell-based)
|
||||
- Isometric view is purely visual
|
||||
- Build mode:
|
||||
- shows grid overlay
|
||||
- allows placing, moving and removing objects
|
||||
- View mode:
|
||||
- allows planting and harvesting
|
||||
- Obstacles must be cleared before building
|
||||
|
||||
---
|
||||
|
||||
## 6. Time & Progression
|
||||
|
||||
- Server calculates:
|
||||
- whether a quest is available today
|
||||
- whether a crop is grown
|
||||
- streak progression
|
||||
- Time is based on user local date stored on server
|
||||
- No background jobs required for MVP
|
||||
|
||||
---
|
||||
|
||||
## 7. Data Flow
|
||||
|
||||
1. Frontend requests current state
|
||||
2. Backend recalculates progression if needed
|
||||
3. Backend returns updated state
|
||||
4. Frontend updates Pinia stores
|
||||
5. UI reflects the new state
|
||||
|
||||
---
|
||||
|
||||
## 8. Non-Goals
|
||||
|
||||
- No SSR optimization
|
||||
- No WebSocket connections
|
||||
- No offline mode
|
||||
- No push notifications
|
||||
156
GEMINI/BUSINESS_REQUIREMENTS.md
Normal file
156
GEMINI/BUSINESS_REQUIREMENTS.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# Business Requirements
|
||||
|
||||
## 1. Product Goal
|
||||
|
||||
Create a mobile-first web application for habit tracking with a light game layer.
|
||||
|
||||
Core idea:
|
||||
Daily habits → quests → rewards → village development → EXP → leaderboard.
|
||||
|
||||
The project is an MVP / pet project.
|
||||
No monetization, no anti-cheat, no social pressure mechanics.
|
||||
|
||||
---
|
||||
|
||||
## 2. Target Audience
|
||||
|
||||
- Users who want to build daily habits
|
||||
- Users who like visual progress and game mechanics
|
||||
- Mobile users as primary platform
|
||||
|
||||
---
|
||||
|
||||
## 3. Core User Loop
|
||||
|
||||
1. User opens the app
|
||||
2. Completes a habit or daily quest
|
||||
3. Receives coins
|
||||
4. Spends coins on village development
|
||||
5. Collects crops and gains EXP
|
||||
6. Sees progress and leaderboard position
|
||||
7. Returns the next day
|
||||
|
||||
---
|
||||
|
||||
## 4. Functional Requirements
|
||||
|
||||
### 4.1 User & Profile
|
||||
|
||||
- Registration and login via email + password
|
||||
- One email = one account
|
||||
- Email confirmation is NOT required (MVP)
|
||||
- Profile contains:
|
||||
- public nickname
|
||||
- public avatar
|
||||
- settings:
|
||||
- sound on/off
|
||||
- confetti on/off
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Habits
|
||||
|
||||
- Maximum 3 habits per user
|
||||
- Habit fields:
|
||||
- name (custom or predefined)
|
||||
- active days of week
|
||||
- Habits are:
|
||||
- permanent
|
||||
- editable
|
||||
- removable
|
||||
- Missed days:
|
||||
- are not penalized
|
||||
- shown as red cells in calendar
|
||||
- Completed days:
|
||||
- shown as green cells
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Quests
|
||||
|
||||
#### Habit quests
|
||||
- Can be completed only on active days
|
||||
- Reward: 3 coins per completion
|
||||
|
||||
#### Daily quest
|
||||
- “I visited the site today”
|
||||
- Can be completed once per day
|
||||
- Reward: 1 coin
|
||||
|
||||
#### Streak
|
||||
- 5 consecutive daily visits → +10 coins
|
||||
- Streak resets after reward
|
||||
|
||||
#### UX
|
||||
- Quest completion triggers:
|
||||
- light confetti animation
|
||||
- short success sound
|
||||
- Both effects can be disabled in settings
|
||||
|
||||
---
|
||||
|
||||
### 4.4 Village
|
||||
|
||||
- 2D isometric grid
|
||||
- Grid fits into one mobile screen (no scroll)
|
||||
- Two modes:
|
||||
- view mode
|
||||
- build mode
|
||||
|
||||
#### Objects
|
||||
- House (1 house = 1 worker)
|
||||
- Field
|
||||
- Road
|
||||
- Fence
|
||||
- Obstacles (rocks, bushes, mushrooms)
|
||||
|
||||
#### Rules
|
||||
- Fields cannot exceed number of workers
|
||||
- Removing objects does NOT refund coins
|
||||
- Removing houses blocks building new fields but does not remove existing ones
|
||||
|
||||
---
|
||||
|
||||
### 4.5 Crops & EXP
|
||||
|
||||
- Crop types:
|
||||
- Blueberries
|
||||
- Corn (grows longer)
|
||||
- Growth:
|
||||
- real-time based
|
||||
- no acceleration mechanics
|
||||
- Harvest:
|
||||
- manual
|
||||
- does not expire
|
||||
- Rewards:
|
||||
- harvesting gives EXP
|
||||
- corn additionally gives +1 coin
|
||||
|
||||
---
|
||||
|
||||
### 4.6 Leaderboard
|
||||
|
||||
- Global leaderboard
|
||||
- Period: monthly
|
||||
- Sorted by EXP
|
||||
- Shows:
|
||||
- rank
|
||||
- avatar
|
||||
- nickname
|
||||
- EXP
|
||||
- Equal EXP results in shared ranks
|
||||
(e.g. 1, 2, 2, 2, 3, 4, 5, 5)
|
||||
|
||||
---
|
||||
|
||||
## 5. MVP Exclusions
|
||||
|
||||
The MVP explicitly excludes:
|
||||
- donations or payments
|
||||
- levels
|
||||
- progress acceleration
|
||||
- social features
|
||||
- chat
|
||||
- push notifications
|
||||
- anti-cheat
|
||||
- email verification
|
||||
65
GEMINI/TECH_STACK.md
Normal file
65
GEMINI/TECH_STACK.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Technical Stack
|
||||
|
||||
## 1. General Approach
|
||||
|
||||
- Monorepo
|
||||
- Single codebase for frontend and backend
|
||||
- SPA (no SEO requirements)
|
||||
- Mobile-first
|
||||
- Backend used as API and calculation layer
|
||||
|
||||
---
|
||||
|
||||
## 2. Frontend
|
||||
|
||||
- Nuxt 3
|
||||
- Vue 3
|
||||
- TypeScript
|
||||
- Pinia (state management)
|
||||
- Vite (build tool)
|
||||
- CSS or Tailwind CSS (implementation choice)
|
||||
|
||||
---
|
||||
|
||||
## 3. Backend
|
||||
|
||||
- Node.js via Nuxt Nitro
|
||||
- REST API (no GraphQL)
|
||||
- Server-side calculation for:
|
||||
- crop growth
|
||||
- quest availability
|
||||
- streaks
|
||||
- rewards
|
||||
|
||||
---
|
||||
|
||||
## 4. Database
|
||||
|
||||
- SQLite
|
||||
- Prisma ORM
|
||||
- Migrations required
|
||||
- Seed data required (initial crops, obstacles, presets)
|
||||
|
||||
---
|
||||
|
||||
## 5. State Management
|
||||
|
||||
- Pinia as a single source of truth on frontend
|
||||
- Server is authoritative for:
|
||||
- time-based logic
|
||||
- rewards
|
||||
- progression
|
||||
|
||||
---
|
||||
|
||||
## 6. Internationalization
|
||||
|
||||
- i18n support enabled from start
|
||||
- Default language: RU
|
||||
- EN prepared for future use
|
||||
|
||||
---
|
||||
|
||||
## 7. Testing
|
||||
|
||||
- Unit tests are NOT required for MVP
|
||||
214
README.md
Normal file
214
README.md
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
# Smurf Habits
|
||||
|
||||
Habit tracker with a light game layer (village, quests, EXP).
|
||||
Mobile-first web application.
|
||||
|
||||
---
|
||||
|
||||
## 1. Tech Stack
|
||||
|
||||
- Node.js **20 LTS** (required)
|
||||
- Nuxt **4.x**
|
||||
- Vue 3
|
||||
- Prisma **6.x** (⚠️ NOT 7)
|
||||
- SQLite (development & MVP)
|
||||
- TypeScript
|
||||
|
||||
---
|
||||
|
||||
## 2. Environment Requirements
|
||||
|
||||
### Node.js
|
||||
|
||||
**Required:**
|
||||
```
|
||||
Node >= 20.x (LTS)
|
||||
```
|
||||
|
||||
❌ Node 22 / 24 are NOT supported
|
||||
❌ Do not use experimental Node versions
|
||||
|
||||
Check:
|
||||
```bash
|
||||
node -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Project Structure
|
||||
|
||||
```text
|
||||
/
|
||||
├─ app/ # UI (pages, components, layouts)
|
||||
├─ server/ # Backend (API, utils, Prisma)
|
||||
│ ├─ api/
|
||||
│ └─ utils/
|
||||
├─ prisma/
|
||||
│ ├─ schema.prisma
|
||||
│ └─ migrations/
|
||||
├─ public/
|
||||
├─ .env
|
||||
├─ nuxt.config.ts
|
||||
└─ README.md
|
||||
```
|
||||
|
||||
### Important rules
|
||||
|
||||
- `app/` — UI only
|
||||
- `server/` — backend only
|
||||
- `server/` MUST be in project root (not inside `app/`)
|
||||
- Do NOT change this structure
|
||||
|
||||
---
|
||||
|
||||
## 4. Prisma Setup (IMPORTANT)
|
||||
|
||||
### Prisma version
|
||||
|
||||
This project **intentionally uses Prisma 6**.
|
||||
|
||||
❌ Do NOT upgrade to Prisma 7
|
||||
❌ Do NOT use Prisma adapters
|
||||
❌ Do NOT remove `DATABASE_URL`
|
||||
|
||||
Reason:
|
||||
- Prisma 7 has unstable adapter-based API
|
||||
- Prisma 6 is stable and well-supported by Nuxt and tooling
|
||||
|
||||
---
|
||||
|
||||
### Prisma schema
|
||||
|
||||
`prisma/schema.prisma` uses classic datasource config:
|
||||
|
||||
```prisma
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Environment variables
|
||||
|
||||
`.env`:
|
||||
|
||||
```env
|
||||
DATABASE_URL="file:./dev.db"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Prisma workflow
|
||||
|
||||
Whenever you change `schema.prisma`:
|
||||
|
||||
```bash
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
Never forget migrations.
|
||||
|
||||
---
|
||||
|
||||
## 5. Prisma Client Usage
|
||||
|
||||
Prisma client is initialized here:
|
||||
|
||||
```ts
|
||||
server/utils/prisma.ts
|
||||
```
|
||||
|
||||
```ts
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export default prisma
|
||||
```
|
||||
|
||||
### Rules
|
||||
|
||||
- Do NOT initialize PrismaClient elsewhere
|
||||
- Do NOT use dynamic imports
|
||||
- Do NOT change this file without a good reason
|
||||
|
||||
---
|
||||
|
||||
## 6. Development
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Generate Prisma client:
|
||||
|
||||
```bash
|
||||
npx prisma generate
|
||||
```
|
||||
|
||||
Run dev server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. API Example
|
||||
|
||||
Health check:
|
||||
|
||||
```
|
||||
GET /api/health
|
||||
```
|
||||
|
||||
Expected response:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"usersCount": 0
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Deployment Notes
|
||||
|
||||
- Use Node 20 on hosting
|
||||
- Run Prisma migrations during deployment
|
||||
- SQLite is acceptable for MVP
|
||||
- Database file: `dev.db`
|
||||
|
||||
---
|
||||
|
||||
## 9. AI / Gemini Rules (IMPORTANT)
|
||||
|
||||
When using Gemini / AI tools:
|
||||
|
||||
**DO NOT ALLOW:**
|
||||
- changing Node version
|
||||
- upgrading Prisma
|
||||
- changing Prisma configuration
|
||||
- modifying project structure
|
||||
|
||||
**ALLOWED:**
|
||||
- adding models to `schema.prisma`
|
||||
- generating API endpoints
|
||||
- implementing business logic
|
||||
|
||||
---
|
||||
|
||||
## 10. Why these constraints exist
|
||||
|
||||
This setup was intentionally chosen to:
|
||||
- avoid unstable Prisma 7 API
|
||||
- keep development predictable
|
||||
- ensure compatibility with Nuxt and Node
|
||||
- prevent tooling-related regressions
|
||||
|
||||
Breaking these rules will likely break the project.
|
||||
6
app/app.vue
Normal file
6
app/app.vue
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<NuxtRouteAnnouncer />
|
||||
<NuxtWelcome />
|
||||
</div>
|
||||
</template>
|
||||
BIN
assets/raw/smurf1.jpg
Normal file
BIN
assets/raw/smurf1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
BIN
assets/raw/smurf2.jpg
Normal file
BIN
assets/raw/smurf2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 223 KiB |
BIN
assets/raw/smurf3.jpg
Normal file
BIN
assets/raw/smurf3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
5
nuxt.config.ts
Normal file
5
nuxt.config.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
devtools: { enabled: true }
|
||||
})
|
||||
10892
package-lock.json
generated
Normal file
10892
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "smurfhabits",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.19.1",
|
||||
"nuxt": "^4.2.2",
|
||||
"prisma": "^6.19.1",
|
||||
"vue": "^3.5.26",
|
||||
"vue-router": "^4.6.4"
|
||||
}
|
||||
}
|
||||
14
prisma.config.ts
Normal file
14
prisma.config.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// This file was generated by Prisma, and assumes you have installed the following:
|
||||
// npm install --save-dev prisma dotenv
|
||||
import "dotenv/config";
|
||||
import { defineConfig } from "prisma/config";
|
||||
|
||||
export default defineConfig({
|
||||
schema: "prisma/schema.prisma",
|
||||
migrations: {
|
||||
path: "prisma/migrations",
|
||||
},
|
||||
datasource: {
|
||||
url: process.env["DATABASE_URL"],
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- Added the required column `password` to the `User` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `updatedAt` to the `User` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- CreateTable
|
||||
CREATE TABLE "Habit" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"name" TEXT NOT NULL,
|
||||
"daysOfWeek" JSONB NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
CONSTRAINT "Habit_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "HabitCompletion" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"date" DATETIME NOT NULL,
|
||||
"habitId" INTEGER NOT NULL,
|
||||
CONSTRAINT "HabitCompletion_habitId_fkey" FOREIGN KEY ("habitId") REFERENCES "Habit" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DailyVisit" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"date" DATETIME NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
CONSTRAINT "DailyVisit_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Village" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"userId" INTEGER NOT NULL,
|
||||
CONSTRAINT "Village_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VillageObject" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"type" TEXT NOT NULL,
|
||||
"x" INTEGER NOT NULL,
|
||||
"y" INTEGER NOT NULL,
|
||||
"obstacleMetadata" TEXT,
|
||||
"cropType" TEXT,
|
||||
"plantedAt" DATETIME,
|
||||
"villageId" INTEGER NOT NULL,
|
||||
CONSTRAINT "VillageObject_villageId_fkey" FOREIGN KEY ("villageId") REFERENCES "Village" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- RedefineTables
|
||||
PRAGMA defer_foreign_keys=ON;
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_User" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"nickname" TEXT,
|
||||
"avatar" TEXT DEFAULT '/avatars/default.png',
|
||||
"coins" INTEGER NOT NULL DEFAULT 0,
|
||||
"exp" INTEGER NOT NULL DEFAULT 0,
|
||||
"soundOn" BOOLEAN NOT NULL DEFAULT true,
|
||||
"confettiOn" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
INSERT INTO "new_User" ("createdAt", "email", "id") SELECT "createdAt", "email", "id" FROM "User";
|
||||
DROP TABLE "User";
|
||||
ALTER TABLE "new_User" RENAME TO "User";
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
PRAGMA foreign_keys=ON;
|
||||
PRAGMA defer_foreign_keys=OFF;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "HabitCompletion_habitId_date_key" ON "HabitCompletion"("habitId", "date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DailyVisit_userId_date_key" ON "DailyVisit"("userId", "date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Village_userId_key" ON "Village"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "VillageObject_villageId_x_y_key" ON "VillageObject"("villageId", "x", "y");
|
||||
|
|
@ -1,3 +1,12 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// prisma/schema.prisma
|
||||
|
||||
// Enums
|
||||
|
|
@ -61,7 +70,7 @@ model Habit {
|
|||
// This creates a history of the user's progress for each habit.
|
||||
model HabitCompletion {
|
||||
id Int @id @default(autoincrement())
|
||||
date DateTime @db.Date // Store only the date part
|
||||
date DateTime // Store only the date part
|
||||
|
||||
// Relations
|
||||
habit Habit @relation(fields: [habitId], references: [id], onDelete: Cascade)
|
||||
|
|
@ -74,7 +83,7 @@ model HabitCompletion {
|
|||
// quest and for calculating 5-day streaks.
|
||||
model DailyVisit {
|
||||
id Int @id @default(autoincrement())
|
||||
date DateTime @db.Date // Store only the date part
|
||||
date DateTime // Store only the date part
|
||||
|
||||
// Relations
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
|
@ -113,4 +122,4 @@ model VillageObject {
|
|||
villageId Int
|
||||
|
||||
@@unique([villageId, x, y]) // Ensure only one object per grid cell per village
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
User-Agent: *
|
||||
Disallow:
|
||||
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.server.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.shared.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user