Bygg NeuroSemantics AI: minimal mobilapp, en backend, IaC och CI/CD
Ersätter den tidigare webappen på denna branch med ett fokuserat monorepo: - apps/mobile: Expo/React Native med tre vyer (Welcome, Chat, Paywall), Cognito hosted UI-inloggning (Apple/Google/e-post) och In-App Purchase/Play Billing via en gemensam purchases-modul. - services/api: en enda Lambda-backend — OpenAI Responses API med Markdown-kunskapsbas som systeminstruktioner, free tier-gräns i PostgreSQL (HTTP 402 -> paywall) och kvittoverifiering bakom ett delat PaymentProvider-interface (Apple/Google, Stripe kan läggas till för webb senare). - infra: AWS CDK-stack med API Gateway (JWT-authorizer), Lambda, Cognito, Aurora Serverless v2 och Secrets Manager. - db/migrations: minimal datamodell (users + usage), inga konversationer sparas. - GitHub Actions: CI (lint, typecheck, test) och deploy från main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0118DaxZR36RpnY524vRqx3z
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { canSendMessage, shouldResetUsage } from '../src/usage.js';
|
||||
|
||||
describe('canSendMessage', () => {
|
||||
it('allows messages under the free limit', () => {
|
||||
expect(canSendMessage(0, 'free', 50)).toBe(true);
|
||||
expect(canSendMessage(49, 'free', 50)).toBe(true);
|
||||
});
|
||||
|
||||
it('blocks free users at the limit', () => {
|
||||
expect(canSendMessage(50, 'free', 50)).toBe(false);
|
||||
expect(canSendMessage(51, 'free', 50)).toBe(false);
|
||||
});
|
||||
|
||||
it('never blocks active subscribers', () => {
|
||||
expect(canSendMessage(10_000, 'active', 50)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldResetUsage', () => {
|
||||
const day = 24 * 60 * 60 * 1000;
|
||||
|
||||
it('does not reset within the window', () => {
|
||||
const now = new Date();
|
||||
expect(shouldResetUsage(new Date(now.getTime() - 29 * day), now, 30)).toBe(false);
|
||||
});
|
||||
|
||||
it('resets once the window has passed', () => {
|
||||
const now = new Date();
|
||||
expect(shouldResetUsage(new Date(now.getTime() - 30 * day), now, 30)).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user