Skip to content

Commit d1dee58

Browse files
committed
feat(billing): implement billing plan management and usage tracking
- Introduced billing plans with associated quotas for tenants, including maximum upload sizes and processing limits. - Added new endpoints and services for managing tenant billing plans and tracking usage events. - Enhanced the dashboard with components for viewing and updating tenant plans, including a new tenant management interface. - Implemented database migrations to support billing-related data structures and relationships. - Updated documentation to reflect the new billing plan features and usage tracking capabilities. Signed-off-by: Innei <tukon479@gmail.com>
1 parent a5afd8b commit d1dee58

File tree

83 files changed

+5637
-643
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+5637
-643
lines changed

AGENTS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ class PhotoLoader {
184184
- **Manifest Building**: `pnpm run build:manifest` processes photos and updates the static `photos-manifest.json`.
185185
- **Type Safety**: Shared types between builder, SPA, and servers ensure consistency.
186186
- **Page Structure**: Keep files under `pages/` as thin routing shells; move reusable UI/logic into `modules/<domain>/**`.
187+
- **State Isolation**: When a UI feature has deep subtrees (e.g., photo library actions), do not thread handler props through multiple layers. Lift shared logic into colocated contexts or local stores (Jotai/Zustand) that expose hooks and let the consuming components trigger actions directly. This minimizes prop drilling and avoids unnecessary React re-renders.
187188

188189
### Code Quality Rules
189190

@@ -214,4 +215,4 @@ class PhotoLoader {
214215
This project contains multiple web applications with distinct design systems. For specific UI and design guidelines, please refer to the `AGENTS.md` file within each application's directory:
215216

216217
- **`apps/web`**: Contains the "Glassmorphic Depth Design System" for the main user-facing photo gallery. See `apps/web/AGENTS.md` for details.
217-
- **`be/apps/dashboard`**: Contains guidelines for the functional, data-driven UI of the administration panel. See `be/apps/dashboard/AGENTS.md` for details.
218+
- **`be/apps/dashboard`**: Contains guidelines for the functional, data-driven UI of the administration panel. See `be/apps/dashboard/AGENTS.md` for details.

apps/landing/DESIGN_SYSTEM.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,12 @@ import { spacing, typography } from '~/lib/design-tokens'
246246

247247
```tsx
248248
// Hero 渐变背景
249-
<div className="bg-gradient-to-br from-accent/40 via-purple-600/40 to-slate-900/70">
249+
<div className="bg-linear-to-br from-accent/40 via-purple-600/40 to-slate-900/70">
250250
...
251251
</div>
252252

253253
// 文字渐变
254-
<span className="bg-gradient-to-r from-sky-300 via-accent to-purple-400 bg-clip-text text-transparent">
254+
<span className="bg-linear-to-r from-sky-300 via-accent to-purple-400 bg-clip-text text-transparent">
255255
渐变文字
256256
</span>
257257
```

apps/landing/QUICK_START.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ import { FeatureCard } from '~/components/landing'
140140
'relative overflow-hidden',
141141
radius['3xl'],
142142
shadows.heavy,
143-
'bg-gradient-to-br from-accent/40 via-purple-600/40 to-slate-900/70',
143+
'bg-linear-to-br from-accent/40 via-purple-600/40 to-slate-900/70',
144144
'p-10 text-white'
145145
)}>
146146
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top,_rgba(255,255,255,0.25),_transparent_55%)] opacity-80" />

apps/landing/global.d.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/* eslint-disable @typescript-eslint/method-signature-style */
2+
/* eslint-disable @typescript-eslint/no-empty-object-type */
13
import type { FC, PropsWithChildren } from 'react'
24

35
declare global {
@@ -38,7 +40,3 @@ declare module 'react' {
3840
'data-testid'?: string
3941
}
4042
}
41-
42-
export {}
43-
44-
export {}

apps/landing/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
"packageManager": "pnpm@9.15.9",
66
"scripts": {
77
"analyze": "cross-env NODE_ENV=production ANALYZE=true BUNDLE_ANALYZE=browser next build",
8+
"prebuild": "rimraf .next || exit 0",
89
"build": "cross-env NODE_ENV=production next build",
910
"build:ci": "cross-env NODE_ENV=production CI=true next build",
1011
"dev": "cross-env NODE_ENV=development next dev --turbopack -p 1111",
1112
"lint": "eslint --cache --fix",
12-
"prebuild": "rimraf .next || exit 0",
1313
"prepare": "pnpm exec simple-git-hooks && test -f .env || cp .env.template .env",
1414
"start": "npm run dev"
1515
},

apps/landing/src/app/page.tsx

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
'use client'
22

3-
import { BackgroundDecor } from '~/components/landing/BackgroundDecor'
4-
import { CTASection } from '~/components/landing/CTASection'
5-
import { FeatureSection } from '~/components/landing/FeatureSection'
6-
import { HeroSection } from '~/components/landing/HeroSection'
7-
import { MetricStrip } from '~/components/landing/MetricStrip'
8-
import { PreviewSection } from '~/components/landing/PreviewSection'
3+
import { NocturneBackground } from '~/components/landing/NocturneBackground'
4+
import {
5+
ArtistNote,
6+
ClosingCTA,
7+
GalleryPreview,
8+
JourneySection,
9+
NocturneHero,
10+
PillarsSection,
11+
} from '~/components/landing/NocturneSections'
912
import { Footer } from '~/components/layout/Footer'
10-
import { Header } from '~/components/layout/Header'
13+
import { PageHeader } from '~/components/layout/PageHeader'
1114

1215
export default function Home() {
1316
return (
14-
<div className="bg-background text-text relative isolate overflow-hidden">
15-
<BackgroundDecor />
16-
<Header />
17-
18-
<div className="relative z-10 mx-auto flex w-full max-w-6xl flex-col gap-20 px-4 pt-32 pb-16 sm:px-6 lg:px-0">
19-
<HeroSection />
20-
<MetricStrip />
21-
<PreviewSection />
22-
<FeatureSection />
23-
<CTASection />
24-
</div>
25-
26-
<Footer />
17+
<div className="relative min-h-screen overflow-hidden bg-[#020202] text-white">
18+
<NocturneBackground />
19+
<main className="relative z-10 mx-auto flex w-full max-w-6xl flex-col gap-20 px-4 py-16 sm:px-6 lg:px-0">
20+
<PageHeader />
21+
<NocturneHero />
22+
<PillarsSection />
23+
<JourneySection />
24+
<GalleryPreview />
25+
<ArtistNote />
26+
<ClosingCTA />
27+
<Footer />
28+
</main>
2729
</div>
2830
)
2931
}

apps/landing/src/components/common/404.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
/* eslint-disable react/no-unknown-property */
21
export const NotFound404 = () => {
32
return (
4-
<div className="center flex absolute inset-0 flex-col space-y-6">
3+
<div className="center absolute inset-0 flex flex-col space-y-6">
54
<$404SVG className="size-[400px]" />
65
<p>这颗星球还没有知识哦,去其他地方探索吧</p>
76
</div>

apps/landing/src/components/landing/CTASection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const CTASection = () => (
1010
<section>
1111
<div
1212
className={clsxm(
13-
'relative overflow-hidden border border-white/10 bg-gradient-to-br from-accent/40 via-purple-600/40 to-slate-900/70 p-10 text-white',
13+
'relative overflow-hidden border border-white/10 bg-linear-to-br from-accent/40 via-purple-600/40 to-slate-900/70 p-10 text-white',
1414
radius['3xl'],
1515
)}
1616
>

apps/landing/src/components/landing/HeroSection.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const HeroSection = () => (
6363
<div className="space-y-5">
6464
<h1 className="text-4xl leading-tight font-semibold text-white sm:text-5xl lg:text-6xl">
6565
Afilmory
66-
<span className="via-accent block bg-gradient-to-r from-sky-300 to-purple-400 bg-clip-text text-transparent">
66+
<span className="via-accent block bg-linear-to-r from-sky-300 to-purple-400 bg-clip-text text-transparent">
6767
让每一张照片都值得被看见
6868
</span>
6969
</h1>
@@ -76,7 +76,7 @@ export const HeroSection = () => (
7676
<div className="flex flex-wrap items-center gap-3">
7777
<Button
7878
asChild
79-
className="to-accent text-background shadow-accent/30 min-w-[160px] bg-gradient-to-r from-sky-400 shadow-lg"
79+
className="to-accent text-background shadow-accent/30 min-w-[160px] bg-linear-to-r from-sky-400 shadow-lg"
8080
>
8181
<Link
8282
href="https://afilmory.innei.in"
@@ -190,7 +190,7 @@ const HeroPreview = () => (
190190
<m.div
191191
aria-hidden
192192
className={clsxm(
193-
'absolute bottom-6 -left-6 w-60 rounded-3xl border border-white/20 bg-gradient-to-br from-emerald-100/60 to-white/60 p-4 text-sm',
193+
'absolute bottom-6 -left-6 w-60 rounded-3xl border border-white/20 bg-linear-to-br from-emerald-100/60 to-white/60 p-4 text-sm',
194194
blur['2xl'],
195195
)}
196196
initial={{ opacity: 0, y: 20, scale: 0.95 }}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
'use client'
2+
3+
import { m } from 'motion/react'
4+
5+
import { cn } from '~/lib/cn'
6+
7+
const floatingOrbs = [
8+
{
9+
size: 360,
10+
initial: { x: -200, y: -80, opacity: 0.35 },
11+
animate: { x: -160, y: -10, opacity: 0.6 },
12+
className: 'from-[#6A4DFB]/25 via-transparent to-transparent',
13+
duration: 18,
14+
},
15+
{
16+
size: 420,
17+
initial: { x: 240, y: 120, opacity: 0.2 },
18+
animate: { x: 200, y: 60, opacity: 0.45 },
19+
className: 'from-[#CBB28B]/35 via-transparent to-transparent',
20+
duration: 24,
21+
},
22+
{
23+
size: 280,
24+
initial: { x: -40, y: 360, opacity: 0.25 },
25+
animate: { x: 10, y: 310, opacity: 0.5 },
26+
className: 'from-[#2E2A40]/60 via-transparent to-transparent',
27+
duration: 30,
28+
},
29+
]
30+
31+
const auroraBands = [
32+
{
33+
rotate: '-12deg',
34+
className: 'from-transparent via-white/5 to-transparent',
35+
delay: 0,
36+
},
37+
{
38+
rotate: '18deg',
39+
className: 'from-transparent via-purple-400/10 to-transparent',
40+
delay: 4,
41+
},
42+
]
43+
44+
export const NocturneBackground = () => {
45+
return (
46+
<div className="pointer-events-none absolute inset-0 overflow-hidden">
47+
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top,rgba(255,255,255,0.08),transparent_55%)]" />
48+
<div className="absolute inset-x-0 top-0 h-64 bg-linear-to-b from-black via-black/70 to-transparent" />
49+
50+
{floatingOrbs.map((orb, index) => (
51+
<m.div
52+
key={index}
53+
initial={orb.initial}
54+
animate={orb.animate}
55+
transition={{
56+
duration: orb.duration,
57+
repeat: Infinity,
58+
repeatType: 'mirror',
59+
ease: 'easeInOut',
60+
}}
61+
className="absolute blur-[90px]"
62+
>
63+
<div
64+
className={cn('rounded-full bg-linear-to-br', orb.className)}
65+
style={{
66+
width: orb.size,
67+
height: orb.size,
68+
}}
69+
/>
70+
</m.div>
71+
))}
72+
73+
{auroraBands.map((band) => (
74+
<m.div
75+
key={band.rotate}
76+
initial={{ opacity: 0 }}
77+
animate={{ opacity: [0.1, 0.4, 0.1], x: [-20, 20, -20] }}
78+
transition={{
79+
duration: 20,
80+
repeat: Infinity,
81+
delay: band.delay,
82+
ease: 'easeInOut',
83+
}}
84+
className="absolute inset-x-[-20%] top-1/4 h-56"
85+
style={{ rotate: band.rotate }}
86+
>
87+
<div
88+
className={cn(
89+
'h-full w-full rounded-[60px] bg-linear-to-r blur-[60px]',
90+
band.className,
91+
)}
92+
/>
93+
</m.div>
94+
))}
95+
96+
<div className="absolute inset-0 opacity-40">
97+
{Array.from({ length: 20 }).map((_, idx) => (
98+
<m.div
99+
key={idx}
100+
className="absolute h-px w-32 bg-linear-to-r from-white/10 via-white/50 to-transparent"
101+
style={{
102+
top: `${(idx * 13) % 100}%`,
103+
left: `${(idx * 27) % 100}%`,
104+
}}
105+
initial={{ opacity: 0.2 }}
106+
animate={{ opacity: [0.1, 0.4, 0.15], x: [0, 20, 0] }}
107+
transition={{
108+
duration: 12 + idx * 0.3,
109+
repeat: Infinity,
110+
repeatType: 'mirror',
111+
ease: 'easeInOut',
112+
}}
113+
/>
114+
))}
115+
</div>
116+
</div>
117+
)
118+
}

0 commit comments

Comments
 (0)