feat: subscriptions
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\IdentityVerificationStatus;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\IdentityVerificationRequest>
|
||||
*/
|
||||
class IdentityVerificationRequestFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'status' => IdentityVerificationStatus::PENDING,
|
||||
'document_disk' => 'identity_documents',
|
||||
'document_path' => 'submissions/'.fake()->uuid().'.jpg',
|
||||
'document_mime_type' => 'image/jpeg',
|
||||
'document_size' => fake()->numberBetween(100_000, 2_000_000),
|
||||
'submitted_at' => now(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('identity_verification_requests', function (Blueprint $table): void {
|
||||
$table->ulid('id')->primary();
|
||||
$table->foreignUlid('user_id')->unique()->constrained('users')->cascadeOnDelete();
|
||||
$table->string('status', 32)->default('pending')->index();
|
||||
$table->string('document_disk');
|
||||
$table->string('document_path', 2048)->nullable();
|
||||
$table->string('document_mime_type', 128);
|
||||
$table->unsignedBigInteger('document_size');
|
||||
$table->timestampTz('submitted_at')->index();
|
||||
$table->timestampTz('reviewed_at')->nullable();
|
||||
$table->foreignUlid('reviewed_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->text('rejection_reason')->nullable();
|
||||
$table->timestampTz('document_deleted_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('identity_verification_requests');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table): void {
|
||||
$table->timestampTz('certification_purchased_at')
|
||||
->nullable()
|
||||
->after('account_verified_at')
|
||||
->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table): void {
|
||||
$table->dropColumn('certification_purchased_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('credit_products', function (Blueprint $table): void {
|
||||
$table->string('purpose', 32)->nullable()->after('type')->unique();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('credit_products', function (Blueprint $table): void {
|
||||
$table->dropColumn('purpose');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -14,7 +14,7 @@ class LegalDocumentSeeder extends Seeder
|
||||
public function run(): void
|
||||
{
|
||||
LegalDocument::query()->updateOrCreate(
|
||||
['slug' => 'privacy-policy', 'version' => 1],
|
||||
['slug' => 'privacy-policy', 'version' => 2],
|
||||
[
|
||||
'type' => LegalDocumentType::PRIVACY_POLICY,
|
||||
'title' => [
|
||||
@@ -51,7 +51,20 @@ class LegalDocumentSeeder extends Seeder
|
||||
'title' => 'Notifications et appareil',
|
||||
'body' => [
|
||||
'Si tu actives les notifications, Bowli enregistre un token Expo Push pour envoyer des notifications liées à ton compte.',
|
||||
'La caméra et la bibliothèque photo ne sont utilisées que lorsque tu choisis d’ajouter une image à un repas ou à ton profil.',
|
||||
'La caméra et la bibliothèque photo ne sont utilisées que lorsque tu choisis d’ajouter une image à un repas, à ton profil ou à une demande de certification.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'title' => 'Certification et pièce d’identité',
|
||||
'body' => [
|
||||
'Si tu achètes la certification et demandes le badge, Bowli traite la photo de ta pièce d’identité uniquement pour vérifier que ton profil correspond à une personne réelle.',
|
||||
'Le document est stocké dans un espace privé chiffré, accessible uniquement aux administrateurs autorisés par un lien temporaire, puis supprimé après l’acceptation ou le refus. Le statut de la vérification et sa date sont conservés avec ton compte.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'title' => 'Paiements et abonnements',
|
||||
'body' => [
|
||||
'Stripe traite les paiements, les abonnements, les factures et les informations de moyen de paiement. Bowli conserve uniquement les identifiants et statuts nécessaires au suivi de la transaction et de tes droits d’accès.',
|
||||
],
|
||||
],
|
||||
[
|
||||
@@ -69,7 +82,7 @@ class LegalDocumentSeeder extends Seeder
|
||||
);
|
||||
|
||||
LegalDocument::query()->updateOrCreate(
|
||||
['slug' => 'terms-of-service', 'version' => 1],
|
||||
['slug' => 'terms-of-service', 'version' => 2],
|
||||
[
|
||||
'type' => LegalDocumentType::TERMS,
|
||||
'title' => [
|
||||
@@ -102,6 +115,13 @@ class LegalDocumentSeeder extends Seeder
|
||||
'Tu t’engages à ne pas publier de contenu illégal, trompeur, haineux, violent, discriminatoire, attentatoire à la vie privée ou aux droits de tiers.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'title' => 'Essai, abonnement et certification',
|
||||
'body' => [
|
||||
'La publication de plats reste accessible sans abonnement. L’analyse automatique des photos est accessible pendant la période d’essai indiquée dans l’application, puis avec l’unique formule d’abonnement active.',
|
||||
'La certification est un achat unique distinct de l’abonnement. Le paiement donne le droit de soumettre une demande, mais le badge n’est accordé qu’après vérification d’une pièce d’identité valide. En cas de refus, une nouvelle pièce peut être envoyée sans nouvel achat.',
|
||||
],
|
||||
],
|
||||
[
|
||||
'title' => 'Modération et disponibilité',
|
||||
'body' => [
|
||||
|
||||
Reference in New Issue
Block a user