Document Control
Version | Description | Date |
---|---|---|
1.0.0 | Init document | 30 Jan 2024 |
I. Overview
xStreamer comes with 3 big parts
API server
Frontend web server (aka front office, user)
Backend web server (aka back office, admin)
II. Details
...
With structures above we can see xStreamer split applications to smaller modules, each module is responsible the app logic
Modules | Description |
---|---|
Auth | Service provides APIs to execute all use-cases related to authentication and authorization such as Sign In, Sign Out, Access Token Verification and User's Roles and Permissions and etc. |
User | Service provides APIs to execute all use-cases related to user domain such as Get, Edit Profile and etc |
Payment | Service provides APIs to execute all use-cases related to payment such as CCBill payment, payment history… |
File | Service provides APIs to execute all use-cases related to user domain such as convert file, create thumbnails, save file to protected folder, get file details… |
Mailer | Service provides APIs to execute all use-cases related to send mail such as create content from template, send mail in queue, etc… |
Message | Service provides APIs to execute all use-cases related to message such as public chat, group chat, private chat |
Performer | Service provides APIs to execute all use-cases related to performer domain such as Get, Edit Profile and etc |
Assets | Service provides APIs to execute all use-cases related to performer domain such as Get, Edit, Upload media data, etc… |
Stream | Service provides APIs to execute all use-cases related to stream such as create connection to ant media |
Socket | Service provides method to communicate between server and browser in with real time message |
Settings | Service provides APIs to execute all user-cases related to settings such as update config, get public config |
Statistic | Service provides API to execute all user-cases related to statistic |
Utils | Service provides common APIs which using among services |
… |
|
1.2 Module structure
A general module will come with below structure.
...
Code Block |
---|
src --app ---layout.tsx ---account -----page.tsx ---videos ----page.tsx --components --interfaces --lib @types style --default.scss public --fonts --icons --sounds --image-file.png --... |
# | Description |
---|---|
src | Contains React components, Redux storage, Socket handler which we use in the app. Written with typescript Check here for nextJS structure |
style | Provide definition of style in the app such as color, font weight… |
public | Contains public static files such as icons, images, sounds |
3. Backend web
Frontend web use NextJS as a main framework, Ant design for UI components with structure is same Frontend web
...
Code Block |
---|
import { Body, Controller, Post, UsePipes, ValidationPipe } from '@nestjs/common'; import { DataResponse } from 'src/core'; import { LoginPasswordPayload } from 'src/payloads'; import { AuthService } from 'src/services'; @Controller('/auth/login') export class LoginController { constructor( private authService: AuthService ) {} @Post() @UsePipes(new ValidationPipe({ transform: true, whitelist: true })) async register( @Body() payload: LoginPasswordPayload ) { const res = await this.authService.loginWithPassword(payload); return DataResponse.ok(res); } } |
Login form
Code Block |
---|
'use client'; import Link from 'next/link'; import { Formik, Form, Field, FieldProps } from 'formik'; import { signIn } from 'next-auth/react'; import { useTranslation } from 'react-i18next'; import * as yup from 'yup'; import { FormItem, Input } from '@components/ui/form'; import { useState } from 'react'; import { FormattedMessage } from '@components/i18n'; import { useMainThemeLayout } from 'src/providers/main-layout.provider'; const schema = yup.object().shape({ username: yup.string().required('Username is required!'), password: yup.string().required('Password is required!') }); export default function Login() { const { t } = useTranslation(); const [error, setError] = useState<string | null>(); const { register, forgotPassword, closePopup } = useMainThemeLayout(); return ( <div className="w-full space-y-5 p-10 text-center"> <Link href="/" className="font-bold text-4xl text-center"> xStreamer </Link> <h2 className="text-center text-2xl font-bold leading-9 tracking-tigh"> {t('signin', 'Sign in')} </h2> <Formik initialValues={{ username: '', password: '' }} validationSchema={schema} onSubmit={async (values, actions) => { const res = await signIn('credentials', { ...values, redirect: false }); if (res && res.ok) { closePopup(); // loadProfile(); return; } setError(res!.error); actions.setSubmitting(false); }} > {({ handleSubmit }) => ( <Form className="space-y-3" onSubmit={handleSubmit}> <Field name="username"> {({ field, meta }: FieldProps) => ( <FormItem> <Input placeholder="Username" {...field} /> {meta.touched && !!meta.error && ( <FormItem.Error>{meta.error}</FormItem.Error> )} </FormItem> )} </Field> <div> <Field name="password"> {({ field, meta }: FieldProps) => ( <FormItem> <Input type="password" placeholder="Password" {...field} /> {meta.touched && !!meta.error && ( <FormItem.Error>{meta.error}</FormItem.Error> )} </FormItem> )} </Field> </div> <div className="flex items-center justify-between"> <div className="text-sm text-primary"> <button onClick={forgotPassword} role="button" type="button"> <FormattedMessage id="forgotPassword" defaultValue="Forgot password" subifx="?" /> </button> </div> </div> {error && ( <div className="bg-red-100 dark:bg-red-950 border border-red-900 text-red-700 dark:text-white px-4 py-3 rounded relative" role="alert" > <span className="text-sm font-medium">{error}</span> </div> )} <div className="text-center"> <button type="submit" className="rounded-md bg-orange-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-orange-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-orange-600" > {t('signin', 'Sign in')} </button> </div> </Form> )} </Formik> <p className="mt-10 text-center text-sm text-gray-500"> Don't have an account? {' '} <a onClick={register} className="font-semibold leading-6 cursor-pointer hover:text-primary" > {t('signup', 'Sign Up')} </a> </p> </div> ); } |