GitHub Copilot을 활용하여 Stock App을 초신속하게 생성하는 방법을 설명합니다.
Stock 앱을 위해 필요 정보 수집
Stock App 디자인 하기
- 샘플 스크린샷 기반으로 모으기
- Figma 디자인 하기
Stock Data 가져오기
- Nasdaq 정보 수집
- symbol 수집: 검색엔진 또는 M365 Copilot으로 검색 → ftp.nasdaq에서 파일 수집
- 실시간 api 수집: alphavantage API를 이용하여 준실시간 데이터 가져오기
기능 구현하기
- VS Code 세팅
- Figma → Web source 가져오기
- Azure Infra 만들기 (어플리케이션에 대한 정보 설명)
내가 주식 관련한 웹 앱을 만들기 위해서 stock symbol을 검색할 수 있는 시스템을 만들고 싶어. 그래서 첨부한 파일을 기반으로 Azure에서 검색 가능하도록 API를 구성하고 싶거든. 예를 들면, Web 검색창에서 Microsoft를 검색하면 MSFT Symbol을 추천해주는 형태야. 물론 MSFT로 검색이 되어도 좋고, MS만 치더라도 MSFT가 추천되어 나오는걸 기대해. 그래서 위 파일의 내용을 DB에 두고, 검색이 되게끔 만들고 싶은데, 검색 조건으로 유의어도 자동으로 연동될 수 있도록 구성하고 싶어. 예를 들면 처음에는 위 리스트 기반으로 DB에 저장 되지만, 나중에는 해당 데이터 기반 유의어도 검색되도록 업데이트를 할 수 있는 구조를 가져가고 싶어. 이를 위해서 Azure에서 조합해서 쓸 수 있는 서비스들과 아키텍처를 추천해줘.
- { Bicep 몇번이나 에러가 났음. 이 부분에 대해서는 몇 번 반복하면서 최소화 할 수 있도록 노력 필요
param location string = resourceGroup().location @minLength(2) @maxLength(24) param searchServiceName string = 'stocksearch${uniqueString(resourceGroup().id)}' @minLength(3) @maxLength(44) param cosmosAccountName string = 'stockcosmos${uniqueString(resourceGroup().id)}' param cosmosDatabaseName string = 'stockdb' param cosmosContainerName string = 'tickers' @minLength(3) @maxLength(24) param storageAccountName string = 'stockstore${uniqueString(resourceGroup().id)}' param functionAppName string = 'stockfunc-${uniqueString(resourceGroup().id)}' param appInsightsName string = 'stockai-${uniqueString(resourceGroup().id)}' param keyVaultName string = 'stockkv-${uniqueString(resourceGroup().id)}' var functionRuntimeVersion = '~4' var functionWorkerRuntime = 'node' resource search 'Microsoft.Search/searchServices@2023-11-01' = { name: searchServiceName location: location sku: { name: 'basic' } properties: { replicaCount: 1 partitionCount: 1 hostingMode: 'default' networkRuleSet: { ipRules: [] } } } resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = { name: cosmosAccountName location: location kind: 'GlobalDocumentDB' properties: { databaseAccountOfferType: 'Standard' locations: [ { locationName: location failoverPriority: 0 isZoneRedundant: false } ] consistencyPolicy: { defaultConsistencyLevel: 'Session' } capabilities: [ { name: 'EnableServerless' } ] ipRules: [] isVirtualNetworkFilterEnabled: false publicNetworkAccess: 'Enabled' } } resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2024-05-15' = { parent: cosmosAccount name: cosmosDatabaseName properties: { resource: { id: cosmosDatabaseName } } } resource cosmosContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2024-05-15' = { parent: cosmosDb name: cosmosContainerName properties: { resource: { id: cosmosContainerName partitionKey: { paths: ['/symbol'] kind: 'Hash' } indexingPolicy: { indexingMode: 'consistent' automatic: true includedPaths: [{ path: '/*' }] excludedPaths: [{ path: '/"searchVector"/*' }] } } options: {} } } resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: storageAccountName location: location sku: { name: 'Standard_LRS' } kind: 'StorageV2' properties: { supportsHttpsTrafficOnly: true allowBlobPublicAccess: false minimumTlsVersion: 'TLS1_2' } } resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: appInsightsName location: location kind: 'web' properties: { Application_Type: 'web' Flow_Type: 'Bluefield' Request_Source: 'rest' } } resource hostingPlan 'Microsoft.Web/serverfarms@2022-09-01' = { name: 'plan-${functionAppName}' location: location sku: { name: 'Y1' tier: 'Dynamic' size: 'Y1' family: 'Y' capacity: 0 } properties: { reserved: false targetWorkerCount: 0 targetWorkerSizeId: 0 } } resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = { parent: storage name: 'default' } resource functionStorage 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = { parent: blobService name: '$web' properties: { publicAccess: 'None' } } resource functionApp 'Microsoft.Web/sites@2022-09-01' = { name: functionAppName location: location kind: 'functionapp' identity: { type: 'SystemAssigned' } properties: { serverFarmId: hostingPlan.id httpsOnly: true siteConfig: { appSettings: [ { name: 'AzureWebJobsStorage' value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storage.listKeys().keys[0].value}' } { name: 'FUNCTIONS_EXTENSION_VERSION' value: functionRuntimeVersion } { name: 'FUNCTIONS_WORKER_RUNTIME' value: functionWorkerRuntime } { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' value: appInsights.properties.InstrumentationKey } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: appInsights.properties.ConnectionString } { name: 'WEBSITE_RUN_FROM_PACKAGE' value: '0' } ] } } } resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = { name: keyVaultName location: location properties: { sku: { name: 'standard' family: 'A' } tenantId: subscription().tenantId enableSoftDelete: true publicNetworkAccess: 'Enabled' enabledForTemplateDeployment: true accessPolicies: [ { tenantId: subscription().tenantId objectId: functionApp.identity.principalId permissions: { secrets: [ 'Get' 'List' ] } } ] } }