first commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
# Keep environment variables out of version control
|
||||
.env
|
||||
|
||||
/generated/prisma
|
||||
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"css.validate": false,
|
||||
"scss.validate": false,
|
||||
"less.validate": false,
|
||||
"tailwindCSS.includeLanguages": {
|
||||
"html": "html",
|
||||
"javascript": "javascript",
|
||||
"typescript": "typescript",
|
||||
"javascriptreact": "javascriptreact",
|
||||
"typescriptreact": "typescriptreact"
|
||||
},
|
||||
"tailwindCSS.experimental.classRegex": [
|
||||
"class[:]\\s*['\"`]([^'\"`]*)['\"`]",
|
||||
"className[:]\\s*['\"`]([^'\"`]*)['\"`]"
|
||||
]
|
||||
}
|
||||
128
FIREBASE_SETUP.md
Normal file
128
FIREBASE_SETUP.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Firebase Authentication Setup Guide
|
||||
|
||||
This guide will help you set up Firebase authentication for the Tabungin application.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. A Google account
|
||||
2. Access to the [Firebase Console](https://console.firebase.google.com/)
|
||||
|
||||
## Step 1: Create a Firebase Project
|
||||
|
||||
1. Go to the [Firebase Console](https://console.firebase.google.com/)
|
||||
2. Click "Create a project"
|
||||
3. Enter project name (e.g., "tabungin-app")
|
||||
4. Choose whether to enable Google Analytics (optional)
|
||||
5. Click "Create project"
|
||||
|
||||
## Step 2: Enable Authentication
|
||||
|
||||
1. In your Firebase project, go to **Authentication** in the left sidebar
|
||||
2. Click on the **Sign-in method** tab
|
||||
3. Enable the following providers:
|
||||
- **Email/Password**: Click on it and toggle "Enable"
|
||||
- **Google**: Click on it, toggle "Enable", and set your project's public-facing name
|
||||
|
||||
## Step 3: Get Web App Configuration
|
||||
|
||||
1. Go to **Project Settings** (gear icon in the left sidebar)
|
||||
2. In the "General" tab, scroll down to "Your apps"
|
||||
3. Click "Add app" and select the web icon (`</>`)
|
||||
4. Register your app with a nickname (e.g., "Tabungin Web")
|
||||
5. Copy the Firebase configuration object
|
||||
|
||||
## Step 4: Configure Web App Environment
|
||||
|
||||
1. Copy the `.env.example` file to `.env.local` in the `apps/web` directory:
|
||||
```bash
|
||||
cd apps/web
|
||||
cp .env.example .env.local
|
||||
```
|
||||
|
||||
2. Fill in your Firebase configuration in `.env.local`:
|
||||
```env
|
||||
VITE_FIREBASE_API_KEY=your_api_key_here
|
||||
VITE_FIREBASE_AUTH_DOMAIN=your_project_id.firebaseapp.com
|
||||
VITE_FIREBASE_PROJECT_ID=your_project_id
|
||||
VITE_FIREBASE_STORAGE_BUCKET=your_project_id.appspot.com
|
||||
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
|
||||
VITE_FIREBASE_APP_ID=your_app_id
|
||||
VITE_API_URL=http://localhost:3000
|
||||
```
|
||||
|
||||
## Step 5: Set up Firebase Admin SDK (for API)
|
||||
|
||||
1. In Firebase Console, go to **Project Settings** > **Service accounts**
|
||||
2. Click "Generate new private key"
|
||||
3. Download the JSON file and keep it secure
|
||||
4. Copy the `.env.example` file to `.env` in the `apps/api` directory:
|
||||
```bash
|
||||
cd apps/api
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
5. Fill in your Firebase Admin configuration in `.env`:
|
||||
```env
|
||||
FIREBASE_PROJECT_ID=your_project_id
|
||||
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your_project_id.iam.gserviceaccount.com
|
||||
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY_HERE\n-----END PRIVATE KEY-----\n"
|
||||
```
|
||||
|
||||
## Step 6: Configure Authorized Domains
|
||||
|
||||
1. In Firebase Console, go to **Authentication** > **Settings**
|
||||
2. In the "Authorized domains" tab, add your development domain:
|
||||
- `localhost` (should already be there)
|
||||
- Add your production domain when ready
|
||||
|
||||
## Step 7: Test the Setup
|
||||
|
||||
1. Start the development servers:
|
||||
```bash
|
||||
# From the root directory
|
||||
npm run dev
|
||||
```
|
||||
|
||||
2. Open your browser to `http://localhost:5173`
|
||||
3. Try signing up with email/password
|
||||
4. Try signing in with Google
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **"Firebase configuration not found"**
|
||||
- Check that all environment variables are set correctly
|
||||
- Restart the development server after changing `.env.local`
|
||||
|
||||
2. **"Popup blocked" error**
|
||||
- Allow popups for localhost in your browser
|
||||
- Try using a different browser
|
||||
|
||||
3. **"Network request failed"**
|
||||
- Check your internet connection
|
||||
- Verify Firebase project is active
|
||||
|
||||
4. **"Invalid API key"**
|
||||
- Double-check the API key in your `.env.local`
|
||||
- Make sure you copied it correctly from Firebase Console
|
||||
|
||||
### Debug Mode
|
||||
|
||||
The application includes detailed logging for authentication issues. Check the browser console for specific error messages.
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit `.env` or `.env.local` files to version control
|
||||
- Keep your Firebase private key secure
|
||||
- Use different Firebase projects for development and production
|
||||
- Regularly rotate your Firebase keys in production
|
||||
|
||||
## Production Deployment
|
||||
|
||||
When deploying to production:
|
||||
|
||||
1. Create a separate Firebase project for production
|
||||
2. Update environment variables with production values
|
||||
3. Add your production domain to Firebase authorized domains
|
||||
4. Use Firebase hosting or your preferred hosting service
|
||||
81
PROJECT_PLAN.md
Normal file
81
PROJECT_PLAN.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Tabungin — Cross‑Platform Final Plan (v1)
|
||||
|
||||
_Last updated: 11 Aug 2025_
|
||||
|
||||
---
|
||||
|
||||
## 1) Executive summary
|
||||
**Goal:** Build a **simple but flexible** cross‑platform personal finance app (web, desktop via Tauri, Android via Tauri Mobile) with a freemium model. Core features: money wallets, transactions (incl. recurring), basic reports. Premium priorities (in order): **Assets**, **Exports**, **API/Webhooks**.
|
||||
|
||||
**Principles:** One backend for all clients; one shared UI + core logic; thin platform shells; OIDC-based login that works everywhere; data consistency within 10s across devices. Keep the stack lean to avoid unnecessary complexity or startup‑scale overhead.
|
||||
|
||||
---
|
||||
|
||||
## 2) Architecture overview
|
||||
- **Clients:**
|
||||
- Web SPA (client-side pages) / optional PWA
|
||||
- Desktop app (Tauri) for Win/macOS/Linux
|
||||
- Android app (Tauri Mobile); iOS later if needed
|
||||
- **Shared packages:**
|
||||
- `packages/core` — domain models, currency math, recurrence engine, validations (TS)
|
||||
- `packages/ui` — React components/screens, theming, accessibility
|
||||
- **Backend:** NestJS (Node + TypeScript). REST API with typed SDK. Jobs/queues for recurring txns, price updates, exports, and notifications.
|
||||
- **Database:** PostgreSQL (self‑hosted on Coolify) — no reliance on 3rd‑party DB vendors.
|
||||
- **Auth:** OIDC via **Supabase Auth** (cost‑effective, quick to set up) with mapping to our own `users` table for vendor independence.
|
||||
- **Notifications:** In‑app center + Email; other channels (Web Push, Desktop OS, Android Push) can be added later.
|
||||
|
||||
---
|
||||
|
||||
## 3) Technology choices (finalized for v1)
|
||||
- **Frontend:** React + Tailwind CSS.
|
||||
- **Desktop/Mobile shell:** Tauri v2.
|
||||
- **Backend framework:** **NestJS** — opinionated structure, modular, maintainable.
|
||||
- **ORM & schema:** **Prisma** — type‑safe queries, smooth migrations.
|
||||
- **Database hosting:** Self‑hosted PostgreSQL on Coolify.
|
||||
- **Email delivery:** Elastic Email (API-based) with backend webhook support for bounces/complaints; fallback to SMTP if desired.
|
||||
- **Charting library:** **Recharts**.
|
||||
- **Export libraries:** CSV (built‑in first), Excel (ExcelJS, later), PDF (Playwright for server‑side render, later).
|
||||
- **Jobs/queues:** **pg-boss** (Postgres‑based) — minimal extra infra.
|
||||
- **Object storage:** Not needed for v1 (direct downloads); S3‑compatible (e.g., Cloudflare R2) later.
|
||||
- **Error tracking:** Optional for v1; add Sentry when in public beta.
|
||||
- **Date/time & validation:** date‑fns (+TZ) and Zod.
|
||||
|
||||
---
|
||||
|
||||
## 4) Single‑Dev Lean Mode Workflow
|
||||
**Purpose:** Deliver a usable cross‑platform MVP quickly without committing to full “startup‑scale” complexity.
|
||||
|
||||
**Keep for v1:**
|
||||
- Web SPA as the first client; desktop shell added once web is stable.
|
||||
- NestJS backend + Prisma with Postgres on Coolify.
|
||||
- Supabase Auth (OIDC) → local `users` table mapping.
|
||||
- In‑app notifications.
|
||||
- Elastic Email API for critical notices.
|
||||
- CSV export (inline download).
|
||||
- Simple recurring engine (pg-boss).
|
||||
|
||||
**Defer to later:**
|
||||
- Mobile shell (after desktop parity).
|
||||
- Push notifications (Web, Desktop OS, Android FCM).
|
||||
- PDF/Excel exports.
|
||||
- Object storage.
|
||||
- Public API + webhooks.
|
||||
- Sentry and advanced monitoring.
|
||||
|
||||
**Benefit:** Lower development overhead, fewer vendors, faster iteration. All deferred features are planned so they can be slotted in without re‑architecture.
|
||||
|
||||
---
|
||||
|
||||
## 5) Roadmap & acceptance criteria
|
||||
- **Phase 1:** Web MVP (auth, wallets, transactions, recurrences, basic reports, CSV export, email notices).
|
||||
- **Phase 2:** Desktop app (Tauri) with parity.
|
||||
- **Phase 3:** Android app (Tauri Mobile) with local notifications.
|
||||
- **Phase 4:** Premium features (Assets → Exports → API/Webhooks) + extra notification channels.
|
||||
|
||||
---
|
||||
|
||||
## 6) Next steps
|
||||
1) Finalize Elastic Email API integration + webhook handling.
|
||||
2) Prepare sprint‑ready tickets for Phase 1.
|
||||
3) Implement in Lean Mode, keeping deferred features behind flags for future expansion.
|
||||
|
||||
BIN
apps/.DS_Store
vendored
Normal file
BIN
apps/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
apps/api/.DS_Store
vendored
Normal file
BIN
apps/api/.DS_Store
vendored
Normal file
Binary file not shown.
16
apps/api/.env.example
Normal file
16
apps/api/.env.example
Normal file
@@ -0,0 +1,16 @@
|
||||
# Database Configuration
|
||||
DATABASE_URL="postgresql://username:password@localhost:5432/tabungin_dev"
|
||||
SHADOW_DATABASE_URL="postgresql://username:password@localhost:5432/tabungin_shadow"
|
||||
|
||||
# Firebase Admin SDK Configuration
|
||||
# Get these from Firebase Console > Project Settings > Service Accounts
|
||||
FIREBASE_PROJECT_ID=your_project_id
|
||||
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your_project_id.iam.gserviceaccount.com
|
||||
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_PRIVATE_KEY_HERE\n-----END PRIVATE KEY-----\n"
|
||||
|
||||
# API Configuration
|
||||
PORT=3000
|
||||
WEB_APP_URL=http://localhost:5173
|
||||
|
||||
# Development User ID (run seed script to create this user)
|
||||
TEMP_USER_ID=16b74848-daa3-4dc9-8de2-3cf59e08f8e3
|
||||
5
apps/api/.gitignore
vendored
Normal file
5
apps/api/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
# Keep environment variables out of version control
|
||||
.env
|
||||
|
||||
/generated/prisma
|
||||
4
apps/api/.prettierrc
Normal file
4
apps/api/.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
98
apps/api/README.md
Normal file
98
apps/api/README.md
Normal file
@@ -0,0 +1,98 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Project setup
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
## Compile and run the project
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
## Run tests
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
|
||||
|
||||
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
|
||||
|
||||
```bash
|
||||
$ npm install -g @nestjs/mau
|
||||
$ mau deploy
|
||||
```
|
||||
|
||||
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
|
||||
|
||||
## Resources
|
||||
|
||||
Check out a few resources that may come in handy when working with NestJS:
|
||||
|
||||
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
|
||||
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
|
||||
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
|
||||
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
|
||||
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
|
||||
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
|
||||
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
|
||||
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
|
||||
6
apps/api/dist/app.controller.d.ts
vendored
Normal file
6
apps/api/dist/app.controller.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { AppService } from './app.service';
|
||||
export declare class AppController {
|
||||
private readonly appService;
|
||||
constructor(appService: AppService);
|
||||
getHello(): string;
|
||||
}
|
||||
35
apps/api/dist/app.controller.js
vendored
Normal file
35
apps/api/dist/app.controller.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const app_service_1 = require("./app.service");
|
||||
let AppController = class AppController {
|
||||
appService;
|
||||
constructor(appService) {
|
||||
this.appService = appService;
|
||||
}
|
||||
getHello() {
|
||||
return this.appService.getHello();
|
||||
}
|
||||
};
|
||||
exports.AppController = AppController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", String)
|
||||
], AppController.prototype, "getHello", null);
|
||||
exports.AppController = AppController = __decorate([
|
||||
(0, common_1.Controller)(),
|
||||
__metadata("design:paramtypes", [app_service_1.AppService])
|
||||
], AppController);
|
||||
//# sourceMappingURL=app.controller.js.map
|
||||
1
apps/api/dist/app.controller.js.map
vendored
Normal file
1
apps/api/dist/app.controller.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,+CAA2C;AAGpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAGvD,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF,CAAA;AAPY,sCAAa;AAIxB;IADC,IAAA,YAAG,GAAE;;;;6CAGL;wBANU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE8B,wBAAU;GADxC,aAAa,CAOzB"}
|
||||
2
apps/api/dist/app.module.d.ts
vendored
Normal file
2
apps/api/dist/app.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class AppModule {
|
||||
}
|
||||
77
apps/api/dist/app.module.js
vendored
Normal file
77
apps/api/dist/app.module.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const path = __importStar(require("path"));
|
||||
const prisma_module_1 = require("./prisma/prisma.module");
|
||||
const auth_module_1 = require("./auth/auth.module");
|
||||
const health_controller_1 = require("./health/health.controller");
|
||||
const users_module_1 = require("./users/users.module");
|
||||
const wallets_module_1 = require("./wallets/wallets.module");
|
||||
const transactions_module_1 = require("./transactions/transactions.module");
|
||||
const categories_module_1 = require("./categories/categories.module");
|
||||
let AppModule = class AppModule {
|
||||
};
|
||||
exports.AppModule = AppModule;
|
||||
exports.AppModule = AppModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
config_1.ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: [
|
||||
path.resolve(process.cwd(), '.env'),
|
||||
path.resolve(process.cwd(), '../../.env'),
|
||||
],
|
||||
}),
|
||||
prisma_module_1.PrismaModule,
|
||||
auth_module_1.AuthModule,
|
||||
users_module_1.UsersModule,
|
||||
wallets_module_1.WalletsModule,
|
||||
transactions_module_1.TransactionsModule,
|
||||
categories_module_1.CategoriesModule,
|
||||
],
|
||||
controllers: [health_controller_1.HealthController],
|
||||
providers: [],
|
||||
})
|
||||
], AppModule);
|
||||
//# sourceMappingURL=app.module.js.map
|
||||
1
apps/api/dist/app.module.js.map
vendored
Normal file
1
apps/api/dist/app.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAC9C,2CAA6B;AAC7B,0DAAsD;AACtD,oDAAgD;AAChD,kEAA8D;AAC9D,uDAAmD;AACnD,6DAAyD;AACzD,4EAAwE;AACxE,sEAAkE;AAqB3D,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IAnBrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE;oBACX,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC;oBACnC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC;iBAC1C;aACF,CAAC;YACF,4BAAY;YACZ,wBAAU;YACV,0BAAW;YACX,8BAAa;YACb,wCAAkB;YAClB,oCAAgB;SACjB;QACD,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,EAAE;KACd,CAAC;GACW,SAAS,CAAG"}
|
||||
3
apps/api/dist/app.service.d.ts
vendored
Normal file
3
apps/api/dist/app.service.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export declare class AppService {
|
||||
getHello(): string;
|
||||
}
|
||||
20
apps/api/dist/app.service.js
vendored
Normal file
20
apps/api/dist/app.service.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
let AppService = class AppService {
|
||||
getHello() {
|
||||
return 'Hello World!';
|
||||
}
|
||||
};
|
||||
exports.AppService = AppService;
|
||||
exports.AppService = AppService = __decorate([
|
||||
(0, common_1.Injectable)()
|
||||
], AppService);
|
||||
//# sourceMappingURL=app.service.js.map
|
||||
1
apps/api/dist/app.service.js.map
vendored
Normal file
1
apps/api/dist/app.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.service.js","sourceRoot":"","sources":["../src/app.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAGrC,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,QAAQ;QACN,OAAO,cAAc,CAAC;IACxB,CAAC;CACF,CAAA;AAJY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;GACA,UAAU,CAItB"}
|
||||
8
apps/api/dist/auth/auth.guard.d.ts
vendored
Normal file
8
apps/api/dist/auth/auth.guard.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { CanActivate, ExecutionContext } from '@nestjs/common';
|
||||
import { FirebaseService } from './firebase.service';
|
||||
export declare class AuthGuard implements CanActivate {
|
||||
private firebaseService;
|
||||
constructor(firebaseService: FirebaseService);
|
||||
canActivate(context: ExecutionContext): Promise<boolean>;
|
||||
private extractTokenFromHeader;
|
||||
}
|
||||
49
apps/api/dist/auth/auth.guard.js
vendored
Normal file
49
apps/api/dist/auth/auth.guard.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AuthGuard = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const firebase_service_1 = require("./firebase.service");
|
||||
let AuthGuard = class AuthGuard {
|
||||
firebaseService;
|
||||
constructor(firebaseService) {
|
||||
this.firebaseService = firebaseService;
|
||||
}
|
||||
async canActivate(context) {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
if (!this.firebaseService.isFirebaseConfigured()) {
|
||||
console.warn('⚠️ Firebase not configured - allowing request without auth');
|
||||
return true;
|
||||
}
|
||||
const token = this.extractTokenFromHeader(request);
|
||||
if (!token) {
|
||||
throw new common_1.UnauthorizedException('No token provided');
|
||||
}
|
||||
try {
|
||||
const decodedToken = await this.firebaseService.verifyIdToken(token);
|
||||
request.user = decodedToken;
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
throw new common_1.UnauthorizedException('Invalid token');
|
||||
}
|
||||
}
|
||||
extractTokenFromHeader(request) {
|
||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
};
|
||||
exports.AuthGuard = AuthGuard;
|
||||
exports.AuthGuard = AuthGuard = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [firebase_service_1.FirebaseService])
|
||||
], AuthGuard);
|
||||
//# sourceMappingURL=auth.guard.js.map
|
||||
1
apps/api/dist/auth/auth.guard.js.map
vendored
Normal file
1
apps/api/dist/auth/auth.guard.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.guard.js","sourceRoot":"","sources":["../../src/auth/auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAkG;AAClG,yDAAqD;AAG9C,IAAM,SAAS,GAAf,MAAM,SAAS;IACA;IAApB,YAAoB,eAAgC;QAAhC,oBAAe,GAAf,eAAe,CAAiB;IAAG,CAAC;IAExD,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAGpD,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE,EAAE,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,CAAC,mBAAmB,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,8BAAqB,CAAC,eAAe,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,OAAY;QACzC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACtE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;CACF,CAAA;AA/BY,8BAAS;oBAAT,SAAS;IADrB,IAAA,mBAAU,GAAE;qCAE0B,kCAAe;GADzC,SAAS,CA+BrB"}
|
||||
2
apps/api/dist/auth/auth.module.d.ts
vendored
Normal file
2
apps/api/dist/auth/auth.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class AuthModule {
|
||||
}
|
||||
22
apps/api/dist/auth/auth.module.js
vendored
Normal file
22
apps/api/dist/auth/auth.module.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AuthModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const firebase_service_1 = require("./firebase.service");
|
||||
const auth_guard_1 = require("./auth.guard");
|
||||
let AuthModule = class AuthModule {
|
||||
};
|
||||
exports.AuthModule = AuthModule;
|
||||
exports.AuthModule = AuthModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
providers: [firebase_service_1.FirebaseService, auth_guard_1.AuthGuard],
|
||||
exports: [firebase_service_1.FirebaseService, auth_guard_1.AuthGuard],
|
||||
})
|
||||
], AuthModule);
|
||||
//# sourceMappingURL=auth.module.js.map
|
||||
1
apps/api/dist/auth/auth.module.js.map
vendored
Normal file
1
apps/api/dist/auth/auth.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,yDAAqD;AACrD,6CAAyC;AAMlC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAJtB,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,kCAAe,EAAE,sBAAS,CAAC;QACvC,OAAO,EAAE,CAAC,kCAAe,EAAE,sBAAS,CAAC;KACtC,CAAC;GACW,UAAU,CAAG"}
|
||||
9
apps/api/dist/auth/firebase.service.d.ts
vendored
Normal file
9
apps/api/dist/auth/firebase.service.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as admin from 'firebase-admin';
|
||||
export declare class FirebaseService {
|
||||
private app;
|
||||
private isConfigured;
|
||||
constructor();
|
||||
verifyIdToken(idToken: string): Promise<admin.auth.DecodedIdToken>;
|
||||
getUser(uid: string): Promise<admin.auth.UserRecord>;
|
||||
isFirebaseConfigured(): boolean;
|
||||
}
|
||||
113
apps/api/dist/auth/firebase.service.js
vendored
Normal file
113
apps/api/dist/auth/firebase.service.js
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FirebaseService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const admin = __importStar(require("firebase-admin"));
|
||||
let FirebaseService = class FirebaseService {
|
||||
app = null;
|
||||
isConfigured = false;
|
||||
constructor() {
|
||||
const projectId = process.env.FIREBASE_PROJECT_ID;
|
||||
const clientEmail = process.env.FIREBASE_CLIENT_EMAIL;
|
||||
const privateKey = process.env.FIREBASE_PRIVATE_KEY;
|
||||
if (projectId && clientEmail && privateKey) {
|
||||
try {
|
||||
if (!admin.apps.length) {
|
||||
this.app = admin.initializeApp({
|
||||
credential: admin.credential.cert({
|
||||
projectId,
|
||||
clientEmail,
|
||||
privateKey: privateKey.replace(/\\n/g, '\n'),
|
||||
}),
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.app = admin.app();
|
||||
}
|
||||
this.isConfigured = true;
|
||||
console.log('✅ Firebase Admin initialized successfully');
|
||||
}
|
||||
catch (error) {
|
||||
console.warn('⚠️ Firebase Admin initialization failed:', error.message);
|
||||
this.isConfigured = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn('⚠️ Firebase credentials not found. Auth will use fallback mode.');
|
||||
this.isConfigured = false;
|
||||
}
|
||||
}
|
||||
async verifyIdToken(idToken) {
|
||||
if (!this.isConfigured || !this.app) {
|
||||
throw new Error('Firebase not configured');
|
||||
}
|
||||
try {
|
||||
return await admin.auth().verifyIdToken(idToken);
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error('Invalid token');
|
||||
}
|
||||
}
|
||||
async getUser(uid) {
|
||||
if (!this.isConfigured || !this.app) {
|
||||
throw new Error('Firebase not configured');
|
||||
}
|
||||
try {
|
||||
return await admin.auth().getUser(uid);
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
}
|
||||
isFirebaseConfigured() {
|
||||
return this.isConfigured;
|
||||
}
|
||||
};
|
||||
exports.FirebaseService = FirebaseService;
|
||||
exports.FirebaseService = FirebaseService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [])
|
||||
], FirebaseService);
|
||||
//# sourceMappingURL=firebase.service.js.map
|
||||
1
apps/api/dist/auth/firebase.service.js.map
vendored
Normal file
1
apps/api/dist/auth/firebase.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"firebase.service.js","sourceRoot":"","sources":["../../src/auth/firebase.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA4C;AAC5C,sDAAwC;AAGjC,IAAM,eAAe,GAArB,MAAM,eAAe;IAClB,GAAG,GAAyB,IAAI,CAAC;IACjC,YAAY,GAAY,KAAK,CAAC;IAEtC;QAEE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAClD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;QACtD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAEpD,IAAI,SAAS,IAAI,WAAW,IAAI,UAAU,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACvB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,aAAa,CAAC;wBAC7B,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;4BAChC,SAAS;4BACT,WAAW;4BACX,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;yBAC7C,CAAC;qBACH,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACzB,CAAC;gBACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YAC3D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;YAC5B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;YAChF,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAe;QACjC,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,oBAAoB;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;CACF,CAAA;AA5DY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;;GACA,eAAe,CA4D3B"}
|
||||
28
apps/api/dist/categories/categories.controller.d.ts
vendored
Normal file
28
apps/api/dist/categories/categories.controller.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import { CategoriesService } from '../categories/categories.service';
|
||||
import { CreateCategoryDto } from '../categories/dto/create-category.dto';
|
||||
export declare class CategoriesController {
|
||||
private readonly categoriesService;
|
||||
constructor(categoriesService: CategoriesService);
|
||||
private userId;
|
||||
create(createCategoryDto: CreateCategoryDto): Promise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
}>;
|
||||
findAll(): Promise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
}[]>;
|
||||
remove(id: string): Promise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
}>;
|
||||
}
|
||||
66
apps/api/dist/categories/categories.controller.js
vendored
Normal file
66
apps/api/dist/categories/categories.controller.js
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CategoriesController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const categories_service_1 = require("../categories/categories.service");
|
||||
const create_category_dto_1 = require("../categories/dto/create-category.dto");
|
||||
const user_util_1 = require("../common/user.util");
|
||||
let CategoriesController = class CategoriesController {
|
||||
categoriesService;
|
||||
constructor(categoriesService) {
|
||||
this.categoriesService = categoriesService;
|
||||
}
|
||||
userId() {
|
||||
return (0, user_util_1.getTempUserId)();
|
||||
}
|
||||
create(createCategoryDto) {
|
||||
return this.categoriesService.create({
|
||||
...createCategoryDto,
|
||||
userId: this.userId(),
|
||||
});
|
||||
}
|
||||
findAll() {
|
||||
return this.categoriesService.findAll(this.userId());
|
||||
}
|
||||
remove(id) {
|
||||
return this.categoriesService.remove(id, this.userId());
|
||||
}
|
||||
};
|
||||
exports.CategoriesController = CategoriesController;
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [create_category_dto_1.CreateCategoryDto]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CategoriesController.prototype, "create", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CategoriesController.prototype, "findAll", null);
|
||||
__decorate([
|
||||
(0, common_1.Delete)(':id'),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CategoriesController.prototype, "remove", null);
|
||||
exports.CategoriesController = CategoriesController = __decorate([
|
||||
(0, common_1.Controller)('categories'),
|
||||
__metadata("design:paramtypes", [categories_service_1.CategoriesService])
|
||||
], CategoriesController);
|
||||
//# sourceMappingURL=categories.controller.js.map
|
||||
1
apps/api/dist/categories/categories.controller.js.map
vendored
Normal file
1
apps/api/dist/categories/categories.controller.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"categories.controller.js","sourceRoot":"","sources":["../../src/categories/categories.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAOwB;AACxB,yEAAqE;AACrE,+EAA0E;AAC1E,mDAAoD;AAG7C,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACF;IAA7B,YAA6B,iBAAoC;QAApC,sBAAiB,GAAjB,iBAAiB,CAAmB;IAAG,CAAC;IAE7D,MAAM;QACZ,OAAO,IAAA,yBAAa,GAAE,CAAC;IACzB,CAAC;IAGD,MAAM,CAAS,iBAAoC;QACjD,OAAO,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;YACnC,GAAG,iBAAiB;YACpB,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAGD,OAAO;QACL,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAGD,MAAM,CAAc,EAAU;QAC5B,OAAO,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;CACF,CAAA;AAxBY,oDAAoB;AAQ/B;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAAoB,uCAAiB;;kDAKlD;AAGD;IADC,IAAA,YAAG,GAAE;;;;mDAGL;AAGD;IADC,IAAA,eAAM,EAAC,KAAK,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;kDAElB;+BAvBU,oBAAoB;IADhC,IAAA,mBAAU,EAAC,YAAY,CAAC;qCAEyB,sCAAiB;GADtD,oBAAoB,CAwBhC"}
|
||||
2
apps/api/dist/categories/categories.module.d.ts
vendored
Normal file
2
apps/api/dist/categories/categories.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class CategoriesModule {
|
||||
}
|
||||
26
apps/api/dist/categories/categories.module.js
vendored
Normal file
26
apps/api/dist/categories/categories.module.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CategoriesModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const categories_service_1 = require("./categories.service");
|
||||
const categories_controller_1 = require("./categories.controller");
|
||||
const prisma_module_1 = require("../prisma/prisma.module");
|
||||
const auth_module_1 = require("../auth/auth.module");
|
||||
let CategoriesModule = class CategoriesModule {
|
||||
};
|
||||
exports.CategoriesModule = CategoriesModule;
|
||||
exports.CategoriesModule = CategoriesModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [prisma_module_1.PrismaModule, auth_module_1.AuthModule],
|
||||
controllers: [categories_controller_1.CategoriesController],
|
||||
providers: [categories_service_1.CategoriesService],
|
||||
exports: [categories_service_1.CategoriesService],
|
||||
})
|
||||
], CategoriesModule);
|
||||
//# sourceMappingURL=categories.module.js.map
|
||||
1
apps/api/dist/categories/categories.module.js.map
vendored
Normal file
1
apps/api/dist/categories/categories.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"categories.module.js","sourceRoot":"","sources":["../../src/categories/categories.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6DAAyD;AACzD,mEAA+D;AAC/D,2DAAuD;AACvD,qDAAiD;AAQ1C,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAG,CAAA;AAAnB,4CAAgB;2BAAhB,gBAAgB;IAN5B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,wBAAU,CAAC;QACnC,WAAW,EAAE,CAAC,4CAAoB,CAAC;QACnC,SAAS,EAAE,CAAC,sCAAiB,CAAC;QAC9B,OAAO,EAAE,CAAC,sCAAiB,CAAC;KAC7B,CAAC;GACW,gBAAgB,CAAG"}
|
||||
30
apps/api/dist/categories/categories.service.d.ts
vendored
Normal file
30
apps/api/dist/categories/categories.service.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { CreateCategoryDto } from './dto/create-category.dto';
|
||||
export declare class CategoriesService {
|
||||
private prisma;
|
||||
constructor(prisma: PrismaService);
|
||||
create(data: CreateCategoryDto & {
|
||||
userId: string;
|
||||
}): Promise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
}>;
|
||||
findAll(userId: string): Promise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
}[]>;
|
||||
remove(id: string, userId: string): Promise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
}>;
|
||||
findOrCreate(names: string[], userId: string): Promise<any[]>;
|
||||
}
|
||||
74
apps/api/dist/categories/categories.service.js
vendored
Normal file
74
apps/api/dist/categories/categories.service.js
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CategoriesService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("../prisma/prisma.service");
|
||||
let CategoriesService = class CategoriesService {
|
||||
prisma;
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
async create(data) {
|
||||
try {
|
||||
return await this.prisma.category.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
userId: data.userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
if (error.code === 'P2002') {
|
||||
throw new common_1.ConflictException('Category already exists');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async findAll(userId) {
|
||||
return this.prisma.category.findMany({
|
||||
where: { userId },
|
||||
orderBy: { name: 'asc' },
|
||||
});
|
||||
}
|
||||
async remove(id, userId) {
|
||||
const category = await this.prisma.category.findFirst({
|
||||
where: { id, userId },
|
||||
});
|
||||
if (!category) {
|
||||
throw new common_1.NotFoundException('Category not found');
|
||||
}
|
||||
return this.prisma.category.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
async findOrCreate(names, userId) {
|
||||
const categories = [];
|
||||
for (const name of names) {
|
||||
let category = await this.prisma.category.findFirst({
|
||||
where: { name, userId },
|
||||
});
|
||||
if (!category) {
|
||||
category = await this.prisma.category.create({
|
||||
data: { name, userId },
|
||||
});
|
||||
}
|
||||
categories.push(category);
|
||||
}
|
||||
return categories;
|
||||
}
|
||||
};
|
||||
exports.CategoriesService = CategoriesService;
|
||||
exports.CategoriesService = CategoriesService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], CategoriesService);
|
||||
//# sourceMappingURL=categories.service.js.map
|
||||
1
apps/api/dist/categories/categories.service.js.map
vendored
Normal file
1
apps/api/dist/categories/categories.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"categories.service.js","sourceRoot":"","sources":["../../src/categories/categories.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAkF;AAClF,6DAAyD;AAIlD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACR;IAApB,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE7C,KAAK,CAAC,MAAM,CAAC,IAA4C;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACvC,IAAI,EAAE;oBACJ,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,MAAM,EAAE,IAAI,CAAC,MAAM;iBACpB;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC3B,MAAM,IAAI,0BAAiB,CAAC,yBAAyB,CAAC,CAAC;YACzD,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACnC,KAAK,EAAE,EAAE,MAAM,EAAE;YACjB,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;SACzB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,MAAc;QACrC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;YACpD,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,0BAAiB,CAAC,oBAAoB,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACjC,KAAK,EAAE,EAAE,EAAE,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAe,EAAE,MAAc;QAChD,MAAM,UAAU,GAAU,EAAE,CAAC;QAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAClD,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;aACxB,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;oBAC3C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;iBACvB,CAAC,CAAC;YACL,CAAC;YAED,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,UAAU,CAAC;IACpB,CAAC;CACF,CAAA;AA3DY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAEiB,8BAAa;GAD9B,iBAAiB,CA2D7B"}
|
||||
3
apps/api/dist/categories/dto/create-category.dto.d.ts
vendored
Normal file
3
apps/api/dist/categories/dto/create-category.dto.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export declare class CreateCategoryDto {
|
||||
name: string;
|
||||
}
|
||||
24
apps/api/dist/categories/dto/create-category.dto.js
vendored
Normal file
24
apps/api/dist/categories/dto/create-category.dto.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CreateCategoryDto = void 0;
|
||||
const class_validator_1 = require("class-validator");
|
||||
class CreateCategoryDto {
|
||||
name;
|
||||
}
|
||||
exports.CreateCategoryDto = CreateCategoryDto;
|
||||
__decorate([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], CreateCategoryDto.prototype, "name", void 0);
|
||||
//# sourceMappingURL=create-category.dto.js.map
|
||||
1
apps/api/dist/categories/dto/create-category.dto.js.map
vendored
Normal file
1
apps/api/dist/categories/dto/create-category.dto.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"create-category.dto.js","sourceRoot":"","sources":["../../../src/categories/dto/create-category.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAAkE;AAElE,MAAa,iBAAiB;IAI5B,IAAI,CAAS;CACd;AALD,8CAKC;AADC;IAHC,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;IACZ,IAAA,2BAAS,EAAC,EAAE,CAAC;;+CACD"}
|
||||
3
apps/api/dist/common/user.util.d.ts
vendored
Normal file
3
apps/api/dist/common/user.util.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export declare function getTempUserId(): string;
|
||||
export declare function getUserIdFromRequest(request: any): string;
|
||||
export declare function createUserDecorator(): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
||||
23
apps/api/dist/common/user.util.js
vendored
Normal file
23
apps/api/dist/common/user.util.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getTempUserId = getTempUserId;
|
||||
exports.getUserIdFromRequest = getUserIdFromRequest;
|
||||
exports.createUserDecorator = createUserDecorator;
|
||||
function getTempUserId() {
|
||||
const id = process.env.TEMP_USER_ID?.trim();
|
||||
if (!id) {
|
||||
throw new Error('TEMP_USER_ID is not set. Run the seed and set it in apps/api/.env');
|
||||
}
|
||||
return id;
|
||||
}
|
||||
function getUserIdFromRequest(request) {
|
||||
if (request.user?.uid) {
|
||||
return request.user.uid;
|
||||
}
|
||||
return getTempUserId();
|
||||
}
|
||||
function createUserDecorator() {
|
||||
return (target, propertyKey, descriptor) => {
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=user.util.js.map
|
||||
1
apps/api/dist/common/user.util.js.map
vendored
Normal file
1
apps/api/dist/common/user.util.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"user.util.js","sourceRoot":"","sources":["../../src/common/user.util.ts"],"names":[],"mappings":";;AAAA,sCAMG;AAEH,oDAQC;AAED,kDAKC;AAvBD,SAAgB,aAAa;IACzB,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAEH,SAAgB,oBAAoB,CAAC,OAAY;IAE/C,IAAI,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;IAC1B,CAAC;IAGD,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC;AAED,SAAgB,mBAAmB;IACjC,OAAO,CAAC,MAAW,EAAE,WAAmB,EAAE,UAA8B,EAAE,EAAE;IAG5E,CAAC,CAAC;AACJ,CAAC"}
|
||||
11
apps/api/dist/health/health.controller.d.ts
vendored
Normal file
11
apps/api/dist/health/health.controller.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
export declare class HealthController {
|
||||
private readonly prisma;
|
||||
constructor(prisma: PrismaService);
|
||||
ok(): {
|
||||
status: string;
|
||||
};
|
||||
db(): Promise<{
|
||||
db: string;
|
||||
}>;
|
||||
}
|
||||
45
apps/api/dist/health/health.controller.js
vendored
Normal file
45
apps/api/dist/health/health.controller.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.HealthController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("../prisma/prisma.service");
|
||||
let HealthController = class HealthController {
|
||||
prisma;
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
ok() {
|
||||
return { status: 'ok' };
|
||||
}
|
||||
async db() {
|
||||
await this.prisma.$queryRaw `SELECT 1`;
|
||||
return { db: 'connected' };
|
||||
}
|
||||
};
|
||||
exports.HealthController = HealthController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", void 0)
|
||||
], HealthController.prototype, "ok", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('db'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], HealthController.prototype, "db", null);
|
||||
exports.HealthController = HealthController = __decorate([
|
||||
(0, common_1.Controller)('health'),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], HealthController);
|
||||
//# sourceMappingURL=health.controller.js.map
|
||||
1
apps/api/dist/health/health.controller.js.map
vendored
Normal file
1
apps/api/dist/health/health.controller.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"health.controller.js","sourceRoot":"","sources":["../../src/health/health.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,6DAAyD;AAGlD,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACE;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAGtD,EAAE;QACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1B,CAAC;IAGK,AAAN,KAAK,CAAC,EAAE;QAEN,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAA,UAAU,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC;IAC7B,CAAC;CACF,CAAA;AAdY,4CAAgB;AAI3B;IADC,IAAA,YAAG,GAAE;;;;0CAGL;AAGK;IADL,IAAA,YAAG,EAAC,IAAI,CAAC;;;;0CAKT;2BAbU,gBAAgB;IAD5B,IAAA,mBAAU,EAAC,QAAQ,CAAC;qCAEkB,8BAAa;GADvC,gBAAgB,CAc5B"}
|
||||
1
apps/api/dist/main.d.ts
vendored
Normal file
1
apps/api/dist/main.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
18
apps/api/dist/main.js
vendored
Normal file
18
apps/api/dist/main.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core_1 = require("@nestjs/core");
|
||||
const app_module_1 = require("./app.module");
|
||||
async function bootstrap() {
|
||||
const app = await core_1.NestFactory.create(app_module_1.AppModule);
|
||||
const webOrigin = process.env.WEB_APP_URL ?? 'http://localhost:5173';
|
||||
app.enableCors({
|
||||
origin: webOrigin,
|
||||
credentials: true,
|
||||
});
|
||||
app.setGlobalPrefix('api');
|
||||
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
|
||||
await app.listen(port);
|
||||
console.log(`API listening on http://localhost:${port}`);
|
||||
}
|
||||
bootstrap();
|
||||
//# sourceMappingURL=main.js.map
|
||||
1
apps/api/dist/main.js.map
vendored
Normal file
1
apps/api/dist/main.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAGhD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,uBAAuB,CAAC;IACrE,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAE3B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC;AACD,SAAS,EAAE,CAAC"}
|
||||
2
apps/api/dist/prisma/prisma.module.d.ts
vendored
Normal file
2
apps/api/dist/prisma/prisma.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class PrismaModule {
|
||||
}
|
||||
22
apps/api/dist/prisma/prisma.module.js
vendored
Normal file
22
apps/api/dist/prisma/prisma.module.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PrismaModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("./prisma.service");
|
||||
let PrismaModule = class PrismaModule {
|
||||
};
|
||||
exports.PrismaModule = PrismaModule;
|
||||
exports.PrismaModule = PrismaModule = __decorate([
|
||||
(0, common_1.Global)(),
|
||||
(0, common_1.Module)({
|
||||
providers: [prisma_service_1.PrismaService],
|
||||
exports: [prisma_service_1.PrismaService],
|
||||
})
|
||||
], PrismaModule);
|
||||
//# sourceMappingURL=prisma.module.js.map
|
||||
1
apps/api/dist/prisma/prisma.module.js.map
vendored
Normal file
1
apps/api/dist/prisma/prisma.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"prisma.module.js","sourceRoot":"","sources":["../../src/prisma/prisma.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,qDAAiD;AAO1C,IAAM,YAAY,GAAlB,MAAM,YAAY;CAAG,CAAA;AAAf,oCAAY;uBAAZ,YAAY;IALxB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,8BAAa,CAAC;QAC1B,OAAO,EAAE,CAAC,8BAAa,CAAC;KACzB,CAAC;GACW,YAAY,CAAG"}
|
||||
6
apps/api/dist/prisma/prisma.service.d.ts
vendored
Normal file
6
apps/api/dist/prisma/prisma.service.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { INestApplication, OnModuleInit } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
export declare class PrismaService extends PrismaClient implements OnModuleInit {
|
||||
onModuleInit(): Promise<void>;
|
||||
enableShutdownHooks(app: INestApplication): Promise<void>;
|
||||
}
|
||||
26
apps/api/dist/prisma/prisma.service.js
vendored
Normal file
26
apps/api/dist/prisma/prisma.service.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PrismaService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const client_1 = require("@prisma/client");
|
||||
let PrismaService = class PrismaService extends client_1.PrismaClient {
|
||||
async onModuleInit() {
|
||||
await this.$connect();
|
||||
}
|
||||
async enableShutdownHooks(app) {
|
||||
process.on('beforeExit', async () => {
|
||||
await app.close();
|
||||
});
|
||||
}
|
||||
};
|
||||
exports.PrismaService = PrismaService;
|
||||
exports.PrismaService = PrismaService = __decorate([
|
||||
(0, common_1.Injectable)()
|
||||
], PrismaService);
|
||||
//# sourceMappingURL=prisma.service.js.map
|
||||
1
apps/api/dist/prisma/prisma.service.js.map
vendored
Normal file
1
apps/api/dist/prisma/prisma.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"prisma.service.js","sourceRoot":"","sources":["../../src/prisma/prisma.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4E;AAC5E,2CAA8C;AAGvC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,qBAAY;IAC7C,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAGD,KAAK,CAAC,mBAAmB,CAAC,GAAqB;QAC7C,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;YAClC,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAXY,sCAAa;wBAAb,aAAa;IADzB,IAAA,mBAAU,GAAE;GACA,aAAa,CAWzB"}
|
||||
1
apps/api/dist/seed.d.ts
vendored
Normal file
1
apps/api/dist/seed.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
37
apps/api/dist/seed.js
vendored
Normal file
37
apps/api/dist/seed.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function main() {
|
||||
const userId = '16b74848-daa3-4dc9-8de2-3cf59e08f8e3';
|
||||
const user = await prisma.user.upsert({
|
||||
where: { id: userId },
|
||||
update: {},
|
||||
create: {
|
||||
id: userId,
|
||||
},
|
||||
});
|
||||
const existing = await prisma.wallet.findFirst({
|
||||
where: { userId: user.id, kind: 'money' },
|
||||
});
|
||||
if (!existing) {
|
||||
await prisma.wallet.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
kind: 'money',
|
||||
name: 'Cash',
|
||||
currency: 'IDR',
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log('Seed complete. TEMP_USER_ID=', user.id);
|
||||
}
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
//# sourceMappingURL=seed.js.map
|
||||
1
apps/api/dist/seed.js.map
vendored
Normal file
1
apps/api/dist/seed.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":";;AAAA,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,sCAAsC,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE;QACrB,MAAM,EAAE,EAAE;QACV,MAAM,EAAE;YACN,EAAE,EAAE,MAAM;SACX;KACF,CAAC,CAAC;IAGH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QAC7C,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;KAC1C,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;YACzB,IAAI,EAAE;gBACJ,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,KAAK;aAChB;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,IAAI,EAAE;KACH,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;KACD,OAAO,CAAC,KAAK,IAAI,EAAE;IAClB,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC,CAAC,CAAC"}
|
||||
12
apps/api/dist/transactions/transaction.dto.d.ts
vendored
Normal file
12
apps/api/dist/transactions/transaction.dto.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
export declare const TransactionUpdateSchema: z.ZodObject<{
|
||||
amount: z.ZodOptional<z.ZodNumber>;
|
||||
direction: z.ZodOptional<z.ZodEnum<{
|
||||
in: "in";
|
||||
out: "out";
|
||||
}>>;
|
||||
date: z.ZodOptional<z.ZodString>;
|
||||
category: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
memo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
||||
}, z.core.$strip>;
|
||||
export type TransactionUpdateDto = z.infer<typeof TransactionUpdateSchema>;
|
||||
12
apps/api/dist/transactions/transaction.dto.js
vendored
Normal file
12
apps/api/dist/transactions/transaction.dto.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TransactionUpdateSchema = void 0;
|
||||
const zod_1 = require("zod");
|
||||
exports.TransactionUpdateSchema = zod_1.z.object({
|
||||
amount: zod_1.z.number().positive().optional(),
|
||||
direction: zod_1.z.enum(['in', 'out']).optional(),
|
||||
date: zod_1.z.string().datetime().optional(),
|
||||
category: zod_1.z.string().min(1).nullable().optional(),
|
||||
memo: zod_1.z.string().min(1).nullable().optional(),
|
||||
});
|
||||
//# sourceMappingURL=transaction.dto.js.map
|
||||
1
apps/api/dist/transactions/transaction.dto.js.map
vendored
Normal file
1
apps/api/dist/transactions/transaction.dto.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"transaction.dto.js","sourceRoot":"","sources":["../../src/transactions/transaction.dto.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEX,QAAA,uBAAuB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC9C,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACxC,SAAS,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC1C,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACtC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACjD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC"}
|
||||
61
apps/api/dist/transactions/transactions.controller.d.ts
vendored
Normal file
61
apps/api/dist/transactions/transactions.controller.d.ts
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import type { Response } from 'express';
|
||||
import { TransactionsService } from './transactions.service';
|
||||
export declare class TransactionsController {
|
||||
private readonly tx;
|
||||
constructor(tx: TransactionsService);
|
||||
list(walletId: string): import("@prisma/client").Prisma.PrismaPromise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: import("@prisma/client/runtime/library").Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}[]>;
|
||||
create(walletId: string, body: {
|
||||
amount: number | string;
|
||||
direction: 'in' | 'out';
|
||||
date?: string;
|
||||
category?: string;
|
||||
memo?: string;
|
||||
}): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: import("@prisma/client/runtime/library").Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}>;
|
||||
exportCsv(walletId: string, from: string | undefined, to: string | undefined, category: string | undefined, direction: 'in' | 'out' | undefined, res: Response): Promise<void>;
|
||||
update(walletId: string, id: string, body: unknown): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: import("@prisma/client/runtime/library").Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}>;
|
||||
delete(walletId: string, id: string): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: import("@prisma/client/runtime/library").Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}>;
|
||||
}
|
||||
115
apps/api/dist/transactions/transactions.controller.js
vendored
Normal file
115
apps/api/dist/transactions/transactions.controller.js
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TransactionsController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const transactions_service_1 = require("./transactions.service");
|
||||
const transaction_dto_1 = require("./transaction.dto");
|
||||
let TransactionsController = class TransactionsController {
|
||||
tx;
|
||||
constructor(tx) {
|
||||
this.tx = tx;
|
||||
}
|
||||
list(walletId) {
|
||||
return this.tx.list(walletId);
|
||||
}
|
||||
create(walletId, body) {
|
||||
return this.tx.create(walletId, body);
|
||||
}
|
||||
async exportCsv(walletId, from, to, category, direction, res) {
|
||||
const rows = await this.tx.listWithFilters(walletId, { from, to, category, direction });
|
||||
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="transactions_${walletId}.csv"`);
|
||||
res.write(`date,category,memo,direction,amount\n`);
|
||||
const esc = (v) => {
|
||||
if (v === null || v === undefined)
|
||||
return '';
|
||||
const s = String(v);
|
||||
return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
||||
};
|
||||
for (const r of rows) {
|
||||
const line = [
|
||||
r.date.toISOString(),
|
||||
esc(r.category ?? ''),
|
||||
esc(r.memo ?? ''),
|
||||
r.direction,
|
||||
r.amount.toString(),
|
||||
].join(',');
|
||||
res.write(line + '\n');
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
async update(walletId, id, body) {
|
||||
try {
|
||||
const parsed = transaction_dto_1.TransactionUpdateSchema.parse(body);
|
||||
return this.tx.update(walletId, id, parsed);
|
||||
}
|
||||
catch (e) {
|
||||
throw new common_1.BadRequestException(e?.errors ?? 'Invalid payload');
|
||||
}
|
||||
}
|
||||
delete(walletId, id) {
|
||||
return this.tx.delete(walletId, id);
|
||||
}
|
||||
};
|
||||
exports.TransactionsController = TransactionsController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__param(0, (0, common_1.Param)('walletId')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], TransactionsController.prototype, "list", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
__param(0, (0, common_1.Param)('walletId')),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], TransactionsController.prototype, "create", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('export.csv'),
|
||||
__param(0, (0, common_1.Param)('walletId')),
|
||||
__param(1, (0, common_1.Query)('from')),
|
||||
__param(2, (0, common_1.Query)('to')),
|
||||
__param(3, (0, common_1.Query)('category')),
|
||||
__param(4, (0, common_1.Query)('direction')),
|
||||
__param(5, (0, common_1.Res)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object, Object, Object, Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TransactionsController.prototype, "exportCsv", null);
|
||||
__decorate([
|
||||
(0, common_1.Put)(':id'),
|
||||
__param(0, (0, common_1.Param)('walletId')),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], TransactionsController.prototype, "update", null);
|
||||
__decorate([
|
||||
(0, common_1.Delete)(':id'),
|
||||
__param(0, (0, common_1.Param)('walletId')),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], TransactionsController.prototype, "delete", null);
|
||||
exports.TransactionsController = TransactionsController = __decorate([
|
||||
(0, common_1.Controller)('wallets/:walletId/transactions'),
|
||||
__metadata("design:paramtypes", [transactions_service_1.TransactionsService])
|
||||
], TransactionsController);
|
||||
//# sourceMappingURL=transactions.controller.js.map
|
||||
1
apps/api/dist/transactions/transactions.controller.js.map
vendored
Normal file
1
apps/api/dist/transactions/transactions.controller.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"transactions.controller.js","sourceRoot":"","sources":["../../src/transactions/transactions.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAkH;AAElH,iEAA6D;AAC7D,uDAA4D;AAGrD,IAAM,sBAAsB,GAA5B,MAAM,sBAAsB;IACJ;IAA7B,YAA6B,EAAuB;QAAvB,OAAE,GAAF,EAAE,CAAqB;IAAG,CAAC;IAGxD,IAAI,CAAoB,QAAgB;QACtC,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAGD,MAAM,CACe,QAAgB,EAC3B,IAA2G;QAEnH,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;IAGK,AAAN,KAAK,CAAC,SAAS,CACM,QAAgB,EACpB,IAAwB,EAC1B,EAAsB,EAChB,QAA4B,EAC3B,SAAmC,EAChD,GAAa;QAEpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAGxF,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;QACzD,GAAG,CAAC,SAAS,CAAC,qBAAqB,EAAE,sCAAsC,QAAQ,OAAO,CAAC,CAAC;QAG5F,GAAG,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAGnD,MAAM,GAAG,GAAG,CAAC,CAAM,EAAE,EAAE;YACrB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;YAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACpB,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG;gBACX,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE;gBACpB,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;gBACrB,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;gBACjB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;aACpB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACZ,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACzB,CAAC;QAED,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM,CAAoB,QAAgB,EAAe,EAAU,EAAU,IAAa;QAC9F,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,yCAAuB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,MAAM,IAAI,4BAAmB,CAAC,CAAC,EAAE,MAAM,IAAI,iBAAiB,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAGD,MAAM,CAAoB,QAAgB,EAAe,EAAU;QACjE,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACtC,CAAC;CACF,CAAA;AArEY,wDAAsB;AAIjC;IADC,IAAA,YAAG,GAAE;IACA,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;;;;kDAEtB;AAGD;IADC,IAAA,aAAI,GAAE;IAEJ,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;IACjB,WAAA,IAAA,aAAI,GAAE,CAAA;;;;oDAGR;AAGK;IADL,IAAA,YAAG,EAAC,YAAY,CAAC;IAEf,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;IACjB,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;IACjB,WAAA,IAAA,cAAK,EAAC,WAAW,CAAC,CAAA;IAClB,WAAA,IAAA,YAAG,GAAE,CAAA;;;;uDA8BP;AAGK;IADL,IAAA,YAAG,EAAC,KAAK,CAAC;IACG,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;IAAoB,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;oDAOjF;AAGD;IADC,IAAA,eAAM,EAAC,KAAK,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;IAAoB,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;oDAEvD;iCApEU,sBAAsB;IADlC,IAAA,mBAAU,EAAC,gCAAgC,CAAC;qCAEV,0CAAmB;GADzC,sBAAsB,CAqElC"}
|
||||
2
apps/api/dist/transactions/transactions.module.d.ts
vendored
Normal file
2
apps/api/dist/transactions/transactions.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class TransactionsModule {
|
||||
}
|
||||
25
apps/api/dist/transactions/transactions.module.js
vendored
Normal file
25
apps/api/dist/transactions/transactions.module.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TransactionsModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const transactions_service_1 = require("./transactions.service");
|
||||
const transactions_controller_1 = require("./transactions.controller");
|
||||
const prisma_module_1 = require("../prisma/prisma.module");
|
||||
let TransactionsModule = class TransactionsModule {
|
||||
};
|
||||
exports.TransactionsModule = TransactionsModule;
|
||||
exports.TransactionsModule = TransactionsModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [prisma_module_1.PrismaModule],
|
||||
providers: [transactions_service_1.TransactionsService],
|
||||
controllers: [transactions_controller_1.TransactionsController],
|
||||
exports: [transactions_service_1.TransactionsService],
|
||||
})
|
||||
], TransactionsModule);
|
||||
//# sourceMappingURL=transactions.module.js.map
|
||||
1
apps/api/dist/transactions/transactions.module.js.map
vendored
Normal file
1
apps/api/dist/transactions/transactions.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"transactions.module.js","sourceRoot":"","sources":["../../src/transactions/transactions.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,iEAA6D;AAC7D,uEAAmE;AACnE,2DAAuD;AAQhD,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;CAAG,CAAA;AAArB,gDAAkB;6BAAlB,kBAAkB;IAN9B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,SAAS,EAAE,CAAC,0CAAmB,CAAC;QAChC,WAAW,EAAE,CAAC,gDAAsB,CAAC;QACrC,OAAO,EAAE,CAAC,0CAAmB,CAAC;KAC/B,CAAC;GACW,kBAAkB,CAAG"}
|
||||
91
apps/api/dist/transactions/transactions.service.d.ts
vendored
Normal file
91
apps/api/dist/transactions/transactions.service.d.ts
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import type { TransactionUpdateDto } from './transaction.dto';
|
||||
export declare class TransactionsService {
|
||||
private prisma;
|
||||
constructor(prisma: PrismaService);
|
||||
private userId;
|
||||
list(walletId: string): Prisma.PrismaPromise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: Prisma.Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}[]>;
|
||||
listAll(): Prisma.PrismaPromise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: Prisma.Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}[]>;
|
||||
listWithFilters(walletId: string, filters: {
|
||||
from?: string;
|
||||
to?: string;
|
||||
category?: string;
|
||||
direction?: 'in' | 'out';
|
||||
}): Prisma.PrismaPromise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: Prisma.Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}[]>;
|
||||
create(walletId: string, input: {
|
||||
amount: string | number;
|
||||
direction: 'in' | 'out';
|
||||
date?: string;
|
||||
category?: string;
|
||||
memo?: string;
|
||||
}): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: Prisma.Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}>;
|
||||
update(walletId: string, id: string, dto: TransactionUpdateDto): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: Prisma.Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}>;
|
||||
delete(walletId: string, id: string): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: Prisma.Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}>;
|
||||
}
|
||||
120
apps/api/dist/transactions/transactions.service.js
vendored
Normal file
120
apps/api/dist/transactions/transactions.service.js
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TransactionsService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("../prisma/prisma.service");
|
||||
const user_util_1 = require("../common/user.util");
|
||||
let TransactionsService = class TransactionsService {
|
||||
prisma;
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
userId() {
|
||||
return (0, user_util_1.getTempUserId)();
|
||||
}
|
||||
list(walletId) {
|
||||
return this.prisma.transaction.findMany({
|
||||
where: { userId: this.userId(), walletId },
|
||||
orderBy: { date: 'desc' },
|
||||
take: 200,
|
||||
});
|
||||
}
|
||||
listAll() {
|
||||
return this.prisma.transaction.findMany({
|
||||
where: { userId: this.userId() },
|
||||
orderBy: { date: 'desc' },
|
||||
take: 1000,
|
||||
});
|
||||
}
|
||||
listWithFilters(walletId, filters) {
|
||||
const where = {
|
||||
userId: (0, user_util_1.getTempUserId)(),
|
||||
walletId,
|
||||
};
|
||||
if (filters.direction)
|
||||
where.direction = filters.direction;
|
||||
if (filters.category)
|
||||
where.category = filters.category;
|
||||
if (filters.from || filters.to) {
|
||||
where.date = {};
|
||||
if (filters.from)
|
||||
where.date.gte = new Date(filters.from);
|
||||
if (filters.to)
|
||||
where.date.lte = new Date(filters.to);
|
||||
}
|
||||
return this.prisma.transaction.findMany({
|
||||
where,
|
||||
orderBy: { date: 'desc' },
|
||||
});
|
||||
}
|
||||
async create(walletId, input) {
|
||||
const amountNum = typeof input.amount === 'string' ? Number(input.amount) : input.amount;
|
||||
if (!Number.isFinite(amountNum))
|
||||
throw new Error('amount must be a number');
|
||||
const date = input.date ? new Date(input.date) : new Date();
|
||||
const wallet = await this.prisma.wallet.findFirst({
|
||||
where: { id: walletId, userId: this.userId(), deletedAt: null },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!wallet)
|
||||
throw new Error('wallet not found');
|
||||
return this.prisma.transaction.create({
|
||||
data: {
|
||||
userId: this.userId(),
|
||||
walletId,
|
||||
amount: amountNum,
|
||||
direction: input.direction,
|
||||
date,
|
||||
category: input.category ?? null,
|
||||
memo: input.memo ?? null,
|
||||
},
|
||||
});
|
||||
}
|
||||
async update(walletId, id, dto) {
|
||||
const existing = await this.prisma.transaction.findFirst({
|
||||
where: { id, walletId, userId: this.userId() },
|
||||
});
|
||||
if (!existing)
|
||||
throw new Error('transaction not found');
|
||||
const data = {};
|
||||
if (dto.amount !== undefined)
|
||||
data.amount = Number(dto.amount);
|
||||
if (dto.direction)
|
||||
data.direction = dto.direction;
|
||||
if (dto.category !== undefined)
|
||||
data.category = dto.category || null;
|
||||
if (dto.memo !== undefined)
|
||||
data.memo = dto.memo || null;
|
||||
if (dto.date !== undefined)
|
||||
data.date = new Date(dto.date);
|
||||
return this.prisma.transaction.update({
|
||||
where: { id: existing.id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async delete(walletId, id) {
|
||||
const existing = await this.prisma.transaction.findFirst({
|
||||
where: { id, walletId, userId: this.userId() },
|
||||
});
|
||||
if (!existing)
|
||||
throw new Error('transaction not found');
|
||||
return this.prisma.transaction.delete({
|
||||
where: { id: existing.id },
|
||||
});
|
||||
}
|
||||
};
|
||||
exports.TransactionsService = TransactionsService;
|
||||
exports.TransactionsService = TransactionsService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], TransactionsService);
|
||||
//# sourceMappingURL=transactions.service.js.map
|
||||
1
apps/api/dist/transactions/transactions.service.js.map
vendored
Normal file
1
apps/api/dist/transactions/transactions.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"transactions.service.js","sourceRoot":"","sources":["../../src/transactions/transactions.service.ts"],"names":[],"mappings":"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"}
|
||||
1
apps/api/dist/tsconfig.build.tsbuildinfo
vendored
Normal file
1
apps/api/dist/tsconfig.build.tsbuildinfo
vendored
Normal file
File diff suppressed because one or more lines are too long
16
apps/api/dist/users/users.controller.d.ts
vendored
Normal file
16
apps/api/dist/users/users.controller.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { UsersService } from './users.service';
|
||||
export declare class UsersController {
|
||||
private readonly users;
|
||||
constructor(users: UsersService);
|
||||
me(): Promise<{
|
||||
id: string;
|
||||
email: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
name: string | null;
|
||||
avatarUrl: string | null;
|
||||
defaultCurrency: string | null;
|
||||
timeZone: string | null;
|
||||
} | null>;
|
||||
}
|
||||
35
apps/api/dist/users/users.controller.js
vendored
Normal file
35
apps/api/dist/users/users.controller.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UsersController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const users_service_1 = require("./users.service");
|
||||
let UsersController = class UsersController {
|
||||
users;
|
||||
constructor(users) {
|
||||
this.users = users;
|
||||
}
|
||||
me() {
|
||||
return this.users.me();
|
||||
}
|
||||
};
|
||||
exports.UsersController = UsersController;
|
||||
__decorate([
|
||||
(0, common_1.Get)('me'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", void 0)
|
||||
], UsersController.prototype, "me", null);
|
||||
exports.UsersController = UsersController = __decorate([
|
||||
(0, common_1.Controller)('users'),
|
||||
__metadata("design:paramtypes", [users_service_1.UsersService])
|
||||
], UsersController);
|
||||
//# sourceMappingURL=users.controller.js.map
|
||||
1
apps/api/dist/users/users.controller.js.map
vendored
Normal file
1
apps/api/dist/users/users.controller.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"users.controller.js","sourceRoot":"","sources":["../../src/users/users.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,mDAA+C;AAGxC,IAAM,eAAe,GAArB,MAAM,eAAe;IACG;IAA7B,YAA6B,KAAmB;QAAnB,UAAK,GAAL,KAAK,CAAc;IAAG,CAAC;IAGpD,EAAE;QACA,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;IACzB,CAAC;CACF,CAAA;AAPY,0CAAe;AAI1B;IADC,IAAA,YAAG,EAAC,IAAI,CAAC;;;;yCAGT;0BANU,eAAe;IAD3B,IAAA,mBAAU,EAAC,OAAO,CAAC;qCAEkB,4BAAY;GADrC,eAAe,CAO3B"}
|
||||
2
apps/api/dist/users/users.module.d.ts
vendored
Normal file
2
apps/api/dist/users/users.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class UsersModule {
|
||||
}
|
||||
25
apps/api/dist/users/users.module.js
vendored
Normal file
25
apps/api/dist/users/users.module.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UsersModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const users_service_1 = require("./users.service");
|
||||
const users_controller_1 = require("./users.controller");
|
||||
const prisma_module_1 = require("../prisma/prisma.module");
|
||||
let UsersModule = class UsersModule {
|
||||
};
|
||||
exports.UsersModule = UsersModule;
|
||||
exports.UsersModule = UsersModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [prisma_module_1.PrismaModule],
|
||||
providers: [users_service_1.UsersService],
|
||||
controllers: [users_controller_1.UsersController],
|
||||
exports: [users_service_1.UsersService],
|
||||
})
|
||||
], UsersModule);
|
||||
//# sourceMappingURL=users.module.js.map
|
||||
1
apps/api/dist/users/users.module.js.map
vendored
Normal file
1
apps/api/dist/users/users.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"users.module.js","sourceRoot":"","sources":["../../src/users/users.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,mDAA+C;AAC/C,yDAAqD;AACrD,2DAAuD;AAQhD,IAAM,WAAW,GAAjB,MAAM,WAAW;CAAG,CAAA;AAAd,kCAAW;sBAAX,WAAW;IANvB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,SAAS,EAAE,CAAC,4BAAY,CAAC;QACzB,WAAW,EAAE,CAAC,kCAAe,CAAC;QAC9B,OAAO,EAAE,CAAC,4BAAY,CAAC;KACxB,CAAC;GACW,WAAW,CAAG"}
|
||||
16
apps/api/dist/users/users.service.d.ts
vendored
Normal file
16
apps/api/dist/users/users.service.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
export declare class UsersService {
|
||||
private prisma;
|
||||
constructor(prisma: PrismaService);
|
||||
me(): Promise<{
|
||||
id: string;
|
||||
email: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: string;
|
||||
name: string | null;
|
||||
avatarUrl: string | null;
|
||||
defaultCurrency: string | null;
|
||||
timeZone: string | null;
|
||||
} | null>;
|
||||
}
|
||||
31
apps/api/dist/users/users.service.js
vendored
Normal file
31
apps/api/dist/users/users.service.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UsersService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("../prisma/prisma.service");
|
||||
const user_util_1 = require("../common/user.util");
|
||||
let UsersService = class UsersService {
|
||||
prisma;
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
async me() {
|
||||
const userId = (0, user_util_1.getTempUserId)();
|
||||
return this.prisma.user.findUnique({ where: { id: userId } });
|
||||
}
|
||||
};
|
||||
exports.UsersService = UsersService;
|
||||
exports.UsersService = UsersService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], UsersService);
|
||||
//# sourceMappingURL=users.service.js.map
|
||||
1
apps/api/dist/users/users.service.js.map
vendored
Normal file
1
apps/api/dist/users/users.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"users.service.js","sourceRoot":"","sources":["../../src/users/users.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAC5C,6DAAyD;AACzD,mDAAoD;AAG7C,IAAM,YAAY,GAAlB,MAAM,YAAY;IACH;IAApB,YAAoB,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAE7C,KAAK,CAAC,EAAE;QACN,MAAM,MAAM,GAAG,IAAA,yBAAa,GAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IAChE,CAAC;CACF,CAAA;AAPY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAEiB,8BAAa;GAD9B,YAAY,CAOxB"}
|
||||
87
apps/api/dist/wallets/wallets.controller.d.ts
vendored
Normal file
87
apps/api/dist/wallets/wallets.controller.d.ts
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
import { WalletsService } from './wallets.service';
|
||||
import { TransactionsService } from '../transactions/transactions.service';
|
||||
export declare class WalletsController {
|
||||
private readonly wallets;
|
||||
private readonly transactions;
|
||||
constructor(wallets: WalletsService, transactions: TransactionsService);
|
||||
list(): import("@prisma/client").Prisma.PrismaPromise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}[]>;
|
||||
getAllTransactions(): Promise<{
|
||||
category: string | null;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
userId: string;
|
||||
amount: import("@prisma/client/runtime/library").Decimal;
|
||||
direction: string;
|
||||
date: Date;
|
||||
memo: string | null;
|
||||
walletId: string;
|
||||
recurrenceId: string | null;
|
||||
}[]>;
|
||||
create(body: {
|
||||
name: string;
|
||||
currency?: string;
|
||||
kind?: 'money' | 'asset';
|
||||
unit?: string;
|
||||
initialAmount?: number;
|
||||
pricePerUnit?: number;
|
||||
}): import("@prisma/client").Prisma.Prisma__WalletClient<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}, never, import("@prisma/client/runtime/library").DefaultArgs, import("@prisma/client").Prisma.PrismaClientOptions> | {
|
||||
error: string;
|
||||
};
|
||||
update(id: string, body: {
|
||||
name?: string;
|
||||
currency?: string;
|
||||
kind?: 'money' | 'asset';
|
||||
unit?: string;
|
||||
initialAmount?: number;
|
||||
pricePerUnit?: number;
|
||||
}): import("@prisma/client").Prisma.Prisma__WalletClient<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}, never, import("@prisma/client/runtime/library").DefaultArgs, import("@prisma/client").Prisma.PrismaClientOptions>;
|
||||
delete(id: string): import("@prisma/client").Prisma.Prisma__WalletClient<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}, never, import("@prisma/client/runtime/library").DefaultArgs, import("@prisma/client").Prisma.PrismaClientOptions>;
|
||||
}
|
||||
85
apps/api/dist/wallets/wallets.controller.js
vendored
Normal file
85
apps/api/dist/wallets/wallets.controller.js
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WalletsController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const wallets_service_1 = require("./wallets.service");
|
||||
const transactions_service_1 = require("../transactions/transactions.service");
|
||||
let WalletsController = class WalletsController {
|
||||
wallets;
|
||||
transactions;
|
||||
constructor(wallets, transactions) {
|
||||
this.wallets = wallets;
|
||||
this.transactions = transactions;
|
||||
}
|
||||
list() {
|
||||
return this.wallets.list();
|
||||
}
|
||||
async getAllTransactions() {
|
||||
return this.transactions.listAll();
|
||||
}
|
||||
create(body) {
|
||||
if (!body?.name) {
|
||||
return { error: 'name is required' };
|
||||
}
|
||||
return this.wallets.create(body);
|
||||
}
|
||||
update(id, body) {
|
||||
return this.wallets.update(id, body);
|
||||
}
|
||||
delete(id) {
|
||||
return this.wallets.delete(id);
|
||||
}
|
||||
};
|
||||
exports.WalletsController = WalletsController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", void 0)
|
||||
], WalletsController.prototype, "list", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('transactions'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], WalletsController.prototype, "getAllTransactions", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], WalletsController.prototype, "create", null);
|
||||
__decorate([
|
||||
(0, common_1.Put)(':id'),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], WalletsController.prototype, "update", null);
|
||||
__decorate([
|
||||
(0, common_1.Delete)(':id'),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], WalletsController.prototype, "delete", null);
|
||||
exports.WalletsController = WalletsController = __decorate([
|
||||
(0, common_1.Controller)('wallets'),
|
||||
__metadata("design:paramtypes", [wallets_service_1.WalletsService,
|
||||
transactions_service_1.TransactionsService])
|
||||
], WalletsController);
|
||||
//# sourceMappingURL=wallets.controller.js.map
|
||||
1
apps/api/dist/wallets/wallets.controller.js.map
vendored
Normal file
1
apps/api/dist/wallets/wallets.controller.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wallets.controller.js","sourceRoot":"","sources":["../../src/wallets/wallets.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAiF;AACjF,uDAAmD;AACnD,+EAA2E;AAGpE,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAET;IACA;IAFnB,YACmB,OAAuB,EACvB,YAAiC;QADjC,YAAO,GAAP,OAAO,CAAgB;QACvB,iBAAY,GAAZ,YAAY,CAAqB;IACjD,CAAC;IAGJ,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAGK,AAAN,KAAK,CAAC,kBAAkB;QACtB,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC;IAGD,MAAM,CAAS,IAAiI;QAC9I,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;YAChB,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC;QACvC,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAGD,MAAM,CAAc,EAAU,EAAU,IAAkI;QACxK,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC;IAGD,MAAM,CAAc,EAAU;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;CACF,CAAA;AAjCY,8CAAiB;AAO5B;IADC,IAAA,YAAG,GAAE;;;;6CAGL;AAGK;IADL,IAAA,YAAG,EAAC,cAAc,CAAC;;;;2DAGnB;AAGD;IADC,IAAA,aAAI,GAAE;IACC,WAAA,IAAA,aAAI,GAAE,CAAA;;;;+CAKb;AAGD;IADC,IAAA,YAAG,EAAC,KAAK,CAAC;IACH,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;+CAEtC;AAGD;IADC,IAAA,eAAM,EAAC,KAAK,CAAC;IACN,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;+CAElB;4BAhCU,iBAAiB;IAD7B,IAAA,mBAAU,EAAC,SAAS,CAAC;qCAGQ,gCAAc;QACT,0CAAmB;GAHzC,iBAAiB,CAiC7B"}
|
||||
2
apps/api/dist/wallets/wallets.module.d.ts
vendored
Normal file
2
apps/api/dist/wallets/wallets.module.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare class WalletsModule {
|
||||
}
|
||||
26
apps/api/dist/wallets/wallets.module.js
vendored
Normal file
26
apps/api/dist/wallets/wallets.module.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WalletsModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const wallets_service_1 = require("./wallets.service");
|
||||
const wallets_controller_1 = require("./wallets.controller");
|
||||
const transactions_service_1 = require("../transactions/transactions.service");
|
||||
const prisma_module_1 = require("../prisma/prisma.module");
|
||||
let WalletsModule = class WalletsModule {
|
||||
};
|
||||
exports.WalletsModule = WalletsModule;
|
||||
exports.WalletsModule = WalletsModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [prisma_module_1.PrismaModule],
|
||||
providers: [wallets_service_1.WalletsService, transactions_service_1.TransactionsService],
|
||||
controllers: [wallets_controller_1.WalletsController],
|
||||
exports: [wallets_service_1.WalletsService],
|
||||
})
|
||||
], WalletsModule);
|
||||
//# sourceMappingURL=wallets.module.js.map
|
||||
1
apps/api/dist/wallets/wallets.module.js.map
vendored
Normal file
1
apps/api/dist/wallets/wallets.module.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wallets.module.js","sourceRoot":"","sources":["../../src/wallets/wallets.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uDAAmD;AACnD,6DAAyD;AACzD,+EAA2E;AAC3E,2DAAuD;AAQhD,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IANzB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,CAAC;QACvB,SAAS,EAAE,CAAC,gCAAc,EAAE,0CAAmB,CAAC;QAChD,WAAW,EAAE,CAAC,sCAAiB,CAAC;QAChC,OAAO,EAAE,CAAC,gCAAc,CAAC;KAC1B,CAAC;GACW,aAAa,CAAG"}
|
||||
72
apps/api/dist/wallets/wallets.service.d.ts
vendored
Normal file
72
apps/api/dist/wallets/wallets.service.d.ts
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
export declare class WalletsService {
|
||||
private prisma;
|
||||
constructor(prisma: PrismaService);
|
||||
private userId;
|
||||
list(): import("@prisma/client").Prisma.PrismaPromise<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}[]>;
|
||||
create(input: {
|
||||
name: string;
|
||||
currency?: string;
|
||||
kind?: 'money' | 'asset';
|
||||
unit?: string;
|
||||
initialAmount?: number;
|
||||
pricePerUnit?: number;
|
||||
}): import("@prisma/client").Prisma.Prisma__WalletClient<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}, never, import("@prisma/client/runtime/library").DefaultArgs, import("@prisma/client").Prisma.PrismaClientOptions>;
|
||||
update(id: string, input: {
|
||||
name?: string;
|
||||
currency?: string;
|
||||
kind?: 'money' | 'asset';
|
||||
unit?: string;
|
||||
initialAmount?: number;
|
||||
pricePerUnit?: number;
|
||||
}): import("@prisma/client").Prisma.Prisma__WalletClient<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}, never, import("@prisma/client/runtime/library").DefaultArgs, import("@prisma/client").Prisma.PrismaClientOptions>;
|
||||
delete(id: string): import("@prisma/client").Prisma.Prisma__WalletClient<{
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
userId: string;
|
||||
kind: string;
|
||||
currency: string | null;
|
||||
unit: string | null;
|
||||
initialAmount: import("@prisma/client/runtime/library").Decimal | null;
|
||||
pricePerUnit: import("@prisma/client/runtime/library").Decimal | null;
|
||||
deletedAt: Date | null;
|
||||
}, never, import("@prisma/client/runtime/library").DefaultArgs, import("@prisma/client").Prisma.PrismaClientOptions>;
|
||||
}
|
||||
86
apps/api/dist/wallets/wallets.service.js
vendored
Normal file
86
apps/api/dist/wallets/wallets.service.js
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WalletsService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("../prisma/prisma.service");
|
||||
const user_util_1 = require("../common/user.util");
|
||||
let WalletsService = class WalletsService {
|
||||
prisma;
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
userId() {
|
||||
return (0, user_util_1.getTempUserId)();
|
||||
}
|
||||
list() {
|
||||
return this.prisma.wallet.findMany({
|
||||
where: { userId: this.userId(), deletedAt: null },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
});
|
||||
}
|
||||
create(input) {
|
||||
const kind = input.kind ?? 'money';
|
||||
return this.prisma.wallet.create({
|
||||
data: {
|
||||
userId: this.userId(),
|
||||
name: input.name,
|
||||
kind,
|
||||
currency: kind === 'money' ? (input.currency ?? 'IDR') : null,
|
||||
unit: kind === 'asset' ? (input.unit ?? null) : null,
|
||||
initialAmount: input.initialAmount || null,
|
||||
pricePerUnit: kind === 'asset' ? (input.pricePerUnit || null) : null,
|
||||
},
|
||||
});
|
||||
}
|
||||
update(id, input) {
|
||||
const updateData = {};
|
||||
if (input.name !== undefined)
|
||||
updateData.name = input.name;
|
||||
if (input.kind !== undefined) {
|
||||
updateData.kind = input.kind;
|
||||
if (input.kind === 'money') {
|
||||
updateData.currency = input.currency ?? 'IDR';
|
||||
updateData.unit = null;
|
||||
}
|
||||
else {
|
||||
updateData.unit = input.unit ?? null;
|
||||
updateData.currency = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (input.currency !== undefined)
|
||||
updateData.currency = input.currency;
|
||||
if (input.unit !== undefined)
|
||||
updateData.unit = input.unit;
|
||||
}
|
||||
if (input.initialAmount !== undefined)
|
||||
updateData.initialAmount = input.initialAmount || null;
|
||||
if (input.pricePerUnit !== undefined)
|
||||
updateData.pricePerUnit = input.pricePerUnit || null;
|
||||
return this.prisma.wallet.update({
|
||||
where: { id, userId: this.userId() },
|
||||
data: updateData,
|
||||
});
|
||||
}
|
||||
delete(id) {
|
||||
return this.prisma.wallet.update({
|
||||
where: { id, userId: this.userId() },
|
||||
data: { deletedAt: new Date() },
|
||||
});
|
||||
}
|
||||
};
|
||||
exports.WalletsService = WalletsService;
|
||||
exports.WalletsService = WalletsService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], WalletsService);
|
||||
//# sourceMappingURL=wallets.service.js.map
|
||||
1
apps/api/dist/wallets/wallets.service.js.map
vendored
Normal file
1
apps/api/dist/wallets/wallets.service.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"wallets.service.js","sourceRoot":"","sources":["../../src/wallets/wallets.service.ts"],"names":[],"mappings":"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"}
|
||||
34
apps/api/eslint.config.mjs
Normal file
34
apps/api/eslint.config.mjs
Normal file
@@ -0,0 +1,34 @@
|
||||
// @ts-check
|
||||
import eslint from '@eslint/js';
|
||||
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ['eslint.config.mjs'],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
eslintPluginPrettierRecommended,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.jest,
|
||||
},
|
||||
sourceType: 'commonjs',
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn'
|
||||
},
|
||||
},
|
||||
);
|
||||
8
apps/api/nest-cli.json
Normal file
8
apps/api/nest-cli.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
12272
apps/api/package-lock.json
generated
Normal file
12272
apps/api/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
87
apps/api/package.json
Normal file
87
apps/api/package.json
Normal file
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"name": "api",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"dev": "nest start --watch",
|
||||
"prisma:generate": "prisma generate",
|
||||
"postinstall": "prisma generate",
|
||||
"seed": "ts-node src/seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/config": "^4.0.2",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/swagger": "^11.2.0",
|
||||
"@prisma/client": "^6.17.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.2",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"firebase-admin": "^13.5.0",
|
||||
"jose": "^6.0.12",
|
||||
"pg": "^8.16.3",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"zod": "^4.0.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@nestjs/cli": "^11.0.10",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^22.10.7",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-prettier": "^5.2.2",
|
||||
"globals": "^16.0.0",
|
||||
"jest": "^30.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prisma": "^6.14.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-loader": "^9.5.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.20.0"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'active',
|
||||
"email" TEXT,
|
||||
"name" TEXT,
|
||||
"avatarUrl" TEXT,
|
||||
"defaultCurrency" TEXT,
|
||||
"timeZone" TEXT,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."AuthAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"issuer" TEXT NOT NULL,
|
||||
"subject" TEXT NOT NULL,
|
||||
"lastLogin" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AuthAccount_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"ip" TEXT,
|
||||
"userAgent" TEXT,
|
||||
"revokedAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."Wallet" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"kind" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"currency" TEXT,
|
||||
"unit" TEXT,
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Wallet_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."Transaction" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"walletId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"date" TIMESTAMP(3) NOT NULL,
|
||||
"amount" DECIMAL(18,2) NOT NULL,
|
||||
"direction" TEXT NOT NULL,
|
||||
"category" TEXT,
|
||||
"memo" TEXT,
|
||||
"recurrenceId" TEXT,
|
||||
|
||||
CONSTRAINT "Transaction_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."Recurrence" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"rule" TEXT NOT NULL,
|
||||
"nextRunAt" TIMESTAMP(3) NOT NULL,
|
||||
"lastRunAt" TIMESTAMP(3),
|
||||
"idempotency" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Recurrence_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "public"."CurrencyRate" (
|
||||
"id" TEXT NOT NULL,
|
||||
"base" TEXT NOT NULL,
|
||||
"quote" TEXT NOT NULL,
|
||||
"at" TIMESTAMP(3) NOT NULL,
|
||||
"rate" DECIMAL(18,6) NOT NULL,
|
||||
|
||||
CONSTRAINT "CurrencyRate_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "public"."User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "AuthAccount_userId_idx" ON "public"."AuthAccount"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "AuthAccount_issuer_subject_key" ON "public"."AuthAccount"("issuer", "subject");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Session_userId_idx" ON "public"."Session"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Wallet_userId_idx" ON "public"."Wallet"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Transaction_userId_walletId_date_idx" ON "public"."Transaction"("userId", "walletId", "date");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Recurrence_idempotency_key" ON "public"."Recurrence"("idempotency");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Recurrence_userId_idx" ON "public"."Recurrence"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CurrencyRate_base_quote_idx" ON "public"."CurrencyRate"("base", "quote");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CurrencyRate_base_quote_at_key" ON "public"."CurrencyRate"("base", "quote", "at");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."AuthAccount" ADD CONSTRAINT "AuthAccount_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Wallet" ADD CONSTRAINT "Wallet_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Transaction" ADD CONSTRAINT "Transaction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Transaction" ADD CONSTRAINT "Transaction_walletId_fkey" FOREIGN KEY ("walletId") REFERENCES "public"."Wallet"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "public"."Recurrence" ADD CONSTRAINT "Recurrence_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
3
apps/api/prisma/migrations/migration_lock.toml
Normal file
3
apps/api/prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
123
apps/api/prisma/schema.prisma
Normal file
123
apps/api/prisma/schema.prisma
Normal file
@@ -0,0 +1,123 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
status String @default("active")
|
||||
email String? @unique
|
||||
name String?
|
||||
avatarUrl String?
|
||||
defaultCurrency String?
|
||||
timeZone String?
|
||||
authAccounts AuthAccount[]
|
||||
categories Category[]
|
||||
Recurrence Recurrence[]
|
||||
sessions Session[]
|
||||
transactions Transaction[]
|
||||
wallets Wallet[]
|
||||
}
|
||||
|
||||
model AuthAccount {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
provider String
|
||||
issuer String
|
||||
subject String
|
||||
lastLogin DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@unique([issuer, subject])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime
|
||||
ip String?
|
||||
userAgent String?
|
||||
revokedAt DateTime?
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Wallet {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
kind String
|
||||
name String
|
||||
currency String?
|
||||
unit String?
|
||||
initialAmount Decimal? @db.Decimal(18, 2)
|
||||
pricePerUnit Decimal? @db.Decimal(18, 2)
|
||||
deletedAt DateTime?
|
||||
transactions Transaction[]
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
name String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@unique([userId, name])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Transaction {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
walletId String
|
||||
createdAt DateTime @default(now())
|
||||
date DateTime
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
direction String
|
||||
category String?
|
||||
memo String?
|
||||
recurrenceId String?
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
wallet Wallet @relation(fields: [walletId], references: [id])
|
||||
|
||||
@@index([userId, walletId, date])
|
||||
}
|
||||
|
||||
model Recurrence {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
rule String
|
||||
nextRunAt DateTime
|
||||
lastRunAt DateTime?
|
||||
idempotency String @unique
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model CurrencyRate {
|
||||
id String @id @default(uuid())
|
||||
base String
|
||||
quote String
|
||||
at DateTime
|
||||
rate Decimal @db.Decimal(18, 6)
|
||||
|
||||
@@unique([base, quote, at])
|
||||
@@index([base, quote])
|
||||
}
|
||||
22
apps/api/src/app.controller.spec.ts
Normal file
22
apps/api/src/app.controller.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
||||
12
apps/api/src/app.controller.ts
Normal file
12
apps/api/src/app.controller.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
getHello(): string {
|
||||
return this.appService.getHello();
|
||||
}
|
||||
}
|
||||
31
apps/api/src/app.module.ts
Normal file
31
apps/api/src/app.module.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import * as path from 'path';
|
||||
import { PrismaModule } from './prisma/prisma.module';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { HealthController } from './health/health.controller';
|
||||
import { UsersModule } from './users/users.module';
|
||||
import { WalletsModule } from './wallets/wallets.module';
|
||||
import { TransactionsModule } from './transactions/transactions.module';
|
||||
import { CategoriesModule } from './categories/categories.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: [
|
||||
path.resolve(process.cwd(), '.env'),
|
||||
path.resolve(process.cwd(), '../../.env'),
|
||||
],
|
||||
}),
|
||||
PrismaModule,
|
||||
AuthModule,
|
||||
UsersModule,
|
||||
WalletsModule,
|
||||
TransactionsModule,
|
||||
CategoriesModule,
|
||||
],
|
||||
controllers: [HealthController],
|
||||
providers: [],
|
||||
})
|
||||
export class AppModule {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user